Memperluas dari dua kelas

150

Bagaimana saya bisa melakukan ini:

public class Main extends ListActivity , ControlMenu 

Juga, saya ingin tahu bahwa pendekatan ini baik-baik saja bahwa saya telah membuat menu di kelas yang ControlMenu dan saya memperluas sisa kegiatan.

umar
sumber
4
Anda tidak dapat memperpanjang dua kelas atau lebih sekaligus. Warisan berganda tidak diizinkan di java.
yogsma

Jawaban:

156

Anda hanya dapat Perpanjang satu kelas. Dan mengimplementasikan Antarmuka dari banyak sumber.

Memperluas beberapa kelas tidak tersedia. Satu-satunya solusi yang dapat saya pikirkan adalah tidak mewarisi kelas mana pun melainkan memiliki variabel internal masing-masing kelas dan melakukan lebih banyak proxy dengan mengarahkan permintaan ke objek Anda ke objek yang Anda inginkan.

 public class CustomActivity extends Activity {

     private AnotherClass mClass;

     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         mClass = new AnotherClass(this);
     }

     //Implement each method you want to use.
     public String getInfoFromOtherClass()
     {
        return mClass.getInfoFromOtherClass();
     }
 }

ini adalah solusi terbaik yang saya miliki. Anda bisa mendapatkan fungsionalitas dari kedua kelas dan Masih hanya benar-benar satu jenis kelas.

Kekurangannya adalah bahwa Anda tidak dapat masuk ke dalam Cetakan kelas Internal menggunakan gips.

The Lazy Coder
sumber
2
Anda lebih cepat :) Saya akan meninggalkan jawaban saya sebagai rambling abstrak untuk dibandingkan dengan contoh konkret Anda;)
Nicolas78
1
Ini adalah alternatif yang sangat bagus, dan memberikan lebih banyak fleksibilitas di masa depan.
David Souther
1
Lihat solusi @SCB untuk lebih banyak solusi OOP
idish
Saya bisa menggunakan contoh yang lebih tepat di sini. Tidak yakin saya mengerti.
Neo42
54

Mengapa Tidak Menggunakan Kelas Batin (Bersarang)

class A extends B {
    private class C extends D {
        //Classes A , B , C , D accessible here 
    }
}
Ifte
sumber
4
Pendekatan intersting, apa pendapat para ahli tentang teknik ini? Saya ingin menggali lebih dalam.
TechNyquist
1
Apakah boleh dengan konvensi?
mulai
2
Tidak dapat membuat kelas dalam bekerja di a Fragment. Aktivitas saya harus diperluas Fragment, yang berarti saya benar-benar perlu getView(), yang tidak akan berfungsi jika itu di dalam kelas batin, dan kode di sana adalah tempat saya perlu menggunakan kode ListActivity, jadi saya tidak dapat memperluas dua kali, ATAU melakukan kelas dalam dalam contoh ini.
Azurespot
Ini adalah solusi terbaik untuk memperluas kelas abstrak di mana Anda memerlukan akses ke variabel dari kelas yang diterapkan.
tak3shi
45

Seperti yang dikatakan semua orang. Tidak bisa. Namun, meskipun orang telah mengatakan berkali-kali selama bertahun-tahun bahwa Anda harus menggunakan banyak antarmuka, mereka belum benar-benar memahami caranya. Semoga ini bisa membantu.

Katakanlah Anda memiliki class Foodan class Barbahwa Anda berdua ingin mencoba memperluas menjadi a class FooBar. Tentu saja, seperti yang Anda katakan, Anda tidak dapat melakukan:

public class FooBar extends Foo, Bar

Orang sudah masuk ke alasan untuk ini sampai batas tertentu sudah. Sebagai gantinya, tulis interfacesuntuk keduanya Foodan Barmencakup semua metode publik mereka. Misalnya

public interface FooInterface {

    public void methodA();

    public int methodB();

    //...
} 

public interface BarInterface {

    public int methodC(int i);

    //...
}

Dan sekarang membuat Foodan Barmengimplementasikan antarmuka relatif:

public class Foo implements FooInterface { /*...*/ }

public class Bar implements BarInterface { /*...*/ }

Sekarang, dengan class FooBar, Anda dapat menerapkan kedua FooInterfacedan BarInterfacesekaligus menjaga Foodan Barobjek dan hanya lewat metode langsung melalui:

public class FooBar implements FooInterface, BarInterface {

    Foo myFoo;
    Bar myBar;

    // You can have the FooBar constructor require the arguments for both
    //  the Foo and the Bar constructors
    public FooBar(int x, int y, int z){
        myFoo = new Foo(x);
        myBar = new Bar(y, z);
    }

