41 votes

Pourquoi reçois-je cet avertissement concernant les classes d'utilitaires en Java

Je suis en train d'apprendre Java et OOPS et pendant la programmation d'une base Bonjour tout le Monde, dans eclipse, je vois un triangle jaune en me disant de "l'utilité des classes ne devraient pas avoir un public, ou de constructeur par défaut'. Je ne suis pas en mesure de comprendre pourquoi c'est exactement ce qui se passe et ce que cela signifie? Que fais-je pas le droit?

class HelloWorld {


public static void main(String[] args)
{
    // TODO Auto-generated method stub
            System.out.println("Hola Mundo!");

}


  }

EDIT1: Modifié le code afin d'y inclure les modifications suggérées.

final class HelloWorld {


private HelloWorld()
{
    throw new AssertionError("Instantiating utility class...");

}
public static void main(String[] args)
{
    // TODO Auto-generated method stub
            System.out.println("Hola Mundo!");

}


}

Encore l'alerte sur la ligne de la Classe HelloWorld.

Edit2:

Créé une nouvelle classe et maintenant ça fonctionne. Merci Jon.Pourquoi la vieille classe encore donner un avertissement? Bohème je ne suis pas encore au courant sur les concepts évoqués par vous dans votre post. Je voudrais revenir à eux une fois que j'ai une meilleure idée. Merci pour expliquer les choses.

66voto

Jon Skeet Points 692016

Cela signifie que quelqu'un peut écrire:

 HelloWorld helloWorld = new HelloWorld();
 

lorsque vous ne le voulez probablement pas - vous ne fournissez aucun membre d'instance, alors pourquoi leur permettre de créer des instances? Réécrivez votre code en:

 final class HelloWorld {

    private HelloWorld() {
        // Prevent instantiation
        // Optional: throw an exception e.g. AssertionError
        // if this ever *is* called
    }

    public static void main(String[] args) {
        System.out.println("Hola Mundo!");
    }
}
 

20voto

Bohemian Points 134107

Ce que Jon a dit, mais vous devez savoir aussi que chaque classe dispose d'un constructeur, si vous déclarez un ou pas. Si vous ne déclarez pas un, alors le "constructeur par défaut" est implicitement définie pour vous.

En d'autres termes, ces deux classes sont identiques dans les comportements:

public class ClassA {
}


public class ClassB {
    public ClassB() {
    }
}

ATTENTION: le fait d'Avoir un constructeur privé n'empêche pas l'instanciation!

Et juste pour être anal, avoir un constructeur de ne pas empêcher quelqu'un de l'instanciation de votre classe, il rend juste plus difficile:

Il y a (au moins) deux façons de les contourner:

Déclarer une méthode de fabrique (évident, mais si c'est votre code de la société, quelqu'un peut le faire):

public class ClassA {
    private ClassA() {}

    public static ClassA create() {
        return new ClassA(); // oops! this one got away
    }
}


Utiliser la réflexion (sournois, et semble mal en quelque sorte, mais ça marche!):

public class ClassA {
    private ClassA() {}
}

// Elsewhere, in another class across town:
Constructor<?> constructor = ClassA.class.getDeclaredConstructor();
// constructor private? no problem... just make it not private!
constructor.setAccessible(true); // muhahahaha
Object obj = constructor.newInstance();
System.out.println(obj.getClass().getSimpleName());  // Prints ClassA!

La seule façon de garantir l'absence de l'un crée une instance est de lancer une exception dans un (pourriez faire ainsi privé) constructeur.

8voto

Uffe Points 4996

Pour être complet, aucun des intervenants ont formulé des commentaires sur la question avec votre classe d'origine

class HelloWorld {

qui, comme l'a suggéré, vous transformé en

final class HelloWorld {

L' final mot-clé sur une classe Java interdit à d'autres classes de l'extension (héritant de), il. Si vous ne faites pas une classe final, une extension de la classe peut faire usage de toutes sortes de choses que vous pourriez ne pas avoir prévu, en raison de l'extension de la classe a accès à l' protected des membres de la classe héritée.

Il est de bonne pratique de toujours faire vos classes, soit abstract ou final, ce qui signifie qu'ils sont destinés uniquement pour les, ou de ne pas pour la, hériter. Il y aura beaucoup de moments où vous aurez à concevoir une classe à la fois instanciables (non abrégé) et extensible (non définitif), mais ce qui en fait une décision consciente est une bonne habitude à prendre.

7voto

Peter Lawrey Points 229686

La façon la plus simple d'écrire une classe utilitaire est que vous avez une enum avec pas de cas. Vous pouvez le faire avec Java 5.0 et au-dessus.

public enum Utility {;
    public static void main(String... args) {
        System.out.println("Hola Mundo!");
    }
}

Vous n'avez pas à définir un constructeur privé et vous ne pouvez pas créer des instances à l'aide de classes internes ou d'autres trucs comme réflexion. (Si vous ignorez la classe Dangereux ;)

BTW: Certains le voient à l'aide d'un enum comme un hack, mais pour moi, il dit explicitement "j'ai une classe avec pas de cas" plutôt que de prévenir les instances en cours de création qui est indirect.

2voto

geffchang Points 560

Jetez un œil à ceci: http://checkstyle.sourceforge.net/config_design.html#HideUtilityClassConstructor
Je suppose que vous utilisez CheckStyle.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X