0

0

Java桥接方法怎么使用

王林

王林

发布时间:2023-04-20 13:07:11

|

1227人浏览过

|

来源于亿速云

转载

1.桥接方法简介

桥接方法是jdk1.5引入泛型后,为使java泛型方法生成的字节码与jdk1.5版本之前的字节码兼容由编译器自动生成的。

可用method.isBridge()判断method是否是桥接方法,在生成的字节码中会有flags标记 ACC_BRIDGE, ACC_SYNTHETIC ,根据来自深入理解java虚拟机的一张访问标志图可以看到 ACC_BRIDGE表示方法是由编译器产生的桥接方法,ACC_SYNTHETIC表示方法由编译器自动产生不属于源码。

Java桥接方法怎么使用

2. 什么时候会生成桥接方法

当子类继承父类(继承接口)实现抽象泛型方法的时候,编译器会为子类自动生成桥接方法

#父类
public abstract class SuperClass<T> {

  public abstract T get(T t) ;
}


#子类
public class SubClass extends SuperClass<String> {

  @Override
  public String get(String s) {
    return s;
  }
}

使用javap -v SubClass.class命令查看类SubClass的字节码:

立即学习Java免费学习笔记(深入)”;

Classfile /Users/xudong/project-maven/test/person-study/dubbo-provider/target/classes/com/monian/dubbo/provider/study/generic/SubClass.class
  Last modified 2022年7月25日; size 777 bytes
  MD5 checksum 1328a7043cde4b809a156e7a239335a6
  Compiled from "SubClass.java"
public class com.monian.dubbo.provider.study.generic.SubClass extends com.monian.dubbo.provider.study.generic.SuperClass<java.lang.String>
  minor version: 0
  major version: 52
  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
  this_class: #4                          // com/monian/dubbo/provider/study/generic/SubClass
  super_class: #5                         // com/monian/dubbo/provider/study/generic/SuperClass
  interfaces: 0, fields: 0, methods: 3, attributes: 2
Constant pool:
   #1 = Methodref          #5.#23         // com/monian/dubbo/provider/study/generic/SuperClass."<init>":()V
   #2 = Class              #24            // java/lang/String
   #3 = Methodref          #4.#25         // com/monian/dubbo/provider/study/generic/SubClass.get:(Ljava/lang/String;)Ljava/lang/String;
   #4 = Class              #26            // com/monian/dubbo/provider/study/generic/SubClass
   #5 = Class              #27            // com/monian/dubbo/provider/study/generic/SuperClass
   #6 = Utf8               <init>
   #7 = Utf8               ()V
   #8 = Utf8               Code
   #9 = Utf8               LineNumberTable
  #10 = Utf8               LocalVariableTable
  #11 = Utf8               this
  #12 = Utf8               Lcom/monian/dubbo/provider/study/generic/SubClass;
  #13 = Utf8               get
  #14 = Utf8               (Ljava/lang/String;)Ljava/lang/String;
  #15 = Utf8               s
  #16 = Utf8               Ljava/lang/String;
  #17 = Utf8               MethodParameters
  #18 = Utf8               (Ljava/lang/Object;)Ljava/lang/Object;
  #19 = Utf8               Signature
  #20 = Utf8               Lcom/monian/dubbo/provider/study/generic/SuperClass<Ljava/lang/String;>;
  #21 = Utf8               SourceFile
  #22 = Utf8               SubClass.java
  #23 = NameAndType        #6:#7          // "<init>":()V
  #24 = Utf8               java/lang/String
  #25 = NameAndType        #13:#14        // get:(Ljava/lang/String;)Ljava/lang/String;
  #26 = Utf8               com/monian/dubbo/provider/study/generic/SubClass
  #27 = Utf8               com/monian/dubbo/provider/study/generic/SuperClass
{
  public com.monian.dubbo.provider.study.generic.SubClass();
    descriptor: ()V
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method com/monian/dubbo/provider/study/generic/SuperClass."<init>":()V
         4: return
      LineNumberTable:
        line 7: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcom/monian/dubbo/provider/study/generic/SubClass;

  public java.lang.String get(java.lang.String);
    descriptor: (Ljava/lang/String;)Ljava/lang/String;
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=1, locals=2, args_size=2
         0: aload_1
         1: areturn
      LineNumberTable:
        line 11: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       2     0  this   Lcom/monian/dubbo/provider/study/generic/SubClass;
            0       2     1     s   Ljava/lang/String;
    MethodParameters:
      Name                           Flags
      s

  public java.lang.Object get(java.lang.Object);
    descriptor: (Ljava/lang/Object;)Ljava/lang/Object;
    flags: (0x1041) ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
    Code:
      stack=2, locals=2, args_size=2
         0: aload_0
         1: aload_1
         2: checkcast     #2                  // class java/lang/String
         5: invokevirtual #3                  // Method get:(Ljava/lang/String;)Ljava/lang/String;
         8: areturn
      LineNumberTable:
        line 7: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       9     0  this   Lcom/monian/dubbo/provider/study/generic/SubClass;
    MethodParameters:
      Name                           Flags
      s                              synthetic
}
Signature: #20                          // Lcom/monian/dubbo/provider/study/generic/SuperClass<Ljava/lang/String;>;
SourceFile: "SubClass.java"

