Java泛型---桥方法

桥方法

桥方法是为了解决类型擦除后与多态的冲突。为了理解什么是桥方法。下面举实例,假设有一个泛型类Pair,它用来保存两个值,first与second,first永远比second大。
现在,创建一个子类去继承它。

package Test;

import java.time.LocalDate;

public class Pair<T>
{
   private T first;
   private T second;

   public Pair(){};
   public Pair(T first, T second) {
       this.first = first;
       this.second = second;
   }

   public T getFirst() {
       return first;
   }

   public void setFirst(T first) {
       this.first = first;
   }

   public T getSecond() {
       return second;
   }

   public void setSecond(T second) {
       this.second = second;
   }

 
}

class DateInterval extends Pair<LocalDate> {
   public void setSecond(LocalDate second){
       if(second.compareTo(getFirst()) >=0)
           super.setSecond(second);
   }
}

那么呢,这个子类重写了父类的setSecond,这是我们的意图,要去重写这个方法,那么注意看子类的方法。由于它继承的是Pair类,所以这个方法的参数也要是LocalData,毕竟要时这个日期保持在第二。现在回到泛型类Pair,它的方法类型擦除后是什么样子

 public void setSecond(Object second){
   this.second = second;
 }

很明显,两个方法的参数不一样,并没有达到重写的目的,而是变成了重载。问题就在这里,如果我们编写下面的代码

       DateInterval dateInterval = new DateInterval(); //创建一个实例
        Pair<LocalDate> pair = dateInterval; //父类引用子类实例

        pair.setSecond(LocalDate.now());

上面的代码是典型的多态概念的体现,根据对象的实际类型而非声明类型来决定调用哪个方法的过程,所以此时,预期中肯定是调用实例的方法。但此时,多态特性与类型擦除产生了冲突,编译器会生成一个桥方法。如果没有桥方法,那它会调用本身的方法,也就是原始类型的setsecond(Objects second)方法。为了解决这个问题,编译器在DateInterval类中生成一个桥方法

public void setSecond(Object second){
  setSecond((LocalData) Second);
}

强制调用预期的方法。这就是桥方法,通过搭建一座看不见的桥,使程序符合Java特性。然而,这样看不见的特性,怎么去证明它确实存在?其一是,这样的桥方法是编译器自动生成,如果你手动编写这样的方法,会与编译器生成的产生冲突,从而报错。
image
其二是通过JDK自带查看字节码的工具,对编译后的.class文件执行以下命令。
bash javap -c -v DataInterval.class

欲重写父类的方法字节码

编译器自动生成的setSecond方法,可以很明显的看到它方法的参数是Object。至于其余的代码,我们主要看这一行:
java 5: invokevirtual #25 // Method setSecond:(Ljava/time/LocalDate;)V

类似的,重写父类的get方法

class DateInterval extends Pair<LocalDate>
{
    //编译器自动生成桥方法
    public LocalDate getSecond(){
        //返回父类的second值并转为LocalDate类
        return (LocalDate) super.getSecond();
    }
    
}

编译器会生成下面的桥方法

LocalDate getSecond();
 Object getSecond();//父类继承

总之,对Java泛型的转换,记住以下几点:

  • 虚拟机中没有泛型,只有普通的类和方法。
  • 所有类型参数都会替换为他们的限定类型。
  • 会合成桥方法来保持多态
  • 为保持类型安全性,必要时会强制插入类型转换。
posted @ 2026-01-18 16:28  韦韦道来  阅读(0)  评论(0)    收藏  举报