我正在尝试找到正确的泛型和通配符安排以使其正常工作。类型已更改,所有其他代码都已删除,以使其尽可能简单。
在这里,我有一个通用类,其上限为Number
,实现了Iterable
。它包含通用类型的List
。
我想传入任何List
子类的Number
,然后从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
从逻辑上来说,现在我很确定将强制返回的迭代器强制转换为(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
我认为也许可以使用辅助功能来弥补差距,但是我的尝试并没有任何运气。
这似乎并不难。强制铸造真的是要走的路吗?还是有一个通用的声明可以使所有这些协同工作?
答案 0 :(得分:1)
对测试进行一次小改动,以使其不试图强制使用GenericQuestion<Number>
(而是让推断类型):
for (Number n : new GenericQuestion<>(new ArrayList<Integer>())) {
您还可以更改List
可迭代类型的声明,例如:
class GenericQuestion<T extends Number, L extends List<T>>
implements Iterable<T> {
private L numbers;
GenericQuestion(L number) {
this.numbers = number;
}
答案 1 :(得分:1)
如果您想在T
上使用变量,我认为您必须在某处有 some 类型的不安全代码。
引起此限制的原因是Iterable<T>
。它需要一种方法Iterator<T> iterator()
。您不确定Iterator<? extends T>
是否可以转换为Iterator<T>
,因为唯一可行的情况是运行时Iterator<? extends T>
是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>())
,要么编写类型不安全的代码。
答案 2 :(得分:0)
我发现的另一个解决方案是用基本类型的迭代器包装通配符迭代器。从技术上讲,我怀疑这是应该如何处理这种情况。
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.min.js"></script>
<div ng-app="myModule">
<div ng-controller="myController">
<div class="item" ng-repeat="room in rooms">
{{ room }}
<input type="text" name="{{ item.key }}" class="form-control" ng-model="item.data['section' + room]">
</div>
</div>
</div>