程序员最重要的是思想,知其然知其所以然。
小编想问,你从一开始就在使用Java吗?你是否还记得Java被称作为”Oak”的时期?那时,面向对象仍然是一个热门的话题,使用C++的人们都认为Java没有任何机会,Applets 也只是一件事情。
重载仅返回类型不同的方法
这样的代码无法编译,对不?
class Test {
Object x() { return "abc"; }
String x() { return "123"; }
}
对。 Java 语言不允许两个方法在同一个类中“等效重载”,而忽略其诸如throws自居或返回类型等的潜在的差异。
查看 Class.getMethod(String, Class…) 的 Javadoc。 其中说明如下:
请注意,类中可能有多个匹配方法,因为 Java 语言禁止在一个类声明具有相同签名但返回类型不同的多个方法,但 Java 虚拟机并不是如此。虚拟机中增加的灵活性可以用于实现各种语言特征。例如,可以用桥接方法实现协变参返回; 桥接方法和被重写的方法将具有相同的签名但拥有不同的返回类型。
小编推荐一个学JAVA的学习裙【 一三三,九三零,六九三】,无论你是大牛还是小白,是想转行还是想入行都可以来了解一起进步一起学习!裙内有开发工具,很多干货和技术资料分享
哇哦,有道理。实际上下面的代码暗藏着很多事情:
abstract class Parent {
abstract T x();
}
class Child extends Parent {
@Override
String x() { return "abc"; }
}
来看看为 Child 生成的字节码:
// Method descriptor #15 ()Ljava/lang/String;
// Stack: 1, Locals: 1
java.lang.String x();
0 ldc [16]
2 areturn
Line numbers:
[pc: 0, line: 7]
Local variable table:
[pc: 0, pc: 3] local: this index: 0 type: Child
// Method descriptor #18 ()Ljava/lang/Object;
// Stack: 1, Locals: 1
bridge synthetic java.lang.Object x();
0 aload_0 [this]
1 invokevirtual Child.x() : java.lang.String [19]
4 areturn
小编推荐一个学JAVA的学习裙【 一三三,九三零,六九三】,无论你是大牛还是小白,是想转行还是想入行都可以来了解一起进步一起学习!裙内有开发工具,很多干货和技术资料分享Line numbers:
[pc: 0, line: 1]
其实在字节码中 T 真的只是 Object。这很好理解。合成的桥方法实际是由编译器生成的,因为 Parent.x() 签名中的返回类型在实际调用的时候正好是 Object。在没有这种桥方法的情况下引入泛型将无法在二进制下兼容。因此,改变 JVM 来允许这个特性所带来的痛苦会更小(副作用是允许协变凌驾于一切之上) 很聪明,不是吗?
Target Type 目标类型
Java Compiler 会根据你指定的目标类型来推断(infers)出method该返回哪种类型的结果,例如:
Collections.emptyList
static List emptyList(); //这个方法没有参数,只有一个T类型的返回类型,那么我不能传入参数这个方法是如何知道用什么返回类型的呢,这就是target type
List listOne = Collections.emptyList();小编推荐一个学JAVA的学习裙【 一三三,九三零,六九三】,无论你是大牛还是小白,是想转行还是想入行都可以来了解一起进步一起学习!裙内有开发工具,很多干货和技术资料分享
listOne是一个List类型的变量,Java Compiler会根据这个目标类型来推断出emptyList method应该返回这个类型,这种类型推断依赖于assignment context,也就是说我要赋给哪个变量,它是什么类型我就返回什么类型。
一句话总结就是:Java 恰好是一种看起来神秘的语言,其实不然。