理解Java中的类型擦除

理解Java中的类型擦除,java,oop,generics,type-erasure,Java,Oop,Generics,Type Erasure,我在JShell中试用了以下Java代码 class X<A> { A id(A a) { return a; } } JShell会输出5,但除了5之外,它还会输出以下错误消息: | Warning: | unchecked call to id(A) as a member of the raw type X | x.id(5) | ^-----^ 对id(A)的未检查调用是什么意思?它似乎无法推断x的类型为x,因为我也可以运行x.id(“5”),只需

我在JShell中试用了以下Java代码

class X<A> {
  A id(A a) {
    return a;
  }
}
JShell会输出5,但除了5之外,它还会输出以下错误消息:

|  Warning:
|  unchecked call to id(A) as a member of the raw type X
|  x.id(5)
|  ^-----^
对id(A)的未检查调用是什么意思?它似乎无法推断
x
的类型为
x
,因为我也可以运行
x.id(“5”)
,只需一个警告,这在案例1中是不可能的。这是否意味着
x
中的标识函数是多态的(与提供的变量类型有关)

案例3

X y = new X<>()
y.id(5)
X z = new X()
z.id(5)
xy=newx()
y、 id(5)
X z=新的X()
z、 id(5)
这种情况与案例2相同。然而,我无法将我的思想集中在代码上。y的参数化类型是什么?除了它们是两个独立的对象之外,对象y和z是相同的吗


我猜类型擦除的概念在其中起了一定作用,但我无法真正理解它并解释上述现象。

在Java泛型中,必须在变量类型上指定泛型类型,而不是它的实现

这意味着你必须

X<Integer> x = new X<>();
X=newx();

X=newx();
对于要注册的类型。自Java7以来,您就被允许使用菱形运算符,这意味着编译器能够从数据类型推断实现类型。如果你有

X x = new X<Integer>();
X=newx();
然后java假设泛型类型只是一个对象。这就是得到未检查赋值的原因,因为就编译器而言,X包含对象,而不是整数

案例3与案例2几乎相同,实现是一个运行时特性,因此编译器总是假定它是一个对象。案例3基本上就是Java5中的情况。

首先

X<Integer> x = new X<Integer>();
X=newx();
不一样

X x = new X<Integer>();
X=newx();
嗯。技术上是这样,但是通过删除左侧的类型,您告诉编译器变量没有特定的类型。 我给你举个例子

List<Integer> l = new ArrayList<>();
l.add(1); //Everything fine
List l = new ArrayList<Integer>();
l.add(1); //Compiler or Runtimeerror
listl=newarraylist();
l、 增加(1)//一切都好吗
列表l=新的ArrayList();
l、 增加(1)//编译器或运行时错误

在Java中,变量的左边部分是最重要的(在Java10中不再有效),这就是为什么如果你以这种方式声明一个变量,你必须在左边告诉他他的类型(在Java10中,这不再是问题,你在左边使用“var”),在右边你可以使用菱形类型。

你刚刚发现。“那么java假设泛型类型只是一个对象。”-不是真的。泛型不是协变的,这就是为什么
X=new X()
不编译。原始类型更糟糕。@Turing85我不确定是否有一种易于理解的方式来表达它,但如果我记得在数据类型中正确指定了
对象,则它强烈定义了它的类型,而完全不指定泛型类型“松散地”将它的类型定义为对象(或基本上允许任何类型)。the““允许任何类型”是关键部分:
X=new X();X s=X;System.out.println(s.id(“Hello”);
这将编译。它甚至会执行。它不会抛出
异常
。这就是原始类型不好的原因。不,
l.add(1);//编译器或运行时错误
都是错误的,两者都是错误的。而且“在Java10中不再有效”这是错误的,因为即使
var
也是在编译时静态键入的。
X<Integer> x = new X<Integer>();
X x = new X<Integer>();
List<Integer> l = new ArrayList<>();
l.add(1); //Everything fine
List l = new ArrayList<Integer>();
l.add(1); //Compiler or Runtimeerror