Java 为什么将 Collections.emptySet() 与泛型一起用于赋值而不是作为方法参数?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3061837/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 16:07:54  来源:igfitidea点击:

Why does using Collections.emptySet() with generics work in assignment but not as a method parameter?

javagenericscollectionstype-inference

提问by Karl von L

So, I have a class with a constructor like this:

所以,我有一个类的构造函数是这样的:

public FilterList(Set<Integer> labels) {
    ...
}

and I want to construct a new FilterListobject with an empty set. Following Joshua Bloch's advice in his book Effective Java, I don't want to create a new object for the empty set; I'll just use Collections.emptySet()instead:

我想FilterList用空集构造一个新对象。遵循 Joshua Bloch 在他的《Effective Java》一书中的建议,我不想为空集创建一个新对象;我只会用Collections.emptySet()

FilterList emptyList = new FilterList(Collections.emptySet());

This gives me an error, complaining that java.util.Set<java.lang.Object>is not a java.util.Set<java.lang.Integer>. OK, how about this:

这给了我一个错误,抱怨它java.util.Set<java.lang.Object>不是java.util.Set<java.lang.Integer>. 好的,这个怎么样:

FilterList emptyList = new FilterList((Set<Integer>)Collections.emptySet());

This also gives me an error! Ok, how about this:

这也给我一个错误!好的,这个怎么样:

Set<Integer> empty = Collections.emptySet();
FilterList emptyList = new FilterList(empty);

Hey, it works! But why? After all, Java doesn't have type inference, which is why you get an unchecked conversion warning if you do Set<Integer> foo = new TreeSet()instead of Set<Integer> foo = new TreeSet<Integer>(). But Set<Integer> empty = Collections.emptySet();works without even a warning. Why is that?

嘿,它有效!但为什么?毕竟,Java 没有类型推断,这就是为什么如果你这样做Set<Integer> foo = new TreeSet()而不是Set<Integer> foo = new TreeSet<Integer>(). 但Set<Integer> empty = Collections.emptySet();工作甚至没有警告。这是为什么?

采纳答案by Andrzej Doyle

The short answer is - that's a limitation of the type inference in Java's generic system. It can infer generic types against concrete variables, but not against method parameters.

简短的回答是 - 这是 Java 通用系统中类型推断的限制。它可以根据具体变量推断泛型类型,但不能根据方法参数推断出泛型类型。

I suspectthis is because methods are dispatched dynamically depending on the runtime class of the owning object, so at compile time (when allgeneric information is resolved) you can't actually know for sure what the class of the method parameter will be and hence can't infer. Variable declarations are nice and constant, so you can.

怀疑这是因为方法是根据拥有对象的运行时类动态调度的,所以在编译时(当所有通用信息都被解析时)你实际上无法确定方法参数的类是什么,因此无法推断。变量声明很好而且是常量,所以你可以。

Someone else might be able to give more detail and/or a nice link. :-)

其他人可能能够提供更多详细信息和/或一个不错的链接。:-)

In any case, you can always specify the type parameters explicitly for generic calls like so:

在任何情况下,您始终可以为泛型调用显式指定类型参数,如下所示:

Collections.<Integer>emptySet();

or even several parameters at once, e.g.

甚至同时有几个参数,例如

Collections.<String, Boolean>emptyMap(); // Returns a Map<String, Boolean>

This often looks a little cleaner than having to cast, in cases where inference doesn't kick in.

在推理没有启动的情况下,这通常看起来比强制转换要干净一些。

回答by jdmichal

You want to do this:

你想这样做:

FilterList emptyList = new FilterList(java.util.Collections.<Integer>emptySet());

That tells the emptySetmethod that its generic parameter should explicitly by Integerinstead of the default Object. And yes, the syntax is completely funky and non-intuitive for this. :)

这告诉emptySet方法它的泛型参数应该显式地Integer代替默认值Object。是的,语法非常时髦且不直观。:)

回答by Andrei Fierbinteanu

try

尝试

FilterList emptyList = new FilterList(Collections.<Integer>emptySet());

You can force the type parameter for methods that have them, in cases where the inference isn't good enough, or to allow you to use subtypes; for example:

您可以为具有它们的方法强制使用类型参数,以防推断不够好,或者允许您使用子类型;例如:

// forces use of ArrayList as parameter instead of the infered List
List<String> l = someObject.<ArrayList<String> methodThatTakesTypeParamForReturnType();

回答by kasperjj

Java does have a type inference, it's just pretty limited. If you are interested in knowing exactly how it works and what its limitations are, this is a really good read:

Java 确实有类型推断,只是非常有限。如果您有兴趣确切了解它的工作原理及其局限性,这是一本非常好的读物:

http://www.angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.html#Type%2BArgument%2BInference

http://www.angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.html#Type%2BArgument%2BInference