java7之Special Methods
1、关于<init>与<clinit>
At the level of the Java Virtual Machine, every constructor written in the Java programming language (JLS §8.8) appears as an instance initialization method that has the special name <init>. This name is supplied by a compiler. Because the name <init> is not a valid identifier, it cannot be used directly in a program written in the Java programming language. Instance initialization methods may be invoked only within the Java Virtual Machine by the invokespecial instruction (§invokespecial), and they may be invoked only on uninitialized class instances. An instance initialization method takes on the access permissions (JLS §6.6) of the constructor from which it was derived.
A class or interface has at most one class or interface initialization method and is initialized (§5.5) by invoking that method. The initialization method of a class or interface has the special name <clinit>, takes no arguments, and is void (§4.3.3).
<clinit> 在jvm第一次加载class文件时调用,包括静态变量初始化语句和静态块的执行
Other methods named <clinit> in a class file are of no consequence. They are not class or interface initialization methods. They cannot be invoked by any Java Virtual Machine instruction and are never invoked by the Java Virtual Machine itself.
In a class file whose version number is 51.0 or above, the method must additionally have its ACC_STATIC flag (§4.6) set in order to be the class or interface initialization method.
This requirement is new in Java SE 7. In a class file whose version number is 50.0 or below, a method named <clinit> that is void and takes no arguments is considered the class or interface initialization method regardless of the setting of its ACC_STATIC flag.
The name <clinit> is supplied by a compiler. Because the name <clinit> is not a valid identifier, it cannot be used directly in a program written in the Java programming language. Class and interface initialization methods are invoked implicitly by the Java Virtual Machine; they are never invoked directly from any Java Virtual Machine instruction, but are invoked only indirectly as part of the class initialization process.
接口中有<clinit>方法,其owner,也就是所属的symbol为java.lang.Object
2、关于invoke与invokeExact
A method is signature polymorphic if and only if all of the following conditions hold:
- It is declared in the java.lang.invoke.MethodHandle class.
- It has a single formal parameter of type Object[].
- It has a return type of Object.
- It has the ACC_VARARGS and ACC_NATIVE flags set.
In Java SE 7, the only signature polymorphic methods are the invoke and invokeExact methods of the class java.lang.invoke.MethodHandle.
invoke()与invokeExact()方法的定义在MethodHandle类中,如下:
public final native @PolymorphicSignature Object invoke(Object... args) throws Throwable; public final native @PolymorphicSignature Object invokeExact(Object... args) throws Throwable;
The Java Virtual Machine gives special treatment to signature polymorphic methods in the invokevirtual instruction (§invokevirtual), in order to effect invocation of a method handle. A method handle is a typed, directly executable reference to an underlying method, constructor, field, or similar low-level operation (§5.4.3.5), with optional transformations of arguments or return values. These transformations are quite general, and include such patterns as conversion, insertion, deletion, and substitution. See the java.lang.invoke package in the Java SE platform API for more information.
import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; public class MethodHandleTest { public static void main(String[] args) throws Throwable { /* * Lookup相当于MethodHandle工厂类,通过findxxx方法可以得到相应的 * MethodHandle,还可以配合反射API创建MethodHandle,对应的方法 * 有unreflect、unreflectSpecial等 */ MethodHandles.Lookup lookup = MethodHandles.lookup(); /* * 调用MethodType的静态方法创建MethodType实例,有三种创建方式: * (1)methodType及其重载方法:需要指定返回值类型以及0到多个参数 * (2)genericMethodType:需要指定参数的个数,类型都为Object * (3)fromMethodDescriptorString:通过方法描述来创建 * 创建好MethodType对象后,还可以对其进行修改,MethodType类中提 * 供了一系列的修改方法,比如: * changeParameterType、changeReturnType等 */ MethodType methodType = MethodType.methodType(int.class, int.class); MethodHandle handle = lookup.findStatic(MethodHandleTest.class, "doubleVal", methodType); /* * (1)invokeExact:调用此方法与直接调用底层方法一样,需要做到参数类型精确匹配 * * (2)invoke:nvoke方法允许更加松散的调用方式。它会尝试在调用的时候进行返回值 * 和参数类型的转换工作。这是通过MethodHandle类的asType方法来完成的, * asType方法的作用是把当前方法句柄适配到新的MethodType上面,并产生一个新的方法句柄。 * 当方法句柄在调用时的类型与其声明的类型完全一致的时候,调用invoke方法等于调用 * invokeExact方法;否则,invoke方法会先调用asType方法来尝试适配到调用时 * 的类型。如果适配成功,则可以继续调用。否则会抛出相关的异常。这种灵活的适配机制, * 使invoke方法成为在绝大多数情况下都应该使用的方法句柄调用方式。 * * (3)invokeWithArguments:直接通过方法参数来调用。 * 其实现是先通过genericMethodType方法得到MethodType,再通过MethodHandle的 * asType转换后得到一个新的MethodHandle,最后通过新MethodHandle的 * invokeExact方法来完成调用。 */ Integer temp = (Integer) handle.invoke(2); System.out.println(temp); // 4 } public static int doubleVal(int val) { return val * 2; } }
关于invoke()与invokeExact()方法:
The types of its parameters are the static types of the actual argument expressions.
An argument expression which is the null literal
null
(§3.10.7) is treated as having the static typeVoid
.The result type is determined as follows:
If the method invocation expression is an expression statement, the method is
void
.Otherwise, if the method invocation expression is the operand of a cast expression (§15.16), the return type is the erasure (§4.6) of the type of the cast expression.
Otherwise, the return type is the method's declared return type,
Object
.
再看一个例子,如下:
import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; public class MethodHandleTest { public MethodHandle getHandler_print() { MethodHandle mh = null; MethodType mt = MethodType.methodType(void.class); MethodHandles.Lookup lk = MethodHandles.lookup(); try { mh = lk.findVirtual(MethodHandleTest.class, "print", mt); } catch (Throwable e) { e.printStackTrace(); } return mh; } public MethodHandle getHandler_substring() { MethodHandle mh = null; MethodType mt = MethodType.methodType(String.class, int.class, int.class); MethodHandles.Lookup lk = MethodHandles.lookup(); try { mh = lk.findVirtual(String.class, "substring", mt); } catch (Throwable e) { e.printStackTrace(); } return mh; } public void test_substring() throws Throwable { MethodHandle mh = new MethodHandleTest().getHandler_substring(); String str = "hello world"; Object result1 = mh.invoke(str, 1, 3); Object result2 = (String) mh.invokeExact(str, 1, 3); // 方法执行时报错,因为方法返回的类型为Object,与声明中为String不符合 // Object result3 = mh.invokeExact(str, 1, 3); // 第二个参数类型为Integer,与声明中为int不符合,则类型适配不符合,系统报错 // Object result4 = (String)mh.invokeExact(str, new Integer(1), 3); System.out.println("result 1:" + result1); System.out.println("result 1:" + result2); } public void test_print() throws Throwable { MethodHandleTest mht = new MethodHandleTest(); MethodHandle mh = mht.getHandler_print(); int result5 = (int) mh.invoke(mht); Object result6 = mh.invoke(mht); System.out.println("result 5:" + result5); System.out.println("result 6:" + result6); } public static void main(String[] args) throws Throwable { MethodHandleTest m = new MethodHandleTest(); m.test_substring(); m.test_print(); } public void print() { System.out.println("invoke print"); } }
class Test{ // e.g 1 // a variable arity parameter,Otherwise,it is a fixed arity method // b 的英文叫法为 a variable arity parameter public int m1(final int a[][],int ...b)[][]{ return a; } // e.g 2 如下m2方法不能共存 public static final void m2(List list){ } public void m2(List<String> list) { } }
3、Miranda Method
In early VM's there was a bug -- the VM didn't walk the interfaces
of a class looking for a method, they only walked the superclass
chain. This meant that abstract methods defined only in interfaces
were not being found. To fix this bug, a counter-bug was introduced
in the compiler -- the so-called Miranda methods. If a class
does not provide a definition for an abstract method in one of
its interfaces then the compiler inserts one in the class artificially.
That way the VM didn't have to bother looking at the interfaces.
This is a problem. Miranda methods are not part of the specification.
But they continue to be inserted so that old VM's can run new code.
Someday, when the old VM's are gone, perhaps classes can be compiled
without Miranda methods. Towards this end, the compiler has a
flag, -nomiranda, which can turn off the creation of these methods.
Eventually that behavior should become the default.
Why are they called Miranda methods? Well the sentence "If the
class is not able to provide a method, then one will be provided
by the compiler" is very similar to the sentence "If you cannot
afford an attorney, one will be provided by the court," -- one
of the so-called "Miranda" rights in the United States.
参考文章:
(1)https://docs.oracle.com/javase/8/docs/api/java/lang/invoke/MethodHandle.html
java7之Special Methods的更多相关文章
- Python Special Methods - 特殊方法
特殊方法 特殊方法的存在是为了给 Python 解释器调用的,通常自己并不需要直接调用它们.也就是说不应该使用 my_object.__len__() 这种写法,而应该使用 len(my_object ...
- 关于Class的invokeDynamic指令
(1)java7之Special Methods (2)invokedynamic指令 https://www.cnblogs.com/wade-luffy/p/6058087.html public ...
- Effective Java 54 Use native methods judiciously
Java Native Interface(JNI) allows Java applications to call native methods, which are special method ...
- Think Python - Chapter 17 - Classes and methods
17.1 Object-oriented featuresPython is an object-oriented programming language, which means that it ...
- Overview over available Turtle and Screen methods
24.5.2.1. Turtle methods Turtle motion Move and draw forward() | fd() backward() | bk() | back() rig ...
- Python中的"Special Method"
The first thing to know about special methods is that they are meant to be called by the Python inte ...
- 对特殊方法的访问 - Special method lookup
对特殊方法的访问 - Special method lookup 对于用户自定义的 class 来说, 特殊方法只有通过定义对象的类型object’s type (而非通过 instance 的 __ ...
- Chapter 7 -- Functional
Caveats 说明 As of Java 7, functional programming in Java can only be approximated through awkward and ...
- .NET平台开源项目速览(13)机器学习组件Accord.NET框架功能介绍
Accord.NET Framework是在AForge.NET项目的基础上封装和进一步开发而来.因为AForge.NET更注重与一些底层和广度,而Accord.NET Framework更注重与机器 ...
随机推荐
- Android-HttpsURLConnectionHelp-工具类
HttpsURLConnectionHelp-工具类 是专门把javax.net.ssl.HttpsURLConnection类的使用,进行了封装,提供了常用的公共方法: package common ...
- Android-GsonUtil-工具类
GsonUtil-工具类 是把Google提供的Gons进行了方法封装,提供了关于一些常用的Gons使用的公共方法: package common.library.utils; import andr ...
- 传智播客.NET视频学习课件
传智播客.NET视频学习课件访问.NET网站了解更多课程详情http://net.itcast.cn(小提示:为什么本书中超链接打不开?)此套课件是伴随 传智播客.net实况教学视频 (小提示:为什么 ...
- 获取web项目中的webroot目录路径
备忘,一段代码: @Override public void init(FilterConfig arg0) throws ServletException { // TODO Auto-genera ...
- [Oracle]Oracle部分函数
1.nvl(a,b) 若a为null,则b 2.to_char(date,'YY-MM-DD') 按格式将date类型转为字符串 to_date('1999/1/1','YY-MM-DD') 将字符串 ...
- 兼容性测试中如何切换和管理多个JDK版本
本文由作者邹珍珍授权网易云社区发布. 一.测试背景: 项目对外提供JAR包,需要测试该JAR包对不同JDK版本(1.6至1.9版本)的兼容性.下面主要介绍在兼容性测试中,JDK多版本共存时如何配置环境 ...
- Android Studio设置字体
一,点"Settings"按钮,调出配置界面: 然后如图找到 Editor-colors&font-font ,默认的不让修改 所以先点击save as 随便起个名字 , ...
- linux命令之文件备份与压缩命令
1.tar:打包备份 该命令是将多个命令打包到一起,并且可以实现解压打包.打包是将多个文件或者目录变成一个总的文件,压缩则是将一个大的文件通过压缩算法变成一个小文件. 参数 说明 z(常用) 通过gz ...
- “全栈2019”Java异常第二十章:自定义异常详解
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java异 ...
- 操作日期时间类 Calendar类
使用Calendar类可以直接创建Calendar的子类GregorianCalendar 来直接实例化, GregorianCalendar calendar = new GregorianCal ...