文章标题

原创 2016年05月31日 07:17:34

在Java的早期版本中,不支持返回类型协变(一个类如果继承/实现了父类/接口的某一个方法,那么返回类型必须与父类/接口的相同),而在Java的后期版本中(具体从几点几开始支持就不太清楚了…)开始支持返回类型协变,支持类型协变的就是Java的桥方法。

接下来列举三个场景来说明桥方法的真实面目和所起到的作用。

场景一:基本的返回类型协变问题
父类代码:

class Father{
    public Number test1(){
        return null;
    }
}

子类代码:

class Son extends Father{
    public Integer test1(){
        return null;
    }

    /**
     *  // Method descriptor #16 ()Ljava/lang/Number;
        // Stack: 1, Locals: 1
    public bridge synthetic java.lang.Number test1();
        0  aload_0 [this]
        1  invokevirtual com.cjs.gohead.generic.classorinterface.Son.test1() : java.lang.Integer [17]
        4  areturn
     */
}

子类中注释的那段即是Java编译器自动生成的桥方法,它由编译器自动生成,存在于class文件,通过那段字节码可以很清楚的看出桥方法的生成。

同时呢返回类型协变也包括泛型擦除(涉及到泛型的实现原理)所引起的一个问题:当一个“子泛型类”实现/继承自一个“父泛型类”的时候,“父泛型类”的类型信息会被擦除为限定类型,这个时候“子泛型类”里面会生成一个桥方法(场景二)。

场景二的例子(注释为编译器所生成的桥方法):

public class BridgeMethodOne {
    public static class BMOne<T> {
        // 由于擦除,类型参数T会被替换为限定类型:Object,擦除之
        // 后,就与场景一的场景相同了
        public T getT() {
            return null;
        }
    }

    public static class BMTwo extends BMOne<String> {
        /**
           // Method descriptor #16()Ljava/lang/Object;
          // Stack: 1, Locals: 1
      public bridge synthetic java.lang.Object getT();
        0  aload_0 [this]
        1  invokevirtual   learn.generic.BridgeMethodOne$BMTwo.getT() : java.lang.String [17]
    4  areturn
        */
        public String getT() {
            return null;
        }
    }
}

桥方法还可以解决另一个也是由泛型擦除所引起的问题:当使用泛型类或泛型接口的时候,当被继承/实现的方法(父类中的方法)含有方法参数的时候(并且方法参数为类型参数),由于擦除,会导致子类不会继承/实现父类的方法,所以这个时候就编译器会生成一个方法来解决这个“继承错误”的问题-方法签名不一致(场景三)。

第三个场景的例子(注释为编译器所生成的桥方法):

public class BridgeMethodTwo {
    public static class BMOne<T> {
        public T getT(T args) {
            return args;
        }
    }

    public static class BMTwo extends BMOne<String> {
        public String getT(String args) {
            return args;
        }
        /**
        // Method descriptor #18 (Ljava/lang/Object;)Ljava/lang/Object;
  // Stack: 2, Locals: 2
  public bridge synthetic java.lang.Object getT(java.lang.Object arg0);
    0  aload_0 [this]
    1  aload_1 [arg0]
    2  checkcast java.lang.String [19]
    5  invokevirtual learn.generic.BridgeMethodTwo$BMTwo.getT(java.lang.String) : java.lang.String [21]
    8  areturn
        */
    }
}

最后总结一下,Java中的桥方法可以解决返回类型协变的问题(场景一和场景二)和由泛型擦除所引起的看似“继承错误”的问题(场景三)。

版权声明:本文为博主原创文章,未经博主允许不得转载。

文章标题自动标注程序

  • 2015年06月25日 17:04
  • 6.93MB
  • 下载

文章标题 CSU 1849: Comparing answers(矩阵降维+随机化思想)

1849: Comparing answers这里写链接内容 题意:题意是有矩阵A,B,然后判断A*A ?= B ,直接做O(n*n*n) 分析:矩阵降维 A*A*C ?= B*C, C 是一...

文章标题上下轮番滚动.zip

  • 2012年09月04日 12:31
  • 28KB
  • 下载

PL/SQL记录和表(oracle type(数组))(最简单!文章下面标黄标题是精华,必看)

PL/SQL记录和表 1.使用%TYPE  (用于基本数据类型) 例1(用户并不知道Course_No的数据类型,只知道他是基于Student_No数据类型的,随着Student_No的类型变化而...

在文章中主标题和副标题的格式问题

请问:如果 大标题居中书写。正常情况下,副标题要在大标题第三个字下开始写破折号,是吗?那如果格数不够,副标题写不开了怎么办?可以把副标题居中写吗? 还是把 大标题和副标题整体前移?不是论文,手写的,公...

文章标题Matlab GUI学习笔记(一)function “funcname” 工作区和基本工作区

最近学习matlab的GUI编程,非图形化方式,发现使用回调函数传递句柄类型的变量是时总是提示该变量未定义: Error using matlab.ui.Figure/set Invalid or ...
  • guguizi
  • guguizi
  • 2016年03月10日 17:03
  • 1356

文章标题 使用ajaxFileupload+struts2完成文件的上传以及回显到jsp的链接地址

积累点滴,从这一刻开始 jsp页面部分 第一步: jsp页面导入 ajaxfileupload.js文件 第二步:编写上传文件的文本框: 第三步: struts2后台部...

dede5.7将图片的ALT注释设置为文章标题且点击图片进入下一页,最后一页进入下一篇

dede5.7将图片的ALT注释设置为文章标题且点击图片进入下一页,最后一页进入下一篇 首先对你的include/arc.archives.class.php文件进行一个备份,以免出错后好修改。 ...
  • bobay
  • bobay
  • 2014年01月07日 10:45
  • 3501

PL/SQL记录和表(oracle type(数组))(最简单!文章下面标黄标题是精华,必看)

PL/SQL记录和表 1.使用%TYPE  (用于基本数据类型) 例1(用户并不知道Course_No的数据类型,只知道他是基于Student_No数据类型的,随着Student_No的类型变化而...
  • cph18
  • cph18
  • 2014年09月03日 16:54
  • 242
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:文章标题
举报原因:
原因补充:

(最多只允许输入30个字)