java - 纠正有界类类型可迭代和有界通配符列表字段迭代器类型
问题描述
我正在尝试找到正确的泛型和通配符安排来完成这项工作。类型已更改,所有其他代码已删除,以使其尽可能简单。
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
我想也许辅助功能可以弥补差距,但我的尝试没有任何运气。
这似乎不应该那么难。强制施法真的可行吗?或者是否有一个通用声明可以使这一切一起工作?
解决方案
我认为如果你想改变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();
}
但正如您所见,您不能使用MyIterable
for 循环。
因此,您要么不允许new GenericQuestion<Number>(new ArrayList<Integer>())
,要么编写类型不安全的代码。
推荐阅读
- java - Java 软引用优先级
- c - 是否可以仅使用不带条件变量的互斥体来实现生产者消费者?
- mysql - 使用触发器确保插入的数据不超过限制
- php - 将 SQL 文件导入 XAMPP 错误。可能的代码错误?
- flutter - 热重载时有效,但重新安装时无效
- angular - WARNING in Exceeded maximum budget for SCSS FILE IN ANGULAR
- batch-file - 进入阻塞模式后执行 .bat cmd 命令
- c++ - c 警告:命名中使用的“结构”标签
- xcode - 重命名 pod init 中的默认“示例”目录
- r - R - 使用 remotes::install_github 安装软件包要求 BiocManager::install() 找不到的更高版本的依赖项