9
votes

Prévenir l'appel d'un constructeur privé de la classe en Java

Nous pouvons limiter la création de l'objet d'une classe en faisant son constructeur privé. Mais ce constructeur pourrait toujours être appelé de l'intérieur de la classe. Y a-t-il un moyen de prévenir cela en Java?

Merci.


2 commentaires

Vous pouvez utiliser AspectJ pour vous assurer. Cependant, il est conseillé de faire si si vous le souhaitez à plus d'un endroit, car il ajouterait une dépendance et une complexité énormes. Plus souvent que non, les normes et les pratiques vous serviront mieux sur cette affaire au lieu d'outils et de contrôle.


Nous jetons une exception non supportée de nos constructeurs privés qui ne sont pas destinés à être instanciés. En fait, cette idiome est tellement commune pour nous que nos IDes sont configurées de sorte que nous tapons pct (quatre coupes) et génère un constructeur privé qui jette une introduction non prêtée.


6 Réponses :


3
votes

Non, il n'y a aucun moyen d'appliquer une seule instance d'un type particulier. Le plus proche que vous puissiez venir est, comme vous le décrivez, rendant le constructeur privé de manière à ce que seule fonctionne dans cette classe puisse l'appeler. Vous pouvez faire quelque chose à l'exécution (comme jetant une exception si votre instance statique existe déjà), mais cela ne vous ferait rien à la compilation.


0 commentaires

14
votes

Non, il n'y a pas de moyen propre pour le faire. Et vraiment je ne peux pas voir une raison de le faire. Parce que si le constructeur est privé, cela signifie qu'il ne peut être appelé qu'à partir du code de cette classe exacte (pas de sous-classes ou d'autres classes de l'emballage), donc si vous ne voulez pas que le constructeur soit appelé, mettez-y un commentaire qui dit donc.

Puisque tous ceux qui sont capables d'utiliser le constructeur seraient en mesure de supprimer toutes les mesures que vous avez posées pour empêcher l'appel du constructeur, il n'aurait aucun effet réel.

En outre, si vous avez besoin d'un singleton, vous voudrez peut-être que le constructeur soit exécuté au moins une fois (sauf si votre idée d'un singleton est une classe purement statique).


1 commentaires

Lancer une exception qui l'empêcherait et c'est un moyen propre. Vous pouvez même écrire un test pour cela. Tout le monde peut l'appeler de la classe ou de réflexion et d'exception sera toujours lancé. Il y a donc une raison de le faire: la réflexion.



6
votes

La réponse officielle est non. Si quelqu'un peut obtenir un accès privé à votre classe, il peut l'installer.

Cependant, vous pouvez le faire: P>

private static int count = 0;

private MyClass(){
    if(++count>1)throw new IllegalStateException(); //allow exactly one instantiation
}


3 commentaires

Bonne idée, mais cette synchronisation doit être une épreuve de balle. Vous voulez probablement utiliser un nombre de numéros de compte à rebours pour cela si cela va de cette façon.


Je ne sais pas quoi dire Duffymo, après avoir ré-lisant l'OP, il s'agit de la réponse la plus adhérente ici (vraiment, de faire correspondre la demande de l'OP, elle devrait toujours jeter une exception, mais cela montre comment vous pourriez toujours appliquer cette condition tout en permettant Pour une instance Singleton, qui est un scénario plus réaliste.) Si vous croyez que la question est une non-sens, c'est un commentaire sur la question, pas une réponse. Mais la question a une réponse.


Duffymo: Bien que votre réponse ait plus de sens en ce qui concerne la question de la question, le mien a plus de sens à y répondre. S'il vous plaît expliquer ce qui ne va pas et pourquoi encore.



9
votes

Si elle est privée, et vous ne voulez pas qu'il a appelé dans sa propre classe, il est un moyen facile d'éviter une telle chose: Ne pas écrire le code qui l'appelle plus d'une fois. Vous êtes l'auteur de la classe. Pourquoi voudriez-vous écrire du code pour vous empêcher de vous faire quelque chose qui est dans votre contrôle?

Il ne peut pas être appelé en dehors de la classe sans avoir recours à la réflexion. Si vous ne voulez pas qu'il a appelé plus d'une fois dans la classe, alors il suffit de ne pas le faire. Pourquoi écrire du code pour éviter une action que vous pouvez choisir de ne pas faire p>

Passons en revue: p>

Nous pouvons résonner la création de l'objet d'une classe en faisant son constructeur Privé. P> Blockquote>

constructeur est privé, donc il ne peut pas être appelé en dehors de la classe, à moins qu'un client utilise l'API de réflexion pour saper les restrictions d'accès. P>

Mais ce constructeur pourrait toujours être appelé de dans strong> la classe. Y a-t-il de toute façon à empêcher strong> ce en Java? p> Blockquote>

L'OP demande d'éviter d'appeler le constructeur restreint à l'intérieur de la classe. P>

Si ces deux déclarations sont correctes, s'il vous plaît expliquer pourquoi il faut une logique empêchant les appels au constructeur.

Voici une utilisation typique d'un constructeur privé. p>

public class Singleton
{
    private static final Singleton instance = new Singleton();

    public static void main(String[] args)
    {
        Singleton singleton = Singleton.getInstance();

        System.out.println(singleton);
    }

    private Singleton() {};

    public static Singleton getInstance() { return Singleton.instance; }

    public String toString() { return Singleton.class.getName(); }
}


14 commentaires

Mais chaque classe aura au moins un constructeur, et il semble que la question soit la question de restreindre les appels à l'intérieur de la classe.


Oui, mais si vous lisez ma réponse, vous réaliserez à quel point la question est ridicule. Votre vote Down n'est pas garantie.


Le constructeur doit encore être écrit, car s'il n'y a pas de constructeur, le compilateur ajoutera un public, ce qui est encore pire.


Non, ce ne sera pas, pas si le constructeur privé est la valeur par défaut. Essayez-le et voyez.


Veuillez expliquer ce que vous entendez par constructeur par défaut privé. Si je crée une nouvelle classe Java sans aucun constructeur, je peux instancier cette classe de savoir où je le souhaite. Pour éviter cela, vous devez créer manuellement un constructeur dans votre classe.


Voir l'exemple que je viens de poster. C'est ce que je veux dire. Vous ne pouvez appeler aucun constructeur sur singleton. Essayez-le et voyez. La seule façon de faire référence à une référence à une référence en appelant la méthode getinstance ().


Voyez ce que j'ai fait? J'ai un constructeur par défaut, le compilateur ne le fournira pas. Je n'ai fourni aucun autre constructeur, à l'exception de celui privé, vous ne pouvez donc pas instancier cette classe où que vous soyez. C'est tout le point d'écrire un singleton de cette façon: contrôler l'instanciation.


Eh bien, c'est vrai, mais cela n'empêche pas quiconque d'ajouter une méthode à votre classe qui crée une nouvelle instance ou des modifications reçoivent une instance pour appeler le constructeur (ce que je suppose que l'OP avait peur de). Je suis d'accord avec vous, que cela n'essaie pas d'empêcher personne de l'intérieur d'appeler le constructeur. Mais votre exemple contredit ce que vous avez dit au début de votre message: que vous n'avez pas besoin d'écrire un constructeur privé.


Ouais mais Duffymo, votre réponse dit "N'écrivez pas un constructeur". Dans votre exemple, vous écrivez un constructeur. Donc ... ? L'OP ne veut pas empêcher un constructeur particulier, mais n'importe quel appel de constructeur . Et pendant que je suis d'accord, cela n'est pas vraiment une question vitale, il demandait spécifiquement comment empêcher un constructeur privé d'être appelé plus d'une fois. Il existe des moyens de le faire (ci-dessous) et votre réponse n'a pas abordé cela.


@Tall: Vous plaignez la sémantique. Vous êtes tous d'accord, vous utilisez simplement différentes façons de décrire la même chose. Je pense que Duffymo signifiait: vous n'avez besoin de rien mettre dans le constructeur privé, vous pouvez le laisser vide. Cela décrivent de manière incorrecte en tant que "constructeur par défaut", tandis que "constructeur par défaut" signifie "Le constructeur de no-arg no-arg fourni automatiquement si vous n'incluez aucun autre constructeur".


@San Owen - Continuez, s'il vous plaît. "N'écrivez pas un constructeur" indiquait que les exigences ne sont pas cohérentes ou logiques. Pourquoi concevriez-vous une classe pour vous empêcher de l'appeler plus d'une fois? Vous êtes le seul à l'appeler si c'est privé. Pourquoi écrire du code pour empêcher quelque chose que vous pouvez choisir de ne pas faire? Cette discussion n'est que plus ridicule la plus longue qui continue.


@FRENETISCH - Mon point réel est que l'exigence est contradictoire et ridicule.


@duffymo +1 Je suis d'accord avec vous dans cette affaire et avec votre dernière modification Aucune contradiction :-)


@duffymo désolé j'ai touché un nerf mais je suis surpris de votre ton. Je vais enlever le -1 si cela aide. Je suis d'accord que votre dernier post clarifie que vous ne répondez pas à la question, mais pense plutôt que ce n'est pas utile, et j'ai tendance à être d'accord. Je suppose que l'idée est, eh bien, si un autre dev entre cela et mèche avec cela et commence à écrire du code qui instancie l'objet, au moins vous pouvez le faire échouer (au moment de l'exécution). Mais si c'est la situation, vous avez de plus gros problèmes.



2
votes

Si vous faites un singleton, Enums sont la meilleure façon d'aller:

public enum MySingleton {
    INSTANCE;
    // add methods & stuff here
}

// Usage:
MySingleton.INSTANCE.doSomething();


0 commentaires

1
votes

Oui, il existe un moyen simple: il suffit de faire jeter le constructeur privé une exception: xxx

Notez que ma réponse est différente parce que j'interprète la question légèrement différemment de la plupart des autres. Réponses répertoriées. De nombreuses autres réponses ont supposé que vous voulez que la classe soit un singleton, auquel cas le constructeur doit être appelé exactement une fois. Je suppose que vous ne voulez pas les cas de la classe, afin que le constructeur soit appelé 0 fois.


0 commentaires