在运行时进行类型擦除验证

时间:2018-12-13 09:29:27

标签: java

我已经阅读了许多有关类型擦除的答案和文章,并且我了解在运行时排除了该类型:

  

类型擦除可以解释为仅在编译时强制执行类型约束并在运行时丢弃元素类型信息的过程。

所以假设我有这个通用类:

public class Stack<E> {
    private E[] stackContent;

    public Stack(int capacity) {
        this.stackContent = (E[]) new Object[capacity];
    }
}

它将被编译为:

public class Stack {
    private Object[] stackContent;

    public Stack(int capacity) {
        this.stackContent = (Object[]) new Object[capacity];
    }

    public void push(Object data) {
        // ..
    }

    public Object pop() {
        // ..
    }
}

我还是不明白我是否创建了“ String”堆栈,它如何确保我不会插入Integer?

Stack<String> stack=new Stack<String>(..);

如果类型被删除并且push函数接受任何对象,怎么知道我只能插入字符串?

4 个答案:

答案 0 :(得分:1)

在运行时您真的不知道只会插入String。此处的目的是避免在编译时出现不良情况。

如果您使用以下签名声明push方法:

public void push(E element) { ... }

如果您尝试在push(12)上调用Stack<String>,则Java编译器将引发错误。

在编译后会发生擦除。类型检查是使用实型完成的。

答案 1 :(得分:1)

一个很好的问题,看到“天真”的答案。您可能会用A.java包含包含类型已擦除代码的编译器编译B.class

在编译时Stack<String>.push(Integer)是错误的。在同一个Java源代码中,这也就不足为奇了。

但是,当声明在另一个类中时,仅给出已编译的.class吗?

肮脏的秘密是<FormalTypeParameter>(已经)也存储在.class中。因此,Java慢慢地进入了没有类型擦除的时代。还请注意,为类型擦除的构造添加了运行时强制转换。 当非一般地使用类Stack st = ...时,会引发运行时错误。

答案 2 :(得分:0)

这是一个把戏。 您不能

声明Stack<String> stack时,然后在编译时,JVM会检查您添加的Stringnot String并引发异常。

但是在运行时,您可以添加所需的任何内容,例如旧的JVM版本(这样做是为了使旧的代码可在新的JVM版本中进行编译)。

即当您声明Stack<?> stack时,正是您在运行时所拥有的。

答案 3 :(得分:0)

this.startMyVisit();本身可以编译为Stack,但是客户端类仍将其作为Object的堆栈。即

String

在编译时无效 。如果要通过使用原始类型在客户端中删除该信息,则可以

Stack<String> stringStack = new Stack<String>();
stringStack.push(-1);