Soru Süper sınıf referansı kullanarak aşırı yüklenmiş miras yöntemlerini arama


Bu Java davranışını anlamıyorum. İki dersim var:

class C1 {
    public void m1(double num) {
        System.out.println("Inside C1.m1(): " + num);
    }
}

class C2 extends C1 {
    public void m1(int num) {
        System.out.println("Inside C2.m1(): " + num);
    }
}

Ve bu benim ana:

public class Main {

    public static void main(String[] args) {
        C1 c = new C2();
        c.m1(10);
    }
}

Ve sonuç şuydu:

Inside C1.m1(): 10.0

Beklediğim zaman:

Inside C2.m1(): 10

Ayrıca, kod sözdizimini tamamlamaya çalıştığımda şunu buldum:

Enter image description here

C2 sınıfının diğer m1 nerede?

Ayrıca Main.class'ın bayt kodunu da kontrol ediyorum ve bunu gördüm:

Compiled from "Main.java"
public class com.company.Main {
  public com.company.Main();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: new           #2                  // class com/company/C2
       3: dup
       4: invokespecial #3                  // Method com/company/C2."<init>":()V
       7: astore_1
       8: aload_1
       9: ldc2_w        #4                  // double 10.0d
      12: invokevirtual #6                  // Method com/company/C1.m1:(D)V
      15: return
}

Bayt kodu, C1.m1 (D) V (satır 12) 'yi çağırdığını söyler.

Neden C1 yöntemi? Bu davranışı anlamaya çalışıyorum.


17
2018-04-25 18:37


Menşei


Ekleyerek unutmayın @Override ikinci m1 için bu IRL olacağından durduracak :) - Navin
olası kopyası Java aşırı yükleme ve devralma kuralları - Raedwald


Cevaplar:


Adınız iki yöntem m1 aynı imzası yok; süper sınıftaki bir doubleve alt sınıftaki bir int. Bu, derleyicinin değişkeninizin derleme zamanı türüne göre çağrı yapmak için yöntem imzasını seçeceği anlamına gelir. C1ve arayacak m1(double). Çalışma zamanında sınıftan beri C2 geçersiz bir sürümü yok m1(double), sürümü C1 çağrılır.

Kural bu yöntemdir imzalar derleme zamanı türlerine göre derleme zamanında hesaplanır; yöntem çağrıları sevk eşzamanlı imzalara dayalı çalışma zamanında.


16
2018-04-25 18:42



Yani, zorunlu bir kadro yapmak zorundayım? veya oluştur C2 c = new C2(); - Robert
@ Rob3 Bu soru, bu yöntemi açıklamıyor m1 içinde C2 aşırı ve değil overriden. Detaylı bir açıklama için cevabımı görün. - CKing
@ Rob3 Çağırmak için birini veya diğerini yapmak zorundasınız m1(int). Hedefin derleme zamanı türünü değiştirecek bir şey C2. - chrylis
Soru başlığı, aşırı yükleme davranışının geçersiz kılmadığını söylüyor - Robert


Parametreler yüzünden. Aradığınız yöntem, çift parametreli bir yöntemdir. C2'nin içindeki m1 bunu geçersiz kılmaz, bunun yerine YÜKSELTMEKTİR.

Eğer C2'de m1'i aramak isterseniz, referansı yapmak için derleyicinin ne yaptığınızı kabul etmesi gerekir.


10
2018-04-25 18:41



OP böyle diyor. o metodu aşırı yüklüyor. - Alboz
o üzerinden bekliyoryüklü çağrılacak yöntem Ben bu kadar aptal düşünmüyorum - Distjubo
Diğer yöntemi çağırmaya çalışıyorum ama görünmüyor .. Ayrıca C2'nin iki yöntemi var: m1(double) ve ikinci: m1(int) M1'i aradığımda (10) ve bunu bekledim. m1(int ) çağrılacak. - Robert
Otherr yöntemini çağırmak için, nesneyi örnek kodlamanız gerekir: ((C2)c).m1(10); - Distjubo
@ Rob3, SRobertz'in cevabını okudu. Görünür olan yöntem, gerçek nesneye değil, değişken TYPE'ye bağlıdır. - Alboz


Çıktının neden görüldüğünün nedeni Inside C1.m1(): 10.0 ve yok Inside C1.m1(): 10 veya Inside C2.m1(): 10.0 Çünkü :

  1. Yöntemi geçersiz kılmıyorsunuz m1 içinde C2. Aşırı yüklüyorsun m1(doube) miras aldığınız yöntem C1 için m1(int) yerine.
  2. C2 şimdi sınıf iki tane var m1 yöntemleri. Bir tane inherited itibaren C1 ve imzası var m1(double) ve aşırı yüklü olan C2 ve imzası var m1(int)
  3. Derleyici çağrıyı gördüğünde c.m1(10)Bu çağrıyı referans türüne göre çözer. Referans tipi olduğundan C1, derleyici bu çağrıyı çözecek m1(double) içinde C1.
  4. Çalışma zamanında, JVM çağrıyı çözecek m1(double) içinde C2 hangi yöntem miras alınan C1. (2. maddede açıklandığı gibi)

