首页 > 解决方案 > 纠正有界类类型可迭代和有界通配符列表字段迭代器类型

问题描述

我正在尝试找到正确的泛型和通配符安排来完成这项工作。类型已更改,所有其他代码已删除,以使其尽可能简单。

Number在这里,我有一个具有该 implements上限的泛型类Iterable。它包含一个List泛型类型。

我想传入List任何子Number类的 a ,并从字段中返回该Iterator类型的。List

这是显然行不通的基本思想。

class GenericQuestion<T extends Number> implements Iterable<T> {
    List<T> numbers;

    GenericQuestion(List<T> number) {
        this.numbers = number;
    }

    public Iterator<T> iterator() {
        return numbers.iterator();
    }

    static void main() {
        for (Number n : new GenericQuestion<Number>(new ArrayList<Integer>())) { // <---- error
            System.out.println(n.byteValue());
        }
    }
}

这给出了预期的错误

incompatible types: ArrayList<Integer> cannot be converted to List<Number>

上限通配符来拯救!几乎...

class GenericQuestion<T extends Number> implements Iterable<T> {
    List<? extends T> numbers;

    GenericQuestion(List<? extends T> number) {
        this.numbers = number;
    }

    public Iterator<T> iterator() {
        return numbers.iterator(); // <----- error
    }

    static void main() {
        for (Number n : new GenericQuestion<Number>(new ArrayList<Integer>())) {
            System.out.println(n.byteValue());
        }
    }
}

现在我对迭代器类型冲突感到困惑。

incompatible types: Iterator<CAP#1> cannot be converted to Iterator<T>
  where T is a type-variable:
    T extends Number declared in class GenericQuestion
  where CAP#1 is a fresh type-variable:
    CAP#1 extends T from capture of ? extends T

现在从逻辑上讲,我很确定强制将返回的迭代器强制转换为 type 是完全安全的(Iterator<T>),但我宁愿以“正确”的方式这样做。我已经尝试了各种各样的事情。这是另一个绝望的尝试,但仍然没有奏效。

class GenericQuestion<T extends Number> implements Iterable<T> {
    List<T> numbers;

    <U extends Number> GenericQuestion(List<U> number) {
        this.numbers = number; // <----- error
    }

    public Iterator<T> iterator() {
        return numbers.iterator();
    }

    static void main() {
        for (Number n : new GenericQuestion<Number>(new ArrayList<Integer>())) {
            System.out.println(n.byteValue());
        }
    }
}

错误。

incompatible types: List<U> cannot be converted to List<T>
  where U,T are type-variables:
    U extends Number declared in constructor <U>GenericQuestion(List<U>)
    T extends Number declared in class GenericQuestion

我想也许辅助功能可以弥补差距,但我的尝试没有任何运气。

这似乎不应该那么难。强制施法真的可行吗?或者是否有一个通用声明可以使这一切一起工作?

标签: javagenerics

解决方案


我认为如果你想改变T.

造成这种限制的原因是Iterable<T>. 它需要一个方法Iterator<T> iterator()。您不能确定您Iterator<? extends T>是否可以转换为,Iterator<T>因为唯一可能的情况是您在运行时Iterator<? extends T>是 a 。Iterator<T>您可能已经了解A<T>无法转换为A<U>即使T extends U.

如果您创建了自己的MyIterable<T>界面,则可以这样做:

class GenericQuestion<T extends Number> implements MyIterable<T> {
    List<? extends T> numbers;

    GenericQuestion(List<? extends T> number) {
        this.numbers = number;
    }

    public Iterator<? extends T> iterator() {
        return numbers.iterator();
    }

    static void main() {
        GenericQuestion<Number> q = new GenericQuestion<>(new ArrayList<Integer>());
        Iterator<? extends Number> iter = q.iterator();
        System.out.println(iter.next().byteValue());
    }
}

interface MyIterable<T> {
    Iterator<? extends T> iterator();
}

但正如您所见,您不能使用MyIterablefor 循环。

因此,您要么不允许new GenericQuestion<Number>(new ArrayList<Integer>()),要么编写类型不安全的代码。


推荐阅读