简体   繁体   English

Java的类型参数通配符到底意味着什么? Foo和Foo之间真正的区别是什么? <?> ?

[英]What does Java's type parameter wildcard really mean? What's the real difference between Foo and Foo<?>?

For a generic interface: 对于通用接口:

public interface Foo<T> {
    void f(T t); 
} 

The difference between the two fields: 两个字段之间的区别:

public class Bar {
    Foo foo1; 
    Foo<?> foo2; 
}

Is that foo2 is a generic Type and foo is not. foo2是泛型类型而foo不是。 Since ? 既然? is a wildcard (which I think means any type) and every type is a sub-type of Object, then I wold expect Foo<?> and Foo<Object> to semantically and syntactically equivalent. 是一个通配符(我认为这意味着任何类型),每个类型都是Object的子类型,然后我希望Foo<?>Foo<Object>在语义和语法上等效。

However, check out the following: 但是,请查看以下内容:

public class Puzzler {
    void f() {
        Integer i = null; 
        Foo<?> foo1 = null;
        foo1.foo(i); // ERROR 
        Foo foo2 = null; 
        foo2.foo(i); // OKAY
        Foo<Integer> foo3 = null; 
        foo3.foo(i); // OKAY 
        Foo<Object> foo4 = null; 
        foo4.foo(i); // OKAY
    }

    private interface Foo<T> {
        void foo(T t);
    } 
}

So Foo<?> and Foo<Object> are not the same syntactically. 所以Foo<?>Foo<Object>在语法上是一样的。

What's going on here? 这里发生了什么? I'm pretty stuck in trying to understand this. 我非常想要了解这一点。

