前言:
子类可以继承父类(除私有化外)的全部属性和方法,当然父类的构造方法也不可以被继承,只能使用super来调用。对于父类的默认无参构造方法,子类会默认调用;但对于父类的有参构造,子类只能使用super来显示调用,且super调用的这行代码必须位于子类相应构造方法的第一行。
其实子类对象中也存在父类的私有化属性和方法,只不过子类无法直接访问这些私有属性和方法,需要通过父类的get、set方法等来调用。有人可能会问这不自相矛盾了吗,你上面不是才说了子类不可以继承父类的私有化属性和方法吗,其实啊,Java官方文档里是这样规定的:父类的私有变量和私有方法虽然存在于子类对象中,但是对于子类对象而言这些私有化属性和方法是不可见的,子类对象无法直接访问和调用,正由于这种虽存在但不可见的特性,所以官方规定其为不可以被继承,大家简单了解就好。
正文:
一、子类可以继承父类的哪些数据域和方法
1、普通属性
private修饰的普通属性不能被子类继承,但是子类可以调用父类提供的访问器和修改器进行访问和修改;
无修饰符的普通属性可以被子类继承;
protected修饰的普通属性可以被子类继承;
public修饰的普通属性可以被子类继承;
2、静态属性
private修饰的静态属性不能被子类继承,但是子类可以调用父类提供的访问器和修改器进行访问和修改;
无修饰符的静态属性可以被子类继承;
protected修饰的静态属性可以被子类继承;
public修饰的静态数属性可以被子类继承;
3、普通方法
private修饰的普通方法不能被子类继承;
无修饰符的普通方法可以被子类继承;
protected修饰的普通方法可以被子类继承;
public修饰的普通方法可以被子类继承;
4、静态方法
private修饰的静态方法不能被子类继承;
无修饰符的静态方可可以被子类继承;
protected修饰的静态方法可以被子类继承;
public修饰的静态方法可以被子类继承;
5、构造方法
父类的构造方法不会被子类继承,但是可以通过super关键字进行调用。
6、总结
除父类中private修饰的属性和方法以及构造方法外,子类都可以继承。
二、子类可以重写父类的哪些方法
1、普通方法
private修饰的普通方法不能被重写,如果子类中定义的方法在父类中是私有的,那么这两个方法完全没有关系;
无修饰符的普通方法可以被重写;
protected修饰的普通方法可以被重写;
public修饰的普通方法可以被重写;
2、静态方法
只要是静态方法就不能被重写,和访问修饰符无关。
三、父类引用指向子类对象时
1、若子类覆盖了某方法,则父类引用调用子类重新定义的新方法
2、若子类未覆盖某方法,则父类引用调用父类本身的旧方法
3、若子类覆盖了某属性,但父类引用仍调用父类本身的旧属性
4、若子类未覆盖某属性,则父类引用调用父类本身的旧属性
5、父类引用不能访问子类新定义的方法
四、子类引用指向自身对象时
1、若子类覆盖了某方法,则子类引用调用子类重新定义的新方法
2、若子类未覆盖某方法,则子类引用调用父类本身的旧方法
3、若子类覆盖了某属性,则子类引用调用子类重新定义的新属性
4、若子类未覆盖某属性,则子类引用调用父类本身的旧属性
5、子类引用可以访问子类新定义的方法
五、实例分析
public class Father {
int a = 1;
int b = 2;
void f1() {
System.out.println(" Father.f1()");
}
void f2() {
System.out.println(" Father.f2()");
}
}
public class Son extends Father {
int a = 3;
@Override
void f1() {
System.out.println("Son.f1()");
}
void f3() {
System.out.println("Son.f3()");
}
public static void main(String[] args) {
Father father= new Son();// 父类引用指向子类对象
father.f1();// 子类覆盖了该方法,所以父类引用调用新方法
father.f2();// 子类未覆盖该方法,所以父类引用调用旧方法
// b.f3();此行去掉注释会报错,父类引用不能访问子类新定义方法
System.out.println(father.a);// 子类覆盖了该属性,但父类引用仍旧访问旧属性
System.out.println(father.b);// 子类未覆盖该属性,父类访问旧属性
System.out.println();
Son son = new Son();// 子类引用指向自身对象
son.f1();// 子类覆盖了父类方法,所以调用新方法
son.f2();// 子类未覆盖父类方法,所以调用旧方法
son.f3();// 子类调用自己新定义的方法
System.out.println(son.a);// 子类覆盖了该属性,所以访问新属性
System.out.println(son.b);// 子类未覆盖该属性,所以访问旧属性
}
}
Son.f1()
Father.f2()
1
2
Son.f1()
Father.f2()
Son.f3()
3
2