java遗珠之泛型类型擦除

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lastsweetop/article/details/83025092

擦除规则

泛型的作用之前已经介绍过了只是用于编译之前更为严格的类型检查,其他的一些特性也都是编译之前的,在编译之后泛型是会被擦除掉的。

类型擦除所做的事情如下:

Object

泛型类型的擦除

无边界类型擦除

public class Node<T> {

    private T data;
    private Node<T> next;

    public Node(T data, Node<T> next) {
        this.data = data;
        this.next = next;
    }

    public T getData() { return data; }
    // ...
}

按照规则第一条 T
是无界的,会用 Object
来代替

public class Node {

    private Object data;
    private Node next;

    public Node(Object data, Node next) {
        this.data = data;
        this.next = next;
    }

    public Object getData() { return data; }
    // ...
}

有边界类型擦除

public class Node<T extends Comparable<T>> {

    private T data;
    private Node<T> next;

    public Node(T data, Node<T> next) {
        this.data = data;
        this.next = next;
    }

    public T getData() { return data; }
    // ...
}

有界限的会替换成边界类型

public class Node {

    private Comparable data;
    private Node next;

    public Node(Comparable data, Node next) {
        this.data = data;
        this.next = next;
    }

    public Comparable getData() { return data; }
    // ...
}

泛型方法的类型擦除

无边界类型擦除

public static <T> int count(T[] anArray, T elem) {
    int cnt = 0;
    for (T e : anArray)
        if (e.equals(elem))
            ++cnt;
        return cnt;
}

和泛型类型同理,擦除如下:

public static <T> int count(T[] anArray, T elem) {
    int cnt = 0;
    for (T e : anArray)
        if (e.equals(elem))
            ++cnt;
        return cnt;
}

有边界类型擦除

class Shape { /* ... */ }
class Circle extends Shape { /* ... */ }
class Rectangle extends Shape { /* ... */ }
public class Util {
    public static <T extends Shape> void draw(T shape) { /* ... */ }
}

类型擦除桥接方法

想想下面那个类的擦除

public class ANode<T> {

    public T data;

    public ANode(T data) { this.data = data; }

    public void setData(T data) {
        System.out.println("Node.setData");
        this.data = data;
    }

    public T getData() { return data; }
    // ...
}

会被擦除成

public class ANode {

    private Object data;

    public ANode(Object data) { this.data = data; }

    public void setData(Object data) {
        System.out.println("Node.setData");
        this.data = data;
    }

    public Object getData() { return data; }
    // ...
}

然后再看它的子类

public class MyNode extends ANode<Integer> {
    public MyNode(Integer data) {
        super(data);
    }
    
    public void setData(Integer data) {
        System.out.println("MyNode.setData");
        super.setData(data);
    }
}

擦除之后

public class MyNode extends ANode {
    public MyNode(Integer data) {
        super(data);
    }
    
    public void setData(Integer data) {
        System.out.println("MyNode.setData");
        super.setData(data);
    }
}

这就有意思了我们在main方法里调用如下:

public static void main(String[] args) {
        ANode n = new MyNode(5);
        n.setData("Hello");
        Integer x = (Integer) n.getData();    // Causes a ClassCastException to be thrown.
    }

如果只看擦除前的代码setData("Hello")
调用的应该是子类的方法,参数不应该是String才对。

但是代码肯定是经过擦除的,从这个角度来说

setData("Hello")
getData()

嗯,到目前为止只是我们期望的,那么一运行,蒙了,直接在 setData("Hello")
就报错了。

Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
	at com.sweetop.studycore.generic.MyNode.main(MyNode.java:18)

这是因为为了保证泛型类型擦除后依然具有多态性,编译器在编译的时候自动增加了一个桥接方法,因此子类擦除后应该是这样的

public class MyNode extends ANode {
    public MyNode(Integer data) {
        super(data);
    }
    
    public void setData(Object data) {
        setData((Integer) data);
    }
    
    public void setData(Integer data) {
        System.out.println("MyNode.setData");
        super.setData(data);
    }
}

如果是这样的话,那么子类就重写了父类的方法,调用的其实还是子类的 setData(Object data)
.

因此就看到了上面那个错误。

之后碰到继承泛型类型的时候,一定要注意这种问题。最好在使用之前先做下类型判断

public static void main(String[] args) {
        ANode n = new MyNode(5);
        Object a = "1";
        if (a instanceof Integer) {
            n.setData("1");
        }
        Integer x = (Integer) n.getData();    // Causes a ClassCastException to be thrown.
}

原文 

https://blog.csdn.net/lastsweetop/article/details/83025092

本站部分文章源于互联网,本着传播知识、有益学习和研究的目的进行的转载,为网友免费提供。如有著作权人或出版方提出异议,本站将立即删除。如果您对文章转载有任何疑问请告之我们,以便我们及时纠正。

PS:推荐一个微信公众号: askHarries 或者qq群:474807195,里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化这些成为架构师必备的知识体系。还能领取免费的学习资源,目前受益良多

转载请注明原文出处:Harries Blog™ » java遗珠之泛型类型擦除

赞 (0)
分享到:更多 ()

评论 0

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址