如何在Java项目中实现一个桥接方法

  介绍

本篇文章给大家分享的是有关如何在Java项目中实现一个桥接方法,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。

什么是桥接方法?

Java中的桥接方法(桥方法)是一种为了实现某些Java语言特性而由编译器自动生成的方法。

我们可以通过方法类的isBridge方法来判断一个方法是否是桥接方法。

在字节码文件中,桥接方法会被标记为ACC_BRIDGE和ACC_SYNTHETIC,其中ACC_BRIDGE用于表示该方法是由编译器产生的桥接方法,ACC_SYNTHETIC用于表示该方法是由编译器自动生成。

什么时候生成桥接方法?

为了实现哪些Java语言特性会生成桥接方法?最常见的两种情况就是协变返回值类型和类型擦除,因为它们导致了父类方法的参数和实际调用的方法参数类型不一致。下面我们通过两个例子更好地理解一下。

协变返回类型

协变返回类型是指子类方法的返回值类型不必严格等同于父类中被重写的方法的返回值类型,而可以是更“具体”的类型。

在Java 1.5添加了对协变返回类型的支持,即子类重写父类方法时,返回的类型可以是子类方法返回类型的子类。下面看一个例子:

public  class  Parent  {   Number 才能;get (), {   ,,,return  1;   ,,}   } public  class  Child  extends  Parent  {      @Override才能   Integer 才能;get (), {   ,,,return  1;   ,,}   }

子类重写其父类母公司的获得方法,母公司的获得方法返回类型为数字,而儿童类中得到方法返回类型为整数。

将这段代码进行编译,再反编译:

javac  Child.java   javap  -v  -c 儿童。类

结果如下:

公共类子扩展父
……省略部分结果……
,. lang。整数get (),
,,,描述符:()Ljava/lang/整数;
,,,国旗:
,,,代码:
,,,,,堆栈=1,当地人=1,args_size=1
,,,,,,,,0:iconst_1
,,,,,,,,1:invokestatic # 2,,,,,,,,,,,,,,,,,//java/lang/Integer.valueOf方法:(I) Ljava/lang/整数;
,,,,,,,,4:areturn
,,,,,LineNumberTable:
,,,,,,,第5行:0


,. lang。数量();
,,,描述符:()Ljava/lang/数量;
,,,国旗:ACC_BRIDGE ACC_SYNTHETIC
,,,代码:
,,,,,堆栈=1,当地人=1,args_size=1
,,,,,,,,0:aload_0
,,,,,,,,1:invokevirtual # 3,,,,,,,,,,,,,,,,,//方法得到:()Ljava/lang/整数;
,,,,,,,,4:areturn
,,,,,LineNumberTable:
,,,,,,,1号线:0

从上面的结果可以看的到,有一个方法. lang。数量(),在源码中是没有出现过的,是由编译器自动生成的,该方法被标记为ACC_BRIDGE和ACC_SYNTHETIC,就是我们前面所说的桥接方法。

这个方法就起了一个桥接的作用,它所做的就是把对自身的调用通过invokevirtual指令再调用方法. lang。整数get () .

* *编译器这么做的原因是什么呢? * *因为在JVM方法中,返回类型也是方法签名的一部分,而桥接方法的签名和其父类的方法签名一致,以此就实现了协变返回值类型。

类型擦除

泛型是Java 1.5才引进的概念,在这之前是没有泛型的概念的,但泛型代码能够很好地和之前版本的代码很好地兼容,这是为什么呢?

这是因为,在编译期间Java编译器会将类型参数替换为其上界(类型参数中扩展子句的类型),如果上界没有定义,则默认为对象,这就叫做类型擦除。

当一个子类在继承(或实现)一个父类(或接口)的泛型方法时,在子类中明确指定了泛型类型,那么在编译时编译器会自动生成桥接方法,例如:

public  class  Parent, {      void 才能设置(T  t), {   ,,}   } public  class  Child  extends  Parent, {      @Override才能   void 才能;集(String  str), {   ,,}   }

子类在继承其父类父母的泛型方法时,明确指定了泛型类型为字符串,将这段代码进行编译,再反编译:

公共类儿童扩展Parent
……省略部分结果……
,空集(以);
,,,描述符:(Ljava/lang/String;) V
,,,国旗:
,,,代码:
,,,,,堆栈=0,当地人=2,args_size=2
,,,,,,,,0:返回
,,,,,LineNumberTable:
,,,,,,,第5行:0

,空集(java . lang . object);
,,,描述符(Ljava/lang/对象;):V
,,,国旗:ACC_BRIDGE ACC_SYNTHETIC

如何在Java项目中实现一个桥接方法