web-dev-qa-db-fra.com

Pourquoi nous ne devrions pas utiliser statique protégé en Java

Je parcourais cette question Y at-il un moyen de remplacer les variables de classe en Java? Le premier commentaire avec 36 votes positifs était:

Si vous voyez un protected static, exécutez.

Quelqu'un peut-il expliquer pourquoi un protected static est-il mal vu?

108
Zeeshan

C'est plus une chose stylistique qu'un problème direct. Cela suggère que vous n'avez pas bien réfléchi à ce qui se passe dans la classe.

Pensez à ce que static signifie:

Cette variable existe au niveau classe, elle n’existe pas séparément pour chaque instance et elle n’a pas d’existence indépendante dans les classes qui me prolongent.

Pensez à ce que protected signifie:

Cette variable peut être vue par cette classe, les classes du même paquet et les classes qui me prolongent.

Les deux sens ne s’excluent pas exactement, mais c’est assez proche.

Le seul cas où je peux voir où vous pourriez utiliser les deux ensemble est si vous aviez une classe abstraite conçue pour être étendue et que la classe étendue pouvait ensuite modifier le comportement à l'aide de constantes définies dans l'original. Même dans ce cas, c’est une raison très faible, mais il est presque certainement préférable d’avoir les constantes publiques. Cela rend simplement tout plus propre et permet aux gens de classer plus de flexibilité.

Pour développer et expliquer le premier point - essayez cet exemple de code:

public class Program {
    public static void main (String[] args) throws Java.lang.Exception {
        System.out.println(new Test2().getTest());
        Test.test = "changed";
        System.out.println(new Test2().getTest());
    }
}

abstract class Test {
    protected static String test = "test";
}

class Test2 extends Test {
    public String getTest() {
        return test;
    }
}

Vous verrez les résultats:

test
changed

Essayez vous-même à: https://ideone.com/KM8u8O

La classe Test2 peut accéder au membre statique test à partir de Test sans avoir besoin de qualifier le nom - mais elle n'hérite pas ni ne reçoit sa propre copie. Il regarde exactement la même variable.

71
Tim B

C'est mal vu parce que c'est contradictoire.

Faire une variable protected implique qu'il sera utilisé dans le package ou il sera hérité dans une sous-classe}.

Rendre la variable static en fait un membre de la classe, en éliminant les intentions d'hériter. Cela ne laisse que l’intention d’être utilisé dans un paquet}, et nous avons package-private pour cela (pas de modificateur).

