簡體   English   中英

Java中的繼承如何工作?

[英]How does inheritance in Java work?

我們有下一堂課:

class Super {
    void foo() {
        System.out.println("Super");
    }
}

class Sub extends Super {
    void foo() {
        super.foo();
        System.out.println("Sub");
    }
}

public class Clazz {
    public static void main(String[] args) {
        new Sub().foo();
    }
}

輸出是:

問題:

super禮物是什么? 它是父類的對象,哪個孩子保持為字段?

  • 如果是,抽象類的繼承如何工作? 您無法創建抽象類的實例。
  • 如果不是,那么被覆蓋的方法在哪里舉行?

我試過谷歌,但我找到的只是關於如何繼承類等的常見信息。

更新:

你還在告訴我顯而易見的事情。 也許我的問題有點誤導,但我會試着改寫它:

  • 當我們用super調用方法時,你說,我們正在訪問父方法。 但是如何在沒有父對象的情況下調用此方法呢?
  • superthis 如您所知, this是對具體對象的引用。

子類不維護任何表示其父級的特殊字段。 你可能正在思考內部類的某些東西,它們確實維護了對它們外部類的引用。 這是一種特殊情況,並不代表超級子類彼此之間的關系。

在內部,JVM維護一個'方法表',將其加載的每個類與該類可用的方法相關聯。 JVM還知道它加載的所有類之間的關系,包括超子關系。

當您調用super函數時,JVM實際上做了以下幾件事:

  • 確定要從中調用方法的類的父級
  • 確定將要調用的父級的方法
  • 使用特殊指令調用該方法( invokespecial

如果您要檢查Sub類的類文件,您會看到foo方法的類似內容:

void foo();
    flags: 
    Code:
        stack=2, locals=1, args_size=1
            0: aload_0       
            1: invokespecial #2        // Method Super.foo:()V
            4: getstatic     #3        // Field java/lang/System.out:Ljava/io/PrintStream;
            7: ldc           #4        // String Sub
            9: invokevirtual #5        // Method java/io/PrintStream.println:(Ljava/lang/String;)V

清單中的第1行顯示了調用超類方法的特殊指令。

讀取的一個很好的來源是Java虛擬機規范 ,特別是第2.11.8節

好的。 我們一行一步地通過您的代碼。

你的'foo'方法中的第一個陳述是

super.foo();

那是對超類foo方法的顯式調用。 這是:

 void foo() {
    System.out.println("Super");
}

所以“Super”輸出到控制台,因為你已經用super關鍵字明確地調用了這個方法。 super指的是類的父類,以同樣的方式, this指的是當前類。

接下來是子類中foo方法的其余部分:

 void foo() {
    super.foo();
    System.out.println("Sub");
}

super.foo()之后,是時候轉到下一個語句,輸出“Sub”。


你的程序首先移動到子類'方法而不是超類的原因是因為一個叫做Polymorphism的原理。 也就是說,子類從超類中獲取一個方法,並改變它的行為。

抽象類

您不能創建Abstract類的實例,不能,但是使用super關鍵字,您仍然可以訪問超類的功能。

在Java虛擬機的上下文中

那么,當您進行方法調用時,如果它是實例方法,Java虛擬機將在本地類中查找該方法。 如果找不到它,它將移動到超類。 當您使用Polymorphism原理時,JVM會在子類中找到具有正確簽名的方法,並停止查找。 這就是繼承和Polymorphism在Java的上下文中以簡單的方式工作的方式。

覆蓋方法時,可以向子類定義添加具有相同方法簽名(方法字段的名稱,編號和類型)的方法。 這就是JVM找到它的方式,這是存儲重寫方法的地方。

super是一個關鍵字,允許您調用超類中定義的方法實現。 它不是你的子類的一個領域。

如果不是,那么覆蓋的方法在哪里舉行?

我不太清楚你的意思,但是:

  • 打印“超級”的方法保存在超類的類定義中
  • 打印“Sub”的方法保存在子類的類定義中。

由於Sub擴展了SuperSub類的定義包括對Super類定義的引用。

回答更新的問題:

當我們用super調用方法時,你說,我們正在進行父方法。 但是如何在沒有父對象的情況下調用此方法呢?

方法只是一個代碼塊,只是我們需要執行的一系列字節碼指令。 當您調用方法時,JVM的任務是根據您提供的方法名稱和參數確定在哪里找到此代碼塊。 通常,正如其他人所說,它將首先查看調用該方法的對象的類的類定義。 當你使用super ,你告訴JVM不要看這里,而是查看父類定義。

因此,您不需要單獨的SuperSub實例,因為Sub SuperSuper new Sub() instanceof Supertrue ),並且因為JVM知道super關鍵字意味着它應該查找構成方法的代碼在Super的類定義中。

這個超級一樣嗎? 如您所知,這是對具體對象的引用。

不,他們不一樣。 this是對當前對象的引用,而super不是對對象的引用,而是一個關鍵字,它影響JVM查找定義正在調用的方法的代碼的位置。

當你寫super.foo(); 你正在調用超類方法。

class sub的foo方法通過向超類方法添加指令來覆蓋Super的foo方法。

子類.super.foo()中的foo方法覆蓋調用print super,然后調用System.out.println(“Sub”); 顯示Sub。

試試這個繼承

class Super {
    Super()
    {
        System.out.println("1");
    }
    void foo() {
        System.out.println("Super");
    }
}

class Sub extends Super {
    public Sub() {
        // TODO Auto-generated constructor stub
        System.out.println("2");
    }
    void foo() {
       super.foo();
        System.out.println("Sub");
    }
}

只有一個對象同時是Sub,Super和Object。 它具有每個類的所有非靜態字段。 一個類實際上只需要一個代碼副本用於其方法,甚至是非靜態代碼。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM