Kapan TIDAK memanggil metode super () saat mengganti?

113

Ketika saya membuat kelas khusus Android saya sendiri, saya extendkelas aslinya. Kemudian ketika saya ingin mengganti metode dasar, saya selalu memanggil super()metode, seperti yang selalu saya lakukan di onCreate, onStop, dll

Dan saya pikir ini dia, karena sejak awal tim Android menyarankan kami untuk selalu memanggil supersetiap penggantian metode.

Tetapi, di banyak buku saya dapat melihat bahwa para pengembang, yang lebih berpengalaman daripada saya, sering mengabaikan panggilan superdan saya sangat ragu mereka melakukannya karena kurangnya pengetahuan. Misalnya, lihat kelas parser SAX dasar ini di mana superdihilangkan startElement, charactersdan 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
        }
    }
}

Jika Anda mencoba membuat metode penggantian melalui Eclipse atau IDE lainnya, superakan selalu dibuat sebagai bagian dari proses otomatis.

Ini hanyalah contoh sederhana. Buku penuh dengan kode serupa .

Bagaimana mereka tahu kapan Anda harus menelepon superdan kapan Anda bisa mengabaikannya?

PS. Jangan terikat pada contoh khusus ini. Itu hanya contoh yang diambil secara acak dari banyak contoh.

(Ini mungkin terdengar seperti pertanyaan pemula, tapi saya benar-benar bingung.)

sandalone
sumber
3
endElementDokumen API mengatakan "Secara default, tidak melakukan apa-apa. Penulis aplikasi dapat mengganti metode ini ..." yang berarti Anda dapat memanggil super dengan aman karena "tidak melakukan apa-apa" tetapi Anda tidak perlu melakukannya dan Anda benar-benar dapat menggantinya. Anda sering dapat mengetahui apakah Anda harus / tidak dapat / tidak melakukannya jika Anda membaca dokumen untuk metode itu.
zapl
1
Contoh kecil: Saya menggunakan onBackPressed () di layar splash, dan saya TIDAK memanggil super sehingga tidak keluar dari splash, itu hanya menonaktifkan tombol.
Bojan Kogoj
@sandalone Maaf telah bertanya di sini, tetapi apakah Anda memiliki pengalaman tentang cara menangani pajak PPN dengan penagihan dalam aplikasi, dan negara mana yang dilakukan secara otomatis oleh Google, dan ke negara mana saya harus melaporkan / membayar pajak PPN secara manual? lihat stackoverflow.com/questions/36506835/…
Vidar Vestnes

Jawaban:

144

Dengan memanggil supermetode, Anda tidak menimpa perilaku metode, Anda memperluasnya .

Panggilan ke superakan melakukan logika apa pun yang telah ditetapkan kelas yang Anda perluas untuk metode itu. Mempertimbangkan bahwa mungkin penting saat Anda memanggil superimplementasi dalam metode penggantian. Misalnya:

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
    }
}

Panggilan ke B.save()akan menjalankan save()logika untuk keduanya Adan B, dalam urutan khusus ini. Jika Anda tidak menelepon ke super.save()dalam B.save(), A.save()tidak akan dipanggil. Dan jika Anda dipanggil super.save()setelahnya save(b), A.save()akan efektif dilakukan setelahnya B.save().

Jika Anda ingin menimpa super perilaku (yaitu, mengabaikan sepenuhnya implementasinya dan menyediakan semuanya sendiri), Anda tidak boleh menelepon super.

Dalam SAXParsercontoh yang Anda berikan, implementasi dari DefaultHandlermetode mereka hanya kosong, sehingga subclass dapat menimpa mereka dan memberikan perilaku untuk metode tersebut. Dalam javadoc untuk metode ini, hal ini juga ditunjukkan.

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

Tentang super()panggilan default dalam kode yang dihasilkan oleh IDE, seperti yang @barsjuditunjukkan dalam komentarnya, di setiap konstruktor ada panggilan implisit ke super()(bahkan jika Anda tidak menulisnya dalam kode Anda), yang berarti, dalam konteks itu, panggilan ke super' s konstruktor default. Itu IDEhanya menuliskannya untuk Anda, tetapi itu juga akan dipanggil jika Anda menghapusnya. Perhatikan juga bahwa saat mengimplementasikan konstruktor, super()atau variasinya dengan argumen (yaitu super(x,y,z)) hanya dapat dipanggil di awal metode.

Xavi López
sumber
14
Juga tidak perlu diperhatikan bahwa untuk konstruktor super()( konstruktor default kelas super) selalu dipanggil, meskipun Anda tidak menentukannya. Jika kelas super tidak memiliki konstruktor default, Anda akan mendapatkan kesalahan kompilasi jika Anda tidak secara eksplisit memanggil salah satu konstruktor kelas super sebagai pernyataan pertama Anda dalam konstruktor subkelas.
Barsju
1
Ya, pada dasarnya ini hanya kemalasan - untuk metode yang kita tahu tidak melakukan apa-apa, abaikan saja untuk singkatnya
Voo
1
Terima kasih atas komentar berharga Anda, @barjsu, saya telah menyertakan detail ini dalam jawaban.
Xavi López
16

