wake-up-neo.net

Warum sollten wir keine geschützte Statik in Java verwenden?

Ich habe diese Frage durchgegangen Gibt es eine Möglichkeit, Klassenvariablen in Java zu überschreiben? Der erste Kommentar mit 36 ​​Upvotes war:

Wenn Sie jemals einen protected static sehen, führen Sie ihn aus.

Kann jemand erklären, warum ein protected static verpönt ist?

108
Zeeshan

Es ist mehr eine stilistische Sache als ein direktes Problem. Es legt nahe, dass Sie sich nicht genau überlegt haben, was mit der Klasse los ist.

Denken Sie darüber nach, was static bedeutet:

Diese Variable existiert auf Klassenebene, sie ist nicht für jede Instanz separat vorhanden und hat keine unabhängige Existenz in Klassen, die mich erweitern.

Denken Sie darüber nach, was protected bedeutet:

Diese Variable kann von dieser Klasse gesehen werden, Klassen im selben Paket und Klassen, die mich erweitern.

Die beiden Bedeutungen schließen sich nicht genau aus, sind aber ziemlich nahe.

Ich kann nur sehen, wo Sie die beiden zusammen verwenden könnten, wenn Sie über eine abstrakte Klasse verfügen, die erweitert werden soll, und die Erweiterungsklasse das Verhalten dann mithilfe der im Original definierten Konstanten ändern kann. Selbst dann ist es ein sehr schwacher Grund, da Sie die Konstanten fast immer noch als öffentlich empfinden würden. Das macht einfach alles sauberer und ermöglicht den Mitarbeitern eine höhere Flexibilität.

Um den ersten Punkt zu erweitern und zu erläutern, versuchen Sie diesen Beispielcode:

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

Sie sehen die Ergebnisse:

test
changed

Probieren Sie es selbst aus: https://ideone.com/KM8u8O

Die Klasse Test2 kann von test aus auf das statische Member Test zugreifen, ohne den Namen qualifizieren zu müssen. Sie erbt jedoch nicht oder erhält keine eigene Kopie. Es betrachtet genau dieselbe Variable.

71
Tim B

Es ist verpönt, weil es widersprüchlich ist.

Das Erstellen einer Variablen protected impliziert, dass sie innerhalb des Pakets verwendet wird oder innerhalb einer Unterklasse geerbt.

Wenn Sie die Variable static machen, wird sie zum Mitglied der Klasse. Eliminiert die Absicht, sie zu erben. Dies lässt nur die Absicht, innerhalb eines Pakets verwendet zu werden, und wir haben package-private dafür (keinen Modifikator).

