【爱上Java8】ACC_SUPER和早期的invokespecial

class文件中的access flag记录了一个类的相关信息,比如public abstract final等等。其中有一个值ACC_SUPER。现理解如下:

ACC_SUPER是用来表示如何调用父类的方法。在jdk1.1之前,jvm使用一种invokenonvirtual的指令,调用父类方法。这个方法就是现在的invokespecial 前身。既然连名字都改过了,他们的实现差距可以认为已经比较大了。invokenonvirtual是不会进行虚函数查找的,也就是总是静态绑定。

我们知道,在class文件中使用CONSTANT_Methodref_info来表示一个方法。CONSTANT_Methodref_info中有一个指向类的成员,invokenonvirtual会直接使用CONSTANT_Methodref_info中的类进行方法调用,而不去进行虚函数查找。因此,需要由编译器在编译时就绑定到最近的父类。jdk1.1以后,jvm会忽略CONSTANT_Methodref_info 中的class,转而去查找最近的超类方法。

这个改动是非常有意义的,我们来一下下面的代码:

有一个组件A


1

2

3

4

5

6

7


public class GrandParent {

protected void myMethod() {

// ...

}

}

public class Parent extends GrandParent {

}

组件B使用了组件A


1

2

3

4

5

6


public class Child extends Parent {

protected void myMethod() {

// ...

super.myMethod();

}

}

很明显,组件B肯定是用了GrandParent.myMethod()。因为Parent里没有myMethod方法。但是,如果你更新了组件A


1

2

3

4

5

6

7

8

9

10

11


public class GrandParent {

protected void myMethod() {

// ...

}

}

public class Parent extends GrandParent {

protected void myMethod() {

// ...

super.myMethod();

}

}

这个时候,如果使用invokenonvirtual调用方式,你依然会运行GrandParent.myMethod()(在不重新编译Child的情况下)。因为这是在编译时绑定的。使用了CONSTANT_Methodref_info里的class作为调用基准。这个结果显然不是你想看到的。

但如果使用了新的invokespecial ,他就会搜索类层次,找到最近的一个父类进行方法调用,得到正确的结果。第2中方法就是设置了ACC_SUPER时的情况。

现在编译器都会生成ACC_SUPER以支持一个正确的父类调用。

时间: 2024-11-04 04:35:20

【爱上Java8】ACC_SUPER和早期的invokespecial的相关文章

【爱上Java8】BigInteger在Java8中的改进

BigInteger在Java8里增加了一组方法: 123 public byte byteValueExact()public int intValueExact()public long longValueExact() 这些方法后面都有Exact(),在老的JDK版本中,已经有了byteValue,intValue,longValue()为什么还要再增加这些方法呢?因为在原来的方法中,如果BigInteger的值溢出了要目标类型的范围,是不会有任何提示的,那么我们的程序很可能在一个很隐蔽的

【爱上Java8】VirtualMachine所支持的操作

在JDK中com.sun.tools.attach.VirtualMachine提供了一些从外部进程attach到jvm上,并执行一些操作的功能.VirtualMachine的子类HotSpotVirtualMachine表示hotspot的虚拟机,下面的WindowsVirtualMachine是在windows平台下的实现.它提供了以下功能:1. public void loadAgentLibrary(String agentLibrary, String options)载入一个dll的

【爱上Java8】使用POI读取Excel表

最近有这么一个小需求,需要从Excel里读取2张表.如果是表1和表2,那么比较表1,表2,列出在表1中存在,但是表2中不存在的项,以及在表2中存在,在表1中不存在的项.使用POI可以很轻松的完成这个功能.首先,为表建模,表项为:部门代码 部门名称 职位名称 职员代码 职员姓名每一行为一个职员的信息.使用职员代码来标示每一行. 12345678910111213141516171819202122232425262728 package zhoukai; import org.apache.poi

JVM之字节码——Class文件格式

如同讲汇编必先讲计算机组成原理,在开始字节码之前,我们先了解一下JVM的主要构成. 在JVM的内部,主要由如下几个部分构成:     1.数据区 方法区:存放类定义信息.字节码.常量等数据,在Sun HotSpot JVM中,这块也称为Perm Gen. 堆:创建的对象信息将放入堆中,堆内部如何实现各虚拟机各不相同,对于Sun HotSpot JVM来说又分为Young Gen和Tenured Gen,更详细描述参见<[Java性能剖析]Sun JVM内存管理和垃圾回收 > Java 栈:对于

初探Java 9 的的模块化

Java 9中最重要的功能,毫无疑问就是模块化(Module),它将自己长期依赖JRE的结构,转变成以Module为基础的组件,当然这在使用Java 9 开发也和以前有着很大的不同. Java8或更加早期的系统的问题 Jar文件,像rt.jar等jar文件太大的以至于不能使用在小设备和应用中. 因为JDK是太大的,我们的应用或设备不能支持更好的平台. 由于修饰符是public的缘故,每个人都可以通过此来进行访问,所以在当前Java系统的封闭性不是很强. 由于JDK,Jre过于庞大,以至于很难进行

invokespecial指令

早期的指令是invokenonvirtual,但从JDK 1.0.2开始重命名为invokespecial.为了解决下面的问题: Component A - version 1 public class GrandParent { protected void myMethod() { // ... } } public class Parent extends GrandParent { } Component B public class Child extends Parent { pro

通过字节码展示Java8 Lambda的实现

Java8 增加了 Lambda 表达式,很大程度使代码变的更加简洁紧凑了,那么 Java8 是如何实现 Lambda 表达式的呢? 直接看一个简单的创建线程的例子. public class TestLambda { public static void main(String[] args) { new Thread(() -> System.out.print("thread")); } } 执行javac TestLambda.java编译生成文件TestLambda.c

java8 十大新特性

这篇文章是对Java 8中即将到来的改进做一个面向开发者的综合性的总结,JDK的这一特性将会在2013年9月份发布. 在写这篇文章的时候,Java 8的开发工作仍然在紧张有序的进行中,语言特新和API仍然有可能改变,我会尽我最大的努力保持这份文档跟得到Java 8的改动. Java 8的预览版,也就是 “Project Lambda”,现在可以从java.net下载到. 我使用了IntelliJ的预览版做我的IDE,在我看来他是目前支持java 8特性最好的一个IDE,你可以从这里下载到. 由于

Java8新特性浅析

欢迎阅读我编写的Java 8介绍.本教程将带领你一步一步地认识这门语言的新特性.通过简单明了的代码示例,你将会学习到如何使用默认接口方法,Lambda表达式,方法引用和重复注解.看完这篇教程后,你还将对最新推出的API有一定的了解,例如:流控制,函数式接口,map扩展和新的时间日期API等等. 允许在接口中有默认方法实现 Java 8 允许我们使用default关键字,为接口声明添加非抽象的方法实现.这个特性又被称为扩展方法.下面是我们的第一个例子: 1 2 3 4 5 6 7 interfac