都说调用接口要比调用继承类要慢,但慢在何处?
先看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中调用外部C/C++函数的传统方式是使用JNI(Java Native Interface)。然而,JNI的使用过程相对繁琐,涉及多个步骤,包括编写C/C++接口代码、编译DLL/SO文件等。相比之下,JNA(Java Native Access)作为一种更...
在Java中调用数据库中的存储过程是常见的操作之一,这不仅可以提高程序性能和代码可维护性,还可以更好地利用数据库的功能。根据提供的标题、描述以及部分内容,本文将详细介绍Java中调用存储过程的两种方法。 ####...
Java作为广泛使用的编程语言,经常需要与数据库交互,因此理解如何在Java中调用存储过程是至关重要的。 在Java中调用存储过程主要通过JDBC(Java Database Connectivity)接口来实现。JDBC是Java中用来与各种数据库...
#### 在Java中调用存储过程 接下来,我们将在Java程序中调用上面创建的存储过程: ```java import java.sql.Connection; import java.sql.CallableStatement; import java.sql.SQLException; public class ...
依赖是最弱的关系,一个类使用另一个类的服务,如在类B中调用类A的方法。聚合表示整体与部分的关系,如订单类包含多个商品类。继承则是类之间的层次结构,子类继承父类的属性和方法,可以扩展或覆盖。 构造器...
这个类需要继承自`JavaObject`并添加`@JavascriptInterface`注解,确保在WebView中安全调用。例如: ```java import android.webkit.JavascriptInterface; public class JsBridge { @JavascriptInterface ...
1. **创建广播接收器**: 在HBuilder中,新建一个Java类继承自`BroadcastReceiver`,并在类中重写`onReceive()`方法。这个方法会在广播被触发时执行。 2. **注册广播接收器**: 在AndroidManifest.xml文件中,声明你...
在Java中调用明华RF读写器DLL文件需要使用JNI(Java Native Interface)或者JNA(Java Native Access)的方式。这里我们使用JNA来调用DLL文件。首先,在pom.xml文件中添加JNA的依赖,搜索jna并选择jna:5.4.0或者jna...
super 是 JAVA 中调用父类的构造方法或被隐藏的方法的关键字。 本资源摘要信息涵盖了 JAVA 面向对象编程中的一些重要知识点,涵盖了变量类型、运算符、控制语句、函数和继承等方面,为学习 JAVA 的人提供了有价值的...
面向对象编程是Java的核心特性,主要体现...它可以在构造函数中调用来调用其他构造函数,也可以在方法中访问当前类的属性和方法。需要注意的是,`this`不能在静态上下文中使用,因为静态成员属于类,而不属于类的实例。
在Java中调用外部程序(如CUI程序)通常可以通过`Runtime`类来实现。`Runtime`类提供了运行时系统的一个接口,允许执行当前运行环境中的外部进程。在给定的代码片段中,作者演示了如何使用`Runtime.getRuntime()....
6. **CallableStatement**:在JDBC中调用存储过程通常使用CallableStatement,它可以处理存储过程的输出参数和结果集。 7. **连接池**:连接池管理数据库连接,提高性能,减少资源消耗。常用的连接池实现有C3P0和...
本文介绍了Java中的类和对象的基础知识,包括对象的概念、类的定义、如何创建和使用对象,以及通过具体的例子展示了继承的应用。通过这些基础知识的学习,可以更好地理解和掌握面向对象编程的核心思想,并将其应用于...
在JDBC中调用存储过程通常涉及以下步骤: 1. 加载并注册数据库驱动,建立数据库连接。 2. 创建CallableStatement对象,它继承自PreparedStatement,专门用于调用数据库的存储过程。 3. 使用CallableStatement的`{}`...
本篇将介绍如何利用Java Source在Oracle中调用外部程序,并通过一个具体的示例来详细阐述整个过程。 首先,我们需要创建一个Java Source,这是在Oracle数据库内部执行Java代码的基础。Java Source是一个包含Java类...
为了在Java中调用存储过程,可以使用`CallableStatement`接口。`CallableStatement`继承自`PreparedStatement`,特别适合用于调用数据库中的存储过程或函数。以下是一个简单的示例: ```java import java.sql....
- 子类的构造函数中调用了 `super(width, height)`,这是Java中调用父类构造器的语法,确保每个形状都有宽度和高度这两个基本属性。 5. **toString()** 方法: - 各个子类都重写了 `toString()` 方法,这是一个...
为了在Spring Data JPA 中调用存储过程,我们需要创建一个Repository接口,继承自 `CrudRepository` 并添加相应的方法。每个方法对应一个存储过程,通过 `@Procedure` 注解指定存储过程名称,而方法参数对应存储过程...
在Android系统中,每个应用程序默认运行在自己的进程中,因此当需要在一个应用中调用另一个应用的服务时,就需要使用IPC。 首先,让我们来了解AIDL的基本结构。一个AIDL文件通常包含以下元素: 1. **接口声明**:...