- 浏览: 340048 次
- 性别:
- 来自: 杭州
文章分类
最新评论
-
yueshang520:
太厉害了
Spring读取XML配置源码解析 -
levin_china:
jianyan163qq 写道好文章!我现在遇到一个调用的问题 ...
Java中Runtime.exec的一些事 -
wenlongsust:
exec可能存在注入漏洞,如何控制安全问题啊?
Java中Runtime.exec的一些事 -
RainWu:
...
设计模式感触之代理模式应用 -
ch_dj:
面向对象涉及原则:1.开闭原则2.少用继承,多用聚合3.针对 ...
设计模式感触之代理模式应用
Java中的桥方法是合成方法(synthetic methods),合成方法对于实现Java语言特征是必需的。最广为人知的例子就是协变返回类型和泛型中的案例,在泛型中案例基方法的参数被擦除后与实际被调用的方法不同时会使用到桥方法。
首先来看一个例子:
public class BridgeMethodOne { public static class BMOne<T> { public T getT() { return null; } } public static class BMTwo extends BMOne<String> { public String getT() { return null; } } }
事实上这仅仅是一个协变返回类型的例子,在类型擦除之后看起来和下面的片段类似:
public class BridgeMethodOne { public static class BMOne { public Object getT() { return null; } } public static class BMTwo extends BMOne { public String getT() { return null; } } }
然后在编译反编译之后,BMTwo将和下面类似:
public static class learn.generic.BridgeMethodOne$BMTwo extends learn.generic.BridgeMethodOne$BMOne {
.…
// Method descriptor #15 ()Ljava/lang/String;
// Stack: 1, Locals: 1
public java.lang.String getT();
0 aconst_null
1 areturn
// 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
}
在上面可以看见有一个新的合成方法“java.lang.Object getT()”,这是源代码中没有的。这个方法作为一个桥方法,它所做的全部工作就是将调用代理到“java.lang.String getT()”。因为在JVM里,方法的返回类型是方法签名的一部分,而创建桥方法是实现协变返回类型的方式,因此编译器必须这么做。
现在再来看下面这个泛型指定的例子:
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; } } }
在编译之后,BMTwo将被转换成如下:
public static class learn.generic.BridgeMethodTwo$BMTwo extends learn.generic.BridgeMethodTwo$BMOne {
public java.lang.String getT(java.lang.String args);
0 aload_1 [args]
1 areturn
// 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
}
在这里,桥方法重写了基类BMOne,它不仅做了有参数的调用,同时还执行了到“java.lang.String”的类型转换。这意味着在执行下面的代码忽略编译器的“uncheck”警告时,桥方法将抛出ClassCastException异常。
public static void main(String[] args) { BMOne one = new BMTwo(); one.getT(new Object()); }
Exception in thread "main" java.lang.ClassCastException: java.lang.Object cannot be cast to java.lang.String
所列的两个例子是桥方法使用中最广为人知的,但除此之外,桥方法至少还有一个用武之地,那就是被用来改变基类方法的可见性。试着查看下面的例子并尝试着猜测编辑器需要在什么地方创建桥方法。
public class BridgeMethodThree { static class ClassA { public void foo() { } } public static class ClassB extends ClassA { } public static class ClassC extends ClassA { public void foo() { } } }
如果查看ClassB编译后的文件,可以发现发现:
public static class learn.generic.BridgeMethodThree$ClassB extends learn.generic.BridgeMethodThree$ClassA {
public BridgeMethodThree$ClassB();
0 aload_0 [this]
1 invokespecial learn.generic.BridgeMethodThree$ClassA() [8]
4 return
public bridge synthetic void foo();
0 aload_0 [this]
1 invokespecial learn.generic.BridgeMethodThree$ClassA.foo() : void [15]
4 return
}
因为ClassA是包级别限制的,不能被包外访问,而ClassB是公共的,而所有继承的方法必须能够被包外所访问,因此编译器需要桥方法。注意,由于ClassC重写了“foo”方法,不再需要桥方法来增加可见性。
也许还有一些其它地方使用了桥方法,但没有关于这些的源信息。同样,也没有桥方法的定义,虽然从上述的例子已经看出来并可以猜到大致代表什么,但JLS里却没有明确的说明。尽管isBridge是java1.5之后反射API了的公共方法,JVM和JLS没有关于其的确切定义和编译器在何时、如何使用桥方法的定义。一般情况下,当一个类实现了一个参数化的接口或是继承了一个参数化的类时,需要引入桥方法。
英文参考:http://happyenjoylife.iteye.com/blog/1153964
发表评论
-
警告:编码 EUC_CN 的不可映射字符
2013-04-01 15:49 3686使用javac编译时显示: 警告:编码 EUC_CN 的不 ... -
异常处理几则(javac异常与get请求中文乱码)
2013-03-31 18:36 12181 仅当显式请求注释处理时才接受类名称错误 好久没用ja ... -
Java内存管理知识(基础篇)
2013-01-20 16:02 1599第一部分 基础知识 1.1 内存模型 1.2 垃圾回 ... -
Java虚拟机之垃圾收集
2013-01-12 15:07 2986垃圾收集虽说不是JVM ... -
maven坐标查询
2012-12-10 23:11 3376使用maven时,一个经常用到的操作就是去 中央仓库查询相关库 ... -
Maven报错“未结束的字符串字面值” “需要为 class、interface 或 enum”等
2012-12-10 17:26 5956eclipse里面编译完全正常,mvn clean in ... -
String, StringBuilder和StringBuffer性能比较的正确写法
2012-11-22 22:54 2172关于String连接性能的分 ... -
No embedded stylesheet instruction for file:奇怪的错误
2012-11-17 08:14 1336008:09:43,395 INFO [main] Ma ... -
Java中Runtime.exec的一些事
2012-09-09 16:32 503000 预备知识 1 不正确的 ... -
代码重构(一)
2012-08-26 10:55 0真实代码 /** 支付状态校验 * ... -
JAVA正则表达式
2012-08-22 23:04 0JAVA中的正则知识 1.2正则表达式入门 一 ... -
JAVA字节码学习一(初识)
2012-08-20 21:42 0public class MyClass { pub ... -
java类库中Arrays的排序算法探析(Object与泛型类型)
2012-03-10 21:16 1710在Arrays中关于基本类型如int,long,fl ... -
java类库中Arrays的排序算法探析(基础类型)
2012-03-06 23:32 2664java.util.Arrays中有非常方便的array转换为 ... -
Java中List与Array的转换
2012-02-28 18:42 1581在编码中,经常会用到两种存储结构之间的转换,而对 ... -
设计模式感触之代理模式-远程代理
2012-01-08 16:33 37201 远程代理的意义 远程代理为一个位于不同的地址空间的 ... -
设计模式感触之代理模式应用
2012-01-03 17:30 4435设计模式感触之代理模式应用 如果说看完设计模式之 ... -
Java泛型学习
2010-11-06 22:19 1122泛型程序设计(Generic Programming)可以使编 ... -
正在学JAVA的请看看:JAVA学习之路
2010-11-05 15:32 1220JAVA是一种平 ... -
JAVA学习路线图
2010-11-05 15:29 1507最近论坛上看到好几个朋友都在问,如何学习 Java的问 ...
相关推荐
在深入探讨Java中native方法的学习之前,我们先来理解一下native方法的概念以及它在Java中的作用。Native方法是Java编程语言中的一个特性,允许Java代码调用非Java代码(通常是C或C++编写的),这为Java应用程序提供...
本篇文章将详细讲解如何在Java中给自己写的方法添加注释,以便于日后查阅和理解。 首先,我们了解Java中的三种基本注释方式: 1. 单行注释(//):这是最常用的注释方式,适用于单行的描述。 ```java // 这是一个...
在Java代码中,你需要定义一个类,并在其中声明一个native方法。例如: ```java public class MyJavaClass { public native void callFromC(); static { System.loadLibrary("mylib"); } } ``` `callFromC...
在本主题中,我们将深入探讨如何使用C++通过JNI来调用Java中的方法,以及如何实现C++与JavaScript的互调。这在跨平台开发、性能优化或利用现有C/C++库时尤其有用。 首先,我们需要理解JNI的基本结构。JNI接口定义了...
Java是一种跨平台的编程语言,但在与底层操作系统交互时,比如调用Windows系统的动态链接库(DLL)中的方法,就需要一些特殊的工具和技术。本实例主要介绍如何使用Java和jawin库来实现DLL方法的调用。 jawin是一个...
本篇文章将详细探讨如何在C#中调用Java方法,以及与之相关的技术,包括IKVM.NET。我们将通过提供的资源,即“UseJAVA.rar”和“JAVADemo.rar”,来了解具体的实现过程。 首先,让我们理解C#调用Java方法的基本原理...
1. **定义本地方法**:首先,在Java代码中定义一个本地方法(native method),该方法声明为native,表示它是由本地代码实现的。 ```java public native int add(int x, int y); ``` 2. **生成头文件**:使用`...
这份手册详细介绍了Java标准类库中的各种类、接口、方法和异常,是Java学习者和开发者的得力助手。 在Java编程中,类库是预先编写好的一组类和接口的集合,它们提供了丰富的功能,可以帮助开发者构建高效、稳定的...
如果需要在WebView中启用JavaScript调用Android代码的功能,还要在addJavascriptInterface()方法中声明一个Java类的实例,并为其指定一个可以在JavaScript中访问的接口名字。 在Java代码中定义一个内部类,用于接收...
总之,这个示例提供了Java通过Jacob库调用C# DLL的方法,这对于那些需要在Java应用中利用.NET功能的开发者来说,是一个非常有价值的参考资源。通过理解Jacob的工作原理和实践中的调用流程,可以有效地实现Java和.NET...
总的来说,Java的COM桥JCom是Java开发者在Windows环境中利用COM组件的一个重要工具。它简化了Java与COM之间的通信,让Java开发者能够充分利用已有的COM资源,提升了开发效率。然而,使用JCom也需要注意性能和兼容性...
Java中的Native方法是Java语言与本地(Native)代码交互的一种机制,主要涉及到Java的JNI(Java Native Interface)技术。JNI允许Java程序调用C、C++等非Java编写的代码,反之亦然,使得Java可以充分利用本地平台的...
本文将深入解析如何通过Java代码实现与数据库的连接,具体聚焦于“Java代码桥连连接数据库”这一主题,涵盖知识点包括:Java数据库连接(JDBC)的基本原理、关键代码实现细节以及最佳实践。 ### Java数据库连接...
JDBC-ODBC桥是一种早期用于连接Java应用程序与各种数据库的方法。它通过ODBC(开放式数据库连接)来实现,ODBC是一种标准的数据库访问接口,主要用于Windows操作系统。 **1. 加载驱动** ```java Class.forName(...
桥方法是Java编译器在编译泛型代码时,生成的一种特殊方法。桥方法的作用是保证多态性,例如: ```java public class Node<T> { public void setData(T data) { System.out.println("Node.setData"); this.data =...
在Java中,Jython是一个非常有用的工具,它允许我们在Java应用程序中嵌入Python代码,并能够无缝地在Python数据类型和Java数据类型之间进行转换。这极大地扩展了Java的生态系统,让我们能够利用Python丰富的库和简洁...
本教程将详细介绍如何在C语言中调用Java方法。 首先,了解JNI的基本概念。JNI是Java平台标准的一部分,允许Java代码和其他语言写的代码进行交互。当Java程序需要执行一些特定的、效率较高的本地操作时,就会使用JNI...
本地方法是声明在Java类中,但其实现是在本地代码(如C++)中。在Java程序中,我们用`native`关键字来声明本地方法,例如: ```java public class JNITest { static { System.loadLibrary("JNITest"); // 加载DLL...
下面将详细讲解Java中读取文件的主要方法,并结合给出的代码片段进行分析。 首先,Java中最基础的文件读取方式是通过`java.io.File`类来创建文件对象,然后使用`java.io.FileInputStream`或`java.io....