web-dev-qa-db-ja.com

Javaで最終クラスを拡張する方法

これが私が実際に直面している私の問題です。私にはクラスがあります。たとえば、Fooとしましょう。このクラスは、getBarインスタンスを返すBarというメソッドを定義します。クラスBarFoo内で定義され、_public static final_として宣言されます。私がやりたいことは、MyFooを拡張するFooクラスを定義することですが、BarMyBarで拡張して、独自の機能(メソッド、プロパティなど)を追加することもできます。また、getBarMyBarを返すようにします。

問題は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();を呼び出してこれらの構成を取得する必要があります

2つ目は、MyFooおよびMyBarのインスタンス化を制御できないことです。

私を妨げているのは、Barを拡張できないことです。どうすればそれを達成できますか?

17
Dimitri

基本的にはできません。拡張しないようにBarを設計した開発者のようです-したがって、拡張できません。別のデザインを探す必要があります-継承をあまり使用しないものかもしれません...もちろん、既存のコードを変更できない場合を想定しています。

(ここでの実際の目標、つまりシステム全体の設計についての詳細を知らずに、より具体的なアドバイスをすることは困難です。)

29
Jon Skeet

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

もちろん、これはfinalクラスのプライベートフィールドと保護フィールドへのアクセスを許可しませんが、そのゲッターメソッドとセッターメソッドを、Wrapperで宣言した新しいメソッドとフィールドと組み合わせて使用​​できます。希望する結果、または比較的近いものを取得するクラス。

別の解決策は、正当な理由がない場合にfinalクラスを宣言しないことです。

10
flawyte

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

ただし、(少なくとも)2つの回避策があります。

  1. クラスはオープンソースのJenkinsプロジェクトにあるため、プロジェクトをダウンロードして、クラスに必要な変更を加え、jarを再ビルドするだけです。
  2. 多少ハックですが、 Javassist のようなライブラリを使用して、メモリ内のクラスの実装を置き換えることができます
7
Bohemian

Finalクラスを拡張することはできません。つまり、クラスをfinalと宣言するポイントです。最終クラスが継承するインターフェイスと、ラップされた最終クラスへの呼び出しを委譲するラッパークラスの両方を定義できます。問題は、そもそもなぜクラスを最終的なものにするのかということです。

4
antiguru

おそらくあなたが望むのはプロキシです。実装は簡単です。これはすばらしい記事です: http://Java.dzone.com/articles/power-proxies-Java

2
idiogo

一部のインターフェースを実装している場合、 Decorator Design pattern で問題を解決できます。

0
Shahriar

たとえば、TreeSetはInterface Comparableの子ではないため、TreeSetコレクションにStringBufferを追加することはできません。

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

しかし、ラッパーを使用してComparableを実装できます。

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