Kalıtım: Üst sınıftaki kod sanal olarak * alt sınıfa * kopyalanıyor mu veya * alt sınıf * ile mi adlandırılıyor?


10

Sınıf Sub, sınıfın bir alt sınıfıdır Sup. Bu pratikte ne anlama geliyor? Başka bir deyişle, "kalıtım" ın pratik anlamı nedir?

Seçenek 1: Sup'in kodu neredeyse Sub'a kopyalanır . ('kopyala-yapıştır'da olduğu gibi, ancak kopyalanan kod alt sınıfta görsel olarak görülmeden).

Örnek: methodA()başlangıçta Sup. Sub, Sup'i genişletir methodA(), (neredeyse) Sub'a kopyalanır. Şimdi Sub adlı bir yöntem var methodA(). Her methodA()kod satırında Sup ile aynıdır , ancak tamamen Sub'a aittir ve Sup'e bağlı değildir veya Sup ile hiçbir şekilde ilişkili değildir.

Seçenek 2: Sup'in kodu aslında Sub'a kopyalanmaz . Hala sadece üst sınıfta. Ancak bu koda alt sınıftan erişilebilir ve alt sınıf tarafından kullanılabilir.

Örnek: methodA()Sup. Alt yani şimdi, Sup uzanır methodA()şöyle Sub aracılığıyla erişilebilir: subInstance.methodA(). Ama bu aslında methodA()üst sınıfta çağıracak . Bu, methodA () öğesinin alt sınıf tarafından çağrılmış olsa bile üst sınıf bağlamında çalışacağı anlamına gelir .

Soru: İki seçenekten hangisi gerçekten işler nasıl işler? Bunlardan hiçbiri değilse, lütfen bunların nasıl çalıştığını açıklayın.


Bunu kendiniz test etmek kolaydır - kodu yazın, sınıf dosyalarını inceleyin (bir sağlama toplamı bile yapar), süper sınıfı değiştirin, tekrar derleyin, sınıf dosyalarına tekrar bakın. Ayrıca Bölüm 3'ün okunmasını da bulabilirsiniz .

@MichaelT " sanal olarak kopyalandı" anahtar kelimesidir. Ayrıca, kod tam anlamıyla kopyalansa bile, bu yalnızca sınıf yüklendikten sonra olabilir.

@delnan, Hotspot'un (veya diğer çalışma zamanı optimize edicilerinin) kodu bir noktada satır içine alıp almayacağını merak ederdi, ancak bu, JVM'nin bir JVM'den diğerine farklılık gösterebilecek ve bu nedenle doğru şekilde cevaplanamayan bir uygulama detayı haline gelir. Yapılabilecek en iyi şey, derlenmiş bayt koduna (ve gerçekte ne olduğunu açıklayan özel opcode kullanımına)

Yanıtlar:


13

Seçenek 2.

Bayt koduna çalışma zamanında dinamik olarak başvurulur: bu nedenle, örneğin, LinkageErrors oluşur.

Örneğin, iki sınıf derlediğinizi varsayalım:

public class Parent {
  public void doSomething(String x) { ... }
}

public class Child extends Parent {
  @Override
  public void doSomething(String x) {
    super.doSomething(x);
    ...
  }
}

Şimdi alt sınıfı değiştirmeden veya yeniden derlemeden üst sınıfı değiştirin ve yeniden derleyin :

public class Parent {
  public void doSomething(Collection<?> x) { ... }
}

Son olarak, child sınıfını kullanan bir program çalıştırın. Bir NoSuchMethodError alacaksınız :

Bir uygulama bir sınıfın (statik veya örnek) belirli bir yöntemini çağırmaya çalışırsa ve o sınıfın artık bu yöntemin bir tanımı yoksa atılır.

Normalde, bu hata derleyici tarafından yakalanır; Bu hata, yalnızca bir sınıfın tanımı uyumsuzca değiştiğinde çalışma zamanında oluşabilir.


7

İki basit sınıfla başlayalım:

package com.michaelt.so.supers;

public class Sup {
    int methodA(int a, int b) {
        return a + b;
    }
}

ve sonra

package com.michaelt.so.supers;

public class Sub extends Sup {
    @Override
    int methodA(int a, int b) {
        return super.methodA(a, b);
    }
}

Metod A derleme ve bayt koduna bakıldığında:

  methodA(II)I
   L0
    LINENUMBER 6 L0
    ALOAD 0
    ILOAD 1
    ILOAD 2
    INVOKESPECIAL com/michaelt/so/supers/Sup.methodA (II)I
    IRETURN
   L1
    LOCALVARIABLE this Lcom/michaelt/so/supers/Sub; L0 L1 0
    LOCALVARIABLE a I L0 L1 1
    LOCALVARIABLE b I L0 L1 2
    MAXSTACK = 3
    MAXLOCALS = 3

Ve burada Sup sınıf methodA () 'a karşı arama yapan invokespecial yöntemiyle görebilirsiniz.

İnvokespecial işlemkodu aşağıdaki mantığı vardır:

  • C, çözümlenmiş yöntemle aynı ada ve açıklayıcıya sahip bir örnek yöntemi için bir bildirim içeriyorsa, bu yöntem çağrılır. Arama prosedürü sona erer.
  • Aksi takdirde, C'nin bir üst sınıfı varsa, bu aynı arama prosedürü, C'nin doğrudan üst sınıfı kullanılarak tekrarlı olarak gerçekleştirilir.
  • Aksi takdirde, bir AbstractMethodError oluşturulur.

Bu durumda, sınıfında aynı ada ve tanımlayıcıya sahip bir örnek yöntemi yoktur, bu nedenle ilk mermi ateşlenmez. Ancak ikinci mermi bir süper sınıf var ve süper yönteminA'yı çağırıyor.

Derleyici bunu satır içi yapmaz ve sınıfta Sup kaynağının bir kopyası yoktur.

Ancak hikaye henüz bitmedi. Bu sadece derlenmiş kod. Kod JVM'ye çarptığında HotSpot dahil olabilir.

Ne yazık ki, bu konuda o kadar çok şey bilmiyorum, bu yüzden bu konuda otoriteye hitap edeceğim ve Java'da Inlining'e gideceğim, burada HotSpot'un inline yöntemleri (hatta nihai olmayan yöntemler bile) yapabileceği söyleniyor .

Gitmek docs Alt Yöntemia içine) etkin bir şekilde Sup Yöntemia kodu (kopyalama () - o belirli yöntem çağrısı yerine her zaman arama, bu bilgiler satır içine yerleştirilmiş ki yapmanın sıcak nokta olursa belirtilmektedir.

Bu, uygulamanın nasıl davrandığına ve performansı hızlandırmak için hangi optimizasyonların gerekli olduğuna bağlı olarak çalışma zamanında, bellekte yapılır.

HotJpot Internals for OpenJDK'da belirtildiği gibi "Yöntemler genellikle satır içi. Statik, özel, son ve / veya" özel "çağrıların satır içi olması kolaydır."

JVM için seçeneklere girerseniz, -XX:MaxInlineSize=35satır içine alınabilecek maksimum bayt sayısı olan bir seçenek (varsayılan 35'tir) bulacaksınız . Bu yüzden Java'nın birçok küçük yöntemi kullanmayı sevdiğini belirteceğim - çünkü kolayca satır içi olabilirler. Bu küçük yöntemler , daha fazla çağrıldıklarında daha hızlı hale gelir , çünkü satır içi olabilirler . Ve kişi bu sayı ile oynayabilir ve büyütebilirken, diğer optimizasyonların daha az etkili olmasına neden olabilir. (ilgili SO sorusu: HotSpot, HotSpot'un yaptığı inlining içlerine bakmak için bir dizi başka seçeneğe dikkat çeken inline stratejisi ).

Yani, hayır - kod derleme zamanında satır içine alınmaz. Ve evet - performans optimizasyonları gerektiriyorsa kod çalışma zamanında çok iyi bir şekilde sıralanabilir.

HotSpot satır içi yazma hakkında yazdıklarım yalnızca Oracle tarafından dağıtılan HotSpot JVM için geçerlidir. Vikipedi'nin Java sanal makineleri listesine bakarsanız, HotSpot'tan çok daha fazlası vardır ve bu JVM'lerin satır içi işlemeyi ele alma şekli yukarıda açıkladığımdan tamamen farklı olabilir. Apache Harmony, Dalvik, ART - işler orada farklı çalışabilir.


0

kod kopyalanmaz, referans ile erişilir:

  • alt sınıf yöntemlerine ve üst sınıfa başvurur
  • üst sınıf yöntemlerine başvurur

derleyiciler bunun bellekte nasıl temsil edildiğini / yürütüldüğünü optimize edebilir, ancak temel olarak yapı

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.