Bu makalenin teması, mirasın kullanımını teşvik etmek değil, yalnızca mirasın kullanımından kaynaklanan sorunlardan, miras mekanizmasının iyi olmayan kısımlarını tartışmak, böylece olası tuzaklardan kaçınmak için kullanırken dikkatlice seçim yapmaktır.
JAVA'da kalıtım kullanıldığında kaçınılmaz iki eksiklik vardır:
Kalıtım kapsüllemeyi bozar
Bu noktada, aşağıdaki ayrıntılı bir örnek (Etkili Java Makalesi 16'dan)
genel sınıf MyHashSet < E > HashSet'i genişletir < E > { private int addCount = 0; public int getAddCount () { addCount döndür; } @Override public boolean add (E e) { addCount ++; return super.add (e); } @Override public boolean addAll (Koleksiyon < ? E uzatır > c) { addCount + = c.size (); super.addAll (c) döndür; } }Bir HashSet burada özelleştirilir ve iki yöntem yeniden yazılır.Bununla süper sınıf arasındaki tek fark, kaç öğenin eklendiğini saymak için bir sayaç eklemesidir.
Bu yeni özelliğin çalışıp çalışmadığını test etmek için bir test yazın:
public class MyHashSetTest { özel MyHashSet < Tamsayı > myHashSet = yeni MyHashSet < Tamsayı > (); @Ölçek public void testi () { myHashSet.addAll (Arrays.asList (1,2,3)); System.out.println (myHashSet.getAddCount ()); } }Çalıştırdıktan sonra, 3 eleman ekledikten sonra sayacın çıkış değerinin 6 olduğunu göreceksiniz.
Üst sınıfa addAll () yöntemini girin ve hatanın nedenini bulacaksınız: dahili olarak add () yöntemini çağırır. Dolayısıyla bu testte, alt sınıfın addAll () yöntemine girilirken, sayaç 3 artırılır ve ardından üst sınıfın addAll () öğesi çağrılır. Üst sınıfın addAll () öğesi, alt sınıfın add () öğesini üç kez ve ardından sayacı çağırır Üç tane daha eklenecek.
Sorunun kökü
Bu durumu özetleyerek, hatanın üst sınıfın geçersiz kılınabilen yöntemlerinin varlığından kaynaklandığını görebilirsiniz. Kendi kendine kullanım (Yani, süper sınıftaki geçersiz kılınabilen yöntem diğer geçersiz kılınabilen yöntemleri çağırır.) Şu anda, alt sınıf bu yöntemlerden bazılarının üzerine yazarsa, hatalara neden olabilir.
Örneğin, yukarıdaki resimde, Baba sınıfında geçersiz kılınabilen A ve B yöntemleri vardır ve A, B'yi çağırır. Son alt sınıfı, B yöntemini yeniden yazar. Şu anda, alt sınıf miras alınan A yöntemini çağırırsa, A yöntemi artık Father.B () öğesini değil, alt sınıfta Son.B () yöntemini çağıracaktır. Programın doğruluğu Father.B () 'deki bazı işlemlere bağlıysa ve Son.B () bu işlemleri yeniden yazarsa, hatalara neden olma olasılığı yüksektir.
Kilit nokta, alt sınıfın yazılmasının yüzeyde bir sorun gibi görünmeyebileceğidir, ancak bu, geliştiricileri süper sınıfın uygulama ayrıntılarını anlamaya zorlar, böylece nesneye yönelik kapsüllemeyi bozar, çünkü kapsülleme gizleme gerektirir. Uygulama ayrıntıları. Daha tehlikeli olan ise, hataların kolayca tespit edilememesidir.Geliştirici, üst sınıfın uygulama ayrıntılarını anlamaz ve onu yeniden yazarsa, gizli tehlikeler ekilebilir.
Süper sınıf güncellendiğinde bir hata meydana gelebilir
Bunu anlamak daha kolaydır ve esas olarak aşağıdaki olasılıklar vardır:
Devralınabilir sınıflar tasarlayın
Miras alınabilecek sınıfları tasarlarken şunlara dikkat etmelisiniz:
Üçüncü noktayı ayrıntılı olarak açıklayın. Aslında Devralma Sonları Kapsülleme'de tartışılan konuya çok benzer. Şu kodu varsayalım:
public class Father { genel Baba () { someMethod (); } public void someMethod () { } } public class Oğlu, Baba'yı genişletir { özel Tarih tarihi; genel Oğlu () { this.date = new Date (); } @Override public void someMethod () { System.out.println ("Time =" + date.getTime ()); } }Yukarıdaki kod, testi çalıştırırken bir NullPointerException oluşturacaktır:
public class SonTest { özel Oğul oğul = yeni Oğul (); @Ölçek public void testi () { son.someMethod (); } }Üst sınıfın kurucusu alt sınıfın yapıcısından önce çalışacağından, burada üst sınıfın kurucusu someMethod () 'a bağlıdır ve someMethod () geçersiz kılınır, bu nedenle üst sınıfın yapıcısına yapılan çağrı Son.someMethod () ve alt sınıf şu anda başlatılmamıştır, bu nedenle date.getTime () tarihine kadar çalıştığında boş bir işaretçi istisnası atılır.
Bu nedenle, üst sınıfın yapıcısında geçersiz kılınabilen yönteme bağımlılık varsa, devralma sırasında hatalar oluşabilir.
sonuç olarak
Kalıtımın birçok avantajı vardır, ancak kalıtımı kullanırken dikkatli olmalı ve bunu dikkate almalısınız. Ayrıca kodun yeniden kullanımını sağlamak için kullanılır karmaşık , Miras ve kompozisyon kullanıyorsanız (Bu öncüldür) , Daha sonra kompozisyon ilk olarak kullanılmalıdır, çünkü kompozisyon üst sınıfın uygulama detaylarını korumasını sağlayabilir ve yukarıdaki kalıtım eksiklikleri kompozisyon ile önlenebilir. Bu aynı zamanda Kompozisyon, kalıtıma göre önceliklidir .
Miras kullanıyorsanız, üst sınıfta kendi kendine kullanılabilen geçersiz kılınabilen yöntemleri yeniden yazmanın hatalara neden olabileceğinin farkında olmalısınız.Yeniden yazmasanız bile, üst sınıf güncellendiğinde hatalar ortaya çıkabilir. Aynı zamanda, üst sınıf, birbiri olarak adlandırılabilecek geçersiz kılınabilen yöntemler için ayrıntılı belgeler sağlamak üzere dikkatlice tasarlanmalıdır.