简体   繁体   English

java泛型边界

[英]java generics bounds

I have the following code: 我有以下代码:

public <T extends SomeObject> long doSomething(T someObject){
    List<? extends SomeObject> l = new LinkedList<>();
    l.add(someObject);
}

this causes a compilation error - telling me that there is no suitable methods found: add(T), why is that? 这会导致编译错误 - 告诉我找不到合适的方法:add(T),为什么会这样?

If l accept things that extends SomeObject shouldn't it accept someObject as it bounds to extend SomeObject ? 如果l接受扩展的东西SomeObject不应该接受someObject因为它SomeObject扩展SomeObject

List<? extends SomeObject> l

What do you mean by that? 你是什​​么意思? Of course it will generate an error. 当然会产生错误。

Take this example : SomeObject is Fruit , you have 2 derived classes Apple and Orange 举个例子: SomeObjectFruit ,你有2个派生类AppleOrange

Your list what will it contain? 你的清单包含哪些内容? Apple s or Orange s? Apple s还是Orange s? The compiler cannot tell. 编译器无法分辨。 So it generates error. 所以它会产生错误。

If you replace List<? extends SomeObject> l 如果你替换List<? extends SomeObject> l List<? extends SomeObject> l with List<SomeObject> l . 使用List<SomeObject> l List<? extends SomeObject> l List<SomeObject> l Then this will work because Apple and Orange are both Fruit . 然后这将起作用,因为AppleOrange都是Fruit

I would advise you to use this statement: 我建议你使用这个声明:

List<T> l = new LinkedList<T>();

This is no less type-safe then 这样就不那么类型安全了

List<SomeObject> l = new LinkedList<SomeObject>();

and additionally gives you an opportunity to get objects of type T from the list without casting. 此外,您还可以从列表中获取类型为T的对象,而无需进行强制转换。 T is already SomeObject so no casting required to call methods of SomeObject on T. And all that with less typing! T已经是SomeObject所以不需要在T上调用SomeObject的方法进行转换。所有这些都少了输入!

Back to the problem. 回到问题所在。

First thing to note is that wildcard type "?" 首先要注意的是通配符类型“?” means unknown , this is important. 意思是未知 ,这很重要。 You may, however, specify an upper (? extends) or a lower (? super) constraint to it. 但是,您可以为其指定上限(?extends)或下限(?super)。 You declared a list as "List". 您将列表声明为“列表”。

List is known to have objects of SomeObject inside. 已知List中包含SomeObject的对象。 but! 但! the exact type of objects is unknown. 对象的确切类型未知。

Compiler can not say if there are instances of "class A extends SomeObject" or instances of "class B extends SomeObject" inside the list. 编译器不能说列表中是否存在“A类扩展SomeObject”或“B类扩展SomeObject”的实例。 If you call list.get() it can only say that there will be an object of type SomeObject. 如果调用list.get(),它只能说会有SomeObject类型的对象。

SomeObject obj = list.get(1);   // Ok

But inserting an object of any(!) type is unsafe because the actual type of elements in the list is unknown. 但是插入任何(!)类型的对象是不安全的,因为列表中的实际元素类型是未知的。

You could wonder why wildcard type ever exists. 您可能想知道为什么存在通配符类型。 It is here to lower restriction in type casting that will be too strict otherwise. 这是为了降低类型铸造中的限制,否则将过于严格。

Sample 样品

class A { }

class A2 extends A { }

class B <T> {
    void change(T a) { .. };
    T read() { ..  };
}

If there were no wildcards we would not be able to do this: B<A> b = new B<A2>(); 如果没有通配符,我们将无法执行此操作: B<A> b = new B<A2>(); - it does not work. - 这是行不通的。 This is because type conversion from B<A> to B<A2> is unsafe. 这是因为从B<A> to B<A2>类型转换是不安全的。

Why? 为什么? Let's look (copied from http://en.wikipedia.org/wiki/Generics_in_Java ) 我们来看看(复制自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!

What is the solution? 解决办法是什么? Sometimes, we want to do such assignments or pass parameters in a general way! 有时,我们希望以一般方式进行此类分配或传递参数!

Wildcard type helps here: B<? extends A> b = new B<A2>(); 通配符类型有助于: B<? extends A> b = new B<A2>(); B<? extends A> b = new B<A2>(); Method B.void change(T a) is now disabled - this is what your question was about and explained in the first part. 方法B.void change(T a)现已禁用 - 这是您的问题在第一部分中解释和解释。

Method BT read() is still valid and returns A: A a = b.read(); 方法BT read()仍然有效并返回A: A a = b.read(); . Yes, it returns A2 actually but to the caller of b.read() it's visible as A. 是的,它实际上返回A2但是对于b.read()的调用者它是可见的A.

Wildcard types are widely used in Collections Framework. 通配符类型在Collections Framework中广泛使用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM