Geçersiz kılarken super () yöntemi ne zaman çağrılmamalıdır?


113

Kendi Android özel sınıfımı oluşturduğumda, extendonun yerel sınıfıyım. Ben baz yöntemi geçersiz istediğinizde Sonra, hep diyoruz super()hep yapmak gibi, yöntem onCreate, onStopvb

Ve en başından beri Android ekibi bize superher yöntemi geçersiz kılma çağrısında bulunmamızı tavsiye ettiği için bunun bu olduğunu düşündüm .

Ancak birçok kitapta, benden daha deneyimli geliştiricilerin çoğu zaman aramayı ihmal superettiklerini ve bunu bilgi eksikliği olarak yaptıklarından gerçekten şüpheliyim. Örneğin, bu temel bakmak SAX çözümleyici sınıfında superyer atlanırsa startElement, charactersve endElement:

public class SAXParser extends DefaultHandler{
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
        if(qName.equalsIgnoreCase("XXY")) {
            //do something
        }
    }

    public void characters(char[] ch, int start, int length) throws SAXException {
        //do something
    }

    public void endElement(String uri, String localName, String qName) throws SAXException {
        if(qName.equalsIgnoreCase("XXY")) {
            //do something
        }else () {
            //do something
        }
    }
}

Eclipse veya başka bir IDE aracılığıyla herhangi bir geçersiz kılma yöntemi oluşturmaya çalışırsanız, superher zaman otomatik işlemin bir parçası olarak oluşturulur.

Bu sadece basit bir örnekti. Kitaplar benzer kodlarla doludur .

Ne zaman aramanız gerektiğini superve aramayı ne zaman atlayabileceğinizi nasıl biliyorlar ?

PS. Bu özel örneğe bağlanmayın. Pek çok örnekten rastgele seçilmiş bir örnekti.

(Bu başlangıç ​​sorusu gibi gelebilir ama gerçekten kafam karıştı.)


3
endElementAPI dokümanı "Varsayılan olarak, hiçbir şey yapmayın. Uygulama yazarları bu yöntemi geçersiz kılabilir ...", yani "hiçbir şey" yapmadığı için süper'i güvenle çağırabileceğiniz anlamına gelir, ancak buna gerek yoktur ve gerçekten geçersiz kılabilirsiniz. Bu yöntemin belgesini okursanız, yapıp yapamayacağınızı / yapmamanız gerektiğini sık sık anlayabilirsiniz.
zapl

1
Küçük örnek: açılış ekranında onBackPressed () kullanıyorum ve süper çağırmam, böylece açılıştan çıkmaz, sadece düğmeyi devre dışı bırakır.
Bojan Kogoj

@sandalone Sorduğum için özür dilerim, ama uygulama içi faturalandırmayla KDV vergisinin nasıl işleneceği ve Google tarafından hangi ülkelerde otomatik olarak yapıldığı ve KDV vergisini manuel olarak bildirmem / ödemem gerekenler konusunda herhangi bir deneyiminiz var mı? bakınız stackoverflow.com/questions/36506835/…
Vidar Vestnes

Yanıtlar:


144

superYöntemi çağırarak, yöntemin davranışını geçersiz kılmıyorsunuz , genişletiyorsunuz .

Bir çağrı, supergenişletmekte olduğunuz sınıfın o yöntem için tanımladığı herhangi bir mantığı gerçekleştirir. superYönteminizin geçersiz kılınmasında 'uygulamasını çağırdığınız anda önemli olabileceğini göz önünde bulundurun . Örneğin:

public class A { 
    public void save() { 
         // Perform save logic
    }
}

public class B extends A {
    private Object b;
    @Override
    public void save() { 
        super.save(); // Performs the save logic for A
        save(b); // Perform additional save logic
    }
}

Bir çağrı, hem ve hem de bu sırayla mantığı B.save()gerçekleştirecektir . İçeriyi aramasaydın , aranmazdı. Ve sonra ararsanız , daha sonra etkili bir şekilde yerine getirilir .save()ABsuper.save()B.save()A.save()super.save()save(b)A.save()B.save()

Eğer davranışını geçersiz kılmak istiyorsanız super(yani, uygulamasını tamamen göz ardı edin ve hepsini kendiniz sağlayın), aramamalısınız super.

Gelen SAXParserverdiğiniz örnekte, uygulamalar arasında DefaultHandlerbu yöntemleri için alt sınıfları onları geçersiz kılmak ve bu yöntemler için bir davranışı sağlayabilir böylece, sadece boş. Bu yöntem için javadoc'ta bu da belirtilmiştir.

public void startElement (String uri, String localName,
    String qName, Attributes attributes) throws SAXException {
    // no op
}

super()IDE'ler tarafından oluşturulan koddaki varsayılan çağrı hakkında, @barsjuyorumunda belirtildiği gibi, her kurucuda örtük bir çağrı vardır ( kodunuza yazmasanız super()bile), bu da bu bağlamda, super' s varsayılan yapıcısı. IDESadece senin için aşağı yazıyor, ancak bunu kaldırıldı eğer o da denilen olsun istiyorum. Ayrıca yapıcıları super()veya argümanlı varyantlarından herhangi birini (yani super(x,y,z)) uygularken , yalnızca yöntemin en başında çağrılabileceğine dikkat edin.


14
Ayrıca, yapıcılar için super()(süper sınıfın varsayılan kurucusu), siz belirtmeseniz bile her zaman çağrıldığını unutmayın. Süper sınıfın varsayılan kurucusu yoksa, alt sınıf kurucusundaki ilk ifadeniz olarak süper sınıfın yapıcılarından birini açıkça çağırmazsanız bir derleme hatası alırsınız.
barsju

