Java通用通配符及其局限性 [英] Java Generics wildcards and their limitations

查看:85
本文介绍了Java通用通配符及其局限性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个两部分的问题

我的书中指出:如果指定的通配符不带上限 绑定,则只能在类型上调用Object类型的方法. 通配符类型的值"

我不知道这意味着什么.这是什么意思?

在通配符类型(无界和有界)上还有哪些限制?例如,如果我有对MyClass<?>MyClass<? extends SomeOtherClass>的引用,则不允许通过该引用调用哪些方法.我不理解通配符允许或不允许做什么,这可能就是为什么我不理解本书中引用的原因.

第二部分有一个示例:

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.
     }
}

解决方案

通配符边界(上下)通常是集合和返回参数化类型对象的类的必填项.

您会经常听到有关PECS的信息,这意味着生产者扩展,消费者超级" .建议您阅读该问题的答案,以避免重复的答案.

  • 更准确地说,当您使用<? extends TheClass>定义通配符时,您将告诉编译器通配符对象至少为TheClass类型.因此,您可以像TheClass的实例一样使用此对象,并调用此类型建议的任何方法.

  • 现在,当您将通配符定义为<? super TheClass>时,您将告诉编译器通配符对象类型是由TheClass类型实现或扩展的.这意味着对象类型可能不是TheClass,但是TheClass对象可以用作通配引用的实例.因此,您不能在该对象上调用任何东西,因为它的类型仅在运行时才知道,但是您可以将该对象传递给等待通配符的对象的方法.

示例:

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.
}

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"

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>, what methods am I not allowed to call through that reference. 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". 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>, then you're telling the compiler that the wildcarded object is at least of type TheClass. Therefore, you are able to use this object like an instance of TheClass, and call any method this type proposes.

  • Now, when you define your wildcard as <? super TheClass>, you're telling the compiler that your wildcarded object type is implemented or extended by the TheClass type. 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. 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.
}

这篇关于Java通用通配符及其局限性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