Bir parametre değişmez boş değer olduğunda aşırı yüklenmiş bir yöntem nasıl seçilir?


98

Bu soruya bir testte rastladım,

public class MoneyCalc {

   public void method(Object o) {
      System.out.println("Object Verion");
   }

   public void method(String s) {
      System.out.println("String Version");
   }

   public static void main(String args[]) {
      MoneyCalc question = new MoneyCalc();
      question.method(null);
   }
}

Bu programın çıktısı "Dize Sürümü" dür. Ancak, aşırı yüklenmiş bir yönteme bir null değerinin neden dize sürümünü seçtiğini anlayamadım. Null bir String değişkeni hiçbir şeyi işaret etmiyor mu?

Ancak kod olarak değiştirildiğinde,

public class MoneyCalc {

   public void method(StringBuffer sb) {
      System.out.println("StringBuffer Verion");
   }

   public void method(String s) {
      System.out.println("String Version");
   }

   public static void main(String args[]) {
      MoneyCalc question = new MoneyCalc();
      question.method(null);
   }
}

"Yöntem yöntemi (StringBuffer) MoneyCalc türü için belirsiz" diyen bir derleme hatası veriyor


Boş bir değere bir dize atayabilirsiniz, böylece geçerli olur ve java ve çoğu programlama dili için sıra en yakın türe ve sonra nesneye uygun olur.
JonH


6
Görünüşe göre bu sadece başlığı okuyanlar tarafından kopya olarak kapatılmış. Buradaki asıl soru, "null nedir" değil, neden belirli bir aşırı yükün seçildiğidir.
interjay

Yanıtlar:


102

Null bir String değişkeni hiçbir şeyi işaret etmiyor mu?

Boş bir başvuru, herhangi bir sınıf türünün ifadesine dönüştürülebilir. Bu durumda String, bu sorun değil:

String x = null;

Buradaki Stringaşırı yük, JLS'nin 15.12.2.5 bölümüne göre Java derleyicisinin en spesifik aşırı yüklemeyi seçmesi nedeniyle seçilmiştir . Özellikle:

Gayri resmi sezgiye göre, eğer birinci yöntem tarafından ele alınan herhangi bir çağrı diğerine derleme zamanı tipi hatası olmadan aktarılabiliyorsa, bir yöntemin diğerinden daha spesifik olmasıdır.

İkinci durumunuzda, her iki yöntem de hala uygulanabilirdir, ancak ne diğerinden daha spesifiktir ne Stringde StringBufferdiğerinden daha spesifiktir, bu nedenle hiçbir yöntem diğerinden daha spesifik değildir, dolayısıyla derleyici hatasıdır.


3
Ve String aşırı yüklemesi, Nesne aşırı yüklemesinden nasıl daha spesifiktir?
user1610015

12
Çünkü bir Objectherhangi bir türü alıp onu bir içine sarabilir Object, oysa a Stringyalnızca bir String. Bu durumda, Stringtipe göre daha spesifik bir Objecttiptir.
JonH

10
@zakSyed Hangisinin daha özelleşmiş "String" veya "Object" olduğu sorulsaydı, ne derdiniz? Belli ki "İp", değil mi? Size sorulsaydı: daha özel "String" veya "StringBuffer" nedir? Cevap yok, ikisi de ortogonal uzmanlık, aralarında nasıl seçim yapabilirsiniz? O zaman hangisini istediğiniz konusunda açık olmalısınız (yani boş referansınızı question.method((String)null)
atarak

1
@JonSkeet: Bu mantıklı. Yani temelde en spesifik kurala göre bir yöntem arar ve hangisinin daha spesifik olduğuna karar veremezse, derleme zamanı hatası verir.
zakSyed

3
@JonH "null" başvuru türüdür, yöntemlerden biri parametre (yani int) olarak ilkel bir tür alırsa, null türünde bir başvuru için doğru yöntemi seçerken derleyici tarafından bile dikkate alınmayacaktır. "Int" ile java.lang.Integer'ı kastetmeniz veya int ilkel türünü kastetmeniz kafa karıştırıcı.
Edwin Dalorzo

9

Ek olarak, JLS 3.10.7 ayrıca "boş" değerinin "boş tipin" değişmez değeri olduğunu bildirir. Bu nedenle "boş" adlı bir tür vardır.

Daha sonra, JLS 4.1 , değişkenleri bildirmenin imkansız olduğu bir boş tip olduğunu, ancak bunu yalnızca boş değişmez olarak kullanabileceğinizi belirtir. Daha sonra şöyle diyor:

Boş referans, her zaman herhangi bir referans türüne genişleyen bir referans dönüşümünden geçebilir.

Derleyicinin onu neden String'e genişletmeyi seçtiği Jon'un cevabında iyi bir şekilde açıklanabilir .


Bu türün Void olduğundan oldukça eminim.
xavierm02

2
@ xavierm02 Java Dil Spesifikasyonunda bundan bahsedilmiyor. Hepimizin iddianızı doğrulayabilmesi için referansınızı verebilir misiniz?
Edwin Dalorzo

O şeyi asla okumadım. Ama bu yaz biraz Java yaptım ve bir Void nesnesi alan bir yöntemle bir Nesne alan bir yöntemi aşırı yükleyebilirsiniz.
xavierm02

Bir türden çok bir sınıftır.
xavierm02

4
@ xavierm02 Elbette yapabilirsiniz. Java'daki bir yöntemi, istediğiniz diğer türlerden hangisiyle aşırı yükleyebilirsiniz. Yine de bunun soru ya da cevabımla hiçbir ilgisi yok.
Edwin Dalorzo

2

Geçerli olması stringiçin bir nulldeğere atayabilirsiniz ve java ve çoğu programlama dili için sıralama, en yakın türe ve sonra nesneye uygun olur.


2

Başlıktaki soruyu cevaplamak için: nullne a Stringne de an Object, ancak ikisine de atıfta bulunulabilir null.

Aslında bu kodun derlenmesine bile şaşırdım. Daha önce benzer bir şey denedim ve aramanın belirsiz olduğunu söyleyen bir derleyici hatası aldım.

Ancak bu durumda derleyici besin zincirinde en düşük olan yöntemi seçiyor gibi görünüyor. Size yardımcı olmak için yöntemin en az jenerik versiyonunu istediğinizi varsayıyoruz.

Yine de bu (görünüşte) aynı senaryoda bir derleyici hatası aldığım örneği inceleyip inceleyemeyeceğimi görmem gerekecek ...]

