JavaSE5.0, JavaSE6.0在语法上都是遵守最新的The Java Language Specification(Third Edition)。
在JLS的”4.3.4 When Reference Types Are the Same“节中有如下描述:
Two reference types are the same compile-time type if they have the same binary
name (§13.1) and their type parameters, if any, are the same, applying this definition
recursively
就是说: 如同两个引用类型具有相同类名和类型参数的值,那么他们是相同的编译时类型,即使运行时他们对应同一个Class对象。
在JLS的”8.4.2 Method Signature“节中,其描述意思如下:
存在方法签名m1和m2; 等号是包括的意思
1. 方法签名 = 方法名 + 参数类型(argument types)
2. 参数类型(argument types) = 形式参数(formal parameters)+ 形式类型参数 (formal type parameters)
3. 形式参数(formal parameters)= 参数的类型 + 参数的个数
4. 形式类型参数 (formal type parameters)= 类型参数的个数
5. 子签名:如果m1与m2相同或者m1与m2的擦除签名相同,那么m1是m2的子签名。
6. 为了类库的作者考虑,规定方法的任何泛型版本都是非泛型版本的子签名.
7. 覆写相等:如果m1是m2的子签名或者m2是m1的子签名,那么m1和m2覆写相等。
8. 如果两个方法的签名是覆写相等的那么报编译时错误。
这段看起来让人感觉不是很好,他从整个方法签名的角度去描述两个泛型方法(方法参数带类型参数的值)的签名是否冲突,为此还引入了签名的擦除、覆写相等等概念。我认为比较好的做法是把对泛型的处理转移到引用类型上,即将泛型加入到判断引用类型是否相同的逻辑上,这样就得到下图
这样,判断方法签名还是按照以前的传统方式,使用方法的方法名+参数类型+参数个数,而不需要引入“签名的擦除”、“覆写相等”等概念。
感觉JDK6的javac在编译时进行语法检查就是按照这样的方式的进行的。
结合JLS的4.3.4节和8.4.2节,可以得出类型参数的值算入引用类型,当形式参数的参数类型是引用类型时,类型参数的值算入方法签名。
但是,在对JLS的理解上JavaSE5.0有问题,没有将类型参数的值算入method signature,所以存在JDKbug 6182950 (http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6182950),下面是其描述
FULL PRODUCT VERSION :
java version "1.5.0"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0-b64)
Java HotSpot(TM) Client VM (build 1.5.0-b64, mixed mode, sharing)
ADDITIONAL OS VERSION INFORMATION :
customer Windows XP [Version 5.1.2600]
A DESCRIPTION OF THE PROBLEM :
Following code should not compile:
class x {
int f(List<String> l) {return 0;}
double f(List<Integer> l) {return 0;}
}
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Following code should not compile:
class x {
int f(List<String> l) {return 0;}
double f(List<Integer> l) {return 0;}
}
since both method have the same erasure.
JLS3 draft 8.4.8.3 says, it is error if there are two methods m1 and m2 in a class such that:
- m1 and m2 have the same name
- m2 is accessible
- the signature of m1 is not subsignature if m2
- both methods have same erasure
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Error: line (4) name clash: f(java.util.List<java.lang.String>) and f(java.util.List<java.lang.Integer>) have the same erasure
大意是说类
class x {
int f(List<String> l) {return 0;}
double f(List<Integer> l) {return 0;}
}
应该不能通过编译,原因是两个方法具有相同的擦除(难道本意是除去类型参数的值后,两个方法是相同的?)。
用jdk1.5.0_22编译此类报错如下
名称冲突:f(java.util.List<java.lang.Integer>) 和 f(java.util.List<java.lang.String>) 具有相同疑符。
但是JavaSE6.0修正了这个问题。使用JDK1.6.0_17能成功编译此类。然而一些IDE在做语法检查时也有此问题,所以他们会提示语法错误,但是使用javac可以通过编译。