这两天在看《Java核心技术 卷1》的泛型相关章节,其中说到了在泛型子类中override父类的泛型方法时,编译器会自动生成一个桥接方法,这块有点看不明白。

书上的例子代码如下:

public class MyPair <T>{private T first;private T second;public MyPair(){ first = null; second = null;}public MyPair(T first, T second){ this.first = first; this.second = second;}public T getFirst(){ return first;}public T getSecond() {return second;}public void setFirst(T value){ first = value;}public void setSecond(T value) { second = value;}
}

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

public static void main(String[] args) throws InterruptedException {// TODO Auto-generated method stub        DateInterval interval = new DateInterval();interval.setFirst(new Date());interval.setSecond(new Date());System.out.println("second value of interval: " + interval.getSecond().toString());Thread.sleep(10);MyPair<Date> datePair = interval;datePair.setSecond(new Date());System.out.println("second value of interval: " + datePair.getSecond().toString());}

一、通过jd-gui.exe来分析字节码,只能看到类型擦除信息

上网查阅了一些资料还是不明白,然后觉得应该可以通过反编译工具来看,于是找了jd-gui.exe来看,发现反编译出来的东西和原始的类基本相同的,如下,关于书上提到的类型擦除倒是确实存在,可以看到在字节码中其实没有泛型,而是做了类型擦除之后的类型。

public static void main(String[] args)throws InterruptedException{DateInterval interval = new DateInterval();interval.setFirst(new Date());interval.setSecond(new Date());System.out.println("second value of interval: " + ((Date)interval.getSecond()).toString());Thread.sleep(10L);MyPair<Date> datePair = interval;datePair.setSecond(new Date());System.out.println("second value of interval: " + ((Date)datePair.getSecond()).toString());}

二、用jclasslib来看字节码

感觉可能是jd-gui.exe太高级了,反编译做过头了,结果把我需要的信息都过滤掉了,所以找了稍微更原始反编译工具,jclasslib,使用它打开DateInternal.class文件之后,可以看到如下信息。在上面的源码中我们实际上只给DateInternal添加了一个setSecon方法,但是在反编译之后发现可以看到两个setSecond方法,两个方法的信息分别如下。

1)第一个就是我们在源码中定义的setSecond,入参为Date类型的setSecond方法;

2)第二个就是书上所说的桥接方法,可以看到这个方法的flag中,除了有public,还有bridge,synthetic两个标志,这表示这个是由编译器自动生成的桥接方法。

3)在看看方法的内容,其实内部调用了DateInterval.setSecond方法,并且在

三、也可以使用javap命令来查看字节码信息

在命令行输入javap -c -v DateInternal.class

则会输出如下信息,这里看到的信息和jclaslib看到的类似。

