我在JShell中尝试了以下Java代码。
class X<A> {
A id(A a) {
return a;
}
}
案例1
X<Integer> w = new X<Integer>();
w.id(5)
在这种情况下,JShell打印只有5,正如我所料。我希望w中的identity函数可以使用类型Integer
进行参数化,因此只需要Integer
。提供非整数子类型的变量会导致此函数出错。
案例2
X x = new X<Integer>();
x.id(5)
JShell输出5,但是同时输出5,它也会输出以下错误信息:
| Warning:
| unchecked call to id(A) as a member of the raw type X
| x.id(5)
| ^-----^
对id(A)的未经检查的调用是什么意思?它似乎不会将x
的类型推断为X<Integer>
,因为我还能够运行x.id("5")
,只有一个警告,这在案例1中是不可能的。这意味着x
中的身份函数是多态的(相对于提供的变量类型)?
案例3
X y = new X<>()
y.id(5)
X z = new X()
z.id(5)
这种情况与案例2相同。但是,我无法围绕代码进行思考。 y的参数化类型是什么?对象y和z是否与它们是两个独立的对象相同?
我猜测类型擦除的概念在这方面起了作用,但我无法真正理解它并解释上述现象。
答案 0 :(得分:2)
在Java泛型中,您必须在变量类型上指定泛型类型,而不是其实现。
这意味着您必须拥有
X<Integer> x = new X<>();
或
X<Integer> x = new X<Integer>();
表示要注册的类型。从Java 7开始,您被允许使用菱形运算符,这意味着编译器能够从数据类型推断出实现类型。如果你有
X x = new X<Integer>();
然后java假定泛型类型只是一个Object。这就是你获得未经检查的赋值的原因,因为就编译器而言,X包含Objects而不是Integers。
案例3与案例2几乎相同,实现是运行时特性,因此编译器始终假定它是一个对象。案例3基本上与Java 5中的内容相同。
答案 1 :(得分:-1)
首先。
X<Integer> x = new X<Integer>();
与
不同X x = new X<Integer>();
好。它是tecnically,但是通过删除左侧的类型,您告诉编译器该变量没有特定类型。 我举个例子。
List<Integer> l = new ArrayList<>();
l.add(1); //Everything fine
List l = new ArrayList<Integer>();
l.add(1); //Compiler or Runtimeerror
在Java中,变量的左侧部分是最重要的(在Java10中不再有效),这就是为什么如果以这种方式声明变量,你必须在左侧告诉他他的类型(在Java 10中这是你不再关心你在左侧使用“var”),在右侧你可以使用钻石类型&lt;&gt;