invokespecial与invokevirtual指令的区别

 

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  

 

 

 

 

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(invokespecial与invokevirtual指令的区别)