wake-up-neo.net

So erweitern Sie eine letzte Klasse in Java

Hier ist mein Problem, mit dem ich jetzt konfrontiert bin. Ich habe eine Klasse, sagen wir Foo. Diese Klasse definiert eine Methode namens getBar, die eine Bar-Instanz zurückgibt. Die Klasse Bar ist in Foo definiert und wird als public static final deklariert. Ich möchte eine Klasse MyFoo definieren, die Foo erweitert. Ich möchte jedoch Bar um MyBar erweitern, indem ich meine eigenen Funktionalitäten (Methoden, Eigenschaften usw.) hinzufüge. .__ Ich möchte auch, dass getBarMyBar zurückgibt.

Das Problem ist Bar ist endgültig. Hier ist ein Beispiel dafür, was ich machen möchte:

public class Foo {

  Bar bar = new Bar();

  public Bar getBar(){
      return bar;
  } 

   ....

   public static final class Bar {

    } 
}

Was ich tun möchte ist:

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

  } 
}

Wie kann ich das erreichen?

[EDIT] Ich füge meiner Frage weitere Details hinzu. Ich entwickle gerade ein Plugin für Jenkins und nach der Suche wird mir klar, dass es ein Plugin gibt, das die Basisfunktionen bietet, die ich machen möchte, Foo und Bar. Ich möchte Foo und Bar anpassen, damit es meinen Bedürfnissen entspricht. Foo ist die Hauptklasse des Plugins und erweitert eine Klasse namens Builder. Foo definiert eine Methode namens perform, die alle Vorgänge zum Ausführen eines Builds enthält. Bar enthält Operationen für Konfigurationszwecke und Foo benötigt eine Bar, um diese Informationen abzurufen. 

Ich möchte also Foo um MyFoo erweitern und einige Konfigurationen mit MyBar hinzufügen. Und wie Sie sehen, muss MyFoo diese Konfigurationen abrufen, indem Sie getBar(); aufrufen.

Zweitens habe ich keine Kontrolle über die Instanziierung von MyFoo und MyBar

Was mich blockiert, ist, dass ich Bar nicht verlängern kann. Wie kann ich das erreichen? 

15
Dimitri

Das kannst du nicht. Es sieht aus wie der Entwickler, der Bar entworfen hat, damit er nicht erweitert werden kann - Sie können ihn also nicht erweitern. Sie müssen nach einem anderen Design suchen - möglicherweise nach einem, bei dem Vererbung nicht so häufig verwendet wird ... vorausgesetzt, Sie können den vorhandenen Code natürlich nicht ändern.

(Es ist schwer, konkrete Ratschläge zu geben, ohne mehr über das eigentliche Ziel zu erfahren - die Gestaltung des Gesamtsystems.)

29
Jon Skeet

Eine Klasse, die als final deklariert ist, kann nicht erweitert werden. Sie können jedoch eine Zwischenklasse mit dem Namen Wrapper erstellen. Dieser Wrapper enthält im Wesentlichen eine Instanz der ursprünglichen Klasse und stellt alternative Methoden zur Verfügung, um den Status des Objekts entsprechend dem gewünschten Vorgang zu ändern.

Natürlich haben Sie keinen Zugriff auf die privaten und geschützten Felder der final-Klasse. Sie können jedoch die Methoden für Getter und Setter in Kombination mit den neuen Methoden und Feldern verwenden, die Sie in der Wrapper-Klasse angegeben haben, um das gewünschte Ergebnis zu erhalten etwas relativ nah.

Eine andere Lösung besteht darin, final keine Klasse zu deklarieren, wenn es keinen triftigen Grund dafür gibt.

9
flawyte

Sie können eine final-Klasse nicht erweitern. Dies ist der Zweck des final-Schlüsselworts.

Es gibt jedoch (mindestens) zwei Problemumgehungen:

  1. Die Klasse befindet sich im Jenkins-Projekt, das Open Source ist. Sie können also einfach das Projekt herunterladen, die gewünschten Änderungen an der Klasse vornehmen und das Glas neu erstellen
  2. Etwas von einem Hack, aber Sie könnten eine Bibliothek wie Javassist verwenden, um die Implementierung der Klasse im Speicher zu ersetzen
7
Bohemian

Abschlussklassen können nicht erweitert werden. Dies ist der Punkt, bei dem Klassen als endgültig deklariert werden. Sie können eine Schnittstelle definieren, von der sowohl die letzte Klasse als auch eine Wrapper-Klasse erben, die Aufrufe an die umschlossene letzte Klasse delegiert. Die Frage ist dann, warum die Klasse an erster Stelle finalisiert werden soll.

4
antiguru

Wahrscheinlich möchten Sie einen Proxy. Es ist einfach zu implementieren. Dies ist ein großartiger Artikel: http://Java.dzone.com/articles/power-proxies-Java

2
idiogo

Wenn einige Schnittstellen implementiert werden, könnte Decorator Design Pattern das Problem lösen. 

0
Shahriar

Zum Beispiel können wir keinen StringBuffer in der TreeSet-Collection hinzufügen, da TreeSet nicht untergeordnetes Element des Interface Comparable ist:

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

Wir können aber einen Wrapper verwenden, um die Comparable zu implementieren:

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