[英]java generics bounds
我有以下代码:
public <T extends SomeObject> long doSomething(T someObject){
List<? extends SomeObject> l = new LinkedList<>();
l.add(someObject);
}
这会导致编译错误 - 告诉我找不到合适的方法:add(T),为什么会这样?
如果l
接受扩展的东西SomeObject
不应该接受someObject
因为它SomeObject
扩展SomeObject
?
List<? extends SomeObject> l
你是什么意思? 当然会产生错误。
举个例子: SomeObject
是Fruit
,你有2个派生类Apple
和Orange
你的清单包含哪些内容? Apple
s还是Orange
s? 编译器无法分辨。 所以它会产生错误。
如果你替换List<? extends SomeObject> l
使用List<SomeObject> l
List<? extends SomeObject> l
List<SomeObject> l
。 然后这将起作用,因为Apple
和Orange
都是Fruit
。
我建议你使用这个声明:
List<T> l = new LinkedList<T>();
这样就不那么类型安全了
List<SomeObject> l = new LinkedList<SomeObject>();
此外,您还可以从列表中获取类型为T的对象,而无需进行强制转换。 T已经是SomeObject所以不需要在T上调用SomeObject的方法进行转换。所有这些都少了输入!
回到问题所在。
首先要注意的是通配符类型“?” 意思是未知 ,这很重要。 但是,您可以为其指定上限(?extends)或下限(?super)。 您将列表声明为“列表”。
已知List中包含SomeObject的对象。 但! 对象的确切类型未知。
编译器不能说列表中是否存在“A类扩展SomeObject”或“B类扩展SomeObject”的实例。 如果调用list.get(),它只能说会有SomeObject类型的对象。
SomeObject obj = list.get(1); // Ok
但是插入任何(!)类型的对象是不安全的,因为列表中的实际元素类型是未知的。
您可能想知道为什么存在通配符类型。 这是为了降低类型铸造中的限制,否则将过于严格。
样品
class A { }
class A2 extends A { }
class B <T> {
void change(T a) { .. };
T read() { .. };
}
如果没有通配符,我们将无法执行此操作: B<A> b = new B<A2>();
- 这是行不通的。 这是因为从B<A> to B<A2>
类型转换是不安全的。
为什么? 我们来看看(复制自http://en.wikipedia.org/wiki/Generics_in_Java )
List<Integer> ints = new ArrayList<Integer>();
ints.add(2);
List<Number> nums = ints; // valid if List<Integer> were a subtype of List<Number>
nums.add(3.14);
Integer x = ints.get(1); // now 3.14 is assigned to an Integer variable!
解决办法是什么? 有时,我们希望以一般方式进行此类分配或传递参数!
通配符类型有助于: B<? extends A> b = new B<A2>();
B<? extends A> b = new B<A2>();
方法B.void change(T a)
现已禁用 - 这是您的问题在第一部分中解释和解释。
方法BT read()
仍然有效并返回A: A a = b.read();
。 是的,它实际上返回A2但是对于b.read()
的调用者它是可见的A.
通配符类型在Collections Framework中广泛使用。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.