2016-04-18 12 views
1

コンクリートクラスFooを持っていて、Fooを拡張するBarと呼ばれる「エイリアス」を追加したいのですが、どのメソッドもオーバーライドしません。オーバーライドのないサブクラス(エイリアスクラス)

編集:コンテキストFooの名前が正しくないため、FooBarに最終的に名前を変更することです。しかし、Fooは別のプロジェクトに依存しており、FooFooCallerの両方を同じコミットで変更することはできません。 FooCallerを壊すのを避けるために、私は3つの変更を行います:(1)を追加する、(2)FooCallerBarCallerに変更する、(3)FooCallerがなくなったときにFooを削除します。

ここに問題がありますか、BarFooと同じですか?

+2

コンストラクタに注意する必要があると思いますが、親が抽象クラスでない限り、親クラスのメソッドをオーバーライドする義務はありません。 – KevinO

+2

ジェネリック型のパラメータとして 'Foo'や' Bar'を使用しますか? 'リスト'? – rgettman

+0

@rgettman漸進的リファクタのエイリアスではありません – mfrankli

答えて

1

はい、Javaはあなただけのオリジナルのクラスをエイリアシングのために非final具象クラスをサブクラス化できるようになります。

デフォルトコンストラクタが Fooでしかないと仮定して、最小限の実装だろう
public class Foo { /* implementation */ } 

public class Bar extends Foo {} 

Fooで引数を取るコンストラクタがある場合、あなたはあなたのBarインスタンス、例えばを作成するために呼び出す予定のすべてのコンストラクタのためBarにコンストラクタを提供する必要があります。

public class Foo { 
    public Foo(String baz) { /* constructor implementation */ } 
} 

public class Bar extends Foo { 
    public Bar(String baz) { super(baz); } 
} 

Fooのすべての非privateメソッドを継承しますby Bar

汎用タイプのパラメータとしてFooの代わりにBarを使用する予定がある場合のみです。例えば

あなたはList<Bar>List<Foo>を交換した場合、その後、あなたのListはもはやFooを拡張する可能性のあるFooインスタンス、または他のクラスのインスタンスを保持することはできません。 Javaのジェネリックは不変であるため、

はさらに、List<Bar>BarFoo場合でも、List<Foo>のサブタイプではありません。そのような場合の詳細については、Is List a subclass of List? Why aren't Java's generics implicitly polymorphic?を参照してください。また、List<? extends Foo>を使用すると、List<Foo>またはList<Bar>を使用できますが、null以外のものはaddにできません。

あなたはジェネリックでは使用しないと述べていますが、要件が拡張されている場合は注意が必要です。

結局のところ、Javaコンパイラはあなたにそれをさせますが、限定された逆さまで、Fooの代わりにBarをエイリアスとして使用すると、潜在的な欠点として、このエイリアシングプロセスを使用する理由はありません。

+0

また、getClass()に依存するコードの動作が異なる場合があります。 – user140547

+0

ジェネリックの問題は良い点です。私の特定のケースでは、最終的にはFooの名前が正しくないため、Fooの名前をBarに変更することが目標です。しかし、Fooは別のプロジェクトに依存しており、FooとFooCallerの両方を同じコミットで変更することはできません。 FooCallerを破壊しないように、私は3つの変更を行います:(1)Barを追加する、(2)FooCallerをBarCallerに変更する(同じ動作)、(3)Fooを完全に削除する。 – mfrankli

+0

@mfrankliあなたの質問に含める良い文脈です。私はFooをBarにリネームしてから、後方互換性のためにBarを拡張する新しいFooを作成することをお勧めします。 – dsh

1

Barは、適切な可視性を使用する限り、Fooとして動作します。 FooのプライベートメソッドとプロパティはBarにはアクセスできず、保護されたメソッドとプロパティはBarでプライベートであるとみなされます。

以下の例では、コンソールに「Foo」が出力されます。

class Example 
{ 
    public static void main (String[] args) 
    { 
     Bar b = new Bar(); 
     System.out.println(b.getName()); 
    } 
} 

class Foo { 
    protected String name; // Will be private in Bar 

    public Foo() { 
     this.name = "Foo"; 
    } 

    public String getName() { 
     return this.name; 
    } 
} 

class Bar extends Foo { 

}