Foo<?> is semantically the same as Foo<? extends Object> Foo<?>在语义上与Foo<? extends Object>相同Foo<? extends Object> Foo<? extends Object> : it is a Foo with type parameter of something specific, but the only thing known about "something" is that it is some subclass of Object (which isn't saying too much, since all classes are subclasses of Object ). Foo<? extends Object> :它是一个具有特定类型的类型参数的Foo ,但唯一知道“某事”的是它是Object一些子类(由于所有类都是Object子类,因此并没有说太多。 Foo<Object> , on the other hand, is a Foo with type parameter specifically Object . 另一方面, Foo<Object>是一个Foo ,类型参数特别是Object While everything is assignment-compatible with Object , not everything will be assignment-compatible with ? 虽然一切都与Object分配兼容,但并不是所有内容都与赋值兼容? where ? 哪里? extends Object . extends Object

Here's an example of why Foo<?> should generate an error: 以下是Foo<?>应该生成错误的示例:

public class StringFoo implements Foo<String> {
    void foo(String t) { . . . }
}

Now change your example to this: 现在将您的示例更改为:

Foo<?> foo1 = new StringFoo();

Since i is an Integer , there's no way that the compiler should allow foo1.foo(i) to compile. 由于i是一个Integer ,编译器不应该允许foo1.foo(i)编译。

Note that 注意

Foo<Object> foo4 = new StringFoo();

will also not compile according to the rules for matching parameterized types since Object and String are provably distinct types. 也不会根据匹配参数化类型的规则进行编译,因为ObjectString是可证明的不同类型。

Foo (without type parameter at all—a raw type) should usually be considered a programming error. Foo (根本没有类型参数 - 原始类型)通常应被视为编程错误。 According to the Java Language Specification (§4.8) , however, the compiler accepts such code in order to not break non-generic, legacy code. 但是,根据Java语言规范(第4.8节) ,编译器接受此类代码以便不破坏非泛型的遗留代码。

Because of type erasure , none of this makes any difference to generated the byte code. 由于类型擦除 ,这些都不会产生字节代码。 That is, the only differences between these are at compile time. 也就是说,它们之间的唯一区别是在编译时。

Consider these types: 考虑以下类型:

  • List<Object>
  • List<CharSequence>
  • List<String>

Even though String is a subtype of CharSequence which is a subtype of Object , these List types do not have any subtype-supertype relationships. 尽管StringCharSequence的子类型,它是Object的子类型,但这些List类型没有任何子类型 - 超类型关系。 (Curiously, String[] is a subtype of CharSequence[] which is a subtype of Object[] , but that's for historical reasons.) (奇怪的是, String[] CharSequence[]的子类型,它是Object[]的子类型,但这是出于历史原因。)

Suppose we want to write a method which prints a List. 假设我们要编写一个打印List的方法。 If we do 如果我们这样做

void print(List<Object> list) {...}

this will not be able to print a List<String> (without hacks), since a List<String> is not a List<Object> . 这将无法打印List<String> (没有hacks),因为List<String>不是List<Object> But with wildcards, we can write 但是通过通配符,我们可以写

void print(List<?> list) {...}

and pass it any List. 并传递任何列表。

Wildcards can have upper and lower bounds for added flexibility. 通配符可以具有上限和下限,以增加灵活性。 Say we want to print a list which contains only CharSequence s. 假设我们要打印一个仅包含CharSequence的列表。 If we do 如果我们这样做

void print(List<CharSequence> list) {...}

then we encounter the same problem -- we can only pass it a List<CharSequence> , and our List<String> is not a List<CharSequence> . 然后我们遇到同样的问题 - 我们只能传递一个List<CharSequence> ,而我们的List<String>不是List<CharSequence> But if we instead do 但如果我们改为做

void print(List<? extends CharSequence> list) {...}

Then we can pass this a List<String> , and a List<StringBuilder> , and so forth. 然后我们可以传递一个List<String>和一个List<StringBuilder> ,等等。

Well, due to the type erasure, anything generics-related is compile-time only; 好吧,由于类型擦除,任何与泛型相关的只是编译时间; I guess that's what you are calling syntactical. 我猜这就是你所说的语法。
I think your initial assessment is correct and real difference is that makes it a generic-typed variable and plain Foo doesn't. 我认为你的初步评估是正确的,真正的区别在于它使它成为通用类型的变量,而普通的Foo则没有。

Object is the supertype of all types in java. Object是java中所有类型的超类型。 However, Foo is not the supertype of all Foo. 然而,Foo不是所有Foo的超类型。 The supertype of all Foo is Foo. 所有Foo的超类型都是Foo。 see http://docs.oracle.com/javase/tutorial/extra/generics/wildcards.html for more details. 有关详细信息,请参阅http://docs.oracle.com/javase/tutorial/extra/generics/wildcards.html

The wildcard in Foo<?> indicates that within the current scope, you don't know or care what type of 'Foo' you have. Foo<?>的通配符表示在当前范围内,您不知道或不关心您拥有什么类型的“Foo”。

Foo<?> and Foo<? extends Object> Foo<?>Foo<? extends Object> Foo<? extends Object> are the same (the first is shorthand for the other). Foo<? extends Object>是相同的(第一个是另一个的简写)。 Foo<Object> is different. Foo<Object>是不同的。

A concrete example : 一个具体的例子

You can assign any sort of List to List<?> eg 您可以将任何类型的List分配给List<?>例如

List<?> list1 = new ArrayList<String>();
List<?> list2 = new ArrayList<Object>();
List<?> list3 = new ArrayList<CharSequence>();

If you have a List<?> you can call size() because you don't need to know what type of list it is to find out its size. 如果你有一个List<?>你可以调用size()因为你不需要知道它的大小是什么类型的列表。 And you can call get(i) because we know that the list contains some sort of Object , so the compiler will treat it as if get returns and Object . 你可以调用get(i)因为我们知道列表包含某种Object ,所以编译器会把它看作是get return和Object
But you can't call add(o) because you don't know (and the compiler doesn't know) what sort of list you're dealing with. 但是你不能调用add(o)因为你不知道(并且编译器不知道)你正在处理什么类型的列表。
In our example above you wouldn't want to allow list1.add(new Object()); 在上面的示例中,您不希望允许list1.add(new Object()); because that's supposed to be a list of String s 因为那应该是一个String列表

The reason for wildcards is so you can do things like this: 通配符的原因是你可以做这样的事情:

public static boolean containsNull(List<?> list)
{
    for(Object o : list )
    {
       if( o == null ) return true;
    }
    return false;
}

That code can work on any sort of list that you want, a List<String> , List<Object> , List<Integer> , etc. 该代码可以在任何类型的列表上工作, List<String>List<Object>List<Integer>等。

If the signature was public static boolean containsNull(List<Object> list) then you could only pass List<Object> to it, List<String> wouldn't work. 如果签名是public static boolean containsNull(List<Object> list)那么你只能将List<Object>传递给它, List<String>将不起作用。

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

相关问题 之间有什么区别 <foo></foo> 在JAXB中为null? - What's difference between <foo></foo> and null in JAXB? Foo :: new和() - > new Foo()有什么区别? - What's the difference between Foo::new and () -> new Foo()? Java中if(!foo)和if(foo == false)之间的性能差异(如果有)是什么? - What is the performance difference, if any, between if(!foo) and if(foo == false) in Java? false:maybeFoo.equals(“ Foo”)和“ Foo” .equals(maybeFoo)和也许Foo == null有什么区别? - What's the difference between “Foo”.equals(maybeFoo) and maybeFoo==null?false:maybeFoo.equals(“Foo”)? 不应该指定参数'foo' - 有什么危害? - The parameter 'foo' should not be assigned — what's the harm? 新的Foo(bar)是什么{public void baz(){…}}; 在Java中意味着什么? - What does new Foo(bar) {public void baz(){…} }; mean in Java? 在Java中,当类型后跟尖括号(如List中所示)是什么意思 <Foo> )? - In Java, what does it mean when a type is followed by angle brackets (as in List<Foo>)? 有什么区别<t extends foo>和<!--? extends Foo--> ?</t> - What difference between <T extends Foo> and <? extends Foo>? Java Generics - 无限通配符中真正存在的是什么? - Java Generics - What's really in a unbounded wildcard? java线程的状态究竟意味着什么? - What does the java thread's state really mean?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM