为什么我的泛型函数返回不同的捕获?

时间:2016-10-27 07:07:04

标签: java generics

我有一个超类,其泛型类型扩展了超类型(<E extends ...>)。该类有一个抽象方法,返回泛型类型的列表 我还有一些实现抽象方法的子类 当我调用此方法并尝试替换列表中的对象时,java编译器显示错误。我认为错误是因为我的转换函数返回了一个不同的类型捕获,因为它作为参数得到 以下是使用Exception作为通用超类型的示例代码:

import java.util.ArrayList;
import java.util.List;

public class GenericTest {

    abstract class Super<E extends Exception>{
        abstract List<E> foo();
    }

    class Sub1 extends Super<NullPointerException>{
        @Override
        List<NullPointerException> foo(){
            return new ArrayList<NullPointerException>();
        }
    }

    GenericTest(Super<? extends Exception> s){
        List<? extends Exception> list = s.foo();
        list.set(0, convertException(list.get(0)));
    }

    static <F extends Exception> F convertException(F exception){...}
}


中出现两个错误
list.set(0, convertException(list.get(0)));

编译器说set

The method set(int, capture#2-of ? extends Exception) in the type List<capture#2-of ? extends Exception> is not applicable for the arguments (int, capture#3-of ? extends Exception)

convertException

Type mismatch: cannot convert from capture#3-of ? extends Exception to capture#2-of ? extends Exception

为什么不转换EException会返回相同的capture#x?它需要F并返回F.
感谢您的帮助!

2 个答案:

答案 0 :(得分:3)

这是因为您将Super作为原始类型传递给构造函数。您没有使用通用。由于您未指定泛型类型,因此编译器会将该列表视为Object列表。

应该是这样的:

GenericTest(Super<Exception> s){
        Exception e = s.foo().get(0);
    }

这将编译好

<强>更新

  

编译器对set

说      

类型List中的方法set(int,capture#2-of?extends Exception)不适用于参数(int,capture#3-of?extends Exception)

当您使用通配符时,Java不允许您添加或更新Collection的元素。所以,使用:

List<? extends Exception> list = s.foo();
        list.set(0, /*anything but null*/);

是被禁止的。 原因是为了避免这种情况:

class Animal {}
class Dog extends Animal {}
class Cat extends Animal {}

public void method() {

        List<Dog> dogs = new ArrayList<Dog>();

        addCats(dogs);
    }

    void addCats(List<? extends Animal> list) {
        list.add(new Cat());
    }

你明白了吗?如果允许添加操作,则可能会将猫添加到狗列表中。

回到你的问题。我不明白你要做什么,如果你真的需要一个具有特定子类异常的列表,我建议你也把GenericTest作为泛型类。否则,您可以将列表声明为Exception的简单列表:

GenericTest(Super<Exception> s){
        List<Exception> list = s.foo();
        list.set(0, convertException(list.get(0)));
    }

然后对列表元素进行instanceof检查。

希望这有帮助

更新2

  

为什么convertException不知道,它会返回与列表相同的类型?

问题不在于编译器不知道“F扩展Exception ==?extends Exception”。这段代码:

GenericTest(Super<Exception> s){
        List<? extends Exception> list = getList();

    }

    <F extends Exception> List<F> getList(){...}

将编译。问题是你在带有通配符的集合上使用set方法,这是禁止的,无论你实际传递的是什么对象。

答案 1 :(得分:1)

你可以使用施法。 Object是一个超类https://docs.oracle.com/javase/tutorial/java/IandI/objectclass.html

    Exception e =  (Exception) s.foo().get(0);

我认为这是你的目标?

    List<NullPointerException> ds = new GenericTest.Sub1().foo();
    Exception e2 = ds.get(0);