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更注重与机器 ...
随机推荐
- 用shell脚本 计算两个数的加减乘除取余
#! /bin/bash # read -p '请输入数:' a //输入 read -p '请输入数:' b echo '$a+$b=' $(( a + b )) //输出 echo '$a-$b= ...
- Java对象和XML转换
有时候,我们需要把Java对象转换成XML文件.这时可以用JAXB来实现.(JDK1.6及以后的版本无需导入依赖包,因为已经包含在JDK里了) 假如某个公司有许多部门,每个部门有许多职员,我们可以这样 ...
- ASP.NET MVC Core的TagHelper (高级特性)
这篇博文ASP.NET MVC Core的TagHelper(基础篇)介绍了TagHelper的基本概念和创建自定义TagHelper的方式,接着继续介绍一些新的看起来比较高级的特性.(示例代码紧接着 ...
- 在github创建用户
在Github注册账户 第一个是创建用户名,第二个是填写邮箱,第三个是设置密码 进入给github会让你选择账户类型 第二步完成后会让你完成邮箱的验证 验证完邮箱以后此时就验证成功了点击绿色的 let ...
- Tempdb--临时对象缓存
SQL Server删除一个临时对象时,不移除该对象的条目,当再次使用时,就无须重新创建临时对象,SQL Server为临时对象缓存一个数据页和一个IAM页,并回收剩余页,如果临时表的大小超过8MB, ...
- C#语言各个版本特性(三)
三.查询集合 1.找出List<Product>列表中符合特定条件的所有元素 C#1.1 查询步骤:循环,if判断,打印 product类 using System.Collections ...
- File Path Directory总结
阅读目录 开始 Path 对路径 字符串进行操作 获得后缀 能合并路径 获取文件名 Directory和DirectoryInfo 对目录进行操作 判断目录是否存在 创建目录 删除目录 获取目录下所 ...
- AT指令框架的实现
AT指令概述 AT指令是应用于终端设备与PC应用之间的连接与通信的指令.AT 即Attention.每个AT命令行中只能包含一条AT指令:对于AT指令的发送,除AT两个字符外,最多可以接收1056个字 ...
- 用MVC5+EF6+WebApi 做一个小功能(三) 项目搭建
一般一个项目开始之前都会有启动会,需求交底等等,其中会有一个环节,大讲特讲项目的意义,然后取一个高大上的项目名字,咱这是一个小功能谈不上项目,但是名字不能太小气了.好吧,就叫Trump吧.没有任何含义 ...
- P2278 操作系统
P2278 操作系统 题目描述 写一个程序来模拟操作系统的进程调度.假设该系统只有一个CPU,每一个进程的到达时间,执行时间和运行优先级都是已知的.其中运行优先级用自然数表示,数字越大,则优先级越高. ...