我在ideone.com中看到以下代码:
import java.util.*;
class Test{
interface Visitor{
public <T> void visit(T Value);
}
class MyVisitor<T> implements Visitor{
List<T> list = new ArrayList<T>();
public <T> void visit(T value){
list.add(value);
}
}
}
编译后,该代码将产生以下+错误:
<>之前Main.java:12:错误:没有找到合适的方法添加(t# 1)list.add(价值);^方法List.add(int, t# 2)不适用(实际论证表和正式论证表的长度不同)方法List.add(t# 2)不适用(实际参数t# 1不能通过方法调用转换转换为t# 2)其中t# 1, t# 2是类型变量:t# 1扩展了方法visit中声明的对象(t# 1)t# 2扩展了在类Test中声明的Object。MyVisitor 1错误之前问题是visit中的类型T不被认为与list 中的 T相同。如何修复此编译问题?class MyVisitor<T> implements Visitor{
List<T> list = new ArrayList<T>();
public <T> void visit(T value){
list.add(value);
}
}
等价于
class MyVisitor<T> implements Visitor{
List<T> list = new ArrayList<T>();
public <V> void visit(V value){
list.add(value);
}
}
。类的T
参数和visit
方法的T
参数是不相关的,两者都不一定可赋给对方。如果Visitor
本身是一个参数化接口
interface Visitor<V>{
public void visit(V Value);
}
则可以是MyVisitor<T> implements Visitor<T>
T的则是相同的
interface Visitor{
public void visit(Object Value);
}
您声明了两次泛型类型<T>
:
- 关于
visit
方法 - 关于
MyVisitor
类
编译器阻止添加到列表:list.add(value);
,因为这两种类型可能不同。
解决问题的一种方法是使Visitor
接口在<T>
中泛型,并在visit方法上删除<T>
:
interface Visitor<T> {
public void visit(T Value);
}
class MyVisitor<T> implements Visitor<T>{
List<T> list = new ArrayList<T>();
public void visit(T value){
list.add(value);
}
}
接口必须为Visitor<T>
编辑:界面必须是这样的
interface Visitor<T> {
void visit(T Value);
}
正确的解决方案是:
class Test {
interface Visitor<T> {
public void visit(T Value);
}
class MyVisitor<T> implements Visitor<T> {
List<T> list = new ArrayList<T>();
@Override
public void visit(T value) {
list.add(value);
}
}
}
您将MyVisitor<T>
中的类型参数T
(以及list
中的项目类型)与方法签名中的类型参数CC_15(可以是完全不同的类型)隐藏起来。(传递给visit()
的任何类型,可以是任何类型,也可以是Object
。)您应该重新命名其中一个。
实际上,就Java泛型而言,访问器中的方法签名是空洞的。把它改成void visit(Object o)
就行了,它完全相同,不那么令人困惑。这样做也使问题更清楚,您正在尝试将Object
添加到List<T>
。如果您需要Visitor
中的方法签名是这样的,则必须进行强制类型转换。(这将需要Class.cast()
,因此Class<T>
在MyVisitor
的某个地方)