说我有一个Iterable<T> iter
,并说我有一个想以某种方式加入Iterable的Object v
。
我发现这似乎是错误的:
var x = List.of(iter);
x.add(v);
return x.iterator();
以上操作无效,因为它希望我改为执行此操作:
var x = List.of(iter);
x.add((Iterable<T>)v);
return x.iterator();
为什么不允许我这样做?:
var x = List.of(iter);
x.add((T)v); // does not compile, expects Iterable<T> not T
return x.iterator();
我一定做错了..我该如何假装成Iterable?
答案 0 :(得分:1)
他不允许您这样做:
var x = List.of(iter);
x.add((Iterable<T>)v);
return x.iterator();
因为我认为List x包含(Iterable)类型的对象,所以有必要将要添加到此List的Object强制转换为(Iterable)
答案 1 :(得分:1)
之所以无法进行编译,是因为您最终得到以下内容(未使用var
,因此类型很容易看到)。
List<Iterable<T>> x = List.of(iter); // List of Iterable<T> with a single element: "iter"
x.add(v); // Won't compile because "v" is an Object, not an Iterable<T>
x.add((Iterable<T>) v); // Compiles with warnings, will probably fail with ClassCastException at runtime
x.add((T) v); // Won't compile, "v" is being cast to "T" which is not an Iterable<T>
尽管如此,List.of
工厂方法返回的是不可修改 List
。即使可以编译,最终也会在运行时抛出UnsupportedOperationException
。
Iterable
接口不提供任何用于添加元素的API,仅通过Iterator
删除元素(如果实现支持)。这意味着您通常不能在Iterable
之前添加元素。如果您需要提供Iterable
的API,则可以向其中添加元素,而不应该首先返回Iterable
。最好返回Collection
,或者,由于需要添加元素,所以最好返回List
或Deque
。请注意,上述替代方案均从Iterable
接口扩展:
如果由于某种原因必须返回Iterable
,或者问题出在第三方API上,那么最好的选择是创建一个副本并将元素添加到副本中。
Iterable<T> iter = ...;
Object v = ...;
List<Object> copy = new ArrayList<>();
copy.add(v); // add v first
iter.forEach(copy::add); // add rest of iterable after v
请注意,List
现在是Object
的列表。您指定要添加Iterable
的{{1}}中的T
。没有更多信息,这两种类型的共同祖先是Object
。
如果您不想要副本,并且知道Object
的实现类似于可修改 Iterable
,则可以进行强制转换然后添加:
List
但是,您拥有((List<T>) iter).add(0, v); // in this case "v" must be of type "T"
的事实表明产生该API的API既不希望也不希望您被该API的使用者修改。