棘手的Java泛型:用泛型方法实现非泛型接口的泛型类

棘手的Java泛型:用泛型方法实现非泛型接口的泛型类,java,generics,Java,Generics,我有以下代码: 编译此代码时将产生以下+错误: 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

我有以下代码:

编译此代码时将产生以下+错误:

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类型不同。如何解决此编译问题?

必须使用Visitor接口

编辑:界面必须如下所示

interface Visitor<T> {
    void visit(T Value);
}
然后你可以让MyVisitor实现Visitor,然后T将是相同的

请记住,泛型方法的要点是将两个或多个参数的类型链接起来,或者将参数的类型链接到方法的返回类型,例如,采用某个类型的参数并返回相同类型列表的方法。当泛型方法只使用它的参数一次时,它实际上并没有从泛型中获得任何好处,也就是说,您将从安全性中获得同样多的类型

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

与原始访问者界面相同。

您两次声明泛型类型:

论访问方式 关于MyVisitor类 编译器阻止添加到列表:list.addvalue;因为这两种类型可能不同

解决此问题的一种方法是在中使访问者界面通用,并删除on the Visite方法:

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

正确的解决方案是:

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,因此列表中的项的类型与方法签名中的项的类型相同,它们可以是完全不同的类型。传递给visit的任何类型,可以是任何类型,也可以是对象。您应该重命名其中一个


事实上,就Java泛型而言,访问者中的方法签名是空洞的。只需将其设为无效VisitoObject,它完全等效,并且不那么混乱。这样做还可以使问题更清楚,因为您正在尝试将对象添加到列表中。如果需要Visitor中的方法签名,则必须强制转换。这将需要Class.cast,因此在MyVisitor中的某个地方需要一个类,这可能会让事情变得更加混乱,因为泛型类型参数阴影。我认为建议在类“T.Oops”中使方法泛型,忘了提到您还必须去掉泛型方法定义。这也不会compile@Andremoniy这个答案用另一个例子解释了OP在代码中真正做了什么,所以它当然也不会编译。如果我不能修改访问者界面?Ian Roberts说,由于我无法匹配T,擦除后T将成为对象,我是否必须使用原始类型列表warnings@Andr在没有警告和@SuppressWarnings的情况下执行此操作的唯一方法是使用构造函数MyVisitorClass cls,并在运行时传入类对象对应MyVisitor的type参数,则在visit do list.addcls.castvalue中;这将进行编译,但如果使用错误类型的参数调用visit,则在运行时仍会失败。
interface Visitor<V>{
    public void visit(V Value);
}
interface Visitor{
    public void visit(Object Value);
}
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);
    }
}
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);
        }
    }
}