方法调用
方法识别
Java 虚拟机识别方法的关键在于类名、方法名以及方法描述符(method descriptor)
- 方法描述符是由方法的参数类型以及返回类型所构成,Java 层面叫方法特征签名
- 在同一个类中,如果同时出现多个名字相同且描述符也相同的方法,那么 Java 虚拟机会在类的验证阶段报错
JVM 根据名字和描述符来判断的,只要返回值不一样(方法描述符不一样),其它完全一样,在 JVM 中是允许的,但 Java 语言不允许
// 返回值类型不同,编译阶段直接报错 public static Integer invoke(Object... args) { return 1; } public static int invoke(Object... args) { return 2; }
调用机制
方法调用并不等于方法执行,方法调用阶段唯一的任务就是确定被调用方法的版本,不是方法的具体运行过程
在 JVM 中,将符号引用转换为直接引用有两种机制:
- 静态链接:当一个字节码文件被装载进 JVM 内部时,如果被调用的目标方法在编译期可知,且运行期保持不变,将调用方法的符号引用转换为直接引用的过程称之为静态链接(类加载的解析阶段)
- 动态链接:如果被调用的方法在编译期无法被确定下来,只能够在程序运行期将调用方法的符号引用转换为直接引用,由于这种引用转换过程具备动态性,因此被称为动态链接(初始化后的解析阶段)
对应方法的绑定(分配)机制:静态绑定和动态绑定。绑定是一个字段、方法或者类从符号引用被替换为直接引用的过程,仅发生一次:
- 静态绑定:被调用的目标方法在编译期可知,且运行期保持不变,将这个方法与所属的类型进行绑定
- 动态绑定:被调用的目标方法在编译期无法确定,只能在程序运行期根据实际的类型绑定相关的方法
- Java 编译器已经区分了重载的方法(静态绑定和动态绑定),因此可以认为虚拟机中不存在重载
非虚方法:
- 非虚方法在编译期就确定了具体的调用版本,这个版本在运行时是不可变的
- 静态方法、私有方法、final 方法、实例构造器、父类方法都是非虚方法
- 所有普通成员方法、实例方法、被重写的方法都是虚方法
动态类型语言和静态类型语言:
- 在于对类型的检查是在编译期还是在运行期,满足前者就是静态类型语言,反之则是动态类型语言
- 静态语言是判断变量自身的类型信息;动态类型语言是判断变量值的类型信息,变量没有类型信息
- Java 是静态类型语言(尽管 Lambda 表达式为其增加了动态特性),JS,Python 是动态类型语言
String s = "abc"; //Java info = "abc"; //Python