2013-04-11 99 views
0

我有以下代码as seen in ideone.com整蛊Java泛型:泛型类实现非通用接口与通用方法

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: error: no suitable method found for add(T#1) 
      list.add(value); 
       ^
    method List.add(int,T#2) is not applicable 
     (actual and formal argument lists differ in length) 
    method List.add(T#2) is not applicable 
     (actual argument T#1 cannot be converted to T#2 by method invocation conversion) where T#1,T#2 are type-variables: 
    T#1 extends Object declared in method visit(T#1) 
    T#2 extends Object declared in class Test.MyVisitor 1 error 

的问题是在访问的类型T不能视为相同T IN列表。我该如何解决这个编译问题?

回答

8
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参数类和T参数给visit我这是不相关的,两者都不一定可以分配给另一方。如果Visitor本身是个参数接口

interface Visitor<V>{ 
    public void visit(V Value); 
} 

那么你可以有MyVisitor<T> implements Visitor<T>和T的则是相同的。

记住的通用方法的点是链接的两个或更多个参数的种类,或以一个参数的类型链接到方法的返回类型(例如一种方法,其需要一些类型并返回的参数)的列表相同类型。当一个泛型方法只使用它的参数,一旦它并没有真正被通用获得任何东西,即你从

interface Visitor{ 
    public void visit(Object Value); 
} 

得到一样多类型安全:从你的原Visitor界面会。在visit方法上MyVisitor

编译器

  • 防止添加到列表:

+0

这也不会编译 – Andremoniy 2013-04-11 11:32:14

+0

@Andremoniy这个答案解释了OP在替代例子中的代码真的做了什么,当然它也不会编译。 – Pshemo 2013-04-11 11:38:03

+0

如果我不能改变'访客'界面?我将不得不使用原始类型List,因为我无法匹配'T',擦除后'T'会变成'Object'? – 2013-04-11 11:44:32

1

的接口必须Visitor<T>

编辑:该接口有看起来像这样

interface Visitor<T> { 
    void visit(T Value); 
} 
+0

不是真的,这将使事情变得更加混乱,因为泛型类型参数阴影 – millimoose 2013-04-11 11:30:41

+0

的认为这个建议是为了使该方法在类'通用T'。 – 2013-04-11 11:31:53

+0

糟糕,忘了提及你也必须摆脱泛型方法的定义。 – 2013-04-12 11:38:05

1

您在声明泛型类型<T>两次list.add(value);为两种类型可能会有所不同。解决问题

的一种方法是使Visitor接口通用在<T>和访问方法去除<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); 
    } 
} 
0

正确的解决方案将是:

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); 
     } 
    } 
} 
0

你”重新使用方法签名中的类型参数T,MyVisitor<T>(以及因此list中的项目类型),它可以是完全不同的类型。 (任何类型传递给visit()可以是任何类型,也可以是Object。)您应该重命名其中一个。

事实上,就Java泛型而言,访问者中的方法签名是无效的。只要让它void visit(Object o),它是完全相同的,更少混淆。这样做也会使问题更清楚,您正尝试将Object添加到List<T>。如果您需要Visitor中的方法签名,那么您必须投射。 (这将需要一个Class.cast()因而Class<T>在某处MyVisitor