以下代码来自Effective Java book:
Set<Integer> integers = ... ;
Set<Double> doubles = ... ;
Set<Number> numbers = union(integers, doubles);
此代码未编译,作者建议通过告诉编译器确切类型如下来解决此问题:
Set<Number> numbers = Union.<Number>union(integers, doubles)
如果联合的签名如下,为什么早期的程序不能编译?这个特定的解决方法成语是什么?
public static <E> Set<E> union(Set<? extends E> s1,
Set<? extends E> s2)
答案 0 :(得分:5)
请注意,Double和Integer不仅扩展了Number,还实现了Comparable。因此编译器猜测的返回类型将是Set&lt; Number&amp; Comparable&gt;无法转换为Set&lt; Number&gt;。您需要告诉编译器使用哪种类型。使用以下代码,您不需要确切的类型。
interface X {}
class U implements X {}
class V implements X {}
public static void main(String[] args) {
Set<U> integers = new HashSet<U>();
Set<V> doubles = new HashSet<V>();
Set<X> numbers = union(integers, doubles);
}
public static <E> Set<E> union(Set<? extends E> s1, Set<? extends E> s2) {
return null;
}
但是如果你稍微改变它,你会得到原点错误。
interface X {}
interface Y {}
class U implements X, Y {}
class V implements X, Y {}
public static void main(String[] args) {
Set<U> integers = new HashSet<U>();
Set<V> doubles = new HashSet<V>();
Set<X> numbers = union(integers, doubles);
}
public static <E> Set<E> union(Set<? extends E> s1, Set<? extends E> s2) {
return null;
}
答案 1 :(得分:1)
唯一的问题是编译器不够聪明,无法确定用E
替换的类型,因此必须明确指定它。这个成语没有名称,只是你如何明确指定泛型类型参数。
答案 2 :(得分:1)
如果union方法定义为<E> Set<E> union(Set<? extends E> s1, Set<? extends E> s2)
,则较旧的Java编译器不够智能,无法正确推断返回的类型。因此,有必要告诉编译器您希望从该方法返回哪种类型,以确保类型安全。 (我认为Java 7编译器可能能够正确地推断出这一点,但我不确定)。
我也不知道这个'成语'的名称,它只是被称为泛型函数。
答案 3 :(得分:1)
Java编译器尝试尽可能地缩小返回类型。在尝试模拟此示例后,我收到以下编译器错误消息而未指定.<Number>union
:
EffectiveJava.java:19: incompatible types
found : java.util.Set<java.lang.Number&java.lang.Comparable<? extends java.lang.Number&java.lang.Comparable<?>>>
required: java.util.Set<java.lang.Number>
Set<Number> numbers = union(integers, doubles);
它尝试将Comparable
包含在“E”中,因为整数和双打都是Comparable
。所以这就是为什么你必须告诉编译器,不,我只想Number
与.<Number>union
。
据我所知,我不知道这个成语是否有名字。
答案 4 :(得分:0)
当你说
时Set numbers = Union.union(integers, doubles)
此处Union是包含静态方法union
方法的类的名称static Set union(Set s1, Set s2)
所以,如果你的类名是GenericDemo,其中定义了方法union,那么你将编写代码 -
Set numbers = GenericDemo.union(integers, doubles)
如果union是非静态方法,则可以用对象实例替换GenericDemo。
答案 5 :(得分:0)
所有关于泛型符号的原则和概念。我是从ijrandom发布的例子开始的。让我们来看第一个场景,其中U和V仅实现X.目前我们没有将方法输出分配给引用变量。我们调用了union方法,如下所示:
union(整数,双打);
我们知道对于泛型,实际的参数类型是由你在调用方法时指定的类型决定的,所以在这种情况下,方法的返回类型将是Set of X,只需将光标移到方法调用上你就会看到java如何编译器在编译时确定了实际的参数类型。
在我们的第二个场景中,我们再次调用方法union:
union(整数,双精度); //注意我们还没有将返回值赋给变量。
将光标移到方法调用上,您会注意到方法的返回类型更改为Set of unknown extends X,因此编译器无法完全解析实际类型,因为U和V同时实现X和Y,X是因此,只要为变量赋值,就会产生错误,因为编译器仍然无法识别实际类型。在这种情况下,您需要告诉编译器使用哪种实际类型。