引
编译看左,运行看右
这是对Java多态执行问题时的一套口诀:成员变量,静态方法看左边;非静态方法:编译看左边,运行看右边,意思是:当子类的对象指向父类变量时(Parent parent = new Child()),在这个引用变量parent指向的对象中,它的成员变量和静态方法与父类是一致的,它的非静态方法,在编译时与父类一致的,运行时却与子类一直(子类发生重写)
例
创建一个父类,定义两个方法,一个静态方法,一个实例方法
如下所示:
package com.yiyi.vx.duotai;
public class Parent {
// 父类属性
public String name = "父类属性";
public int val = 1;
// 静态方法
public static void means1(){
System.out.println("父类中的函数1");
}
// 实例方法
public void means2(){
System.out.println("父类中的函数2");
}
}
创建一个子类,继承并重写父类的属性和方法
**如下所示: **
package com.yiyi.vx.duotai;
public class Child extends Parent {
// 子类属性
public String name = "子类属性";
public int val = 2;
public static void means1(){
System.out.println("子类中的函数1");
}
@Override
public void means2(){
System.out.println("子类中的函数2");
}
}
测试:
package com.yiyi.vx.duotai;
public class Test {
public static void main(String[] args){
// 多态中成员的访问特点:
// A:成员变量、静态方法:编译看左边,运行看左边。
// B:非静态方法:编译看左边,运行看右边。
// 多态,向上转型(子类对象->指向父类的引用):
Parent p = new Child();
// 编译看左边:
// p.customize(); //访问子类独有方法报错,编译不通过
// 成员变量:运行看左边
System.out.println(p.name); // 父类属性
System.out.println(p.val);// 1
// 静态方法:运行看左边
p.means1();// 父类中的函数1
p.means2();// 子类重写方法:子类中的函数2
}
}
Parent p = new Child();
声明一个变量p为Parent 这个类,然后我们p = new Child();中建立一个子类对象赋值给了p
拥有了被Child类函数覆盖后的Parent 类对象p。(实则是向上转型,子类的实例对象->指向父类的引用)
也就是说:
只有子类的函数覆盖了父类的函数这一个变化,但是p肯定是Parent 这个类的引用。所以p所代表的是函数被复写后(多态的意义)的一个Parent 类,而Parent 类原来有的成员变量没有任何变化----------------获得结论:A:成员变量:编译和运行都看Parent 。
但是p的Parent 类函数被复写了。--------------获得结论:B:非静态方法:编译看Parent ,运行看Child
对于静态方法:编译和运行都看Parent
因为class文件在被类加载器加载时,如果有static方法,此时会分配内存。也就是说,静态方法在类加载时就已经加载了,在类实例对象建立前就已经存在了,所有无法被后出现的子类对象进行重写。---------------获得结论:C:静态方法:编译和运行都看父类。子类可以继承父类的静态方法,但不能重写。如果父类中定义的静态方法在子类中被重新定义,那么在父类中定义的静态方法将被隐藏而非重写。换句话说,父类和子类中含有的其实是两个没有关系的方法,它们的行为也并不具有多态性