DÜZENLEME: Görüyorum. Yaptığım versiyonda, a Stringve an kabul eden iki aşırı yüklenmiş yöntemim vardı Integer. Bu senaryoda, (olduğu gibi hayır "en özel" parametresi vardır Objectve Stringo kodunuzda aksine aralarında seçemezsiniz böylece).

Çok güzel bir soru!


null ne değildir, ancak her ikisine de atanabilir, fark budur ve neden olmasın derler - kesinlikle geçerli koddur.
JonH

0

String tipi, Object tipinden daha spesifiktir. Bir Tamsayı türü alan bir yöntem daha eklediğinizi varsayalım.

public void method(Integer i) {
      System.out.println("Integer Version");
   }

Ardından, aramanın belirsiz olduğunu söyleyen bir derleyici hatası alacaksınız. Şu anda olduğu gibi, aynı önceliğe sahip iki eşit derecede spesifik yöntem.


0

Java derleyicisi, null atamak için çoğu türetilmiş sınıf türünü verir.

İşte onu anlamak için örnek:

class A{

    public void methodA(){
        System.out.println("Hello methodA");
    }
}

class B extends A{
    public void methodB(){
        System.out.println("Hello methodB");
    }
}

class C{
    public void methodC(){
        System.out.println("Hello methodC");
    }
}

public class MyTest {

     public static void fun(B Obj){
         System.out.println("B Class.");
     }
     public static void fun(A Obj){
         System.out.println("A Class.");
     }

    public static void main(String[] args) {
        fun(null);
    }
}

çıktı: B Sınıfı.

diğer yandan:

public class MyTest {

     public static void fun(C Obj){
         System.out.println("B Class.");
     }
     public static void fun(A Obj){
         System.out.println("A Class.");
     }

    public static void main(String[] args) {
        fun(null);
    }
}

Sonuç: Fun (C) yöntemi, MyTest türü için belirsizdir

Umarım bu davayı daha iyi anlamaya yardımcı olur.


0

Kaynak: https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.12.2.5
Konsept: En spesifik yöntem
Açıklama: Birden fazla üye yöntemi hem erişilebilir hem de bir yöntem çağrısı için geçerliyse, çalışma zamanı yöntem gönderimi için tanımlayıcı sağlamak üzere birini seçmek gerekir. Java programlama dili, en özel yöntemin seçildiği kuralı kullanır. Boş değeri belirli bir türe dönüştürmeyi deneyin; istediğiniz yöntem otomatik olarak çağrılacaktır.


İlk örnekte, String, Object'i genişletir, bu nedenle "en spesifik", String'i alan yöntemdir, ancak ikinci örnekte, String ve StringBuffer, her ikisi de Object'i genişletir, bu nedenle bunlar eşit derecede spesifiktir ve bu nedenle derleyici bir seçim yapamaz
David Kerr

-1

Ben de söyleyemem. NULL, bir değer değil bir durumdur. Bununla ilgili daha fazla bilgi için bu bağlantıya göz atın (makale SQL için geçerlidir, ancak sorunuza yardımcı olacağını düşünüyorum).


nullJLS'de tanımlandığı gibi kesinlikle bir değerdir.
Sotirios Delimanolis
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.