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



我在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的则是相同的

请记住,泛型方法的重点是链接两个或多个参数的类型,或者将参数的类型链接到方法的返回类型(例如,一个方法接受某种类型的参数并返回一个相同类型的List)。当泛型方法只使用一次它的形参时,它并没有真正从泛型中获得任何东西,也就是说,你将从 中获得同样多的类型安全
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的某个地方)

最新更新