    // Or have the Foo and Bar objects passed right in
    public FooBar(Foo newFoo, Bar newBar){
        myFoo = newFoo;
        myBar = newBar;
    }

    public void methodA(){
        myFoo.methodA();
    }

    public int methodB(){
        return myFoo.methodB();
    }

    public int methodC(int i){
        return myBar.methodC(i);
    }

    //...

}

Bonus untuk metode ini, adalah bahwa FooBarobjek cocok dengan cetakan keduanya FooInterfacedan BarInterface. Itu berarti ini baik-baik saja:

FooInterface testFoo;
testFoo = new FooBar(a, b, c);
testFoo = new Foo(a);

BarInterface testBar;
testBar = new FooBar(a, b, c);
testBar = new Bar(b, c);

Semoga ini menjelaskan cara menggunakan antarmuka alih-alih beberapa ekstensi. Bahkan jika saya terlambat beberapa tahun.

SCB
sumber
6
ini adalah jawaban terbaik
user3290180
Ini adalah jawaban yang sangat bagus, namun saya melihat beberapa masalah dengannya yang perlu ditangani secara lebih rinci. Pertama memanjang dari dua kelas yang ada akan sedikit lebih bermasalah dan akan ada sejumlah rintangan tambahan untuk dilalui, Kedua adalah jika antarmuka Foo dan Bar keduanya memiliki fungsi yang sama, Anda harus memiliki urutan prioritas. Memperluas kelas Anda secara eksplisit akan memaksa Anda untuk mengambil keputusan di depan. Tetap saja, Pilihan luar biasa :) +1
The Lazy Coder
Bagaimana jika kita harus membuat kelas baru "sering" dan membuat masing-masing kelas mengimplementasikan kedua antarmuka? Kemudian, kita harus mengulangi implementasi boilerplate ini di setiap kelas. Apakah ada cara yang lebih baik untuk membuat kelas "menerapkan" dua set perilaku?
MasterJoe2
1
@ MasterJoe2 Sejujurnya, saya belum banyak menggunakan Java untuk sementara waktu sekarang (saya berhenti ketika saya menulis jawaban ini). Salah satu alasan saya menghindarinya sekarang adalah masalah yang Anda ajukan. Firasat untuk arah yang mungkin bisa Anda selidiki, adalah menulis kelas abstrak yang mengimplementasikan kedua antarmuka, dan memperluasnya. Namun saya tidak tahu apakah itu Java yang valid, dan saya merasa bahwa Anda hanya akan berakhir dengan masalah asli yang sama ketika Anda ingin membuat perubahan pada kelas implementasi di masa depan. Maaf saya tidak bisa membantu.
SCB
37

Anda ingin menggunakan antarmuka. Secara umum, multiple inheritance buruk karena Masalah Berlian:

abstract class A {
 abstract string foo();
}

class B extends A {
 string foo () { return "bar"; }
}

class C extends A  {
 string foo() {return "baz"; }
}

class D extends B, C {
 string foo() { return super.foo(); } //What do I do? Which method should I call?
}

C ++ dan lainnya punya beberapa cara untuk menyelesaikan ini, mis

string foo() { return B::foo(); }

tetapi Java hanya menggunakan antarmuka.

Java Trails memiliki pengantar yang bagus tentang antarmuka: http://download.oracle.com/javase/tutorial/java/concepts/interface.html Anda mungkin ingin mengikutinya sebelum masuk ke nuansa dalam API Android.

David Souther
sumber
24
Saya tidak pernah mengerti mengapa masalah berlian sebenarnya adalah masalah yang mencegah pewarisan berganda. Mengapa kompilator tidak bisa mengeluh hanya jika ada metode yang bertentangan dengan nama yang sama?
pete
1
Untuk kompiler yang cukup cerdas, tidak. Memecahkannya di tingkat kompilator adalah mungkin, dan memang C ++ melakukannya dengan virtual class. Melakukannya datang dengan banyak peringatan dan peringatan, baik untuk kompiler dan pengembang.
David Souther
1
Bagaimana dengan metode standar yang sama di dua antarmuka? Itu adalah contoh lain dari masalah berlian, yang dapat ditangani java.
Lajos Meszaros
1
@ MészárosLajos Tapi Anda tidak menelepon superdari metode pewarisan. Ya, Anda bisa, tetapi Anda harus menentukan metode antarmuka untuk memohon (dan harus menggunakan kata kunci defaultdalam implementasi antarmuka) . Contohnya adalah: di MyIFace.super.foo()mana MyIFace adalah antarmuka. Seperti yang Anda lihat metode antarmuka untuk mengeksekusi didefinisikan dan menghindari Masalah Diamond sepenuhnya. Jika Anda memperpanjang MyClass1dan MyClass2, kedua kelas memiliki foo(), dan memanggil super.foo()kemudian kompiler dilempar oleh Masalah Diamond.
JDSweetBeat
Anda tidak dapat kembali "bar"atau "baz"dengan tipe metode void. Bagaimanapun, penjelasan yang baik xD
xdevs23
22