可以看到字节码中有两个get方法,第二个方法参数和返回值类型都是java.lang.Object 并且可以看到flags有相应标志ACC_BRIDGE, ACC_SYNTHETIC说明此方法就是有编译器自动生成的桥接方法。再看code属性:

aload_0:把this变量装载到操作数栈中

aload_1:把方法变量s装载到操作数栈中

checkcast # 2:校验栈顶变量s是否为java.lang.String类型

invokevirtual # 3: 调用方法 public String get(String s)

Vondy
Vondy

下一代AI应用平台,汇集了一流的工具/应用程序

下载

areturn: 返回结果 

根据上述code解释可以看出编译器生成的桥接方法为这个样子的,桥接方法实际上调用了实际的泛型方法

public String get(String s) {
 return s;
}

#桥接方法
public Object get(Object s) {
  return get((String) s);
}

泛型-类型擦除

public class SubClass extends SuperClass<String> {

  @Override
  public String get(String s) {
    return s;
  }

  public static void main(String[] args) {
    SuperClass subClass = new SubClass();
    Object s = "hello world";
    System.out.println(subClass.get(s));
  }
}

java的泛型在运行时会进行泛型擦除替换成非泛型上边界,java虚拟机无法知道准确的类型。 上述代码能编译通过并且会调用子类SubClass的桥接方法由桥接方法再去调用实际泛型方法。如果定义为SuperClass<String> subClass = new SubClass();那么get方法入参只能为String变量,因为编译器在编译期间会进行类型校验,不符合类型将直接报编译失败。

3. 为什么生成泛型方法

{
  public com.monian.dubbo.provider.study.generic.SuperClass();
    descriptor: ()V
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 7: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcom/monian/dubbo/provider/study/generic/SuperClass;
      LocalVariableTypeTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcom/monian/dubbo/provider/study/generic/SuperClass<TT;>;

  public abstract T get(T);
    descriptor: (Ljava/lang/Object;)Ljava/lang/Object;
    flags: (0x0401) ACC_PUBLIC, ACC_ABSTRACT
    MethodParameters:
      Name                           Flags
      t
    Signature: #18                          // (TT;)TT;
}

为了能够正确的编译,可以看到源码中父类SuperClass get方法参数类型为T(T t),而在字节码层面可以看到,经过编译后,get方法入参和返回值类型都为Object。

可以想象一下,如果没有编译器自动生成的桥接方法,那么编译是不会通过的。父类SubClass get方法经过编译后入参和返回值类型都为Object,而子类get方法入参和返回值类型为String,子类并没有重写父类的get方法(重写:访问的方法的实现过程进行重新编写, 返回值和形参都不能改变)。所有编译器需要生成一个桥接方法,Object get(Object) 就可以编译通过了。

