面向对象的三大特性:封装、继承和多态
封装
封装的好处:
可以将类的属性分为私有和公有属性,私有属性只在本类中调用,公有属性也只提供给外调用的方法;保留调用方法不变的同时,类内部的结构是可以自由修改,而不会影响到调用者的运行结果;同时内部还可以进行一下验证性的修改,同样也不会印象调用者的运行结果。
继承
继承的好处:
提高了代码的复用性,也正是因为有了继承,才会有多态的存在。需要注意的是Java只支持单继承,不支持多继承,这点理解起来很简单,如果多个父类中定义了相同的方法,但是功能不一样的情况下,那子类就懵了,到底是用哪一个方法呢。所以java中是没有多继承的,但是java可以通过多实现来解决多继承问题。
继承后子父类成员的特点
变量的特点:
父类的成员变量私有化之后,子类依然继承,但不能直接访问。
如果子类中出现非私有的同名成员变量时,本类要访问本类中的变量用 this ,要访问父类中的同名变量,用super。
举例如下:Fu类有2个成员变量,一个私有一个公有。
public class Fu {
private int i = 1;
public int j = 2;
}
Zi类继承Fu类,子类有和Fu类同名的成员变量j,从编译和运行结果可以看出继承之后成员变量的特点。
public class Zi extends Fu{
public int j = 3;
public static void main(String[] args) {
new Zi().method();
}
private void method() {
// System.out.println(i);//编译不通过
// System.out.println(super.i);//编译不通过
System.out.println(j);//输出3
System.out.println(super.j);//输出2
System.out.println(this.j);//输出3
}
}
函数的特点
当子类中出现和父类一模一样的函数A时,当子类对象调用函数A,会运行子类函数的内容,父类中的函数会被重写。如果需要调用父类的方法时,需要使用super。
举例:Fu类中有方法Method(),
public class Fu {
public int j = 2;
public void Method() {
System.out.println("Fu");
}
}
子类中也有方法Method()
public class Zi extends Fu {
public int j = 3;
public static void main(String[] args) {
new Zi().Method();
}
public void Method() {
super.Method();//输出Fu
System.out.println("Zi");//输出Zi
}
}
从输出结果看看看出,需要调用父类的方法需要使用关键字super。
另外注意关键字super和this一样指的是类的具体对象的引用,二使用static关键字修饰过的变量或者方法,是和类本身相关的,所以如果这个时候使用this或者super去调用的话,那么编译不会通过,会抛出异常Cannot use this in a static context或者Cannot use super in a static context的异常。
关于重写(覆盖)的几点说明:
1)子类覆盖父类,必须保证子类权限大于等于父类权限,才能重写 。可以简单的理解为重写的目的是为了程序更方便高效,假设重写之后限制更多,实用性更差,那么还有什么必要去重写一个方法呢。所以必须保证子类的权限要大于父类的权限;
2)子类覆盖父类,必须保证子类抛出的异常小于父类抛出的异常。这个的理解参照上面一样的理解就好了。
这里在啰嗦一下重写和重载之间的区别:
重载:只看同名函数的参数列表,即参数的个数,位置不一样的都是重载。
重写:名字返回值类型参数等都要一样才是重写。
构造函数的特点
在对子类对象进行初始化时,父类的构造函数也会运行,那是因为子类的构造函数会隐式调用父类的空参构造函数(即super())。当父类中没有空参数的构造函数时,子类必须手动通过super语句的形式来指定要访问父类中的构造函数。当然子类的构造函数第一行也可以手动指定this语句来访问本类中的构造函数,子类中至少会有一个构造函数会访问父类中的构造函数。
举例如下:Fu类定义了一个有参数的构造方法。
public class Fu {
Fu(int m){//注意此处没有默认的构造函数了
System.out.println("Fu"+m);
}
}
Zi类中有两个构造方法,一个有参数一个没有参数,
public class Zi extends Fu {
Zi() {
// 此处必须手动调用Fu类构造方法,或者调用本类中的构造方法,如果调用本类中的构造方法,那么其他的构造方法至少要有
// 一个调用父类的构造方法,否则编译报错Implicit super constructor Fu() is undefined. Must
// explicitly invoke another constructor
System.out.println("Zi");
}
Zi(int i) {
// 同上
System.out.println("Zi" + i);
}
public static void main(String[] args) {
new Zi();
new Zi(3);
}
}
多态
多态的好处是提高了程序的扩展性,但是有一个前提条件,就是之前说过的,有继承或者实现才有多态的体现,多态体现在父类的引用指向子类的对象。
这里可以参考一个多态的经典例子:
http://blog.csdn.net/free4294/article/details/39054791
个人感觉这个例子中的问题,在实际上是很难遇到的,但是既然看到这个问题了,还是有必要去了解一下的,根据例子中给出的解释:实际上这里涉及方法调用的优先问题 ,优先级由高到低依次为:this.show(O)、super.show(O)、this.show((super)O)、super.show((super)O)。虽然这种顺序是能解释这个问题的,但是关于这个顺序目前没有在其他书籍和文献助攻看到过,这里暂且记下,以后看到了在回过头来补充补充。