0

在 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 扩展了在方法访问中声明的对象(T#1)
     T#2 扩展类 Test.MyVisitor 1 中声明的对象 1 错误

问题是visit 中的类型 T不被认为与list 中的 T相同。我该如何解决这个编译问题?

4

5 回答 5

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's是相同的。

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

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

就像您在原始Visitor界面中一样。

于 2013-04-11T11:31:02.997 回答
1

接口必须是Visitor<T>

编辑:界面必须看起来像这样

interface Visitor<T> {
    void visit(T Value);
}
于 2013-04-11T11:27:04.030 回答
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);
    }
}
于 2013-04-11T11:31:23.333 回答
0

您正在使用方法签名中的类型参数(以及因此中的项目类型)来隐藏类型参数T,它可以是完全不同的类型。(传递给它的任何类型都可以是任何类型,也可能是.)您应该重命名其中一个。MyVisitor<T>listvisit()Object

事实上,就 Java 泛型而言,访问者中的方法签名是空洞的。做吧void visit(Object o),它是完全等价的,不那么令人困惑。这样做也使问题更清楚,您正在尝试将一个添加ObjectList<T>. 如果您需要方法签名,Visitor则必须强制转换。(这将需要 a Class.cast(),因此需要Class<T>a MyVisitor

于 2013-04-11T11:35:59.857 回答
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);
        }
    }
}
于 2013-04-11T11:33:24.613 回答