4. 根据桥接方法获取实际泛型方法 

主要借助Spring的BridgeMethodResolver#findBridgedMethod找到被桥接的方法,原理是首先找到类声明的所有方法,找到与桥接方法简单名称和方法参数数量相同的候选方法,若只要一个则直接返回,若有多个则循环判断方法参数类型是否相同或者候选方法都有相同的方法签名则从其中任选一个方法作为被桥接的方法。

@Slf4j
public class SubClass extends SuperClass<String> {

  @Override
  public String get(String s) {
    return s;
  }

  public static void main(String[] args) throws Exception {

    SubClass subClass = new SubClass();
    Method bridgeMethod = subClass.getClass().getDeclaredMethod("get", Object.class);
    log.info("bridgeMethod is bridge:" + bridgeMethod.isBridge());
    log.info("bridgeMethod:" + bridgeMethod.toString());

    // 实际泛型方法
    Method actualMethod = subClass.getClass().getDeclaredMethod("get", String.class);
    log.info("actualMethod:" + actualMethod.toString());
    // 通过spring #BridgeMethodResolver由桥接方法获取到实际泛型方法
    Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(bridgeMethod);
    log.info("bridgedMethod:" + bridgedMethod.toString());
  }
}

输出如下:

Java桥接方法怎么使用

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

WorkBuddy
WorkBuddy

腾讯云推出的AI原生桌面智能体工作台

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
spring框架介绍
spring框架介绍

本专题整合了spring框架相关内容,想了解更多详细内容,请阅读专题下面的文章。

161

2025.08.06

Java Spring Security 与认证授权
Java Spring Security 与认证授权

本专题系统讲解 Java Spring Security 框架在认证与授权中的应用,涵盖用户身份验证、权限控制、JWT与OAuth2实现、跨站请求伪造(CSRF)防护、会话管理与安全漏洞防范。通过实际项目案例,帮助学习者掌握如何 使用 Spring Security 实现高安全性认证与授权机制,提升 Web 应用的安全性与用户数据保护。

89

2026.01.26

string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

1051

2023.08.02

硬盘接口类型介绍
硬盘接口类型介绍

硬盘接口类型有IDE、SATA、SCSI、Fibre Channel、USB、eSATA、mSATA、PCIe等等。详细介绍:1、IDE接口是一种并行接口,主要用于连接硬盘和光驱等设备,它主要有两种类型:ATA和ATAPI,IDE接口已经逐渐被SATA接口;2、SATA接口是一种串行接口,相较于IDE接口,它具有更高的传输速度、更低的功耗和更小的体积;3、SCSI接口等等。

1960

2023.10.19

PHP接口编写教程
PHP接口编写教程

本专题整合了PHP接口编写教程,阅读专题下面的文章了解更多详细内容。

658

2025.10.17

php8.4实现接口限流的教程
php8.4实现接口限流的教程

PHP8.4本身不内置限流功能,需借助Redis(令牌桶)或Swoole(漏桶)实现;文件锁因I/O瓶颈、无跨机共享、秒级精度等缺陷不适用高并发场景。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2403

2025.12.29

java接口相关教程
java接口相关教程

本专题整合了java接口相关内容,阅读专题下面的文章了解更多详细内容。

47

2026.01.19

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

447

2023.07.18

TypeScript类型系统进阶与大型前端项目实践
TypeScript类型系统进阶与大型前端项目实践

本专题围绕 TypeScript 在大型前端项目中的应用展开,深入讲解类型系统设计与工程化开发方法。内容包括泛型与高级类型、类型推断机制、声明文件编写、模块化结构设计以及代码规范管理。通过真实项目案例分析,帮助开发者构建类型安全、结构清晰、易维护的前端工程体系,提高团队协作效率与代码质量。

26

2026.03.13

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Kotlin 教程
Kotlin 教程

共23课时 | 4.4万人学习

C# 教程
C# 教程

共94课时 | 11.3万人学习

Java 教程
Java 教程

共578课时 | 81.6万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号