整理两篇文章《Java Generics and Collections》读书笔记三:协变式覆盖与泛型重载 与 关于泛型和重载的小问题
《Java Generics and Collections》读书笔记三:协变式覆盖与泛型重载 :http://blog.csdn.net/jk88811/article/details/1794866
http://blog.csdn.net/zzsyzjb/article/details/6024178
1.协变式覆盖
...
public Object clone() { ... }
}
public int x;
public int y;
public Point( int x, int y) { this .x = x; this .y = y; }
public Object clone() { return new Point(x,y); }
}
public int x;
public int y;
public Point( int x, int y) { this .x = x; this .y = y; }
public Point clone() { return new Point(x,y); }
}
public static int sum(List < Integer > ints) {
int sum = 0 ;
for ( int i : ints) sum += i;
return sum;
}
public static String sum(List < String > strings) {
StringBuffer sum = new StringBuffer();
for (String s : strings) sum.append(s);
return sum.toString();
}
}
String sum(List)
为什么会导致这和情况?
我们说的泛型、重载是java语言级别的,但“擦除”技术是关于实现的,它关系到合法class文件的生成,而合法的class文件才能被jvm接受
jvm本来就支持签名相同,但返回类型不同的方法存在。参考《深入java虚拟机》第二版中文版的6.6节:
“在java源文件的同一个类里,如果声明了两个相同名字和相同参数类型、但返回值不同的方法,这个程序将无法编译通过。在java程序设计语言中,不能仅仅通过返回值的不同来重载方法。但是这样的两个方法可以和谐地在一个class文件中共存。”
在java语言角度的添加这种限制也是自然的。比如两个方法:
void test(int i);
int test(int i);
编译器不能确定到底应该调用哪个方法,所以这种情况在java中不允许存在。
但是,对于这两个方法test(ArrayList<String> list)和test(ArrayList<Integer> list),在java语言的级别,这是合法的重载,因为编译器可以通过参数类型信息来确定调用哪个版本。再加上返回类型不同,经过编译和类型擦除得到的两个方法是可以在class文件中共存的。这样问题就解决了。
比如我们写两个方法,
public void test(ArrayList<String> list){}
public void test(ArrayList<Integer> list){}
好,这两个方法是合法的重载吧。从语言角度讲,我们可以说是。但是,经过擦除之后,这两个方法就是完全相同的了,如果编译器支持这种情况,那生成的class文件就是jvm不支持的了。那咋办?编译拒绝通过