Geçersiz kılınan yöntemler dönüş türünde farklılık gösterebilir mi?


134

Geçersiz kılınan yöntemlerin farklı dönüş türleri olabilir mi?


2
Eğer aynı veya daha dar dönüş türüne sahip değilseniz, o zaman şunu alacaksınız:error: method() in subclass cannot override method() in superclass
Quazi Irfan

Yanıtlar:


176

Java, geçersiz kılınan yöntemler için * ortak değişken dönüş türlerini destekler . Bu, geçersiz kılınmış bir yöntemin daha fazla spesifik bir dönüş türüne . Yani, yeni dönüş türü, geçersiz kıldığınız yöntemin dönüş türüne atanabilir olduğu sürece, buna izin verilir.

Örneğin:

class ShapeBuilder {
    ...
    public Shape build() {
    ....
}

class CircleBuilder extends ShapeBuilder{
    ...
    @Override
    public Circle build() {
    ....
}

Bu, Java Dil Belirtimi'nin 8.4.5 bölümünde belirtilmiştir :

Dönüş türleri referans türlerse, iade türleri birbirini geçersiz kılan yöntemler arasında değişiklik gösterebilir. Dönüş türü ikame edilebilirlik kavramı, eş değişken dönüşleri, yani dönüş türünün bir alt türe özelleştirilmesini destekler.

Dönüş türü R1 olan bir yöntem bildirimi d1, dönüş türü R2 ile başka bir yöntem d2 için dönüş tipi ikame edilebilirdir, ancak ve ancak aşağıdaki koşullar geçerliyse:

  • R1 geçersiz ise R2 geçersizdir.

  • R1 ilkel bir türse, R2, R1 ile aynıdır.

  • R1 bir referans tipiyse:

    • R1, ya R2'nin bir alt tipidir ya da R1, kontrolsüz dönüştürme (§5.1.9) ile R2'nin bir alt tipine dönüştürülebilir veya

