Java协变式覆盖(Override)和泛型重载(Overload)
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了Java协变式覆盖(Override)和泛型重载(Overload),小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含2572字,纯文字阅读大概需要4分钟。
内容图文
Java 协变式覆盖(Override)和泛型重载(Overload)
1. 协变式覆盖(Override)
在 Java1.4 及以前,子类方法如果要覆盖超类的某个方法,必须具有完全相同的方法签名,包括返回值也必须完全一样。
Java5.0 放宽了这一限制,只要子类方法与超类方法具有相同的方法签名,或者子类方法的返回值是超类方法的子类型,就可以覆盖 。这样有什么好处呢?以 Object 类的 clone 方法为例:
class
Object {
...
public
Object clone() { ... }
}
在 5.0 以前,如果子类需要重载 clone 方法,必须像下面这样写代码:
class
Point {
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); }
}
虽然在我们的 Point 类里, clone 方法总是返回一个 Point 类型的对象,但却必须把返回类型写成 Object ,在外部使用 clone 方法时也必须使用恼人的强制类型转换。
在 Java5.0 以后,我们就可以利用新的覆盖规则,像下面这样编写代码:
class
Point {
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); }
}
这样,我们就可以直接使用 Point p2 = p1.clone(); 而不用强制类型转换了。
2 .泛型重载(overload)
Java 的方法重载一般指在同一个类中的两个同名方法,规则很简单:两个方法必须具有不同的方法签名。换句话说,就是这两个方法的参数必须不相同,使得编译器能够区分开这两个重载的方法。由于编译器不能仅仅通过方法的返回值类型来区分重载方法,所以如果两个方法只有返回类型不同,其它完全一样,编译是不能通过的。
在泛型方法的重载时,这个规则稍微有一点变化。先看下面代码:
class
Overloaded {
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();
}
}
上面是两个泛型方法的重载例子,由于 Java 的泛型采用擦除法实现, List<Integer> 和 List<String> 在运行时是完全一样的,都是 List 类型。也就是,擦除后的方法签名如下:
int
sum(List)
String sum(List)
Java 允许这两个方法进行重载,虽然它们的方法签名相同,只有返回值类型不同。这在两个普通方法的重载中是不允许的。当然了,如果两个泛型方法的参数在擦除后相同,而且返回值类型也完全一样,那编译肯定是不能通过的。
类似地,一个类不能同时继承两个具有相同擦除类型的父类,也不能同时实现两个具有相同擦除的接口。如 Class A implements Comparable<Integer>, Comparable<Long> 。
总结一下,两个泛型方法在擦除泛型信息后,如果具有相同的参数类型,而返回值不一样,是可以进行重载的。 Java 有足够的信息来区分这两个重载的方法。
为什么会导致这和情况? 我们说的泛型、重载是 java 语言级别的,但 “ 擦除 ” 技术是关于实现的,它关系到合法 class 文件的生成,而合法的 class 文件才能被 jvm 接受
j vm 本来就支持签名相同,但返回类型不同的方法存在 。参考《深入 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 不支持的了。那咋办?编译拒绝通过
原文:http://www.cnblogs.com/ixenos/p/5645741.html
内容总结
以上是互联网集市为您收集整理的Java协变式覆盖(Override)和泛型重载(Overload)全部内容,希望文章能够帮你解决Java协变式覆盖(Override)和泛型重载(Overload)所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。