İçinde iki yol vardır m1(int) yöntem çağrılabilir:

((C2)c).m1(10);

VEYA

C2 c = new C2(); c.m1(10);


7
2018-04-25 18:56





Java, statik türlerde ve değişkeninizde yöntem gönderir c tipi C1, yani m1(int) görünür değil ve 10 için yayınlanıyor double.


6
2018-04-25 18:41



Bu bana en kısa ve en iyi cevap gibi görünüyor. - Alboz
Bu cevap en basit açıklamadır. Genel olarak, bir C1 nesnesi üzerinde m1 (int) çağrısı, örnek bir C2 olsa bile, doğru olmaz, çünkü C1 türünde genel bir nesne böyle bir yönteme sahip değildir. - Patrick White


Her iki yöntem için yöntem imzaları farklıdır.

public void m1(double num) 
public void m1(int num)

Yani bu durumda hiçbir şey yoktur. Şimdi dediğin zaman

    C1 c = new C2();
    c.m1(10);

derleme zamanında, referans türdür C1 hangi yöntemi vardır public void m1(double num) 10 ile uyumlu olan [int genişletmek için çift]. Böylece int iki katına çıkarılır ve buna karşılık gelen yöntem çağrılır (bytecodes'de de gördüğünüz).


4
2018-04-25 18:42





Eğer c.m1'i (10.0) çağırırsanız, ilk önce beklediğiniz gibi atasının yöntemini çağırır.

Örnekleminizde aşırı yükleme yöntemini (aynı adı ve farklı imzayı içeren daha fazla yöntem ekliyor) yöntemi geçersiz kılmak yerine (bir ata sahibinin yönteminin, aynı imza ile yeniden aktararak bir atacının yönteminin uygulanmasını değiştiren AKA, aynıdır) isim ve aynı tür sonuç ve yöntem argümanları - argüman adları önemli olmamalıdır).


3
2018-04-25 19:23





C2 yöntemlerini göremezsiniz, çünkü siz örnek değişkeni C1 olarak bildirilir ve aynı imzaya sahip olmadıkları için. Bir metotta çifte parametreniz var ve ikincisi JVM'yi tamamen farklı metotlar haline getiren int tipine sahipsin (yani miras kalmayacak).

Yani, eğer CI yönteminde int tipiniz varsa, C2 yönteminde int türüne de sahip olmanız gerekir, daha sonra JVM istediğiniz gibi C2'den bir metodu çalıştıracaktır.

Ayrıca C2 türüne değişken atabilirsiniz, sonra C2 yöntemlerine erişebileceksiniz.


2
2018-04-25 18:49





Kodunuza bakarak, istediğiniz cevabı almak için miras alma avantajından yararlanmıyorsunuz. Bu çizgiyi değiştirmek zorundasın

C1 c = new C2();

için

C2 c = new C2();

2
2018-04-25 18:47





Dan beri C1.m1(double num) halka açık bir yöntemdir, C2 devralındı. C2'nizin de bir yöntemi var. m1(double num)ve bu yüzden denir. itibaren main() sen aradın C2.m1(double num).

Not: Şimdi sınıfta C2 İki aşırı yüklü metodunuz var - m1(int num) ve m1(double num). Ve C2.m1(int num) farklı bir yöntemdir C2.m1(double num).


1
2018-04-25 18:41





Java, en spesifik uygulanabilir türü seçer. Bu durumda m1 (int) geçerli değildir.    Aynı sınıftaki nesneyi (c1) veya sınıfın (c2) ve yöntem adının ve parametre listesinin herhangi bir alt sınıfının nesnesini tutan sınıf referansı üzerinde durun.

Çift parametreli yönteminiz çağrılıyor çünkü çift, int üzerinden önceliği alıyor. Bunun nedeni, int'nin bir çifte atanabilmesidir, ancak başka bir şekilde değil.

Yani, yöntem çağrısı (çalışma) zamanında dikkate alınması gereken çok şey var.

Evet, dava için ana sınıfın böyle olması gerekir

        public static void main(String[] args) {
            C1 c = new C2();
            c.m1(10);
            ((C2) c).m1(10);
    //or
            C2 cobj = new C2();
            cobj.m1(10);
        }


**OutPut**
Inside C1.m1(): 10.0
Inside C2.m1(): 10
Inside C2.m1(): 10

0
2018-02-23 13:18