2つのクラスからの拡張


150

これどうやってするの:

public class Main extends ListActivity , ControlMenu 

また、ControlMenuであるクラスでメニューを作成し、残りのアクティビティを拡張していることは、このアプローチで問題ないことを知りたいと思います。


4
一度に2つ以上のクラスを拡張することはできません。Javaでは多重継承は許可されていません。
yogsma

回答:


156

拡張できるクラスは1つだけです。そして、多くのソースからのインターフェースを実装します。

複数のクラスを拡張することはできません。私が考えることができる唯一の解決策は、どちらのクラスも継承せず、代わりに各クラスの内部変数を用意し、オブジェクトへのリクエストを宛先のオブジェクトにリダイレクトすることで、より多くのプロキシを実行することです。

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

これは私が思いついた最高のソリューションです。両方のクラスから機能を取得できますが、実際のクラスタイプは1つだけです。

欠点は、キャストを使用して内部クラスのモールドに適合できないことです。


2
あなたはより速かった:)私はあなたの具体的な例と比較するためにいくつかの抽象的なとりとめとして私の答えを残します;)
Nicolas78 '29

1
これは非常に優れた代替手段であり、将来により多くの柔軟性を提供します。
David Souther、2011

1
より多くのOOPソリューションのための@SCBソリューションを参照してください
idish

ここでより正確な例を使用できます。わかりません。
Neo42、18年

54

内部クラスを使用しない理由(ネスト)

class A extends B {
    private class C extends D {
        //Classes A , B , C , D accessible here 
    }
}

4
興味深いアプローチ、専門家はこの手法についてどう思いますか?掘り下げたいのですが。
TechNyquist 2014年

1
慣習で大丈夫ですか?
2014

2
内部クラスをで機能させることができませんでしたFragment。私のアクティビティは拡張するFragment必要がありますgetView()。つまり、絶対に必要です。これは内部クラス内にある場合は機能せず、そこにあるコードはからのコードを使用する必要がある場所にあるためListActivity、2回拡張することも、内部クラスを実行することもできません。この例では。
Azurespot 2015年

これは、実装クラスの変数にアクセスする必要がある抽象クラスを拡張するための最良のソリューションです。
tak3shi 2016年

45

他の皆が言ったように。いいえ、できません。しかし、人々は何年にもわたって何度も複数のインターフェースを使用するべきだと言ってきましたが、実際にはどのように使用されていないのでしょう。うまくいけば、これが役立ちます。

あなたが持っclass Fooclass Barいて、両方にを拡張してみたいと思ったとしますclass FooBar。もちろん、あなたが言ったように、あなたはできません:

public class FooBar extends Foo, Bar

人々はすでにこの理由にある程度取り組んでいます。代わりに、書き込みinterfacesの両方のためにFooBar自分のパブリックメソッドのすべてをカバーします。例えば

public interface FooInterface {

    public void methodA();

    public int methodB();

    //...
} 

public interface BarInterface {

    public int methodC(int i);

    //...
}

そして今、相対インターフェースを作成FooしてBar実装します:

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

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

これで、とオブジェクトを保持し、メソッドを直接通過させるだけでなく、class FooBar両方FooInterfaceを実装できます。BarInterfaceFooBar

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

    //...

}

この方法のためのボーナスは、ということであるFooBarオブジェクトは、両方の金型にフィットFooInterfaceとしBarInterface。つまり、これはまったく問題ありません。

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

これにより、複数の拡張機能の代わりにインターフェースを使用する方法が明確になることを願っています。数年遅れても。


6
これが最良の答えです
user3290180

これは非常に良い答えですが、より詳細に対処する必要がある問題がいくつかあります。最初に2つの既存のクラスから拡張することは少し問題が多くなり、いくつかの追加のハードルが発生します。2つ目は、インターフェイスFooとBarの両方に同じ機能がある場合、優先順位を付ける必要があります。クラスを明示的に拡張すると、それらの決定を前もって行う必要があります。それでも、優れたオプション:) +1
レイジーコーダー

「頻繁に」新しいクラスを作成し、それらの各クラスに両方のインターフェースを実装させる必要がある場合はどうでしょうか。次に、これらのボイラープレート実装を各クラスで繰り返す必要があります。クラスに2つの動作セットを「実装」させるより良い方法はありますか?
MasterJoe2

1
@ MasterJoe2正直なところ、私はしばらくの間Javaをあまり使用していません(この回答を書いた頃に立ち止まりました)。私が今日それを避ける理由の1つは、あなたが提起するまさに問題です。あなたがたぶん調査できる方向への直感は、両方のインターフェースを実装する抽象クラスを書き、それを拡張することです。ただし、それが有効なJavaであるかどうかはわかりません。将来実装するクラスに変更を加えたい場合は、同じ問題が発生するだけだと思います。すみません、これ以上のお手伝いはできません。
SCB

