面试题答案
一键面试1. 编译期区分重载方法
在编译期,Java编译器根据方法签名来区分重载方法。方法签名由方法名和参数列表构成,不包括返回值类型(不过返回值类型可以作为重载的辅助条件,前提是参数列表不同)。
在字节码中,方法签名以特定格式表示。例如,对于方法public int add(int a, int b)
,其字节码中的签名表示为(II)I
。这里括号内按顺序列出参数类型(I
表示int
类型),括号后表示返回值类型。
编译器在编译时,当遇到方法调用,会根据调用处提供的参数类型和数量,在类的方法表中查找匹配的方法签名。如果找到多个匹配的方法签名(参数类型和数量都相同),且返回值类型不同,编译器会报错,因为这会导致编译期无法确定唯一的方法。
2. 运行期JVM区分重载方法
JVM在运行时,基于编译期生成的字节码信息来解析方法调用。具体流程如下:
- 解析调用指令:当执行到方法调用指令(如
invokevirtual
、invokespecial
等)时,JVM首先从字节码中获取要调用的方法的符号引用,包括类名、方法名和方法签名。 - 查找类的方法表:JVM根据符号引用中的类名,找到对应的类在方法区中的存储结构,然后在该类的方法表中查找与符号引用中方法名和方法签名完全匹配的方法。
- 方法查找算法:
- 对于
invokevirtual
指令(用于调用虚方法,即可能被重写的方法):- 首先在对象实际类型对应的类的方法表中查找匹配的方法。
- 如果没有找到,按照继承关系从子类到父类逐步查找,直到找到匹配方法或到达
java.lang.Object
类。
- 对于
invokespecial
指令(用于调用私有方法、构造方法、父类方法等):- 如果是调用私有方法,直接在当前类的方法表中查找匹配的方法签名。
- 如果是调用构造方法,根据对象创建的具体类,在该类的方法表中查找
<init>
方法。 - 如果是调用父类方法,先找到当前类的父类,然后在父类的方法表中查找匹配的方法签名。
- 对于
通过上述编译期和运行期的流程,JVM能够准确地区分并调用重载方法。