Üst türün beklendiği alt sınıf nesnesini bağımsız değişken olarak geçirerek yöntemleri geçersiz kılma


12

Ben sadece Java öğreniyorum ve pratik bir programcı değilim.

Takip ettiğim kitap, bir yöntemi geçersiz kılarken, argüman türlerinin aynı olması gerektiğini, ancak dönüş türlerinin polimorfik olarak uyumlu olabileceğini söylüyor.

Benim sorum neden geçersiz kılma yöntemine iletilen argümanlar beklenen süper tip bir alt sınıf türü olamaz?

Aşırı yüklenmiş yöntemde, nesne üzerinde çağırdığım herhangi bir yöntem nesnede tanımlanır.


Önerilen kopyalarla ilgili notlar:

Birinci öneri sınıf hiyerarşisi ve nerede işlevselliği koymak konusunda görünüyor. Sorum daha çok dil kısıtlamasının nedenine odaklanıyor.

İkinci öneri Soruyorum ne yapacağını değil, nasıl açıklıyor neden böyle yapılması gereken o olmuştur. Sorum neden üzerinde duruldu.


1
sorulan ve önceki soruda cevaplanan : "Bu genellikle Liskov İkame Prensibi (LSP) başarısız olarak kabul edilir, çünkü eklenen kısıtlama temel sınıf işlemlerinin türetilmiş sınıf için her zaman uygun olmadığını ..."
gnat


@gnat sorusu, argümanlar için daha spesifik alt tiplere ihtiyaç duyulmasının bazı bilgisayar prensibini ihlal edip etmediği değil, soru edalorzo'nun cevaplayıp cevaplayamayacağıdır.
user949300

Yanıtlar:


18

Sorunuzda başlangıçta bahsettiğiniz konsepte kovaryant dönüş türleri denir .

Kovaryant dönüş türleri çalışır, çünkü bir yöntemin belirli türdeki bir nesneyi döndürmesi gerekir ve geçersiz kılma yöntemleri aslında bir alt sınıfını döndürebilir. Java gibi bir dilin alt tür kurallarına dayanarak S, bir alt türü ise T, Tgöründüğü her yerde bir S.

Bu nedenle S, beklenen bir yöntemi geçersiz kılarken bir geri dönmek güvenlidir T.

Geçersiz kılma yönteminin, geçersiz kılınan yöntem tarafından talep edilenlerin alt türleri olan bağımsız değişkenler kullandığını kabul etme öneriniz, tür sistemindeki sessizliğe yol açtığı için çok daha karmaşıktır.

Bir yandan, yukarıda belirtilen aynı alt tip kurallarına göre, büyük olasılıkla yapmak istediğiniz şey için zaten çalışır. Örneğin

interface Hunter {
   public void hunt(Animal animal);
}

Hiçbir şey, bu sınıfın uygulamalarının herhangi bir hayvan almasını engellemez, bu nedenle sorunuzdaki kriterleri zaten karşılar.

Ancak diyelim ki önerdiğiniz gibi bu yöntemi geçersiz kılabiliriz:

class MammutHunter implements Hunter {
  @Override
  public void hunt(Mammut animal) {
  }
}

İşte komik kısım, şimdi bunu yapabilirsiniz:

AnimalHunter hunter = new MammutHunter();
hunter.hunt(new Bear()); //Uh oh

Kamusal arayüze göre AnimalHunterherhangi bir hayvanı avlayabilmelisiniz, ancak uygulamanıza göre MammutHuntersadece Mammutnesneleri kabul ediyorsunuz . Bu nedenle, geçersiz kılma yöntemi genel arabirimi karşılamaz. Burada sadece yazı sisteminin sağlamlığını kırdık.

Jenerikler kullanarak istediğinizi uygulayabilirsiniz.

interface AnimalHunter<T extends Animal> {
   void hunt(T animal);
}

Sonra MammutHunter'ınızı tanımlayabilirsiniz

class MammutHunter implements AnimalHunter<Mammut> {
   void hunt(Mammut m){
   }
}

Ve jenerik kovaryans ve karşıtlık kullanarak, gerektiğinde kuralları kendi lehinize rahatlatabilirsiniz. Örneğin, bir memeli avcının sadece belirli bir bağlamda kedigilleri avlayabileceğinden emin olabiliriz:

AnimalHunter<? super Feline> hunter = new MammalHunter();
hunter.hunt(new Lion());
hunter.hunt(new Puma());

Diyelim MammalHunteruygular AnimalHunter<Mammal>.

Bu durumda bu kabul edilmez:

hunter.hunt(new Mammut()):

Memeler memeliler olsa bile, burada kullandığımız kontravaryant tip üzerindeki kısıtlamalar nedeniyle kabul edilmeyecektir. Yani, bahsettikleriniz gibi şeyler yapmak için türler üzerinde bazı kontrolleri hala deneyebilirsiniz.


3

Sorun, bağımsız değişken olarak verilen nesne ile geçersiz kılma yönteminde yaptığınız şey değildir. Sorun, yönteminizi kullanarak kod yönteminize beslemesine izin verilen bağımsız değişken türü nedir.

Geçersiz kılma yöntemi, geçersiz kılınan yöntemin sözleşmesini yerine getirmelidir. Geçersiz kılınan yöntem bir sınıfın bağımsız değişkenlerini kabul ederse ve bunu yalnızca bir alt sınıfı kabul eden bir yöntemle geçersiz kılarsanız, sözleşmeyi yerine getirmez. Bu yüzden geçerli değil.

Daha spesifik bir argüman türüne sahip bir yöntemi geçersiz kılmak aşırı yükleme olarak adlandırılır . Aynı ada sahip ancak farklı veya daha spesifik bir argüman türüne sahip bir yöntem tanımlar. Orijinal yöntemin yanında aşırı yüklenmiş bir yöntem de vardır. Hangi yöntemin çağrıldığı derleme zamanında bilinen türe bağlıdır. Bir yöntemi aşırı yüklemek için @Override ek açıklamasını bırakmanız gerekir.

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.