代码定义

class Father {    public String name;    public void out(){        System.out.println("father");    }    public void drink(){        System.out.println("father drink");    }}public class Son extends Father {    private String name ;    public void out(){        System.out.println("son");    }    public static void main(String[] args) {        Father father = new Son();        father.name = "lisi";        System.out.println(father.name);        father.out();        father.drink();        Son son =  (Son)father;        son.out();        System.out.println(son.name);    }}

后果
lisi
son
father drink
son
null

发现用父对象援用子实例后,办法能够调用子类对象,然而属性并不能为子类对象赋值。
起初通过反编译后获取如下编译后果

 public static void main(java.lang.String[]);    descriptor: ([Ljava/lang/String;)V    flags: ACC_PUBLIC, ACC_STATIC    Code:      stack=2, locals=3, args_size=1         0: new           #5                  // class example/Son         3: dup         4: invokespecial #6                  // Method "<init>":()V         7: astore_1         8: aload_1         9: ldc           #7                  // String lisi        11: putfield      #8                  // Field example/Father.name:Ljava/lang/String;        14: aload_1        15: invokevirtual #9                  // Method example/Father.out:()V        18: aload_1        19: invokevirtual #10                 // Method example/Father.drink:()V        22: aload_1        23: checkcast     #5                  // class example/Son        26: astore_2        27: aload_2        28: invokevirtual #11                 // Method out:()V        31: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;        34: aload_2        35: getfield      #12                 // Field name:Ljava/lang/String;        38: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V        41: return      LineNumberTable:        line 24: 0        line 25: 8        line 26: 14        line 27: 18        line 28: 22        line 29: 27        line 30: 31        line 31: 41

能够看到11行在设置name属性值的时候,依然用的是父类对象,和父类对象中的name属性,所以在强转子类后,获取name属性为空。
办法也同样如此,第15行调用father.out办法时,也用的是父类对象,以及父类对象中的out办法,然而打印后果却是son,是因为invokevirtural这个指令的问题,起初查阅的知,类在编译实现后会生成一张虚办法表,存储对应子类的办法调用,虚办法配合虚办法表实现多态的性能。
然而属性就没有这种性能了,属性通过本地变量表的办法签名,去获取属性和设置属性,跟理论对象曾经无关,只和左值类型无关
虚办法在应用时会耗费虚拟机性能,如果想缩小虚办法的应用能够用final润饰,或者采纳静态方法,也不要过分纠结性能,依据业务场景和性能写出适合代码。
java的实现多态和c++实现多态有些许类似,借助c++代码能够更好的理解虚拟机帮咱们做了什么操作,以下两个代码块的办法,区别是virtural关键字
在父类办法中退出virtual关键字,就会调用理论类型的办法
去掉virtual关键字,就会依据申明的指针类型,调用办法,不会去管理论类型

class Parent{public:      string name = "10";     virtual void print() {        cout << "parent" << endl;    }};class Son :  public Parent{public:     string name = "20";     virtual void print() {        cout << "son" << endl;    }};int main() {    Parent* p = new Son();    cout<< p->name<< endl;    p->print();    auto son = ((Son*)p);    cout << son->name << endl;    son->print();    system("pause");    return 1;}后果10son20son
class Parent{public:      string name = "10";      void print() {        cout << "parent" << endl;    }};class Son :  public Parent{public:     string name = "20";      void print() {        cout << "son" << endl;    }};int main() {    Parent* p = new Son();    cout<< p->name<< endl;    p->print();    auto son = ((Son*)p);    cout << son->name << endl;    son->print();    system("pause");    return 1;}10parent20son