快速业务通道

JVM在校验阶段不检查接口的实现状况 - 编程入门网

作者 佚名技术 来源 NET编程 浏览 发布时间 2012-06-13

JVM在校验阶段不检查接口的实现状况

时间:2012-01-03 javaeye RednaxelaFX

继续看到底要运行一个Java程序需要做的各种检查是在什么时候发生的。这次我们来看看接口调用的问题。

当前的JVM规范中,与方法调用相关的指令有4个:invokevirtual、invokeinterface、invokestatic与invokespecial。其中调用接口方法时使用的JVM指令是invokeinterface。这个指令与另外3个方法调用指令有一个显著的差异:它不要求JVM的校验器(verifier)检查被调用对象(receiver)的类型;另外3个方法调用指令都要求校验被调用对象。也就是说,使用invokeinterface时如果被调用对象没有实现指定的接口,则应该在运行时而不是链接时抛出异常;而另外3个方法调用指令都要求在链接时抛出异常。

看看JVM规范是怎么说的:

Java Virtual Machine Specification, 2nd Edition 写道

invokeinterface

...

Runtime Exceptions

...

if the class of objectref does not implement the resolved interface, invokeinterface throws an IncompatibleClassChangeError.

可以留意一下另外3个方法调用指令中“IncompatibleClassChangeError”都是Linking Exception而不是Runtime Exception。

这种规定对Java程序来说可见的行为就是:如果一个方法通不过校验,则整个方法都不会被执行;如果能通过校验而抛出运行时异常,则方法当中抛出异常之前的部分都会被执行。

当然,我们直接用Java语言写出来的程序很难引发这样的错误,因为Java编译器会做检查来保证一定程度的类型安全。但是Java的class文件,或者说Java字节码可以由Java编译器以外的别的方式生成,此时就得不到Java编译器对类型安全的保证,而要依赖于JVM对字节码的校验以及运行时的检查了。

我是之前在读John Rose对JSR 292的invokedynamic的讲解时留意到invokeinterface的这个特点的。John特别提到invokedynamic就像invokeinterface一样,都不在校验时对被调用对象的类型做检查。不过之前一直没见过调用对一个没实现接口的对象调用接口方法实际是个什么样子。

好吧,这次就来看个例子。首先创建一个接口IFoo,一个实现了该接口的类FooImpl,和一个未实现该接口的类Bar:

IFoo.java:

Java代码

public interface IFoo {
    void method();
}

FooImpl.java:

Java代码

public class FooImpl implements IFoo {
    public void method() {
        System.out.println("FooImpl.method()");
    }
}

JVM在校验阶段不检查接口的实现状况(2)

时间:2012-01-03 javaeye RednaxelaFX

Bar.java:

Java代码

public class Bar {
    public void anotherMethod() {
        System.out.println("Bar.anotherMethod()");
    }
}

接下来构造出一个能引发运行时异常的程序。大致的意思是这样的:

Java代码

public class TestInterfaceCall {
    public static void main(String[] args) {
        IFoo f = new FooImpl();
        f.method();

        Bar b = new Bar();
        ((IFoo)b).method(); // << watch this
    }
}

注意第7行代码。如果就这么写然后编译的话,生成的字节码里会有一个checkcast指令将Bar类型的引用转换为IFoo类型的引用。如果有checkcast的话,运行时就会在该指令上报错,因为Bar没有实现IFoo。但这次我想引发的错误不是强制转换相关,而是接口调用相关:想达到的效果是以b为被调用对象,但调用IFoo.method()而不是Bar上已有的方法。所以要靠自己来生成字节码,避免checkcast指令。

上个月的两个相关帖里我使用了ObjectWeb的ASM库来生成Java字节码。这个库很实用,但写起来还是繁琐了些。这次我决定用Charles Nutter写的

凌众科技专业提供服务器租用、服务器托管、企业邮局、虚拟主机等服务,公司网站:http://www.lingzhong.cn 为了给广大客户了解更多的技术信息,本技术文章收集来源于网络,凌众科技尊重文章作者的版权,如果有涉及你的版权有必要删除你的文章,请和我们联系。以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢!

分享到: 更多

Copyright ©1999-2011 厦门凌众科技有限公司 厦门优通互联科技开发有限公司 All rights reserved

地址(ADD):厦门软件园二期望海路63号701E(东南融通旁) 邮编(ZIP):361008

电话:0592-5908028 传真:0592-5908039 咨询信箱:web@lingzhong.cn 咨询OICQ:173723134

《中华人民共和国增值电信业务经营许可证》闽B2-20100024  ICP备案:闽ICP备05037997号