Tricky Java Generics:使用泛型方法实现非泛型接口的泛型类

时间:2013-04-11 11:23:55

标签: java generics

我有以下代码as seen in 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: 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 不一样。我该如何解决这个编译问题?

5 个答案:

答案 0 :(得分: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界面一样。

答案 1 :(得分:1)

界面必须是Visitor<T>

编辑:界面必须如下所示

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

答案 2 :(得分:1)

您要声明通用类型<T>两次:

  • visit方法
  • MyVisitor班级

编译器阻止添加到列表: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);
    }
}

答案 3 :(得分: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);
        }
    }
}

答案 4 :(得分:0)

您将方法签名中的类型参数T(以及MyVisitor<T>中的项目类型)与方法签名中的类型参数list相混淆,这可能是不同的完全打字。 (传递给visit()的任何类型都可以是任何类型,也可以是Object。)您应该重命名其中一个。

事实上,就Java泛型而言,访问者中的方法签名是无效的。只需将其设为void visit(Object o),它就完全相同而且不那么令人困惑。这样做也会使问题更加清晰,您尝试将Object添加到List<T>。如果您需要Visitor中的方法签名,那么您必须进行投射。 (这需要Class.cast(),因此Class<T>中某处需要MyVisitor