web-dev-qa-db-fra.com

Classe abstraite finale Java

J'ai une question assez simple:

Je veux avoir une classe Java, qui fournit une méthode statique publique, qui fait quelque chose. Ceci est juste à des fins d'encapsulation (pour avoir tout ce qui est important dans une classe séparée) ...

Cette classe ne doit être ni instanciée ni étendue. Cela m'a fait écrire: 

final abstract class MyClass {
   static void myMethod() {
      ...
   }
   ... // More private methods and fields...
}

(même si je le savais, c'est interdit).

Je sais aussi que je peux rendre cette classe uniquement finale et remplacer le constructeur standard tout en le rendant privé.

Mais cela me semble plus comme une "solution de contournement" et DEVRAIT plus probablement être fait par classe abstraite finale ...

Et je déteste les solutions de contournement. Donc, juste pour mon propre intérêt: Existe-t-il un autre moyen plus efficace?

37
Sauer

Référence: Effective Java 2nd Edition, point 4 "Imposition de l'instabilité à un constructeur privé"

public final class MyClass { //final not required but clearly states intention
    //private default constructor ==> can't be instantiated
    //side effect: class is final because it can't be subclassed:
    //super() can't be called from subclasses
    private MyClass() {
        throw new AssertionError()
    }

    //...
    public static void doSomething() {}
}
45
assylias

Vous ne pouvez pas obtenir beaucoup plus simple que d’utiliser une enum sans instances.

public enum MyLib {;

   public static void myHelperMethod() { }
}

Cette classe est finale, avec explicitement aucune instance et un constructeur privé.

Ceci est détecté par le compilateur plutôt que comme une erreur d'exécution. (contrairement à lancer une exception)

48
Peter Lawrey

Non, vous devez créer un constructeur privé privé qui lève une exception dans son corps. Java est un langage orienté objet et une classe qui ne doit jamais être instanciée est en soi une solution de contournement! :)

final class MyLib{
    private MyLib(){
        throw new IllegalStateException( "Do not instantiate this class." );
    }

    // static methods go here

}
6
ArtB

Non, les classes abstraites sont destinées à être étendues. Utilisez un constructeur privé, ce n'est pas une solution de contournement - c'est le moyen de le faire!

4
scibuff

Déclarez que le constructeur de la classe est private. Cela garantit la non-instabilité et empêche le sous-classement.

2
Gianmarco Biscini

Les suggestions d’assylias (toutes les versions de Java) et de Peter Lawrey (> = Java5) sont la méthode standard dans ce cas.

Cependant, j'aimerais attirer votre attention sur le fait qu'empêcher l'extension d'une classe d'utilitaires statiques est une décision finale qui peut vous hanter plus tard, lorsque vous découvrez que vous avez des fonctionnalités associées dans un projet différent et que vous avez en fait vouloir l'étendre.

Je suggère ce qui suit:

public abstract MyClass {

    protected MyClass() {
    }

    abstract void noInstancesPlease();

    void myMethod() {
         ...
    }
    ... // More private methods and fields...

}

Cela va contre la pratique établie, car cela permet d’extraire la classe si nécessaire, tout en empêchant l’instanciation accidentelle (vous ne pouvez même pas créer une instance de sous-classe anonyme sans obtenir une erreur de compilation très claire).

Pisses me dit toujours que les classes d'utilitaires du JDK (par exemple, Java.util.Arrays) ont été rendues définitives. Si vous voulez avoir votre propre classe Arrays avec des méthodes de comparaison, vous ne pouvez pas, vous devez créer une classe séparée. Cela distribuera une fonctionnalité qui (IMO) appartient ensemble et devrait être disponible via la classe one. Cela vous laisse soit avec des méthodes utilitaires très distribuées, soit vous devez dupliquer chacune des méthodes dans votre propre classe.

Je recommande de ne jamais rendre de telles classes d'utilitaires définitives. Les avantages ne surpassent pas les inconvénients à mon avis.

1
Durandal

Vous ne pouvez pas marquer une classe à la fois abstraite et finale. Ils ont des significations presque opposées. Une classe abstraite doit être sous-classée, alors qu'une classe finale ne doit pas l'être Si vous voyez cette combinaison de modificateurs abstraits et finaux, utilisée pour une déclaration de classe ou de méthode, le code ne sera pas compilé.

0