    • R1 = | R2 |

("| R2 |", JLS'nin §4.6'sında tanımlandığı gibi R2'nin silinmesini ifade eder .)


* Java 5'ten önce Java'nın değişmeyen dönüş türleri vardı ; bu, geçersiz kılınan yöntemle tam olarak eşleşmesi için gereken bir yöntemin geçersiz kılma dönüş türünün gerekli olduğu anlamına geliyordu.


26

Evet farklı olabilir ama bazı sınırlamalar vardır.

Java 5.0'dan önce, bir yöntemi geçersiz kıldığınızda, hem parametreler hem de dönüş türü tam olarak eşleşmelidir. Java 5.0'da, kovaryant dönüş türü adı verilen yeni bir özellik sunar. Aynı imzaya sahip bir yöntemi geçersiz kılabilirsiniz, ancak döndürülen nesnenin bir alt sınıfını döndürür. Başka bir deyişle, bir alt sınıftaki bir yöntem, türü, üst sınıfta aynı imzaya sahip yöntem tarafından döndürülen türün bir alt sınıfı olan bir nesneyi döndürebilir.


20

Evet, bir alt tür döndürürlerse. İşte bir örnek:

package com.sandbox;

public class Sandbox {

    private static class Parent {
        public ParentReturnType run() {
            return new ParentReturnType();
        }
    }

    private static class ParentReturnType {

    }

    private static class Child extends Parent {
        @Override
        public ChildReturnType run() {
            return new ChildReturnType();
        }
    }

    private static class ChildReturnType extends ParentReturnType {
    }
}

Bu kod derler ve çalışır.


9

Genel olarak, evet, geçersiz kılma yönteminin dönüş türü farklı olabilir. Ancak bununla ilgili bazı vakalar olduğu için bu basit değil.

Durum 1: Dönüş türü ilkel bir veri türü veya geçersiz ise.

Çıktı: Dönüş türü void veya ilkel ise, üst sınıf yönteminin veri türü ve geçersiz kılma yöntemi aynı olmalıdır. Örneğin, dönüş türü int, float, string ise aynı olmalıdır

Durum 2: Dönüş türü türetilmiş veri türü ise:

Çıktı: Ana sınıf yönteminin dönüş türü türetilmiş türse, geçersiz kılma yönteminin dönüş türü, türetilmiş veri türüne göre alt sınıfın aynı türetilmiş veri türü olur. Örneğin, benim bir A sınıfım olduğunu, B'nin A'nın alt sınıfını, C'nin B'nin alt sınıfını ve D'nin C'nin alt sınıf olduğunu varsayalım; o zaman süper sınıf A tipi döndürüyorsa, geçersiz kılma yöntemi alt sınıftır, yani alt türleri A, B, C veya D tipi döndürebilir. Buna kovaryans da denir.


Bu yorumun belirsiz bir AB sınıfım var, AC'nin alt sınıfı, AC'nin alt sınıfı, bunun anlamı AB Sınıfı AC veya A'nın alt sınıfı, B, A'nın Alt Sınıfı, C Kafa karıştırıcı anlamına geliyor
dinesh kandpal

5

evet Bu mümkündür .. dönüş türü ancak ana sınıf yöntemi dönüş türü
süper bir çocuk sınıfı türü ise dönüş türü farklı olabilir ..
anlamı

class ParentClass {
    public Circle() method1() {
        return new Cirlce();
    }
}

class ChildClass extends ParentClass {
    public Square method1() {
        return new Square();
    }
}

Class Circle {

}

class Square extends Circle {

}


Bu durumda farklı dönüş türüne izin verilebilir ...


2

evet, cevap evet ... VE HAYIR.

soruya bağlıdır. burada herkes Java> = 5 ile ilgili cevapladı ve bazıları Java <5'in kovaryant dönüş türleri içermediğinden bahsetti.

aslında Java dili özelliği> = 5 bunu destekler, ancak Java çalışma zamanı desteklemez. özellikle, JVM, kovaryant dönüş türlerini desteklemek için güncellenmedi.

O zamanlar "zeki" bir hareket olarak görülen, ancak Java tarihindeki en kötü tasarım kararlarından biri olan Java 5, JVM'yi veya sınıf dosyası özelliklerini hiç değiştirmeden bir dizi yeni dil özelliği uyguladı. bunun yerine tüm özellikler javac'ta hile ile uygulandı: derleyici, iç içe / iç sınıflar için düz sınıflar üretir / kullanır, jenerikler için tür silme ve yayınlar, iç içe / iç sınıf özel "arkadaşlık" için sentetik erişimciler, dış 'this' için sentetik örnek alanları işaretçiler, '.class' değişmez değerleri için sentetik statik alanlar vb.

ve kovaryant dönüş türleri, javac tarafından eklenen daha fazla sözdizimsel şekerdir.

örneğin, bunu derlerken:

class Base {
  Object get() { return null; }
}

class Derived extends Base {
  @Override
  @SomeAnnotation
  Integer get() { return null; }
}

javac, Derived sınıfında iki get yöntemi çıkarır:

Integer Integer:Derived:get() { return null; }
synthetic bridge Object Object:Derived:get() { return Integer:Derived:get(); }

oluşturulan köprü yöntemi (işaretli syntheticve bridgebayt kodlu) gerçekte geçersiz kılan şeydir Object:Base:get(), çünkü JVM için farklı dönüş türlerine sahip yöntemler tamamen bağımsızdır ve birbirlerini geçersiz kılamazlar. beklenen davranışı sağlamak için, köprü basitçe "gerçek" yönteminizi çağırır. Yukarıdaki örnekte javac, @SomeAnnotation ile Derived uygulamasında hem köprü hem de gerçek yöntemlere açıklama ekleyecektir.

Bu çözümü Java <5'te elle kodlayamayacağınızı unutmayın, çünkü köprü ve gerçek yöntemler yalnızca dönüş türünde farklılık gösterir ve bu nedenle bir Java programında bir arada var olamazlar. ancak JVM dünyasında, yöntem dönüş türleri yöntem imzasının bir parçasıdır (tıpkı bağımsız değişkenleri gibi) ve bu nedenle, aynı adı verilen ve aynı bağımsız değişkenleri alan iki yöntem, farklı dönüş türleri nedeniyle yine de JVM tarafından tamamen bağımsız olarak görülür. ve bir arada var olabilir.

(BTW, alan türleri benzer şekilde bayt kodundaki alan imzasının bir parçasıdır, bu nedenle farklı türlerde birkaç alana sahip olmak ancak tek bir bayt kodu sınıfı içinde aynı şekilde adlandırılmak yasaldır.)

sorunuzu tam olarak yanıtlamak için: JVM, kovaryant dönüş türlerini desteklemez, ancak javac> = 5, onu bir tatlı sözdizimsel şeker kaplamasıyla derleme zamanında taklit eder.


1

Geçersiz Kılma ve Dönüş Türleri ve Kovaryant İade
Alt sınıf, devralınan sürümle tam olarak eşleşen bir yöntemi tanımlamalıdır. Veya Java 5'ten itibaren, geri dönüş türünü

basit kod


                                                                                                            class Alpha {
          Alpha doStuff(char c) {
                  return new Alpha();
              }
           }
             class Beta extends Alpha {
                    Beta doStuff(char c) { // legal override in Java 1.5
                    return new Beta();
                    }
             } } 
Java 5, bu kod derlenecek. Bu kodu bir 1.4 derleyicisiyle derlemeye çalışırsanız, uyumsuz dönüş türünü kullanmaya çalıştığınızı söyleyecektir - sandeep1987 1 dakika önce


1

Diğer cevapların hepsi doğrudur, ancak şaşırtıcı bir şekilde burada teorik yönü dışarıda bırakır: dönüş türleri farklı olabilir, ancak Liskov İkame İlkesi nedeniyle yalnızca süper sınıfta kullanılan türü kısıtlayabilirler .

Çok basit: Bir yöntemi çağıran "istemci" kodunuz olduğunda:

int foo = someBar.bar();

o zaman yukarıdakilerin çalışması gerekir (ve inthangi uygulamasının bar()çağrıldığına bakılmaksızın bir şey döndürmesi ).

Anlamı: geçersiz kılan bir Bar alt sınıfı bar()varsa, yine de "arayan kodunu" bozmayan bir şey döndürmeniz gerekir.

Başka bir deyişle: tabanın bar()int döndürmesi gerektiğini varsayalım . O zaman bir alt sınıf geri dönebilir short- ancak longarayanlar bir shortdeğerle ilgilenirken sorun olmayacağı için değil, a long!


0

Dönüş türü, üst sınıftaki orijinal geçersiz kılınan yöntemde bildirilen dönüş türü ile aynı veya bunun bir alt türü olmalıdır.


5
İki cevabınızı birleştirmelisiniz.
theblang

0

EVET mümkün olabilir

class base {

