面试题答案
一键面试1. Base obj = new Derived(); obj.performAction();
- 方法查找过程:
- 首先,
new Derived()
创建了一个Derived
类的实例对象。 - 然后,
Base obj
将这个Derived
实例赋值给Base
类型的引用。这里发生了向上转型,虽然引用类型是Base
,但实际对象类型是Derived
。 - 当调用
obj.performAction()
时,由于Java的动态绑定机制(多态),JVM会在运行时根据对象的实际类型(Derived
)来查找方法。具体来说,从Derived
类开始查找是否有匹配的performAction()
方法,如果没有则沿着继承链向上查找。这里Derived
类重写了performAction()
方法,所以会调用Derived
类中的该方法。
- 首先,
- 字节码指令:
new
指令用于创建Derived
类的新实例,并将其引用压入操作数栈。dup
指令复制操作数栈顶元素,为后续调用构造函数做准备。invokespecial
指令用于调用Derived
类的构造函数,初始化新创建的对象。astore_1
将对象引用存储到局部变量表的索引1位置(假设obj
是第一个局部变量)。- 当调用
obj.performAction()
时,会使用invokevirtual
指令。invokevirtual
指令会根据对象的实际类型在运行时动态查找并调用方法。它首先会在对象的实际类型(Derived
)的虚方法表(vtable)中查找performAction()
方法的入口地址,然后调用该方法。
- 多态在字节码层面的体现:
- 多态通过
invokevirtual
指令实现。该指令在运行时根据对象的实际类型来动态绑定方法,而不是根据引用的静态类型。在这个例子中,尽管obj
的静态类型是Base
,但由于实际对象类型是Derived
,invokevirtual
指令会调用Derived
类中的performAction()
方法,体现了多态特性。
- 多态通过
2. Derived obj2 = new Derived(); obj2.performAction(5);
- 方法查找过程:
- 同样,
new Derived()
创建Derived
类的实例对象,并赋值给Derived
类型的引用obj2
。 - 当调用
obj2.performAction(5)
时,因为参数类型是int
,JVM会在Derived
类中查找与参数列表匹配的方法。这里Derived
类没有直接定义performAction(int)
方法,所以会沿着继承链向上查找,在Base
类中找到了performAction(int)
方法,因此调用Base
类中的该方法。
- 同样,
- 字节码指令:
- 前面创建对象部分(
new
、dup
、invokespecial
、astore_2
,假设obj2
是第二个局部变量)与第一个例子类似。 - 当调用
obj2.performAction(5)
时,同样使用invokevirtual
指令。由于方法参数为int
,JVM会根据方法名和参数列表在Derived
类及其父类的虚方法表中查找匹配的方法。找到Base
类中的performAction(int)
方法后,调用该方法。
- 前面创建对象部分(
- 重载在字节码层面的体现:
- 重载通过方法名相同但参数列表不同来实现。在字节码层面,
invokevirtual
指令在查找方法时不仅考虑方法名,还会严格匹配参数列表。当调用obj2.performAction(5)
时,JVM根据参数类型int
来确定具体调用哪个performAction
方法,这体现了重载的特性。如果在Derived
类中有一个performAction(int)
方法,就会调用Derived
类中的该方法,而不是Base
类中的。
- 重载通过方法名相同但参数列表不同来实现。在字节码层面,