Bagaimana mereka tahu kapan Anda harus menelepon super dan kapan Anda bisa menghilangkannya?

Biasanya, jika metode API khusus memiliki arti penting untuk siklus hidup konteks kerangka kerja yang mendasarinya, metode itu akan selalu dinyatakan secara eksplisit dan disorot dalam dokumentasi API, seperti Activity.onCreate()dokumentasi API . Selain itu, jika API mengikuti desain yang kuat, API harus mengeluarkan beberapa pengecualian untuk memperingatkan pengembang konsumen pada waktu kompilasi proyek, dan memastikan itu tidak akan menghasilkan kesalahan pada waktu proses.

Jika ini tidak secara eksplisit dinyatakan dalam dokumentasi API, maka cukup aman bagi pengembang konsumen untuk menganggap metode API tidak wajib dipanggil saat menimpanya. Terserah pengembang konsumen untuk memutuskan apakah akan menggunakan perilaku default (memanggil supermetode) atau menggantinya sepenuhnya.

Jika kondisi diizinkan (Saya suka perangkat lunak sumber terbuka), pengembang konsumen selalu dapat memeriksa kode sumber API dan melihat bagaimana metode tersebut sebenarnya ditulis di bawah tenda. Lihat Activity.onCreate()sumber danDefaultHandler.startElement() sumber misalnya.

yorkw
sumber
Terima kasih telah menjelaskan hal tambahan kepada saya. Terima kasih telah mengingatkan saya untuk memeriksa kode sumber.
sandalone
7

Tes yang harus Anda lakukan di kepala Anda adalah:

"Apakah saya ingin semua fungsi metode ini dilakukan untuk saya, dan kemudian melakukan sesuatu setelahnya?" Jika ya, maka Anda ingin menelepon super(), lalu selesaikan metode Anda. Ini akan benar untuk metode "penting" sepertionDraw() , yang menangani banyak hal di latar belakang.

Jika Anda hanya menginginkan beberapa fungsionalitas (seperti kebanyakan metode yang akan Anda timpa) maka Anda mungkin tidak ingin memanggil super().

Michael
sumber
3

Nah, Xavi memberikan jawaban yang lebih baik .. tetapi Anda mungkin tahu apa artinyasuper() dilakukan ketika dipanggil dengan metode yang diganti ... ini mengiklankan apa yang telah Anda lakukan dengan perilaku default ..

misalnya:

onDraw() 

metode dalam kelas tampilan saat diganti .. Anda menggambar sesuatu sebelum mengatakan super.onDraw () itu muncul setelah tampilan digambar sepenuhnya .. jadi di sini pemanggilan superdiperlukan karena android memiliki beberapa hal yang sangat penting untuk dilakukan (seperti onCreate ())

tapi diwaktu yang sama

onLongClick()

ketika Anda menimpa ini, Anda tidak ingin memanggil super karena menampilkan dialog dengan daftar opsi untuk EditText atau tampilan serupa lainnya .. Itulah perbedaan dasar .. Anda memiliki pilihan untuk membiarkannya beberapa kali .. tetapi untuk metode lain seperti onCreate() , onStop()Anda harus membiarkan OS menanganinya ..

ngesh
sumber
2

Saya tidak mendapatkan pertanyaan Anda dengan jelas, tetapi jika Anda bertanya tentang mengapa tidak memanggil supermetode ini:

Ada alasan untuk memanggil supermetode ini: jika tidak ada konstruktor argumen nol di kelas induk maka tidak mungkin membuat kelas anak untuk itu, jadi Anda perlu menyimpan konstruktor tanpa argumen di kelas induk atau Anda perlu untuk mendefinisikan super()pernyataan panggilan dengan argument(how much argument constructor you have used in super class)di bagian atas konstruktor kelas anak.

Saya harap ini membantu. Jika tidak, beri tahu saya.

Vikas Gupta
sumber
2

Saya menerapkan daftar array kendala seperti

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;
  }
}

Jika Anda melihat kodenya, ia hanya melakukan beberapa pemeriksaan awal sebelum benar-benar membiarkan kelas super melakukan penambahan elemen sebenarnya ke daftar. Ini memberi tahu salah satu dari dua alasan lipat untuk penggantian metode:

  1. Perluasan di mana Anda ingin memperluas apa yang dapat dilakukan kelas super
  2. Kekhususan di mana Anda ingin menambahkan perilaku tertentu melalui polimorfisme seperti dalam contoh Semantik gerakan di Kerajaan Hewan umum di mana cara burung bergerak (terbang) dan katak bergerak (lompat) spesifik untuk setiap sub kelas.
maress
sumber
2

Bagi mereka yang juga bertanya-tanya metode mana yang harus diganti dari Android Framework yang harus memanggil superdan menemukan pertanyaan ini - berikut adalah petunjuk terbaru dari 2019 - Android Studio 3+ akan memberi tahu Anda saat Anda membutuhkannya .

masukkan deskripsi gambar di sini

dominik
sumber