Ya, seperti yang ditulis semua orang, Anda tidak dapat melakukan banyak pewarisan di Jawa. Jika Anda memiliki dua kelas dari mana Anda ingin menggunakan kode, Anda biasanya hanya subkelas satu (katakanlah kelas A). Untuk kelas B, Anda abstrak metode penting itu ke antarmuka BInterface(nama jelek, tetapi Anda mendapatkan ide), lalu katakan Main extends A implements BInterface. Di dalam, Anda dapat membuat instance objek kelas Bdan menerapkan semua metode BInterfacedengan memanggil fungsi yang sesuaiB .

Ini mengubah hubungan "is-a" menjadi hubungan "has-a" seperti Mainsekarang A, tetapi memilikiB . Tergantung pada kasus penggunaan Anda, Anda bahkan dapat membuat perubahan itu secara eksplisit dengan menghapus BInterfacedari Akelas Anda dan sebagai gantinya memberikan metode untuk mengakses objek B Anda secara langsung.

Nicolas78
sumber
Ini adalah penjelasan yang paling mudah dibaca dan mudah dipahami. Tolong, lebih banyak upvotes.
Algorini
12

Buat antarmuka. Java tidak memiliki banyak pewarisan.

http://csis.pace.edu/~bergin/patterns/multipleinheritance.html

fitnah
sumber
9
aww mengapa downvote? Saya tidak bersikap jahat, saya hanya berpikir dia mampu melakukan beberapa bacaan dan memikirkan masalah sendiri terlebih dahulu sebelum kami membangun kelasnya untuknya
slandau
6

Java tidak mendukung multiple inheritance, tetapi Anda dapat mencoba mengimplementasikan dua atau lebih antarmuka.


sumber
4

Iya. fitnah benar. Java tidak mengizinkan perluasan dari beberapa kelas.

Apa yang Anda inginkan mungkin public class Main extends ListActivity implements ControlMenu . Saya kira Anda mencoba membuat daftar.

Semoga itu bisa membantu.

angin puyuh
sumber
3

Seperti alternatif lain, mungkin Anda dapat menggunakan antarmuka dengan implementasi metode standar. Itu tentu saja tergantung dari apa yang ingin Anda lakukan.

Misalnya, Anda bisa membuat kelas abstrak dan antarmuka:

public abstract class FatherClass {

    abstract void methodInherit() {
        //... do something
    }
}

public interface InterfaceWithDefaultsMethods {
    default void anotherMethod() {
        //... do something
        //... maybe a method with a callable for call another function.
    }
}

Jadi, setelah itu, Anda bisa memperluas dan mengimplementasikan kedua kelas dan menggunakan kedua metode.

public class extends FatherClass implements InterfaceWithDefaultsMethods {

    void methode() {
        methodInherit();
        anotherMethod();
    }
}

Semoga ini bisa membantu Anda ...

sidik jari
sumber
2

Memperluas dari beberapa kelas tidak diperbolehkan di java .. untuk mencegah Deadly Diamond of death !

akkig
sumber
2

itu mungkin

public class ParallaxViewController<T extends View & Parallaxor> extends ParallaxController<T> implements AbsListView.OnScrollListener {

//blah
}
Jonathan
sumber
Parallaxordan ParallaxControllertidak diketahui, jadi saya berasumsi mereka bukan kelas-SDK. Jadi ini tidak berfungsi untuk saya (dan dengan demikian jawaban ini menunjukkan kesalahan). Apa itu ParallaxController? Apakah ini ketergantungan khusus? Tolong jelaskan
Zoe
1

Pembuat java memutuskan bahwa masalah multiple inheritance lebih besar daripada manfaatnya, jadi mereka tidak menyertakan multiple inheritance. Anda dapat membaca tentang salah satu masalah terbesar dari multiple inheritance (masalah berlian ganda) di sini .

Dua konsep yang paling mirip adalah implementasi antarmuka dan termasuk objek dari kelas lain sebagai anggota kelas saat ini. Menggunakan metode default di antarmuka hampir persis sama dengan multiple inheritance, namun dianggap praktik yang buruk untuk menggunakan antarmuka dengan metode standar saja.

Pika sang Penyihir Paus
sumber
0

Anda tidak dapat melakukan banyak pewarisan di java. pertimbangkan menggunakan antarmuka:

interface I1 {}
interface I2 {}
class C implements I1, I2 {}

atau kelas batin:

class Outer {
    class Inner1 extends Class1 {}
    class Inner2 extends Class2 {}
}

sumber