Java系列:关于Java中的桥接方法
这两天在看《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.class
Last modified 2015-12-1; size 771 bytes
MD5 checksum f8d67b651cd0aa143e3fbe03c5edd519
Compiled from "DateInterval.java"
public class me.ygc.javabasic.learnJava.DateInterval extends me.ygc.javabasic.learnJava.MyPair<java.util.Date>
minor version: 0
major version: 49
flags: 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: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #8 // Method me/ygc/javabasic/learnJava/MyPair."<init>":()V
4: return
LineNumberTable:
line 6: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lme/ygc/javabasic/learnJava/DateInterval;
public void setSecond(java.util.Date);
descriptor: (Ljava/util/Date;)V
flags: ACC_PUBLIC
Code:
stack=2, locals=2, args_size=2
0: aload_1
1: aload_0
2: invokevirtual #16 // Method getFirst:()Ljava/lang/Object;
5: checkcast #20 // class java/util/Date
8: invokevirtual #22 // Method java/util/Date.compareTo:(Ljava/util/Date;)I
11: iflt 19
14: aload_0
15: aload_1
16: invokespecial #26 // Method me/ygc/javabasic/learnJava/MyPair.setSecond:(Ljava/lang/Object;)V
19: return
LineNumberTable:
line 8: 0
line 9: 14
line 10: 19
LocalVariableTable:
Start Length Slot Name Signature
0 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;)V
flags: ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
Code:
stack=2, locals=2, args_size=2
0: aload_0
1: aload_1
2: checkcast #20 // class java/util/Date
5: invokevirtual #31 // Method setSecond:(Ljava/util/Date;)V
8: return
LineNumberTable:
line 1: 0
LocalVariableTable:
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的转换,然后转换失败了。
Java系列:关于Java中的桥接方法的更多相关文章
- Java基础之Bridge method(桥接方法)
1.什么是桥接方法 桥接方法是 JDK 1.5 引入泛型后,为了使Java的泛型方法生成的字节码和 1.5 版本前的字节码相兼容,由编译器自动生成的方法. 判断方法 我们可以通过 Method.isB ...
- java 执行 jar 包中的 main 方法
java 执行 jar 包中的 main 方法 通过 OneJar 或 Maven 打包后 jar 文件,用命令: java -jar ****.jar执行后总是运行指定的主方法,如果 jar 中有多 ...
- java中的桥接方法
本文转载自java中什么是bridge method(桥接方法) 导语 在看spring-mvc的源码的时候,看到在解析handler方法时,有关于获取桥接方法代码,不明白什么是桥接方法,经过查找资料 ...
- Java并发编程--多线程中的join方法详解
Java Thread中, join()方法主要是让调用该方法的thread在完成run方法里面的部分后, 再执行join()方法后面的代码 例如:定义一个People类,run方法是输出姓名年龄. ...
- java.util.Stack类中的peek()方法
java.util.stack类中常用的几个方法:isEmpty(),add(),remove(),contains()等各种方法都不难,但需要注意的是peek()这个方法. peek()查看栈顶的对 ...
- Java系列:JVM中的OopMap(zz)
调用栈里的引用类型数据是GC的根集合(root set)的重要组成部分:找出栈上的引用是GC的根枚举(root enumeration)中不可或缺的一环. JVM选择用什么方式会影响到GC的实现: 如 ...
- 重拾java系列一java基础(2)
1.分支流程控制 if(布尔表达式/分支条件){ //语句块} if(布尔表达式/分支条件){ //语句块1}else{ //语句块2} if(条件1){ //语句块1}else if(条件2 ...
- 重拾java系列一java基础(1)
前言,不知不觉,从接触java到工作至今已有两年的时间,突然感觉自己的基础知识还很薄弱,有些知识虽然知道,但是停留在表面上,没有深挖,或者实践过,感觉掌握的很肤浅,而且时间一长,就觉得忘记了,我觉得这 ...
- 【java系列】java开发环境搭建
描述 本篇文章主要讲解基于windows 10系统搭建java开发环境,主要内容包括如下: (1)安装资料准备 (2)安装过程讲解 (3)测试是否安装成功 (4)Hello Word测试 1 安装 ...
随机推荐
- OC语言-04-OC语言-核心语法
一.点语法 1> 基本使用 点语法本质上是set方法/get方法的调用 2> 使用注意 若出现在赋值操作符的右边,在执行时会转换成get方法 若出现在赋值操作符的左边,在执行时会转换成se ...
- 从1.5k到18k, 一个程序员的5年成长之路
昨天收到了心仪企业的口头offer, 回首当初什么都不会开始学编程, 到现在恰好五年. 整天在社区晃悠, 看了不少的总结, 在这个时间点, 我也写一份自己的总结吧. 我一直在社区分享, 所以, 这篇总 ...
- socket服务器开发中的SO_REUSEADDR选项与让人心烦的TIME_WAIT
1 发现问题 我在开发一个socket服务器程序并反复调试的时候,发现了一个让人无比心烦的情况:每次kill掉该服务器进程并重新启动的时候,都会出现bind错误:error:98,Address al ...
- Effective Java 61 Throw exceptions appropriate to the abstraction
Exception translation: higher layers should catch lower-level exceptions and, in their place, throw ...
- 【同步复制常见错误处理3】找不到存储的过程 sp_MSins_tablename
环境在SQL2008 R2同步复制时出错 这个错误提示是由于在订阅端没有找到同步时调用的同步存储过程,MS错误说明: 当某个事务发布在 SQL SERVER自动同步设置选择订阅服务器插入. 更新和删除 ...
- 烂泥:kvm安装windows系统蓝屏
本文由秀依林枫提供友情赞助,首发于烂泥行天下. 最近一直在学习有关KVM的知识,实验一直是在虚拟机VM中进行的.今天刚好公司有一台空闲的服务器,直接拿来安装centos.kvm等等,然后相关的配置. ...
- sql server 之函数小技巧 && 整数类型为空是用空字符串替代实现
1.判空函数 说明:使用指定的替换值替换 NULL. 语法:ISNULL ( check_expression , replacement_value ) 参数: check_expression:将 ...
- Swift学习笔记--变量与常量
1.Swift是一门强类型语言,不能为变量赋予其自身数据类型之外的值: 2.声明变量使用var关键字,声明常量使用let关键字: 3.声明变量或常量时没有对其指定类型且赋予了初值,则编译器会自动推断常 ...
- .net framework 4.6.2 下载
.net framework .net framework版本: 4.6.2 File Name: NDP462-KB3151800-x86-x64-AllOS-ENU.exe 发布日期: 201 ...
- oracle 11g dataguard创建的简单方法
oracle 10g可以通过基于备份的rman DUPLICATE实现dataguard,通过步骤需要对数据库进行备份,并在standby侧进行数据库的恢复.而到了11g,oracle推出了Dupli ...
