2012-11-08 9 views
12

ここに私の問題は実際に直面しています。 私はクラスを持っています。Fooとしましょう。このクラスはgetBarというメソッドを定義し、Barというインスタンスを返します。クラスBarは、Fooの内部に定義され、public static finalと宣言されています。私がしたいのは、Fooを拡張するクラスMyFooを定義することですが、BarMyBarに拡張したいのは、独自の機能(メソッド、プロパティなど)を追加することです。 また、getBarMyBarを返すようにします。Javaで最終クラスを拡張する方法

問題はBarが最終です。ここで私は何をしたいのかの実例である:私は何をしたいか

public class Foo { 

    Bar bar = new Bar(); 

    public Bar getBar(){ 
     return bar; 
    } 

    .... 

    public static final class Bar { 

    } 
} 

は次のとおりです。

public class MyFoo extends Foo { 


    public MyBar getBar(){ // here I want to return an instance of MyBar 

    } 

    public static final class MyBar extends Bar { // That's impossible since Bar is final 

    } 
} 

どのように私はそれを達成することができますか?

[編集]私は私の質問に詳細を追加しています。 実際にJenkins用のプラグインを開発していて、検索した後、私がやりたい基本機能、すなわちFooBarを提供するプラグインがあることに気付きました。私はカスタムFooBarにしたいので、私のニーズに合っています。 Fooはプラグインのメインクラスであり、Builderというクラスを拡張します。 Fooは、performというメソッドを定義しています。このメソッドには、ビルドを実行するためのすべての操作が含まれています。 Barには設定のための操作が含まれており、Fooにはこれらの情報を取得するためのBarが必要です。

私がしたいことは、MyFooでFooを拡張し、MyBarでいくつかの設定を追加することです。そして、あなたが見るように、MyFoogetBar();

を呼び出すことによって、これらのconfiguationsを取得する必要があります2つ目は、私が何ブロック私をMyFooMyBar

のインスタンス化の制御することはできません、私はバーを拡張することができないということです。それをどうすれば実現できますか?

+8

'final'修飾子は' Bar'をサブクラス化できないようにするため、 "wrapping"することをお勧めします。 – mre

+0

'Bar'が' final class'である場合、通常は何らかの正当な理由があります。 'Foo'の不変量者の中にはそれが必要だからです。だから私はそれをやりません。少なくとも、関連するすべてのソースコードを正確に理解し、おそらくそれを書き直すべきです。 –

+2

'Bar'の開発者に、最終的なものにするか、またはmre suggestsとして委任を使用するよう依頼してください。 –

答えて

26

基本的にはできません。 Barを拡張しないように設計した開発者のように見えるので、拡張することはできません。あなたは、おそらく既存のコードを変更することができないと仮定して、おそらく継承をあまり使用しない別の設計を探す必要があります。

(それはここで本当の目標について詳しく知らなくても、より具体的な助言を与えることは難しい - 。システム全体の設計を)

+1

Jenkinsのプラグインを実際に開発していますが、FooとBarには拡張したい機能がたくさんあります。それで私はFooとBarの同じコードを書き直すことができなくなるでしょう。 – Dimitri

+1

@Dimitri:これは、継承の代わりに合成を使うのが妥当かどうかを知るための十分な情報を与えません。 –

+0

'Foo'と' Bar'はあなたがそれらを拡張できないように故意に設計されました。あなたには本当に別の選択肢はありません。 –

4

あなたはそれが最終的なクラスを宣言する時点で、最終的にクラスを拡張することはできません。最終クラスが継承するインターフェイスと、ラップされた最終クラスに呼び出しを委譲するラッパークラスを定義できます。問題はなぜクラスを最初に最後にするかです。

6

finalと宣言されているクラスを拡張することはできません。ただし、Wrapperと呼ばれる中間クラスを作成できます。このラッパーには基本的に元のクラスのインスタンスが含まれていて、実行したいものに従ってオブジェクトの状態を変更する代替メソッドを提供します。もちろん

このfinalクラスのプライベート&保護フィールドへのアクセス権を与えることはありませんが、あなたはそのgetterとsetterメソッドを使用することができ、その結果あなたを得るためにあなたがWrapperクラスで宣言された新しいメソッド&フィールドと組み合わせ欲しい、または比較的近くにある何か。

有効な理由がない場合、finalクラスを宣言しないこともできます。

5

finalクラスを拡張することはできません。これがfinalキーワードの目的です。

はしかし、2回避策は、(少なくとも)があります。

  1. クラスは、オープンソースであるジェンキンスプロジェクト、であるので、あなたはちょうどあなたがしたい変更を行い、プロジェクトをダウンロードすることができますクラスと再構築のjar
  2. ややハックのが、あなたはあなたが望むおそらくメモリ
  3. にクラスの実装を置き換えるために Javassistよう
+0

誰かがなぜクラスを最終決定するのですか?それは恐ろしい質問のように聞こえるかもしれませんが、私はプログラミングの初心者です。 私はScannerクラスを拡張しようとしていましたが(私ができるかどうかを確認するために)、動作しないことがわかりました。私の友人は、Scannerクラスが最終的だったからだと教えてくれました。 理論的には最終的なものではなく、誰かがそれを拡張したとしましょう。 子クラス内で変更された変数は親クラスを変更する必要がないため、どのような問題がありますか?等Idk –

+0

私はScannerクラスをオーバーライドすることと関係があることを知っていますが、最終的ではない場合は上書きする方法もわかりません。 –

2

をライブラリを使用することができますが、プロキシです。実装が簡単です。 TreeSetのはComparableインタフェースの子ではありませんので、我々は、TreeSetのコレクションでのStringBufferを追加することはできません例えばhttp://java.dzone.com/articles/power-proxies-java

0

:これは素晴らしい記事です

public class Main(){ 
public static void main(String[] args){ 
    TreeSet treeSetSB = new TreeSet(); 
    treeSetSB.add(new StringBuffer("A")); //error, Comparable is not implemented 
} 

しかし、我々は、実装するためのラッパーを使用することができます比較:

class myWrap implements Comparable{ 
    TreeSet treeset; 
    public myWrap() { 
     this.treeset=new TreeSet<>(); 

    } 
    public TreeSet getTreeset() { 
     return treeset; 
    } 
    public void setTreeset(TreeSet treeset) { 
     this.treeset = treeset; 
    } 
} 


public class Main(){ 
public static void main(String[] args){ 

    myWrap myWrap =new myWrap(); 
    TreeSet myTrs =myWrap.getTreeset(); 
    myTrs.add("b"); // no error anymore 
    myTrs.add("a"); 
    myTrs.add("A"); 
    System.out.println(myTrs); 
} 
関連する問題