web-dev-qa-db-fra.com

Comment étendre une dernière classe en Java

Voici mon problème en fait je suis confronté maintenant. J'ai une classe, disons Foo et cette classe définit une méthode appelée getBar qui renvoie une instance Bar. La classe Bar est définie dans Foo et et est déclarée public static final. Ce que je veux faire, c'est définir une classe MyFoo qui étend Foo mais je veux aussi étendre Bar avec MyBar en ajoutant mes propres fonctionnalités (méthodes, propriétés, etc.). Je veux aussi que getBar renvoie MyBar.

Le problème est Bar est final. Voici une illustration de ce que je veux faire:

public class Foo {

  Bar bar = new Bar();

  public Bar getBar(){
      return bar;
  } 

   ....

   public static final class Bar {

    } 
}

Ce que je veux faire c'est:

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

  } 
}

Comment puis-je y arriver?

[EDIT] J'ajoute plus de détails à ma question. Je développe actuellement un plugin pour Jenkins et, après une recherche, je me rends compte qu’il existe un plug-in qui offre les fonctionnalités de base que je souhaite utiliser, Foo et Bar. Je veux personnaliser Foo et Bar, afin que cela corresponde à mes besoins. Foo est la classe principale du plugin et étend une classe appelée Builder. Foo définit une méthode appelée perform qui contient toutes les opérations permettant d'effectuer une construction. Bar contient des opérations de configuration et Foo a besoin de Bar pour obtenir ces informations. 

Donc, ce que je veux faire, c'est étendre Foo avec MyFoo et ajouter quelques configurations avec MyBar. Et comme vous le voyez, MyFoo devra obtenir ces configurations en appelant getBar();

La deuxième chose est que je n’ai aucun contrôle sur l’instanciation de MyFoo et MyBar

Ce qui me bloque, c'est que je ne peux pas prolonger Bar. Comment puis-je y arriver? 

15
Dimitri

Vous ne pouvez pas, fondamentalement. Cela ressemble au développeur qui a conçu Bar pour qu'il ne soit pas étendu - vous ne pouvez donc pas l'étendre. Vous devrez rechercher un modèle différent - peut-être un modèle qui utilise moins l'héritage ... en supposant que vous ne pouvez pas modifier le code existant, bien sûr.

(Il est difficile de donner des conseils plus concrets sans en savoir plus sur le véritable objectif - la conception du système global.)

29
Jon Skeet

Vous ne pouvez pas étendre une classe déclarée final. Cependant, vous pouvez créer une classe intermédiaire, appelée Wrapper. Cet encapsuleur contiendra essentiellement une instance de la classe d'origine et fournira des méthodes alternatives pour modifier l'état de l'objet en fonction de ce que vous souhaitez faire.

Bien sûr, cela ne donnera pas accès aux champs privés et protégés de la classe final, mais vous pouvez utiliser ses méthodes d’obtention et de réglage, combinées aux nouvelles méthodes et champs que vous avez déclarés dans la classe Wrapper pour obtenir le résultat souhaité, ou quelque chose de relativement proche.

Une autre solution consiste à ne pas déclarer une classe final s'il n'existe aucune raison valable de le faire.

9
flawyte

Vous ne pouvez pas étendre une classe final - c'est le but du mot clé final.

Cependant, il y a (au moins) deux solutions:

  1. La classe est dans le projet Jenkins, qui est open source, vous pouvez donc simplement télécharger le projet, apporter les modifications souhaitées à la classe et reconstruire le fichier jar.
  2. Un peu d'un bidouillage, mais vous pourriez utiliser une bibliothèque comme Javassist pour remplacer l'implémentation de la classe en mémoire
7
Bohemian

Vous ne pouvez pas étendre les classes finales, c'est le point de déclarer des classes finales. Vous pouvez définir une interface dont la classe finale hérite et une classe wrapper qui délègue les appels à la classe finale encapsulée. La question est alors pourquoi rendre la classe finale en première place.

4
antiguru

Probablement ce que vous voulez, c'est un proxy. C'est facile à mettre en œuvre. C'est un excellent article: http://Java.dzone.com/articles/power-proxies-Java

2
idiogo

S'il implémente des interfaces, Motif de conception de décorateur pourrait résoudre le problème. 

0
Shahriar

Par exemple, nous ne pouvons pas ajouter de StringBuffer dans la collection TreeSet, car TreeSet n'est pas l'enfant de l'interface comparable:

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

Mais nous pouvons utiliser un wrapper pour implémenter le 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