java中调用接口及调用继承类效率区别

  都说调用接口要比调用继承类要慢,但慢在何处?

  先看byteCodeInterpreter.cpp里面对这invokevirtual和invokeInterface的区别。

        CASE(_invokeinterface): { //调用接口
        u2 index = Bytes::get_native_u2(pc+1);

        ConstantPoolCacheEntry* cache = cp->entry_at(index);

        methodOop callee;
        klassOop iclass = (klassOop)cache->f1();
        int parms = cache->parameter_size();
        oop rcvr = STACK_OBJECT(-parms);
        CHECK_NULL(rcvr);
        instanceKlass* int2 = (instanceKlass*) rcvr->klass()->klass_part();
        itableOffsetEntry* ki = (itableOffsetEntry*) int2->start_of_itable();
        int i;
        for ( i = 0 ; i < int2->itable_length() ; i++, ki++ ) {//搜索整个接口表,进行比较,直至找到
          if (ki->interface_klass() == iclass) break;
        }

        .......

        int mindex = cache->f2();
        itableMethodEntry* im = ki->first_method_entry(rcvr->klass());
        callee = im[mindex].method();//通过找到的接口,找到要调用的方法

   而invokevirtual(调用继承类)

       CASE(_invokevirtual):

          u2 index = Bytes::get_native_u2(pc+1);

          ConstantPoolCacheEntry* cache = cp->entry_at(index);

          methodOop callee;

          int parms = cache->parameter_size();

          instanceKlass* rcvrKlass = (instanceKlass*) STACK_OBJECT(-parms)->klass()->klass_part();

          callee = (methodOop) rcvrKlass->start_of_vtable()[ cache->f2()]; //直接调用方法

  由上面可见,最大的区别就是接口调用每次都需要搜索接口表,而调用继承类可以直接找到。

  再看看权威书籍《深入java虚拟机》P336页给出的答案,“java虚拟机使用不同于类引用的操作码来调用接口引用的方法,这是因为java不能象使用引用那样,使用许多与方法表偏移量相关的假设。对于类引用来说,无论对象实际的类是什么,方法在方法表始终占据相同的位置。但对于接口引用来说,情况就不是这样了,位于不同类的同一个方法所占据的位置是不同的,尽管这些类实现同一个接口。”

  由此可知,调用接口引用方法可能要比调用类引用要慢。一般情况下,单个类实现的接口都不多,其实这方面的效率影响还是蛮小的

你可能感兴趣的:(java,虚拟机,cache,oop,idea)