1
Evet, bu temelde sadece tembellik - hiçbir şey yapmadığını bildiğimiz yöntemler için kısalık olsun diye ihmal edin
Voo

1
Değerli yorumlarınız için teşekkürler, @barjsu, bu ayrıntıları yanıta ekledim.
Xavi López

16

Ne zaman süper aramanız gerektiğini ve ne zaman aramayı bırakabileceğinizi nasıl anlarlar?

Genellikle özel bir API yöntemi yatan çerçeve bağlam yaşam döngüsü eleştirel anlama sahipse, her zaman açıkça belirtilecektir ve benzeri API belgelerinde vurgulanan Activity.onCreate()API belgeleri . Ayrıca, API sağlam bir tasarım izlerse, proje derleme zamanında tüketici geliştiriciyi uyarmak için bazı istisnalar atmalı ve çalışma zamanında bir hata oluşturmayacağından emin olmalıdır.

Bu, API belgelerinde açıkça belirtilmemişse, tüketici geliştiricinin, API yöntemini geçersiz kılarken çağırmanın zorunlu olmadığını varsayması oldukça güvenlidir. Varsayılan davranışı kullanmak ( superyöntemi çağırmak ) veya tamamen geçersiz kılmak , tüketicinin geliştiricisine bağlıdır .

Koşula izin verilirse (açık kaynaklı yazılımı seviyorum), tüketici geliştirici her zaman API kaynak kodunu kontrol edebilir ve yöntemin aslında başlık altında nasıl yazıldığını görebilir. Örneğin Activity.onCreate()kaynağı ve DefaultHandler.startElement()kaynağı kontrol edin .


Bana ek şeyler açıkladığınız için teşekkürler. Kaynak kodunu kontrol etmemi hatırlattığın için teşekkürler.
sandalone

7

Kafanızda yapmanız gereken test şudur:

"Bu yöntemin tüm işlevlerinin benim için yapılmasını ve daha sonra bir şeyler yapmasını istiyor muyum?" Evetse, aramak super()ve ardından yönteminizi bitirmek istersiniz . Bu onDraw(), arka planda birçok şeyi işleyen "önemli" yöntemler için geçerli olacaktır .

İşlevselliğin yalnızca bir kısmını istiyorsanız (geçersiz kılacağınız çoğu yöntemde olduğu gibi), o zaman muhtemelen aramak istemezsiniz super().


3

Eh Xavi , daha iyi bir cevap verdi .. ama muhtemelen gelmez bilerek olabilir super()varsayılan davranışı ile yaptıklarını bir geçersiz kılınmış yöntemle ... Bu reklamlar çağrıldığında yapmak ..

Örneğin:

onDraw() 

geçersiz kılındığında görünüm sınıfında yöntem .. super.onDraw () demeden önce bir şey çizersiniz, görünüm tamamen çizildiğinde görünür .. bu yüzden burada arama supergereklidir çünkü android'in yapması gereken kritik öneme sahip bazı şeyler vardır (onCreate () gibi)

ama aynı zamanda

onLongClick()

bunu geçersiz kıldığınızda, süper olarak çağırmak istemezsiniz çünkü bir EditText veya benzer bir görünüm için seçeneklerin listesini içeren bir iletişim kutusu açar .. Bu temel farktır .. onu bazen bırakma seçeneğiniz vardır .. onCreate() , onStop()sizin gibi diğer yöntemler , işletim sisteminin işlemesine izin vermelidir ..


2

Sorunuzu net bir şekilde anlamadım, ancak superyöntemi neden çağırmadığınızı soruyorsanız :

superYöntemi çağırmanın bir nedeni vardır: ebeveyn sınıfta sıfır bağımsız değişken oluşturucu yoksa, bunun için bir alt sınıf oluşturmak mümkün değildir, bu nedenle ya ana sınıfta bir bağımsız değişken oluşturucu tutmamanız gerekir ya da alt sınıf yapıcısının en üstünde olan super()çağırma ifadesini tanımlamak argument(how much argument constructor you have used in super class)için.

Umarım bu yardımcı olur. Değilse, bana bildirin.


2

Gibi bir kısıt dizisi listesi uyguladım

public class ConstraintArrayList<T> extends ArrayList<T> {
  ConstraintArrayList(Constraint<T> cons) {this.cons = cons;}
  @Override
  public boolean add(T element) {
    if (cons.accept(element))
      return super.add(element);
    return false;
  }
}

Koda bakarsanız, aslında süper sınıfın listeye gerçek öğe eklemesini gerçekleştirmesine izin vermeden önce bazı ön kontroller yapar. Bu, yöntemin geçersiz kılınmasının iki kat nedeninden birini açıklar:

  1. Süper sınıfın yapabileceklerini genişletmek istediğiniz yerde genişletilebilirlik
  2. Kuşların hareket etme (uçma) ve kurbağaların hareket etme (zıplama) şeklinin her bir alt sınıfa özgü olduğu yaygın Hayvan krallığı örneğinde olduğu gibi, polimorfizm yoluyla belirli davranış eklemek istediğiniz yerde özgüllük.

2

Android Framework'ten hangi geçersiz kılınmış yöntemlerin superbu soruyu çağırması ve bulması gerektiğini merak edenler için - işte 2019'dan güncel bir ipucu - Android Studio 3+, ihtiyacınız olduğunda size söyleyecektir .

görüntü açıklamasını buraya girin

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.