Java泛型:桥接方法、重载与重写及类型限制
立即解锁
发布时间: 2025-08-17 02:35:38 阅读量: 16 订阅数: 22 


Java编程基础与SCJP认证指南
### Java泛型:桥接方法、重载与重写及类型限制
#### 1. 桥接方法
桥接方法是编译器插入到子类中的,以确保方法的重写能够正确工作。典型的例子是`Comparable`接口的实现。以下是`CmpNode<E>`类擦除后的代码:
```java
class CmpNode extends Node implements Comparable {
CmpNode(Object data, CmpNode next) {
super(data, next);
}
public int compareTo(CmpNode node2) { // (1)
return this.getData().compareTo(node2.getData());
}
public int compareTo(Object node2) { // (2)
return this.compareTo((CmpNode)node2); // Calls the method at (1).
}
}
```
编译器在`(2)`处插入了第二个`compareTo()`方法,其方法签名为`compareTo(Object)`。这是必要的,因为如果没有这个方法,该类将无法正确实现`Comparable`接口,因为接口的`compareTo()`方法将无法被正确重写。
桥接方法不能在源代码中调用,它是为了与遗留代码保持向后兼容性而提供的。有一些Java反编译器可以用来检查编译器生成的代码。
#### 2. 方法签名对重载和重写的影响
##### 2.1 方法签名的定义
方法签名在方法的重载和重写中起着至关重要的作用。方法签名由方法名和形式参数列表组成。两个方法(或构造函数)具有相同的签名,需要满足以下两个条件:
- 它们具有相同的名称。
- 它们具有相同的形式参数类型。
两个方法(或构造函数)具有相同的形式参数类型,需要满足以下两个条件:
- 它们具有相同数量的形式参数和类型参数。
- 在将其中一个的形式参数替换为另一个的相应类型后,形式参数和类型参数的边界相同。
如果满足以下两个条件之一,则方法`m()`的签名是另一个方法`n()`签名的子签名:
- 方法`n()`与方法`m()`具有相同的签名。
- 方法`m()`的签名与方法`n()`签名的擦除相同。
如果满足以下两个条件之一,则两个方法`m()`和`n()`的签名是重写等效的:
- 方法`m()`的签名是方法`n()`签名的子签名。
- 方法`n()`的签名是方法`m()`签名的子签名。
##### 2.2 对重载的影响
根据上述定义,如果两个方法具有相同的名称,但它们的签名不是重写等效的,则这两个方法是重载的。例如,在一个类中有以下三个泛型方法声明:
```java
static <T> void merge (MyStack<T> s1, MyStack<T> s2) { /*...*/ }
static <T> void merge (MyStack<T> s1, MyStack<? extends T> s2) { /*...*/ }
static <T> void merge (MyStack<T> s1, MyStack<? super T> s2) { /*...*/ }
```
擦除后,这三个方法的签名都是`merge(MyStack, MyStack)`,即这些方法的签名是重写等效的,因此这些方法不是重载的。一个类不能包含两个签名重写等效的方法,编译器会报告错误。
而以下三个方法:
```java
static <T> void merge (Node<T> s1, MyStack<T> s2) { /*...*/ }
static <T> void merge (MyStack<T> s1, MyStack<? extends T> s2) { /*...*/ }
static <T> void merge (MyStack<T> s1, Node<? super T> s2) { /*...*/ }
```
擦除后的签名分别为:
- `merge (Node, MyStack)`
- `merge (MyStack, MyStack)`
- `merge (MyStack, Node)`
可以看出,没有两个签名是重写等效的,因此这三个方法是重载的。
下面是`Sup`类的声明,展示了方法签名的一些变化:
```java
class Sup<T> {
void doIt(boolean b) { }
// (1) void doIt(boolean)
void doIt(T t) { }
// (2) void doIt(Object)
List<StringBuilder> doIt(StringBuilder sb) {
// (3) List doIt(StringBuilder)
return null;
}
<E extends Comparable<E>> void doIt(E element) // (4) void doIt(Comparable)
{ }
<E> E doIt(MyStack<? extends E> stack) { // (5) Object doIt(MyStack)
return null;
}
}
```
向`Sup`类添加以下任何方法声明都会出错,因为每个方法声明的签名都与类中已有的某个方法相同,即签名是重写等效的:
```java
void doIt(Object obj) { }
// (2') void doIt(Object)
<E extends StringBuilder> List<E> doIt(E sb) {
// (3') List doIt(StringBuilder)
return null;
}
void doIt(Comparable<T> element) { }
// (4') void doIt(Comparable)
<E> E doIt(MyStack<? super E> stack) {
// (5') Object doIt(MyStack)
return null;
}
```
##### 2.3 对重写的影响
为了使子类型方法重写超类型方法,应满足以下条件:
- 子类型方法的签名是超类型方法签名的子签名。
- 它们的返回类型应该兼容。
- 它们的`throws`子句应该兼容。
这里主要讨论方法签名对重写的影响。
##### 2.4 `@Override`注解
可以借助编译器来确保方法声明正确地重写了继承的方法。如果方法声明前面有`@Override`注解,当该方法没有重写继承的方法时,编译器会发出错误。
以下是使用该注解的示例:
```java
class CmpNode<E extends Comparable<E>>
extends Node<E> implements Comparable<CmpNode<E>> {
CmpNode(E data, CmpNode<E> next) {
super(data, next);
}
@Override
public boolean equals(CmpNode node2) {
// (1) Compile-time error.
//public boolean equals(Object node2) {
// (1') Correct header.
return this.compareTo(node2) == 0;
}
@Override
public int compareTo(Object node2) {
// (2) Compile-time error.
//public int compareTo(CmpNode<E> node2) {
// (2') Correct header
return this.getData().compareTo(node2.getData());
}
}
```
编译`CmpNode`类时,会出现错误提示,因为注解的方法没有重写任何继承的方法,方法签名不是继承的任何方法签名的子签名,形式参数对于重写来说是不正确的。
##### 2.5 非泛型子类型中的非泛型方法重写非泛型超类型中的方法
在以下示例中:
```java
class SupA {
public void set(Integer ref) {/*...*/} // (1)
public void set(List<Integer> lis
```
0
0
复制全文
相关推荐