Die einzige Situation, für die ich dies nützlich finden könnte, ist, wenn Sie eine Klasse deklarieren, die zum Starten der Anwendung verwendet werden soll (wie JavaFXs Application#launch) und nur von einer Unterklasse aus starten möchten final, um hiding nicht zuzulassen. Dies ist jedoch nicht "die Norm" und wurde wahrscheinlich implementiert, um das Hinzufügen von Komplexität durch Hinzufügen einer neuen Methode zum Starten von Anwendungen zu verhindern.

Informationen zu den Zugriffsebenen der einzelnen Modifizierer finden Sie hier: Die Java-Tutorials - Steuern des Zugriffs auf Member einer Klasse

26
Vince Emigh

Ich sehe keinen besonderen Grund, warum dies missbilligt werden sollte. Es kann immer Alternativen geben, um dasselbe Verhalten zu erreichen, und es hängt von der tatsächlichen Architektur ab, ob diese Alternativen "besser" sind als eine geschützte statische Methode oder nicht. Ein Beispiel, bei dem eine geschützte statische Methode zumindest sinnvoll wäre, könnte folgendes sein:

(Zur Aufteilung in separate Pakete bearbeitet, um die Verwendung von protected klarer zu machen)

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

Davon abgeleitet:

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

Eine andere abgeleitete Klasse:

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

Der protected static-Modifikator kann hier sicherlich begründet werden:

  • Die Methoden können static sein, da sie nicht von Instanzvariablen abhängen. Sie sollen nicht direkt als polymorphe Methode verwendet werden, sondern sind "Utility" -Methoden, die standardmäßige Implementierungen bieten, die Teil einer komplexeren Berechnung sind und als "Bausteine" der eigentlichen Implementierung dienen.
  • Die Methoden sollten nicht public sein, da sie ein Implementierungsdetail sind. Sie können nicht private sein, da sie von den Erweiterungsklassen aufgerufen werden sollten. Sie können auch keine "Standardsicht" haben, da sie für die Erweiterungsklassen in anderen Paketen nicht zugänglich sind.

(EDIT: Man könnte davon ausgehen, dass der ursprüngliche Kommentar sich nur aufFelder und nicht auf Methoden bezog - dann war es jedoch zu allgemein)

11
Marco13

Statische Member werden nicht vererbt und geschützte Member sind nur für Unterklassen sichtbar (und natürlich für die enthaltende Klasse). Daher hat ein protected static dieselbe Sichtbarkeit wie static, was auf ein Missverständnis durch den Codierer schließen lässt. 

7
Bohemian

Eigentlich ist mit protected static nichts grundlegend falsch. Wenn Sie wirklich eine statische Variable oder Methode wünschen, die für das Paket und alle Unterklassen der deklarierenden Klasse sichtbar ist, machen Sie es mit protected static.

Einige Leute verwenden generell protected aus verschiedenen Gründen nicht, und manche Leute meinen, nicht endestatic-Variablen sollten unter allen Umständen vermieden werden (ich persönlich sympathisiere bis zu einem gewissen Grad), also denke ich, dass die Kombination von protected und static aussehen muss schlecht ^ 2 zu denen, die zu beiden Gruppen gehören.

4
x4u

Protected wird verwendet, damit es in Unterklassen verwendet werden kann. Es gibt keine Logik beim Definieren einer geschützten Statik, wenn im Kontext konkreter Klassen verwendet wird, da Sie auf dieselbe Variable zugreifen können. Dies geschieht auf statische Weise. Der Complier gibt jedoch eine Warnung aus, um auf die statische Superklasse-Variable statisch zuzugreifen.

3
Mithun Kannoth

Nun, wie die meisten Leute geantwortet haben:

  • protected bedeutet - ' package-private + Sichtbarkeit für Unterklassen - Die Eigenschaft/das Verhalten ist INHERITED '
  • static bedeutet - ' das Gegenteil von Instanz - es handelt sich um eine CLASS-Eigenschaft/ein Verhalten, d. h. es ist NICHT INHERITIERT '

Daher sind sie etwas widersprüchlich und inkompatibel.

Vor kurzem kam ich jedoch zu einem Anwendungsfall, bei dem es sinnvoll sein könnte, diese beiden zusammen zu verwenden. Stellen Sie sich vor, Sie möchten eineabstract-Klasse erstellen, die eine übergeordnete Klasse für immutable types ist, und eine Reihe von Eigenschaften aufweist, die den Untertypen gemeinsam sind. Um Unveränderlichkeit richtig zu implementieren und Lesbarkeit zu erhalten könnte man sich für die Verwendung des Builder - Musters entscheiden.

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

Und warumprotected static? Weil ich möchte, dass ein nicht abstrakter Untertyp von AbstactType, der seinen eigenen nicht abstrakten Builder implementiert und sich außerhalb von package X befindet, auf die BaseBuilder zugreifen und diese wiederverwenden kann.

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

Natürlich können wir die BaseBuilder öffentlich machen, aber dann kommen wir zu anderen widersprüchlichen Aussagen:

  • Wir haben eine nicht instantiierbare Klasse (abstrakt)
  • Wir stellen einen öffentlichen Baumeister dafür zur Verfügung

Also in beiden Fällen mitprotected staticundpublic BUILDER EINES abstract classkombinieren wir widersprüchliche Anweisungen. Es geht um persönliche Vorlieben.

Ich bevorzuge jedoch immer noch denpublic-BUILDER EINES abstract class, weil derprotected staticmir in einer OOD- und OOP - Welt unnatürlicher vorkommt!

0
egelev

Es ist nichts falsch mit protected static. Eine Sache, die viele Leute übersehen, ist, dass Sie Testfälle für statische Methoden schreiben möchten, die Sie unter normalen Umständen nicht zeigen möchten. Ich habe festgestellt, dass dies besonders nützlich ist, um Tests für statische Methoden in Dienstprogrammklassen zu schreiben.

0
Aelphaeis