java泛型-桥方法

虚拟机中没有泛型,只有普通的类和方法。
类型擦除会将类型参数替换成相应的限定类型,如果没有限定类型则替换为Object。
桥方法主要用来解决类型擦除和多态特性的冲突问题。

举例:
定义一个泛型类Pair

public class Pair<T> {
  private T value;

  public Pair() {}
  public Pair(T value) {
    this.value= value;
  }

  public T getValue { return value; }
  public void setValue(T newValue) { value = newValue; }
}

该类因为没有限定类型,所以在类型擦除后的原始类型如下:

public class Pair {
  private Object value;

  public Pair() {}
  public Pair(Object value) {
    this.value= value;
  }

  public Object getValue { return value; }
  public void setValue(Object newValue) { value = newValue; }
}

定义如上Pair类的子类Interval,重写setValue()方法:

public class Interval extends Pair<LocalDate> {
    @Override
    public void setValue(LocalDate value){
            super.setValue(second);
    }
}

如上子类进行类型擦除后的原始类型如下:

public class Interval extends Pair {
    @Override
    public void setValue(LocalDate value){
            super.setValue(second);
    }
}

在执行如下main方法时会存在问题:

public static void main(String[] args) {
    Interval interval = new Interval();
    // 父类引用指向子类对象
    Pair<LocalDate> pair = interval;
    pair.setValue(LocalDate.now());
}

父类引用pair指向子类对象interval,在调用setValue()方法时,应该首先调用子类重写父类的setValue方法,但是:
Interval类中的setValue方法参数类型为LocalDate,而父类中的setValue方法参数类型擦除后为Object,这就造成了类型擦除与多态特性的冲突。
所以Interval类中会生成如下桥方法:

public void setValue(Object newValue) {
  setValue((LocalDate) newValue); 
}

泛型约束和局限性

  1. 不能用基本类型实例化类型参数:类型擦除后变为Object,Object不能存储基本类型的值。

  2. 运行时类型查询只适用于原始类型。
    查询一个对象是否属于某个泛型类型时,使用instanceof会得到编译器错误,如果使用强制类型转换得到一个警告。如下:

if (a instanceof Pair<String>) // Error
if (a instanceof Pair<T>) // Error
Pair<St「ing> p = (Pair<String>) a; // Warning-can only test that a is a Pair

getClass方法总是返回原始类型。如下:

Pair<String> stringPair = . .
Pai「<Employee〉employeePair = . .
// 返回的都是Pair.class
if (stringPair.getClassO == employeePair.getClassO) // they are equal
  1. 不能实例化参数化类型的数组。如下:
Pair<String>[] table = new Pair<String>[10]; // Error

但是声明参数化类型数组的变量是可以的。如下:

Pair<String>[] table;

解决方法:

Pair<String>[] table = (Pair<String>[]) new Pair<?>[10];
  1. 不能实例化类型变量:不能使用像 new T(...),new T[...] 或 T.class这样的表达式中的类型变量。如下:
public Pair() { first = new T(); second = new T(); } // Error

// 解决方法如下:
Pair<String> p = Pair.makePairCString::new);
public static <T> Pair<T> makePair(Supplier<T> constr) {
return new Pair<>(constr.get0. constr.get0); }
  1. 不能构造泛型数组:就像不能实例化一个泛型实例一样,也不能实例化数组。
public static <T extends Comparable〉T[] minmax(T[] a) { T[] mm = new T[2]; . . . } // Error

解决方法如下:

public class Test {
    
    /*public static <T extends Comparable> T[] minmax(T[] a) {
        Object[] mm = new Object[2];
        return (T[]) mm;
    }*/

    public static <T extends Comparable> T[] minmax(IntFunction<T[]> constr, T... elements) {
        T[] mm = constr.apply(2);
        if (elements.length <= 2 && elements.length > 0) {
            return mm = elements;
        }
        return (T[]) mm;
    }

    public static void main(String[] args) {
        String[] strings = new String[2];
        String[] mm = minmax(String[]::new, "hello", "world");
    }
 }
  1. 泛型类静态上下文中的类型变量无效
public class Singleton<T> {
  private static T singlelnstance; // Error
  public static T getSinglelnstanceO // Error
  {
    if (singleinstance == null) construct new instance of T
    return singlelnstance; 
  } 
}
  1. 不能抛出或捕获泛型类的实例:既不能抛出也不能捕获泛型类对象,实际上甚至泛型类扩展Throwable都是不合法的。
    错误示例:
public class Problem<T> extends Exception { /* . . . */ } // Error can't extend Throwable

// catch子句中不能使用类型变量
public static <T extends Throwable〉void doWork(Class<T> t) {
  try
  {
  do work
  }
  catch (T e) // Error can 't catch type variable
  {
  Logger,global.info(...) 
  } 
}

在异常规范中使用类型变量是允许的。

public static <T extends Throwable〉void doWork(T t) throws T // OK
{
  try {
    do work
  }
  catch (Throwable real Cause) 
  { 
    t.initCause(real Cause);
    throw t; 
  } 
}
  1. 擦除后的冲突:要想支持擦除的转换,就需要强行限制一个类或类变量不能同时成为两个接口类型的子类,而这两个接口是同一接口的不同参数化,
// Manager 会实现 Comparable<Employee> 和 Comparable<Manager>, 这是同一接口的不同参数化。
class Employee implements Coinparab1e<Emp1oyee> { . . . }
class Manager extends Employee implements Comparable<Hanager> { . . . } // Error
  1. 泛型类型继承规则
    例如:Manager是Employee的子类,但是Pair不是Pair的子类。

posted @ 2022-12-15 15:52  何时一身轻  阅读(278)  评论(0)    收藏  举报