Perché non dovremmo usare static protetto in java


Stavo affrontando questa domanda C'è un modo per sovrascrivere le variabili di classe in Java? Il primo commento con 36 upvotes è stato:

Se vedi un protected static, esegui.

Qualcuno può spiegare perché un protected static è disapprovato?

Author: Community, 2014-06-18

8 answers

È più una cosa stilistica che un problema diretto. Suggerisce che non hai pensato correttamente a cosa sta succedendo con la classe.

Pensa a cosa significa static:

Questa variabile esiste a livello di classe, non esiste separatamente per ogni istanza e non ha un'esistenza indipendente in classi che estendono me.

Pensa a cosa significa protected:

Questa variabile può essere vista da questa classe, classi in lo stesso pacchetto e le classi che mi estendono .

I due significati non si escludono esattamente a vicenda ma sono piuttosto vicini.

L'unico caso in cui posso vedere dove potresti usare i due insieme è se avessi una classe astratta progettata per essere estesa e la classe di estensione potrebbe quindi modificare il comportamento usando le costanti definite nell'originale. Anche allora è una ragione molto debole però come sarebbe ancora quasi certamente meglio avere le costanti come pubblico. Ciò rende tutto più pulito e consente alle persone di classificare in modo più flessibile.

Per espandere e spiegare il primo punto, prova questo codice di esempio:

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;
    }
}

Vedrai i risultati:

test
changed

Provate voi stessi a: https://ideone.com/KM8u8O

La classe Test2 è in grado di accedere al membro statico test da Test senza bisogno di qualificare il nome, ma non eredita o ottiene la propria copia. Sta guardando esattamente lo stesso variabile.

 66
Author: Tim B, 2015-11-13 22:49:31

Non è visto di buon occhio perché è contraddittorio.

Creare una variabile protected implica che verrà utilizzata all'interno del pacchetto o sarà ereditata all'interno di una sottoclasse .

Rendere la variabile staticla rende un membro della classe, eliminando le intenzioni di ereditarla. Questo lascia solo l'intenzione di essere usato all'interno di un pacchetto, e abbiamo package-private per quello (nessun modificatore).

L'unica situazione per cui ho potuto trovare questo utile è se si stava dichiarando una classe che dovrebbe essere utilizzata per avviare l'applicazione (come Application#launch di JavaFX e si voleva solo essere in grado di avviare da una sottoclasse. In tal caso, assicurarsi che il metodo sia anche finalper disabilitare nascondendo. Ma questa non è "la norma", ed è stata probabilmente implementata per evitare di aggiungere più complessità aggiungendo un nuovo modo per avviare le applicazioni.

Per vedere i livelli di accesso di ciascun modificatore, vedere questo: Le esercitazioni Java-Controllo dell'accesso ai membri di un Classe

 26
Author: Vince Emigh, 2016-08-04 17:04:28

Non vedo un motivo particolare per cui questo dovrebbe essere visto di buon occhio. Ci possono sempre essere alternative per ottenere lo stesso comportamento e dipenderà dall'effettiva architettura se queste alternative sono "migliori" di un metodo statico protetto o meno. Ma un esempio in cui un metodo statico protetto sarebbe ragionevole, almeno, potrebbe essere il seguente:

(modificato per dividere in pacchetti separati, per rendere più chiaro l'uso di protected)

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;
    }
}

Derivato da ca:

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;
    }
}

Un'altra classe derivata:

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;
    }
}

Il modificatore protected static può certamente essere giustificato qui:

  • I metodi possono essere static, perché non dipendono da variabili di istanza. Non sono destinati ad essere utilizzati direttamente come metodo polimorfico, ma piuttosto sono metodi di "utilità" che offrono implementazioni predefinite che fanno parte di un calcolo più complesso e fungono da "blocchi costitutivi" dell'implementazione effettiva.
  • I metodi dovrebbero non essere public, perché sono un dettaglio di implementazione. E non possono essere private perché dovrebbero essere chiamati dalle classi estendenti. Inoltre, non possono avere visibilità "predefinita", perché non saranno accessibili per le classi di estensione in altri pacchetti.

(EDIT: Si potrebbe supporre che il commento originale si riferisse solo ai campi e non ai metodi - quindi, tuttavia, era troppo generale)

 11
Author: Marco13, 2014-06-18 15:40:43

I membri statici non sono ereditati e i membri protetti sono visibili solo alle sottoclassi (e ovviamente alla classe contenente), quindi a protected static ha la stessa visibilità di static, suggerendo un malinteso da parte del codificatore.

 7
Author: Bohemian, 2014-06-18 15:21:33

Protected viene utilizzato in modo che possa essere utilizzato in sottoclassi. Non c'è logica nel definire una statica protetta quando si utilizza nel contesto di classi concrete in quanto è possibile accedere alla stessa variabile è un modo statico.Tuttavia il complier darà un avviso per accedere alla variabile statica super class in modo statico.

 3
Author: Mithun Kannoth, 2014-06-18 15:38:51

In realtà non c'è nulla di fondamentalmente sbagliato in protected static. Se vuoi davvero una variabile statica o un metodo visibile per il pacchetto e tutte le sottoclassi della classe dichiarante, vai avanti e fallo protected static.

Alcune persone generalmente evitano di usare protected per vari motivi e alcune persone pensano che le variabili static non definitive dovrebbero essere evitate con tutti i mezzi (personalmente simpatizzo con quest'ultimo in una certa misura), quindi immagino che la combinazione di protected e static debba guardare bad^2 a quelli che appartengono a entrambi i gruppi.

 3
Author: x4u, 2014-06-18 22:44:52

Non c'è niente di sbagliato nell'avere protected static. Una cosa che molte persone stanno trascurando è che potresti voler scrivere casi di test per metodi statici che non vuoi esporre in circostanze normali. Ho notato che questo è particolarmente utile per scrivere test per il metodo statico nelle classi di utilità.

 0
Author: Aelphaeis, 2016-07-05 15:34:02

Bene, come la maggior parte della gente ha risposto:

  • protected significa - ' pacchetto - privato + visibilità alle sottoclassi - la proprietà / il comportamento è EREDITATO '
  • static significa- ' l'opposto dell'istanza - è una proprietà/comportamento di CLASSE, CIOÈ NON è EREDITATA '

Pertanto sono leggermente contraddittori e incompatibili.

Tuttavia, recentemente sono arrivato a un caso d'uso in cui potrebbe avere senso usare questi due insieme. Immagina di voler creare un abstract classe che è un genitore per immutabile tipi e ha un sacco di proprietà che sono comuni ai sottotipi. Per implementare immutabilità correttamente e mantenere leggibilità si potrebbe decidere di utilizzare il modello 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;
    }
}

E perché protected static ? Perché voglio un sottotipo non astratto di AbstactType che implementa il proprio costruttore non astratto e si trova all'esterno di package X per essere in grado di accedere e riutilizzare il BaseBuilder.

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;
    }
}

Naturalmente possiamo rendere pubblico il BaseBuilder ma poi arriviamo ad altre dichiarazioni contraddittorie:

  • Abbiamo una classe non istanziabile (abstract)
  • Forniamo un costruttore pubblico per esso

Quindi in entrambi i casi con protected static e public costruttore di un abstract class combiniamo dichiarazioni contraddittorie. È una questione di preferenze personali.

Tuttavia, preferisco ancora il public costruttore di un abstract class perché il protected static per me si sente più innaturale in un mondo OOD e OOP !

 0
Author: egelev, 2018-09-06 08:29:40