 base show(){

System.out.println("base class");

return new base();

}
}

class sub extends base{

sub show(){

    System.out.println("sub class");

    return new sub();

 }
}

class inheritance{

 public static void main(String []args) {

        sub obj=new sub();

            obj.show();
 }
}

0

Evet. Geçersiz kılınan yöntemlerin farklı dönüş türlerine sahip olması mümkündür.

Ancak sınırlamalar, geçersiz kılınan yöntemin, gerçek yöntemin dönüş türünün daha spesifik türü olan bir dönüş türüne sahip olması gerektiğidir.

Tüm cevaplar, gerçek yöntemin dönüş türünün bir alt sınıfı olan bir dönüş türüne sahip olmak için geçersiz kılınan yöntemin örneklerini vermiştir.

Örneğin :

public class Foo{

   //method which returns Foo
  Foo getFoo(){
      //your code         
  }

}

 public class subFoo extends Foo{

  //Overridden method which returns subclass of Foo
  @Override
  subFoo getFoo(){
      //your code         
  }

}

Ancak bu sadece alt sınıfla sınırlı değildir, bir arabirim uygulayan sınıflar bile belirli bir arabirim türüdür ve bu nedenle arabirimin beklendiği bir dönüş türü olabilir.

Örneğin :

public interface Foo{

   //method which returns Foo
  Foo getFoo();

}

 public class Fizz implements Foo{

  //Overridden method which returns Fizz(as it implements Foo)
  @Override
  Fizz getFoo(){
      //your code         
  }

}

0
class Phone {
    public Phone getMsg() {
        System.out.println("phone...");
        return new Phone();
    }
}

class Samsung extends Phone{
    @Override
    public Samsung getMsg() {
        System.out.println("samsung...");
        return new Samsung();
    }
    
    public static void main(String[] args) {
        Phone p=new Samsung();
        p.getMsg();
    }
}

Bu soruya nasıl cevap veriyor?
Markasız Manchester

bu, farklı dönüş türü örneğidir.
Parth
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.