转载请注明链接:https://blog.csdn.net/feather_wch/article/details/82564060
JVM中的方法调用
版本:2018/9/10-1(23:59)
问题汇总
- 可变长参数方法的重载
- 官方文档建议避免重载可变长参数方法
- 什么是重载?
- 如何绕开多个方法名字相同、参数类型相同的限制?
- 当一个类(具有多个方法,方法名相同、参数类型相同、但是返回值类型不同)出现在Java编译器的用户路径上时,如何确定应该调用哪个方法?
- 重载方法的识别是在哪个阶段完成的?
- Java编译器如何根据传入参数的声明类型来选取重载方法的?
- 声明类型和实际类型的区别?
- Java编译器在同一个阶段中找到了多个适配的方法,如何选择一个最合适的方法?
- 重载对于从父类继承来的非私有同名方法有效吗?
- JVM中不存在重载这一概念
- 如果子类定义的方法和继承自父类的方法同名,但是参数类型相同,这两个方法有什么关系?
- 父类和子类具有两个同名方法,都是静态方法,都是public。子类中的方法会隐藏了父类中的方法。
- 重写是什么?
- 方法重写是如何体现了Java的多态?
- JVM是如何识别方法的?关键在于三部分
- 方法描述符是什么?
- 如果一个类中出现了方法名相同,方法描述符相同的方法,会在类加载的什么阶段报错?
- JVM和Java语言规范对于方法的限制有哪些不同处?
- JVM的重写和Java语言的重写并不完全相同
- 什么是桥接方法?编译器如何通过生成桥接方法解决了Java和JVM重写语义不同的问题?
- 什么是静态绑定?什么是编译时多态?
- 什么是动态绑定?
- 对于JVM,什么是真正的静态绑定?
- 对于JVM,什么是真正的动态绑定?
- Java字节码中与调用相关的指令一共有五种
- invokeinterface实例
- invokestatic实例
- invokevirtual实例
- invokespecial实例
- invokeastatic和invokespecial,JVM能直接识别具体的目标方法.
- invokevirtual和invokeinterface,JVM需要在执行中,根据调用者的动态类型,来确定目标方法。
- 符号引用的作用?
- 符号引用存储在哪里?
- 符号引用的分类
- 实例中的符号引用
- 符号引用什么时候需要被替换为实际引用?
- JVM如何解析
非接口符号引用
,并替换为实际引用? - 非接口符号引用的解析过程所得到的结论
- 隐藏和重写的区别
- JVM如何解析
接口符号引用
,并替换为实际引用? - 实际引用是什么?
- 如何将java文件翻译成字节码文件
- 虚方法是什么?JVM中的虚方法调用?
- 类有一个非静态的public方法,该方法是否是虚方法?
- 虚方法和设计模式的关系?设计模式为什么需要大量采用虚方法来实现多态?
- 虚方法的性能低下?
- 哪些场景下虚方法的调用开销可以完全消除?
- 为什么JVM中虚方法调用的开销很低?
- 虚方法的性能消耗在哪?
- 需要动态绑定确定目标方法的方法都是虚方法
- 静态绑定的都是非虚方法
- 虚方法中也会涉及到静态绑定?虚方法指向的是final方法会怎么样?
- JVM中如何去提高动态绑定的性能消耗?
- 方法表的作用
- 方法表是何时构造的?类加载的准备阶段做了哪些事情?
- 方法表的底层实现
- 方法表中会存储private方法,或者static方法?
- 子类的方法表中是否包含父类方法表中的所有方法?
- 方法表的实例
- 方法表的动态绑定和静态绑定相比有哪些开销?
- 动态绑定的内存解引用操作的性能损耗可以忽略不计吗?
- Java栈帧是什么?何时创建并且初始化的?
- 方法表就是存储类的所有方法的表?
- 内联缓存是什么?
- 针对多态的优化手段中,具有单态、多态和超多态
- 如何区分多态和超多态?
- 内联缓存有几种?
- JVM采用哪种内联缓存方式?
- 如何没有命中内联缓存,对于内联缓存中的内容,JVM会如何处理?
- 内联缓存并不是真正的内联,依旧有固定开销。
- getter/setter等方法的固定开销超过了方法本身,这就需要方法内联的优化
- HotSpot没有多态内联缓存?
- 单态内联缓存和超多态内联缓存的性能差距?
重载(11)
1、什么是重载?
- Java中,如果同一个类中有多个方法:名字相同,参数类型相同。会无法通过编译。
- 如果想要在同一个类中定义名字相同的方法,参数类型必须不同。
- Java根据参数类型的不同,去选择对应的方法,称之为重载。
2、如何绕开多个方法名字相同、参数类型相同的限制?
- 可以通过字节码工具绕开
- 编译完成后,再向class文件中添加方法名相同、参数类型相同、但是返回值类型不同的方法。
3、当一个类(具有多个方法,方法名相同、参数类型相同、但是返回值类型不同)出现在Java编译器的用户路径上时,如何确定应该调用哪个方法?
- 目前java编译器会直接选取第一个方法名以及参数类型匹配的方法
- 并且根据返回值类型,判断是否可以通过编译,是否需要进行值转换
4、重载方法的识别是在哪个阶段完成的?
编译阶段
5、Java编译器如何根据传入参数的声明类型来选取重载方法的?
- 第一阶段:在不考虑对基本类型自动装拆箱,以及可变长参数的情况下选取
- 第二阶段:没有找到,在允许自动装拆箱,不允许可变长参数的情况下选取
- 第三阶段:还没找到,在允许自动装拆箱,允许可变长参数的情况下选择
6、声明类型和实际类型的区别?
- 声明类型:(Object)str,声明类型就是Object类型。
- 实际类型:(Object)str,实际类型是String
String str = "str";
// 声明类型为String
invoke(str, 1);
// 声明类型为Object
invoke((Object)str, 2);
7、Java编译器在同一个阶段中找到了多个适配的方法,如何选择一个最合适的方法?
- 这个符合程度的决定性因素就是
形式参数类型的继承关系
- 比如传入参数null,可以是Object,也可以是String。因为String是子类,所以Java编译器认为String更符合。
public static void invoke(Object obj) {
System.out.println("Object");
}
public static void invoke(String s) {
System.out.println("String");
}
// null可以是Object,也可以是String
invoke(null);
8、重载对于从父类继承来的非私有同名方法有效吗?
- 子类具有一个方法,和继承自父类的方法,名称相同,参数类型不同。这就属于重载。
9、JVM中不存在重载这一概念
- 重载方法的区分处于编译阶段
可变长参数的方法重载
10、可变长参数方法的重载
void invoke(Object obj, Object... args) { ... }
void invoke(String s, Object obj, Object... args) { ... }
invoke(null, 1);// 调用第二个 invoke 方法
invoke(null, 1, 2);// 调用第二个 invoke 方法 invoke(null, 1, 2);
invoke(null, new Object[]{
1});// 调用第一个 invoke 方法 ,只有手动绕开可变长参数的语法糖,才能调用第一个 invoke 方法
invoke((Object)null,