37

あなたはインターフェースを使いたいでしょう。一般的に、ダイアモンド問題のために多重継承は良くありません:

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 ++などには、これを解決する方法がいくつかあります。

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

しかし、Javaはインターフェースのみを使用します。

Javaのトレイルは、インターフェイス上の偉大な導入を持っている:http://download.oracle.com/javase/tutorial/java/concepts/interface.htmlは おそらくAndroidのAPIでニュアンスにダイビングの前のことをフォローしたいでしょう。


24
ダイヤモンドの問題が実際に多重継承を妨げる問題である理由を理解できませんでした。同じ名前の競合するメソッドがある場合、コンパイラーは単に文句を言わないのはなぜですか?
ピート、2014年

1
十分にインテリジェントなコンパイラにとっては、そうではありません。コンパイラー・レベルでそれを解決することは可能であり、実際にC ++はでそれを行いvirtual classます。これを行うと、コンパイラと開発者の両方に対して、多くの警告と警告が表示されます。
David Souther 2014年

1
2つのインターフェースで同じデフォルトのメソッドはどうですか?これは、Javaが処理できるひし形の問題のもう1つの例です。
Lajos Meszaros、2015

1
@MészárosLajosただしsuper、継承するメソッド内からは呼び出しません。できますが、呼び出すインターフェースメソッドを指定する必要があります(defaultインターフェースの実装ではキーワードを使用する必要があります)。例は次のMyIFace.super.foo()とおりです。MyIFaceはインターフェースです。ご覧のとおり、実行するインターフェースメソッドが定義されており、Diamond Problemを完全に回避しています。MyClass1and を拡張するとMyClass2、両方のクラスにfoo()、およびcall super.foo()があり、ダイヤモンド問題によってコンパイラーがスローされます。
JDSweetBeat

あなたは返すことができない"bar""baz"のメソッドタイプでvoid。とにかく、良い説明xD
xdevs23

22

ええ、他の誰もが書いたように、Javaで多重継承を行うことはできません。コードを使用するクラスが2つある場合、通常は1つだけをサブクラス化します(たとえば、class A)。classのB場合、その重要なメソッドをインターフェイスに抽象化しBInterface(醜い名前ですが、アイデアはわかります)、次にと言いMain extends A implements BInterfaceます。内部では、の対応する関数を呼び出すことにより、クラスのオブジェクトをインスタンス化し、のBすべてのメソッドを実装できます。BInterfaceB

これは、あなたのように「は、」関係する「で、」関係を変更しMain、今でAはなく、持っていますB。ユースケースによっては、クラスBInterfaceからを削除して変更を明示的にしA、代わりにBオブジェクトに直接アクセスするメソッドを提供することもできます。


これは最も読みやすく、理解しやすい説明です。もっと投票してください。
アルゴリーニ2015


6

Javaは多重継承をサポートしていませんが、2つ以上のインターフェースを実装してみることができます。


4

はい。slandauは正しいです。Javaでは、いくつかのクラスからの拡張は許可されていません。

あなたが望むのはおそらく public class Main extends ListActivity implements ControlMenuです。あなたがリストを作ろうとしていると思います。

お役に立てば幸いです。


3

別の代替案と同様に、メソッドのデフォルト実装でインターフェースを使用できる場合があります。もちろん、それはあなたが何をしたいかによります。

たとえば、抽象クラスとインターフェースを作成できます。

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

したがって、その後、両方のクラスを拡張して実装し、両方のメソッドを使用できます。

public class extends FatherClass implements InterfaceWithDefaultsMethods {

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

これがあなたに役立つことを願っています...



2

可能です

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

//blah
}

ParallaxorParallaxController不明なので、SDKクラスではないと思います。したがって、これは私にとっては機能しません(したがって、この回答はエラーを示しています)。ParallaxControllerとは何ですか?これは特定の依存関係ですか?詳しく説明してください
ゾーイ

1

Javaの作成者は、多重継承の問題がメリットを上回ると判断したため、多重継承は含まれていませんでした。多重継承の最大の問題の1つ(二重ひし形問題)については、ここで読むことができます

最も類似した2つの概念は、インターフェースの実装と、現在のクラスのメンバーとして他のクラスのオブジェクトを含めることです。インターフェースでデフォルトのメソッドを使用することは、多重継承とほとんど同じですが、デフォルトのメソッドのみを使用してインターフェースを使用することは悪い習慣と見なされています。


0

Javaでは多重継承はできません。インターフェイスの使用を検討してください:

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

または内部クラス:

class Outer {
    class Inner1 extends Class1 {}
    class Inner2 extends Class2 {}
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.