Java 为什么这个泛型方法调用不起作用?

Java 为什么这个泛型方法调用不起作用?,java,generics,effective-java,Java,Generics,Effective Java,以下代码来自有效的Java书籍: Set<Integer> integers = ... ; Set<Double> doubles = ... ; Set<Number> numbers = union(integers, doubles); 此代码未编译,作者建议通过告诉编译器确切的类型来解决此问题,如下所示: Set<Number> numbers = Union.<Number>union(integers, doubles)

以下代码来自有效的Java书籍:

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)

唯一的问题是编译器不够聪明,无法确定用什么类型替换E,因此必须显式地指定它。这个习惯用法没有名字,只是如何显式指定泛型类型参数。

唯一的问题是编译器不够聪明,无法确定用什么类型替换E,因此必须显式指定它。这个习惯用法没有名字,它只是明确指定泛型类型参数的方式。

如果union方法定义为Set unionSet如果union方法定义为Set unionSet,Java编译器将尝试尽可能缩小返回类型。尝试模拟此示例后,我在未指定.union的情况下收到以下编译器错误消息:

它试图在E中包含Comparable,因为整数和double都是可比较的。所以这就是为什么你必须告诉编译器,不,我只想要带.union的数字


据我所知,我不知道这个习惯用法是否有名字。

Java编译器试图尽可能缩小返回类型。尝试模拟此示例后,我在未指定.union的情况下收到以下编译器错误消息:

它试图在E中包含Comparable,因为整数和double都是可比较的。所以这就是为什么你必须告诉编译器,不,我只想要带.union的数字


据我所知,我不知道这个成语是否有名字。

请注意,Double和Integer不仅扩展了数字,还实现了Comparable。所以,编译器猜测的返回类型将被设置为无法强制转换为Set的返回类型。您需要告诉编译器使用哪一种follow类型。使用以下代码,您不需要精确的类型

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;

}

请注意,Double和Integer不仅扩展了Number,还实现了Comparable。所以,编译器猜测的返回类型将被设置为无法强制转换为Set的返回类型。您需要告诉编译器使用哪一种follow类型。使用以下代码,您不需要精确的类型

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;

}
当你说

Set numbers = Union.union(integers, doubles) 
这里Union是包含静态方法Union的类的名称

static  Set union(Set s1, Set s2) 
因此,如果您的类名是GenericDemo,其中定义了方法联合,那么您将编写的代码-

Set numbers = GenericDemo.union(integers, doubles)
如果union是非静态方法,则可以用对象实例替换GenericDemo

Set numbers = Union.union(integers, doubles) 
这里Union是包含静态方法Union的类的名称

static  Set union(Set s1, Set s2) 
因此,如果您的类名是GenericDemo,其中定义了方法联合,那么您将编写的代码-

Set numbers = GenericDemo.union(integers, doubles)

如果union是非静态方法,则可以用对象实例替换GenericDemo。

这是关于泛型、符号、原则和概念的全部内容。我是从ijrandom发布的示例中继承过来的。让我们来看第一个场景,其中U和V只实现了X。目前我们没有将方法输出分配给引用变量。我们调用了union方法,如下所示:

并整数,双精度

我们知道,对于泛型,实际参数类型由调用方法时指定的类型决定,因此在本例中,方法的返回类型将设置为X,只需将光标移到方法调用上,您将看到java编译器在编译时是如何确定实际参数类型的

在第二个场景中,我们再次调用方法union:

并整数,双精度//注意,我们尚未将返回值赋给变量


将光标移到方法调用上,您会注意到方法的返回类型更改为未知扩展X集,因此在这里,编译器无法完全解析实际类型,因为U和V同时实现X和Y,而X不是Y。因此,只要您为变量赋值,由于编译器仍然无法识别实际类型,因此产生错误。在这种情况下,您需要告诉编译器使用哪种实际类型。

这都是关于泛型、符号、原则和概念的。我是从ijrandom发布的示例中继承过来的。让我们来看第一个场景,其中U和V只实现了X。目前我们没有将方法输出分配给引用变量。我们调用了union方法,如下所示:

并整数,双精度

我们知道,对于泛型,实际参数类型由调用方法时指定的类型决定,因此在本例中,方法的返回类型将设置为X,只需将光标移到方法调用上,您将看到java编译器如何确定 编译时的实际参数类型

在第二个场景中,我们再次调用方法union:

并整数,双精度//注意,我们尚未将返回值赋给变量


将光标移到方法调用上,您会注意到方法的返回类型更改为未知扩展X集,因此在这里,编译器无法完全解析实际类型,因为U和V同时实现X和Y,而X不是Y。因此,只要您为变量赋值,由于编译器仍然无法识别实际类型,因此产生错误。在这种情况下,您需要告诉编译器使用哪种实际类型。

它在Java 7中也会失败。在Java 7中也会失败。为什么您要返回null?它不应该返回两个过程集的并集吗?在演示编译问题时,运行时行为并不重要。为什么您要返回null?它不应该返回集合中两个过程的并集?在演示编译问题时,运行时行为并不重要。