Java基础知识&面试题总结
封装、继承、多态
封装就是信息隐藏,利用抽象数据类型将数据和基于数据的操作封装在一起,数据被保护在抽象数据类型的内部,尽可能地隐藏内部的细节,只保留一些对外接口。用户是无需知道对象内部的细节,但可以通过该对象对外的提供的接口来访问该对象。
优点:
1、良好的封装能够减少耦合。
2、类内部的结构可以自由修改。
3、可以对成员进行更精确的控制。
4、隐藏信息,实现细节。
public class Husband {
/*
* 对属性的封装
* 一个人的姓名、性别、年龄、妻子都是这个人的私有属性
*/
private String name ;
private String sex ;
private int age ;
private Wife wife;
/*
* setter()、getter()是该对象对外开发的接口
*/
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public void setWife(Wife wife) {
this.wife = wife;
}
}
继承是使用已存在的类的定义作为基础建立新类的技术,新类的定义可以增加新的数据或新的功能,也可以用父类的功能,但不能选择性地继承父类。对于若干个相同或者相识的类,我们可以抽象出他们共有的行为或者属相并将其定义成一个父类或者超类,然后用这些类继承该父类,他们不仅可以拥有父类的属性、方法还可以定义自己独有的属性或者方法。
主要有以下规则:
1、子类拥有父类非private的属性和方法。
2、子类可以拥有自己属性和方法,即子类可以对父类进行扩展。
3、子类可以用自己的方式实现父类的方法。
4、向上转型,可以将子类转换成父类。
5、子类不能继承父类的构造器,可以通过super来调用。编译器可以默认给子类调用父类的构造器(父类有默认构造器,否则需要通过调用来定义子类的构造器)。
6、对于protected而言,它指明就类用户而言,他是private,但是对于任何继承与此类的子类而言或者其他任何位于同一个包的类而言,他却是可以访问的。
继承的缺陷:
1、父类变,子类就必须变。
2、继承破坏了封装,对于父类而言,它的实现细节对与子类来说都是透明的。
3、继承是一种强耦合关系。
多态指一个引用变量倒底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。
Java实现多态有三个必要条件:继承、重写、向上转型。
当超类对象引用变量引用子类对象时,被引用对象的类型而不是引用变量的类型决定了调用谁的成员方法,但是这个被调用的方法必须是在超类中定义过的,也就是说被子类覆盖的方法。
1、基于继承实现的多态(class extends)
继承父类的一个或多个子类对某些方法的重写,多个子类对同一方法的重写可以表现出不同的行为。
如果父类是抽象类,那么子类必须要实现父类中所有的抽象方法,这样该父类所有的子类一定存在统一的对外接口,但其内部的具体实现可以各异。
2、基于接口实现的多态(Interface implements)
在接口的多态中,指向接口的引用必须是指定这实现了该接口的一个类的实例程序,在运行时,根据对象引用的实际类型来执行对应的方法。
子类不可以覆盖父类的方法或者变量。即使子类定义与父类相同的变量或者函数,也会被父类取代掉。
注: 继承都是单继承,只能为一组相关的类提供一致的服务接口。但是接口可以是多继承多实现,能够对外提供一致的服务接口,具有更高的灵活性。
注:
public:公有,所有类都可以访问
protected:保护,同一类、同一包、不同包的子类可以访问
缺省:即什么都不写,同一类、同一包可以访问
private:私有,只有同一类中可访问
C++ 重载运算符和重载函数
函数重载
在同一个作用域内,可以声明几个功能类似的同名函数,但是这些同名函数的形式参数(指参数的个数、类型或者顺序)必须不同。您不能仅通过返回类型的不同来重载函数。
#include <iostream>
using namespace std;
class printData
{
public:
void print(int i) {
cout << "整数为: " << i << endl;
}
void print(double f) {
cout << "浮点数为: " << f << endl;
}
void print(char c[]) {
cout << "字符串为: " << c << endl;
}
};
int main(void)
{
printData pd;
// 输出整数
pd.print(5);
// 输出浮点数
pd.print(500.263);
// 输出字符串
char c[] = "Hello C++";
pd.print(c);
return 0;
}
结果为
整数为: 5
浮点数为: 500.263
字符串为: Hello C++
运算符重载
重载的运算符是带有特殊名称的函数,函数名是由关键字 operator 和其后要重载的运算符符号构成的。与其他函数一样,重载运算符有一个返回类型和一个参数列表。
#include <iostream>
using namespace std;
class Box
{
public:
double getVolume(void)
{
return length * breadth * height;
}
void setLength( double len )
{
length = len;
}
void setBreadth( double bre )
{
breadth = bre;
}
void setHeight( double hei )
{
height = hei;
}
// 重载 + 运算符,用于把两个 Box 对象相加
Box operator+(const Box& b)
{
Box box;
box.length = this->length + b.length;
box.breadth = this->breadth + b.breadth;
box.height = this->height + b.height;
return box;
}
private:
double length; // 长度
double breadth; // 宽度
double height; // 高度
};
// 程序的主函数
int main( )
{
Box Box1; // 声明 Box1,类型为 Box
Box Box2; // 声明 Box2,类型为 Box
Box Box3; // 声明 Box3,类型为 Box
double volume = 0.0; // 把体积存储在该变量中
// Box1 详述
Box1.setLength(6.0);
Box1.setBreadth(7.0);
Box1.setHeight(5.0);
// Box2 详述
Box2.setLength(12.0);
Box2.setBreadth(13.0);
Box2.setHeight(10.0);
// Box1 的体积
volume = Box1.getVolume();
cout << "Volume of Box1 : " << volume <<endl;
// Box2 的体积
volume = Box2.getVolume();
cout << "Volume of Box2 : " << volume <<endl;
// 把两个对象相加,得到 Box3
Box3 = Box1 + Box2;
// Box3 的体积
volume = Box3.getVolume();
cout << "Volume of Box3 : " << volume <<endl;
return 0;
}
结果为
Volume of Box1 : 210
Volume of Box2 : 1560
Volume of Box3 : 5400
for循环中的i++和++i
在Java中++i 和 i++ 是没有区别的,在for循环中,经过JVM编译优化后,不论是i++还是++i,最终执行的方式都是++i,因此执行效率是相同的
for (语句1; 语句2; 语句3) {
//代码块......
}
语句1: 在循环开始前执行
语句2: 定义运行循环的条件
语句3: 在循环已被执行之后执行(虽然++i和i++结果是一样的,但是性能不一样)
虽然++i 和 i++的结果是一样的,都是在代码块执行完成之后才执行语句3,但是二者的性能却有差别,在大量数据的前提下++i的性能要比i++的性能好,原因:
i++是在使用当前值之后再+1,需要创建一个临时的变量来转存,Java代码我们可以理解为:
int temp=i;i=i+1;
++i是直接+1,省去了对内存操作的环节,相对而言能够提高性能,Java代码我们可以理解为:
i=i+1;