package com.test19; class Father { public void publicMethod() { privateMethod(); // this是Son对象,调用Father的方法 Son son = (Son)this; System.out.println(son); this.privateMethod(); } private void privateMethod() { System.out.println("Father.privateMethod()"); } public void tm() { System.out.println("Father.tm()"); } } class Son extends Father { public void publicMethod() { System.out.println("Son.publicMethod()"); } public void tm() { super.tm(); finalMethod(); } public final void finalMethod() { System.out.println("Son.finalMethod()"); } } public class TestInvokeMethod { public static void main(String[] args) { Father test = new Son(); test.publicMethod(); // Son.publicMethod() } }
在运行时,this对象是Son,但是通过this.privateMethod()调用的是Father类的私有方法,因为运行时,invokespecial选择方法基于引用声明的类型,而不是对象实际的类型。但invokevirtual则选择当前引用的对象的类型。
当为子类添加public void privateMethod(){}方法时,仍然调用父类方法,没有任何影响。
以下情况使用invokespecial操作码:
1、init()函数,就是调用构造函数生产一个实例的时候。
2、私有方法
3、通过super.method()形式调用的方法
TestInvokeMethod.class
Constant pool:
#1 = Methodref #6.#15 // java/lang/Object."":()V
#2 = Class #16 // com/test19/Son
#3 = Methodref #2.#15 // com/test19/Son."":()V
#4 = Methodref #17.#18 // com/test19/Father.publicMethod:()V
#5 = Class #19 // com/test19/TestInvokeMethod
#6 = Class #20 // java/lang/Object
#7 = Utf8
#8 = Utf8 ()V
#9 = Utf8 Code
#10 = Utf8 LineNumberTable
#11 = Utf8 main
#12 = Utf8 ([Ljava/lang/String;)V
#13 = Utf8 SourceFile
#14 = Utf8 TestInvokeMethod.java
#15 = NameAndType #7:#8 // "":()V
#16 = Utf8 com/test19/Son
#17 = Class #21 // com/test19/Father
#18 = NameAndType #22:#8 // publicMethod:()V
#19 = Utf8 com/test19/TestInvokeMethod
#20 = Utf8 java/lang/Object
#21 = Utf8 com/test19/Father
#22 = Utf8 publicMethod
{
public com.test19.TestInvokeMethod();
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."":()V
4: return
LineNumberTable:
line 28: 0
public static void main(java.lang.String[]);
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=2, args_size=1
0: new #2 // class com/test19/Son
3: dup
4: invokespecial #3 // Method com/test19/Son."":()V
7: astore_1
8: aload_1
9: invokevirtual #4 // Method com/test19/Father.publicMethod:()V
12: return
LineNumberTable:
line 30: 0
line 31: 8
line 33: 12
}
Father.class
Constant pool:
#1 = Methodref #4.#14 // java/lang/Object."":()V
#2 = Methodref #3.#15 // com/test19/Father.privateMethod:()V
#3 = Class #16 // com/test19/Father
#4 = Class #17 // java/lang/Object
#5 = Utf8
#6 = Utf8 ()V
#7 = Utf8 Code
#8 = Utf8 LineNumberTable
#9 = Utf8 publicMethod
#10 = Utf8 privateMethod
#11 = Utf8 tm
#12 = Utf8 SourceFile
#13 = Utf8 TestInvokeMethod.java
#14 = NameAndType #5:#6 // "":()V
#15 = NameAndType #10:#6 // privateMethod:()V
#16 = Utf8 com/test19/Father
#17 = Utf8 java/lang/Object
{
com.test19.Father();
flags:
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."":()V
4: return
LineNumberTable:
line 3: 0
public void publicMethod();
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #2 // Method privateMethod:()V
4: aload_0
5: invokespecial #2 // Method privateMethod:()V
8: return
LineNumberTable:
line 6: 0
line 7: 4
line 8: 8
public void tm();
flags: ACC_PUBLIC
Code:
stack=0, locals=1, args_size=1
0: return
LineNumberTable:
line 12: 0
}
Son.class
Constant pool:
#1 = Methodref #5.#15 // com/test19/Father."":()V
#2 = Methodref #5.#16 // com/test19/Father.tm:()V
#3 = Methodref #4.#17 // com/test19/Son.finalMethod:()V
#4 = Class #18 // com/test19/Son
#5 = Class #19 // com/test19/Father
#6 = Utf8
#7 = Utf8 ()V
#8 = Utf8 Code
#9 = Utf8 LineNumberTable
#10 = Utf8 publicMethod
#11 = Utf8 tm
#12 = Utf8 finalMethod
#13 = Utf8 SourceFile
#14 = Utf8 TestInvokeMethod.java
#15 = NameAndType #6:#7 // "":()V
#16 = NameAndType #11:#7 // tm:()V
#17 = NameAndType #12:#7 // finalMethod:()V
#18 = Utf8 com/test19/Son
#19 = Utf8 com/test19/Father
{
com.test19.Son();
flags:
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method com/test19/Father."":()V
4: return
LineNumberTable:
line 16: 0
public void publicMethod();
flags: ACC_PUBLIC
Code:
stack=0, locals=1, args_size=1
0: return
LineNumberTable:
line 18: 0
public void tm();
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #2 // Method com/test19/Father.tm:()V
4: aload_0
5: invokevirtual #3 // Method finalMethod:()V
8: return
LineNumberTable:
line 21: 0
line 22: 4
line 23: 8
public final void finalMethod();
flags: ACC_PUBLIC, ACC_FINAL
Code:
stack=0, locals=1, args_size=1
0: return
LineNumberTable:
line 25: 0
}
final方法的调用也用invoke