La seule situation dans laquelle je pourrais trouver cela utile est si vous déclariez une classe qui devrait être utilisée pour lancer l’application (comme le Application#launch de JavaFX et que vous ne pouvez lancer qu’à partir d’une sous-classe. Assurez-vous également que la méthode final pour interdire masquer . Mais ce n'est pas "la norme" et a probablement été implémenté pour éviter d'ajouter plus de complexité en ajoutant une nouvelle façon de lancer des applications.

Pour voir les niveaux d'accès de chaque modificateur, voir ceci: Les tutoriels Java - Contrôler l'accès aux membres d'une classe

26
Vince Emigh

Je ne vois pas de raison particulière pour laquelle cela devrait être mal vu. Il peut toujours y avoir des alternatives pour obtenir le même comportement, et cela dépendra de l’architecture réelle de savoir si ces alternatives sont "meilleures" qu’une méthode statique protégée ou non. Mais un exemple où une méthode statique protégée serait raisonnable, au moins, pourrait être le suivant:

(Edité pour scinder en paquets séparés, pour rendre l'utilisation de protected plus claire)

package a;
import Java.util.List;

public abstract class BaseClass
{
    public Integer compute(List<Integer> list)
    {
        return computeDefaultA(list)+computeDefaultB(list);
    }

    protected static Integer computeDefaultA(List<Integer> list)
    {
        return 12;
    }
    protected static Integer computeDefaultB(List<Integer> list)
    {
        return 34;
    }
}

Dérivé de cela:

package a.b;

import Java.util.List;

import a.BaseClass;

abstract class ExtendingClassA extends BaseClass
{
    @Override
    public Integer compute(List<Integer> list)
    {
        return computeDefaultA(list)+computeOwnB(list);
    }

    private static Integer computeOwnB(List<Integer> list)
    {
        return 56;
    }
}

Une autre classe dérivée:

package a.b;

import Java.util.List;

import a.BaseClass;

abstract class ExtendingClassB extends BaseClass
{
    @Override
    public Integer compute(List<Integer> list)
    {
        return computeOwnA(list)+computeDefaultB(list);
    }

    private static Integer computeOwnA(List<Integer> list)
    {
        return 78;
    }
}

Le modificateur protected static peut certainement être justifié ici:

  • Les méthodes peuvent être static, car elles ne dépendent pas de variables d'instance. Elles ne sont pas destinées à être utilisées directement en tant que méthode polymorphe, mais sont plutôt des méthodes "utilitaires" qui offrent des implémentations implémentées par défaut qui font partie d'un calcul plus complexe et servent de "blocs de construction" de la mise en oeuvre réelle.
  • Les méthodes ne doivent pas être public, car elles constituent un détail d'implémentation. Et ils ne peuvent pas être private car ils devraient être appelés par les classes d'extension. Ils ne peuvent pas non plus avoir une visibilité "par défaut", car ils ne seront alors pas accessibles pour les classes d'extension dans d'autres packages.

(EDIT: On pourrait supposer que le commentaire original ne faisait référence qu'à champs, et non à method - alors, c'était trop général)

11
Marco13

Les membres statiques ne sont pas hérités et les membres protégés ne sont visibles que par les sous-classes (et bien sûr par la classe qui les contient). Ainsi, un protected static a la même visibilité que static, ce qui suggère un malentendu de la part du codeur. 

7
Bohemian

Protected est utilisé pour pouvoir être utilisé dans des sous-classes. Il n'y a aucune logique dans la définition d'une statique protégée lors de l'utilisation dans le contexte de classes concrètes, car vous pouvez accéder à la même variable de manière statique. Cependant, le fournisseur vous avertira qu'il doit accéder à la variable statique de super classe de manière statique.

3
Mithun Kannoth

Eh bien, comme la plupart des gens ont répondu:

  • protected signifie - ' package-private + visibilité sur les sous-classes - la propriété/le comportement est HERHERITED '
  • static signifie - ' l'opposé de l'instance - il s'agit d'une propriété/d'un comportement de CLASS, c'est-à-dire qu'il n'est pas hérité '

Par conséquent, ils sont légèrement contradictoires et incompatibles.

Cependant, récemment, je suis arrivé à un cas d'utilisation où il pourrait être judicieux d'utiliser ces deux ensemble. Imaginez que vous souhaitiez créer unabstractclass qui soit un parent pour immuable types et qu'il possède un ensemble de propriétés communes aux sous-types. Pour mettre en œuvre immutability correctement et conserver lisibilité , on peut décider d’utiliser le modèle Builder .

package X;
public abstract class AbstractType {
    protected Object field1;
    protected Object field2;
    ...
    protected Object fieldN;

    protected static abstract class BaseBuilder<T extends BaseBuilder<T>> {
    private Object field1; // = some default value here
    private Object field2; // = some default value here
    ...
    private Object fieldN; // = some default value here

    public T field1(Object value) { this.field1 = value; return self();}
    public T field2(Object value) { this.field2 = value; return self();}
    ...
    public T fieldN(Object value) { this.fieldN = value; return self();}
    protected abstract T self(); // should always return this;
    public abstract AbstractType build();
    }

    private AbstractType(BaseBuilder<?> b) {
        this.field1 = b.field1;
        this.field2 = b.field2;
        ...
        this.fieldN = b.fieldN;
    }
}

Et pourquoiprotected static? Parce que je veux un sous-type non abstrait de AbstactType qui implémente son propre générateur non abstrait et situé en dehors de package X afin de pouvoir accéder à la BaseBuilder et de la réutiliser.

package Y;
public MyType1 extends AbstractType {
    private Object filedN1;

    public static class Builder extends AbstractType.BaseBuilder<Builder> {
        private Object fieldN1; // = some default value here

        public Builder fieldN1(Object value) { this.fieldN1 = value; return self();}
        @Override protected Builder self() { return this; }
        @Override public MyType build() { return new MyType(this); }
    }

    private MyType(Builder b) {
        super(b);
        this.fieldN1 = b.fieldN1;
    }
}

Bien sûr, nous pouvons rendre public la BaseBuilder, mais nous arrivons ensuite à une autre déclaration contradictoire:

  • Nous avons une classe non-instanciable (abstract)
  • Nous fournissons un constructeur public pour cela

Donc, dans les deux cas avecprotected staticetpublic CONSTRUCTEUR D'UN abstract classnous combinons des déclarations contradictoires. C'est une question de préférences personnelles.

Cependant, je préfère toujours le constructeurpublic D'UN abstract classparce que leprotected staticme semble plus contre nature dans un monde OOD et OOP!

0
egelev

Il n'y a rien de mal à avoir protected static. Une chose que beaucoup de gens oublient, c'est que vous pouvez écrire des cas de test pour des méthodes statiques que vous ne voulez pas exposer dans des circonstances normales. J'ai remarqué que ceci est particulièrement utile pour écrire des tests pour la méthode statique dans les classes d'utilitaires.

0
Aelphaeis