简体   繁体   English

Java泛型通配符及其局限性

[英]Java Generics wildcards and their limitations

I have a two part question 我有两个问题

My book states this "If the wildcard is specified without an upper bound, then only the methods of type Object can be invoked on the values of the wildcard type" 我的书中说明了“如果没有上限指定了通配符,那么只能在通配符类型的值上调用Object类型的方法”

I have no idea what this could mean. 我不知道这可能是什么意思。 What does this mean? 这是什么意思?

Also what are the limitations place on wild card types (unbounded and bounded)? 对于外卡类型(无界和有界)有什么限制? For instance if I have a reference to MyClass<?> or MyClass<? extends SomeOtherClass> 例如,如果我有对MyClass<?>MyClass<? extends SomeOtherClass>的引用MyClass<? extends SomeOtherClass> MyClass<? extends SomeOtherClass> , what methods am I not allowed to call through that reference. MyClass<? extends SomeOtherClass> ,我不允许通过该引用调用哪些方法。 I don't understand what the wild card allows or disallows me to do, which is probably why I don't understand the quote from the book. 我不明白外卡允许或禁止我做什么,这可能是我不理解本书引用的原因。

I have an example for the second part: 我有第二部分的例子:

class SomeOtherClass
{
[...]
}

class MyClass<T>
{
[...]
}

class Test
{
     public static void main(String[] arg)
     {
         MyClass<? extends SomeOtherClass> myClass = new MyClass<String>() // for instance what does the wild card reference limit me to in any way. In a general sence.
     }
}

Wildcards bounds (upper and lower) are often mandatory for collections and classes returning objects of parameterized type. 对于返回参数化类型对象的集合和类,通配符边界(上部和下部)通常是必需的。

You'll often hear about PECS , which means "Producer extends, Consumer super" . 你会经常听到PECS ,这意味着“制片人扩展,消费者超级” I suggest you to read the answer to this question , to avoid duplicating answers. 我建议你阅读这个问题的答案 ,以避免重复答案。

  • To be more precise, when you define your wildcard with <? extends TheClass> 更准确地说,当您使用<? extends TheClass>定义通配符时 <? extends TheClass> , then you're telling the compiler that the wildcarded object is at least of type TheClass . <? extends TheClass> ,然后你告诉编译器通配对象至少是类型TheClass Therefore, you are able to use this object like an instance of TheClass , and call any method this type proposes. 因此,您可以像使用TheClass的实例一样使用此对象,并调用此类型建议的任何方法。

  • Now, when you define your wildcard as <? super TheClass> 现在,当您将通配符定义为<? super TheClass> <? super TheClass> , you're telling the compiler that your wildcarded object type is implemented or extended by the TheClass type. <? super TheClass> ,您告诉编译器您的通配对象类型是由TheClass类型实现或扩展的。 It means that the object type may not be TheClass , but that a TheClass object can be used as an instance of your wildcarded reference. 这意味着对象类型可能不是TheClass ,但是TheClass对象可以用作通配符引用的实例。 Therefore, you cannot call anything on that object, since its type is only known at runtime, but you can pass the object to methods waiting for a wildcarded object. 因此,您无法在该对象上调用任何内容,因为其类型仅在运行时已知,但您可以将该对象传递给等待通配对象的方法。

Examples: 例子:

private void foo(List<?> list) {
    Object o = list.get(0); // ok
    list.add(new Object()); // won't compile!

    // you cannot add anything, and only extract Object instances
}

private void foo(List<? extends TheClass> list) {
    Object o1 = list.get(0);   // ok
    TheClass o2 = list.get(0); // ok
    list.add(new Object());    // won't compile!
    list.add(new TheClass());  // won't compile!

    // You are sure that the objects are of a subtype of TheClass,
    // so you can extract TheClass instances safely. However, you cannot
    // add anything to this list since its type is not known (may be
    // different from TheClass, so the compiler does not allow anything).
}

private void foo(List<? super TheClass> list) {
    Object o1 = list.get(0);   // ok
    TheClass o2 = list.get(0); // won't compile!
    list.add(new Object());    // won't compile!
    list.add(new TheClass());  // ok

    // You are sure that the objects are of a type implemented by TheClass,
    // so you can add any TheClass instances to the list. However, you cannot
    // extract TheClass objects since the objects type may be just implemented
    // by TheClass, but different.
}

Normal generic; 普通通用;

ArrayList<Man> list= new ArrayList<Man>();
list.put(man); 
Man m = list.get(0);

Using wildcard with upper bound: 使用带上限的通配符:

ArrayList<? extends Person> list= new ArrayList<? extends Person>();
list.put(man); //Man is a person..
Person p = list.get(0);

Using wildcard: 使用通配符:

ArrayList<?> list= new ArrayList<?>();
list.put(man);
Object o = list.get(0);

If you use the wildcard you cannot know the generic type of ArrayList, hence you can only get Object out of the list which means that you are back to using ArrayLists the old way without generics.. 如果使用通配符,则无法知道ArrayList的泛型类型,因此您只能从列表中获取Object,这意味着您将返回使用ArrayLists,而不使用泛型。

For example you have <? 比如你有<? extends MyClass> wildcard. 扩展MyClass>通配符。 This means that any class matching this wildcard may be of MyClass type or any of it's descendants. 这意味着匹配此通配符的任何类都可以是MyClass类型或其任何后代。 But since the only thing we know it is descendant of MyClass, we can only garantee that methods available on class MyClass are available to invoke. 但由于我们唯一知道它是MyClass的后代,我们只能保证MyClass类可用的方法可以调用。

For wildcard with bo upper bound <?> the upper bound will be Object class. 对于带有bo上限<?>的通配符,上限将是Object类。 And this means that all we know is that the class extends Object, so only methods that are garanteed to be present in this class are those that defined in Object class. 这意味着我们所知道的是该类扩展了Object,因此只有保证在此类中存在的方法才是在Object类中定义的方法。

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

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