400 votes

Ce qui ' s mal avec la méthode substituable appelle dans les constructeurs ?

J’ai une classe de page Wicket qui définit le titre de page en fonction du résultat d’une méthode abstraite.

NetBeans m’avertit avec le message « appel de méthode Overridable constructeur », mais ce qui devrait être mal avec elle ? La seule alternative que j’imagine est de transmettre les résultats des méthodes abstraites dans le cas contraire le constructeur super dans les sous-classes. Mais cela pourrait être difficile à lire avec plusieurs paramètres.

504voto

polygenelubricants Points 136838

Sur l'appel du substituables méthode de constructeurs

Simplement, c'est faux, car il inutilement ouvre des possibilités à de NOMBREUX bugs. Lorsque l' @Override est invoquée, l'état de l'objet peut être incohérente et/ou incomplètes.

Une citation de Efficace Java 2nd Edition, Point 17: Conception et document pour l'héritage, ou bien de l'interdire:

Il y a un peu plus de restrictions qu'une classe doit respecter pour permettre à l'héritage. Les constructeurs ne doivent pas invoquer des méthodes substituables, directement ou indirectement. Si vous ne respectez pas cette règle, le programme de l'échec entraîne. Le constructeur de la superclasse s'exécute avant le constructeur de sous-classe, de sorte que la méthode de remplacement dans la sous-classe d'être invoqués devant la sous-classe constructeur a été exécuté. Si la méthode de remplacement dépend de l'initialisation effectuée par le constructeur de sous-classe, la méthode ne fonctionnera pas comme prévu.

Voici un exemple pour illustrer:

public class ConstructorCallsOverride {
    public static void main(String[] args) {
        abstract class Base {
            Base() { overrideMe(); }
            abstract void overrideMe(); 
        }
        class Child extends Base {
            final int x;
            Child(int x) { this.x = x; }
            @Override void overrideMe() {
                System.out.println(x);
            }
        }
        new Child(42); // prints "0"
    }
}

Ici, lors de l' Base constructeur appelle overrideMe, Child n'a pas terminé l'initialisation de l' final int x, et la méthode renvoie la valeur faux. Ce sera presque certainement entraîner des bugs et erreurs.

Questions connexes

Voir aussi


Sur la construction de l'objet avec de nombreux paramètres

Les constructeurs avec de nombreux paramètres peuvent conduire à une mauvaise lisibilité, et de meilleures alternatives existent.

Voici une citation de Efficace Java 2nd Edition, Article 2: Considérons un générateur de modèle lorsqu'ils sont confrontés à de nombreux paramètres du constructeur:

Traditionnellement, les programmeurs ont utilisé le télescopage constructeur modèle, dans lequel vous fournir un constructeur avec uniquement les paramètres requis, l'autre avec un seul des paramètres optionnels, un troisième avec deux paramètres facultatifs, et ainsi de suite...

Le télescopage constructeur modèle est essentiellement quelque chose comme ceci:

public class Telescope {
    final String name;
    final int levels;
    final boolean isAdjustable;

    public Telescope(String name) {
        this(name, 5);
    }
    public Telescope(String name, int levels) {
        this(name, levels, false);
    }
    public Telescope(String name, int levels, boolean isAdjustable) {       
        this.name = name;
        this.levels = levels;
        this.isAdjustable = isAdjustable;
    }
}

Et maintenant, vous pouvez effectuer les opérations suivantes:

new Telescope("X/1999");
new Telescope("X/1999", 13);
new Telescope("X/1999", 13, true);

Vous ne pouvez pas, cependant, actuellement seulement l' name et isAdjustable, et de quitter levels en cas de défaut. Vous pouvez fournir plus de surcharges de constructeur, mais il est évident que le nombre pourrait exploser alors que le nombre de paramètres de croître, et vous pouvez même avoir plusieurs boolean et int arguments, ce qui serait vraiment faire un gâchis de choses.

Comme vous pouvez le voir, ce n'est pas agréable de modèle à écrire, et encore moins agréable à utiliser (Ce qui n'est "vrai"? Ce qui est de 13 ans?).

Bloch recommande l'utilisation d'un générateur de modèle, ce qui vous permettra d'écrire quelque chose comme ceci à la place:

Telescope telly = new Telescope.Builder("X/1999").setAdjustable(true).build();

Notez que les paramètres sont nommés, et vous pouvez les mettre dans l'ordre que vous voulez, et vous pouvez ignorer ceux que vous souhaitez conserver à des valeurs par défaut. C'est certainement beaucoup mieux que le télescopage les constructeurs, surtout quand il y a un grand nombre de paramètres qui appartiennent à un grand nombre des mêmes types.

Voir aussi

Questions connexes

63voto

Nordic Mainframe Points 13717

Voici un exemple qui permet de comprendre cette:

public class Main {
    static abstract class A {
        abstract void foo();
        A() {
            System.out.println("Constructing A");
            foo();
        }
    }

    static class C extends A {
        C() { 
            System.out.println("Constructing C");
        }
        void foo() { 
            System.out.println("Using C"); 
        }
    }

    public static void main(String[] args) {
        C c = new C(); 
    }
}

Si vous exécutez ce code, vous obtenez le résultat suivant:

Constructing A
Using C
Constructing C

Vous voyez? foo() rend l'utilisation de la C avant le C du constructeur a été exécuté. Si foo() C nécessite d'avoir un état (c'est à dire que le constructeur a fini), puis il va à la rencontre d'un état indéfini en C et les choses pourraient se briser. Et puisque vous ne pouvez pas savoir ce que l'écrasé foo() attend, vous obtenez un avertissement.

12voto

Keats Points 8938

Invoquant une méthode substituable dans le constructeur permet de sous-classes de subvertir le code, donc vous ne peut pas garantir que cela fonctionne plus. C’est pourquoi vous recevez un avertissement.

Dans votre exemple, que se passe-t-il si une sous-classe substitue `` et retourne la valeur null ?

Pour « résoudre » ce problème, vous pouvez utiliser une méthode de fabrique au lieu d’un constructeur, c’est un modèle commun d’instanciation d’objets.

4voto

Manuel Selva Points 5760

Si vous appelez des méthodes dans votre constructeur qui se substituent aux sous-classes, cela signifie que vous êtes moins susceptible de faire référence à des variables qui n’existent pas encore si vous divisez votre initialisation logiquement entre le constructeur et la méthode.

Jetez un oeil sur cet échantillon lien http://www.javapractices.com/topic/TopicAction.do?Id=215

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