代码之家  ›  专栏  ›  技术社区  ›  Mohideen Imran Khan

了解Java中的类型擦除[重复]

  •  2
  • Mohideen Imran Khan  · 技术社区  · 6 年前

    我在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函数用type参数化 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中不可能出现的警告。这是否意味着身份功能 十、 多态性(相对于所提供的变量类型)吗?

    案例3

    X y = new X<>()
    y.id(5)
    X z = new X()
    z.id(5)
    

    这种情况与情况2相同。然而,我无法将我的思想集中在代码上。y的参数化类型是什么?除了它们是两个独立的对象之外,对象y和z是否相同?

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

    2 回复  |  直到 6 年前
        1
  •  2
  •   vandench    6 年前

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

    这意味着你必须

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

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

    用于要注册的类型。自Java 7以来,您就被允许使用diamond运算符,这意味着编译器能够从数据类型推断实现类型。如果你有

    X x = new X<Integer>();
    

    然后java假设泛型类型只是一个对象。这就是为什么会得到未经检查的赋值,因为就编译器而言,X包含的是对象,而不是整数。

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

        2
  •  -1
  •   Levent Dag    6 年前

    首先

    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
    

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