Classfile /D:/java/eclipse/learnJava/target/classes/me/ygc/javabasic/learnJava/DateInterval.classLast modified 2015-12-1; size 771 bytesMD5 checksum f8d67b651cd0aa143e3fbe03c5edd519Compiled from "DateInterval.java"
public class me.ygc.javabasic.learnJava.DateInterval extends me.ygc.javabasic.learnJava.MyPair<java.util.Date>minor version: 0major version: 49flags: ACC_PUBLIC, ACC_SUPER
Constant pool:#1 = Class              #2             // me/ygc/javabasic/learnJava/DateInterval#2 = Utf8               me/ygc/javabasic/learnJava/DateInterval#3 = Class              #4             // me/ygc/javabasic/learnJava/MyPair#4 = Utf8               me/ygc/javabasic/learnJava/MyPair#5 = Utf8               <init>#6 = Utf8               ()V#7 = Utf8               Code#8 = Methodref          #3.#9          // me/ygc/javabasic/learnJava/MyPair."<init>":()V#9 = NameAndType        #5:#6          // "<init>":()V#10 = Utf8               LineNumberTable#11 = Utf8               LocalVariableTable#12 = Utf8               this#13 = Utf8               Lme/ygc/javabasic/learnJava/DateInterval;#14 = Utf8               setSecond#15 = Utf8               (Ljava/util/Date;)V#16 = Methodref          #1.#17         // me/ygc/javabasic/learnJava/DateInterval.getFirst:()Ljava/lang/Object;#17 = NameAndType        #18:#19        // getFirst:()Ljava/lang/Object;#18 = Utf8               getFirst#19 = Utf8               ()Ljava/lang/Object;#20 = Class              #21            // java/util/Date#21 = Utf8               java/util/Date#22 = Methodref          #20.#23        // java/util/Date.compareTo:(Ljava/util/Date;)I#23 = NameAndType        #24:#25        // compareTo:(Ljava/util/Date;)I#24 = Utf8               compareTo#25 = Utf8               (Ljava/util/Date;)I#26 = Methodref          #3.#27         // me/ygc/javabasic/learnJava/MyPair.setSecond:(Ljava/lang/Object;)V#27 = NameAndType        #14:#28        // setSecond:(Ljava/lang/Object;)V#28 = Utf8               (Ljava/lang/Object;)V#29 = Utf8               second#30 = Utf8               Ljava/util/Date;#31 = Methodref          #1.#32         // me/ygc/javabasic/learnJava/DateInterval.setSecond:(Ljava/util/Date;)V#32 = NameAndType        #14:#15        // setSecond:(Ljava/util/Date;)V#33 = Utf8               SourceFile#34 = Utf8               DateInterval.java#35 = Utf8               Signature#36 = Utf8               Lme/ygc/javabasic/learnJava/MyPair<Ljava/util/Date;>;
{public me.ygc.javabasic.learnJava.DateInterval();descriptor: ()Vflags: ACC_PUBLICCode:stack=1, locals=1, args_size=10: aload_01: invokespecial #8                  // Method me/ygc/javabasic/learnJava/MyPair."<init>":()V4: returnLineNumberTable:line 6: 0LocalVariableTable:Start  Length  Slot  Name   Signature0       5     0  this   Lme/ygc/javabasic/learnJava/DateInterval;public void setSecond(java.util.Date);descriptor: (Ljava/util/Date;)Vflags: ACC_PUBLICCode:stack=2, locals=2, args_size=20: aload_11: aload_02: invokevirtual #16                 // Method getFirst:()Ljava/lang/Object;5: checkcast     #20                 // class java/util/Date8: invokevirtual #22                 // Method java/util/Date.compareTo:(Ljava/util/Date;)I11: iflt          1914: aload_015: aload_116: invokespecial #26                 // Method me/ygc/javabasic/learnJava/MyPair.setSecond:(Ljava/lang/Object;)V19: returnLineNumberTable:line 8: 0line 9: 14line 10: 19LocalVariableTable:Start  Length  Slot  Name   Signature0      20     0  this   Lme/ygc/javabasic/learnJava/DateInterval;0      20     1 second   Ljava/util/Date;public void setSecond(java.lang.Object);descriptor: (Ljava/lang/Object;)Vflags: ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETICCode:stack=2, locals=2, args_size=20: aload_01: aload_12: checkcast     #20                 // class java/util/Date5: invokevirtual #31                 // Method setSecond:(Ljava/util/Date;)V8: returnLineNumberTable:line 1: 0LocalVariableTable:Start  Length  Slot  Name   Signature
}
SourceFile: "DateInterval.java"
Signature: #36                          // Lme/ygc/javabasic/learnJava/MyPair<Ljava/util/Date;>;

四、通过代码来验证桥接方法的存在

如果编写如下代码:

