java中泛型擦除和多态的冲突及解决

泛型擦除

java的泛型是一种伪泛型,编译器会去除泛型信息,字节码不会包含泛型信息。

public class Client {

  public static void main(String[] args) {
    List<String> nameList = new ArrayList<>();
    List<Integer> ageList = new ArrayList<>();
    //编译后都会变成 List  
    System.out.println(nameList.getClass() == ageList.getClass());// true
  }

}

JVM看到的都是List,所以结果为 true.

和多态的冲突

public class Client2 {

  public static void main(String[] args) {
    DateHolder dateHolder = new DateHolder();
    dateHolder.setValue(new Date());
    Date value = dateHolder.getValue();
    System.out.println(value);
  }

  interface Holder<T> {

    T getValue();

    void setValue(T value);
  }

  static class DateHolder implements Holder<Date> {

    private Date value;

    @Override
    public Date getValue() {
      return this.value;
    }

    @Override
    public void setValue(Date value) {
      this.value = value;
    }
  }
}

定义一个泛型接口,定义一个子类实现泛型接口,泛型接口经过编译器擦除后会变成

static interface Holder {

    public abstract Object getValue();

    public abstract void setValue(Object obj);
}

但是子类重写的方法明明参数和返回值都是 Date 类型啊,这是怎么回事呢?
我们的本意是想将泛型接口变成

static interface Holder {

    public abstract Date getValue();

    public abstract void setValue(Date obj);
}

但编译器没有办法将泛型变成 Date ,只能变成 Object。但编译器使用桥方法实现了这一功能。反编译结果为

static class DateHolder implements Holder {

        public Date getValue() {
            return value;
        }

        public void setValue(Date value) {
            this.value = value;
        }

        public volatile void setValue(Object obj) {
            setValue((Date)obj);
        }

        public volatile Object getValue() {
            return getValue();
        }

        private Date value;

        DateHolder() {
        }
}

编译器通过桥方法解决了泛型擦除和多态之间的冲突。可以看到子类实现中

public Date getValue() {
     return value;
}

public volatile Object getValue() {
    return getValue();
}

我们自己的编码中这样写是不能通过编译器检查的,但编译器自己是可以这样的,因为虚拟机是通过返回值和参数列表来区分方法的。

posted @ 2020-11-08 20:00  strongmore  阅读(804)  评论(0编辑  收藏  举报