代码定义
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;
}
后果
10
son
20
son
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;
}
10
parent
20
son