public static void main(String[] args) throws InterruptedException {// TODO Auto-generated method stub        MyPair datePair = new DateInterval();datePair.setSecond(new Object());}

运行之后会提示如下:

Exception in thread "main" java.lang.ClassCastException: java.lang.Object cannot be cast to java.util.Date

at me.ygc.javabasic.learnJava.DateInterval.setSecond(DateInterval.java:1)

at me.ygc.javabasic.learnJava.MyPair.main(MyPair.java:26)

说明他实际上是去调用了一个setSecond(Object)的方法,然后在内部做了从Object到Date的转换,然后转换失败了。

转载于:https://www.cnblogs.com/strinkbug/p/5019453.html

Java系列:关于Java中的桥接方法相关推荐

  1. java执行jar中的main_浅谈java 执行jar包中的main方法

    浅谈java 执行jar包中的main方法 通过 OneJar 或 Maven 打包后 jar 文件,用命令: java -jar ****.jar 执行后总是运行指定的主方法,如果 jar 中有多个 ...

  2. Java编程:Java的反射机制中的 getComponentType() 方法

    转载自  Java编程:Java的反射机制中的 getComponentType() 方法 Java 中所有的类都继承自 Object,数组本身也是一个 Class,如果我们能够得到数据的 Class ...

  3. Java编程:浅析泛型类型中的桥接方法

    一.什么是桥接方法 在介绍桥接方法之前,我先介绍下泛型.在 JDK1.5 中引入了泛型,泛型类型是基于原始类型.类型擦除原理进行实现的. 原始类型 Java总是会自动的为泛型类型提供一个相应的原始类型 ...

  4. Java 底层知识:什么是 “桥接方法” ?

    作者 | 小志 来源 | 程序员小灰 导语 笔者在最近的日常工作中,因业务需要,研究 Java 字节码层面的知识.具体是,需要根据类字节码,获取特定方法名的方法入参,此方法名在源码中只有一个.但是在实 ...

  5. java finalize 作用_java中的finalize方法有什么作用

    java中的finalize方法是Object类中提供的一个方法,在GC准备释放对象所占用的内存空间之前,它将首先调用finalize()方法. finalize()方法是Object类中提供的一个方 ...

  6. java调用so库中的native方法_Java如何调用本地.so库里的方法

    首先在此之前希望你已经掌握了基本JNI常识的运用,比如Java代码如何调用本地native的方法,native方法如何访问本地变量,本地方法等以及其他相关的基础知识.在此我还是贴上Activity的部 ...

  7. java getbytes 长度_JAVA中的getBytes()方法

    在Java中,String的getBytes()方法是得到一个操作系统默认的编码格式的字节数组.这个表示在不同情况下,返回的东西不一样! String.getBytes(String decode)方 ...

  8. Java线程池ExecutorService中重要的方法

    ExecutorService 介绍 ExecutorService是java线程池定义的一个接口,它在java.util.concurrent包中,在这个接口中定义了和后台任务执行相关的方法. Ja ...

  9. 关于学习java函数式接口Function中的apply方法的一些感悟

    起因是这样的,学习函数式编程的时候学到了Function接口,对于其中的apply方法感到不解,下面贴上我的不解代码 在这里插public class Function接口 {public stati ...

最新文章

  1. 学学这个垃圾×××网站怎么埋头赚大钱的!
  2. Python初识面向对象
  3. 负载策略_面试官:讲一下什么是负载均衡,什么是轮询策略随机策略哈希策略
  4. 无障碍开发(五)之设置获取无障碍属性值
  5. 异常解决——Spring Cloud FeignClient: BeanCreationException: Error creating bean with
  6. mybatis学习(13): 连接数据库之前的准备(测试连接)
  7. ipython vim_python 之ubuntu开发环境vim 和 ipython
  8. Java语言基础(2)
  9. 在Ubuntu10.10下升级内核到2.6.36使用systemtap
  10. Android 开源项目及库汇总
  11. python是一种解释型、面向什么的计算机程序设计语言_Python \解释型计算机程序设计语言...
  12. ubuntu下用VirtualBox安装Windows虚拟机
  13. grads插值_GrADS中格点插值到站点(gr2stn)的详细方法
  14. Golang interface接口深入理解
  15. 基频和倍频的概念_基频峰,泛频峰,倍频峰,二倍频峰的区别
  16. 如何将音视频中的伴奏背景音乐和人声分离?
  17. apollo决策规划学习--施工绕行
  18. Ubuntu软件安装与卸载
  19. 优化产品交互逻辑来提升产品性能
  20. 对象的向上转型和向下转型

热门文章

  1. 海康威视摄像头安装插件检测不到_海康威视摄像机常见问题解答
  2. 每天一个linux命令(7):mv命令
  3. python【Matlibplot绘图库】优雅的画极坐标(玫瑰)图
  4. 【最小费用最大流】Going Home
  5. idea在mac版怎么配置svn_使用Mac自带svn搭建服务器,并使用idea进行连接
  6. php能做定时关机吗,浅谈系统的定时关机
  7. java byte大小_Java中byte大小格式化
  8. frp 内网穿透, 认证配置,安全配置 TOKEN
  9. 进阶学习(3.8) Component Pattern 组合模式
  10. 网站推广专员浅析网站排名越来越差大抵离不开这些网站推广重点