转载自:https://blog.csdn.net/qq_36515344/article/details/84679082
Father father = new Son();//正确
当Son继承于Father类时,这种情况的引用编译器是支持的,
Son son= new Father();//错误
而反之却不能。
这是由内存机制决定的,父类声明的引用的可见区域是父类的字段和方法,而子类声明的引用的可见区域是子类和父类中继承下来的全部字段和方法,这就造成了父类引用访问子类实例的时候是内存安全的,而子类引用访问父类实例是会导致内存问题的。
我们可以使用下面一段代码来验证父类引用的可视性(它只能在内存中找到父类中定义了的相关字段和方法)。
//test.java
public class test{
public static void main(String[] args){
Father father = new Son();
father.run();
//System.out.println(father.son);//错误,对于父类引用father来说,子类实例中的son字段是不存在的
}
//father.java
public class Father{
int fa = 0;
void run(){
System.out.println("father");
}
}
//son.java
public class Son extends Father{
int son = 1;
void run(){
System.out.println("son");
}
}
输出结果为son(调用的是子类中的方法)
这里为什么调用的是子类的方法呢?父类的引用调用了子类的方法
那对于相同名的字段而言会出现像方法一样的情况吗?
public class test{
public static void main(String[] args){
Father father = new Son();
System.out.println(father.fa);
father.run();
}
}
class Father{
int fa = 0;//相同字段
void run(){
System.out.println("father");
}
}
class Son extends Father{
int fa = 1;//相同字段
void run(){
System.out.println(super.fa);
System.out.println(fa);
System.out.println("son");
}
}
输出结果:
我们发现它调用的是父类的fa字段,那这是为什么呢?
说明继承对字段和方法的处理是不一样的,对于字段而言,是不存在重写的,如果有相同的两个字段,是会同时存在的,但是对于父类和子类的引用而言,这两个字段的可见性是不同的,而子类中的方法会重写父类中的同名方法,这时候子类实例的内存空间中是存在两个同名字段和子类重写后的方法的引用。所以,父类引用调用的方法是子类重写过后的方法。