返回信息流最近在学习java的多态,对绑定有些疑惑,java中方法(无论静态方法还是非静态方法)的签名绑定是不是都发生在编译期(静态绑定)呢?如果是的话,那是不是编译完就决定了运行期所执行方法的签名呢?诚心求教
这是一条镜像帖。来源:北邮人论坛 / java / #59443同步于 2018/6/22
该镜像源已超过 30 天没有更新,可能在源站已被删除。
Java机器人发帖
java绑定求解
lvhlvh
2018/6/22镜像同步2 回复
订阅后,新回复会通过你的通知中心匿名送达。
2 条回复
重载的方法,签名都是相同的啊。只不过在运行时根据对象的实际类型确定到底使用哪个版本
给你举个例子
```Java
class Base{
public void doSomething() {
System.out.println("Base::doSomething");
}
}
class Sub extends Base {
@Override
public void doSomething(){
System.out.println("Sub::doSomething");
}
}
public class Main {
public static void main(String[] args){
Base base1 = new Base();
base1.doSomething();
Base base2 = new Sub();
base2.doSomething();
}
}
```
执行`javap -c -v Main`得到如下输出
```
public class Main
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #8.#17 // java/lang/Object."<init>":()V
#2 = Class #18 // Base
#3 = Methodref #2.#17 // Base."<init>":()V
#4 = Methodref #2.#19 // Base.doSomething:()V
#5 = Class #20 // Sub
#6 = Methodref #5.#17 // Sub."<init>":()V
#7 = Class #21 // Main
#8 = Class #22 // java/lang/Object
#9 = Utf8 <init>
#10 = Utf8 ()V
#11 = Utf8 Code
#12 = Utf8 LineNumberTable
#13 = Utf8 main
#14 = Utf8 ([Ljava/lang/String;)V
#15 = Utf8 SourceFile
#16 = Utf8 Main.java
#17 = NameAndType #9:#10 // "<init>":()V
#18 = Utf8 Base
#19 = NameAndType #23:#10 // doSomething:()V
#20 = Utf8 Sub
#21 = Utf8 Main
#22 = Utf8 java/lang/Object
#23 = Utf8 doSomething
{
public Main();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 14: 0
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=3, args_size=1
0: new #2 // class Base
3: dup
4: invokespecial #3 // Method Base."<init>":()V
7: astore_1
8: aload_1
9: invokevirtual #4 // Method Base.doSomething:()V
12: new #5 // class Sub
15: dup
16: invokespecial #6 // Method Sub."<init>":()V
19: astore_2
20: aload_2
21: invokevirtual #4 // Method Base.doSomething:()V
24: return
LineNumberTable:
line 16: 0
line 17: 8
line 19: 12
line 20: 20
line 21: 24
}
SourceFile: "Main.java"
```
关注字节码编号9和字节码编号21,方法引用都是#4,也就是常量池中的`#4 = Methodref #2.#19 // Base.doSomething:()V`。你说的方法签名是完全根据静态类型的,但是实际运行的版本是靠invokevirtual指令来确定的,它会根据__对象实际的类型__以及__方法引用(常量池引用,在上面例子中就是`#4`)__确定最终运行的版本