Was macht das Schlüsselwort 'static' in einer Klasse?

444

Um genau zu sein, habe ich diesen Code ausprobiert:

package hello;

public class Hello {

    Clock clock = new Clock();

    public static void main(String args[]) {
        clock.sayTime();
    }
}

Aber es gab den Fehler

Kein Zugriff auf nicht statisches Feld in der statischen Methode main

Also habe ich die Erklärung dahingehend geändert clock:

static Clock clock = new Clock();

Und es hat funktioniert. Was bedeutet es, dieses Schlüsselwort vor die Deklaration zu setzen? Was genau wird es tun und / oder einschränken, was mit diesem Objekt getan werden kann?

Klicken Sie auf Upvote
quelle
Denken Sie noch einmal daran, dass es pro Klasse und CLASSLOADER eine Instanz einer Statik gibt.
Javamann

Antworten:

633

static Mitglieder gehören der Klasse anstelle einer bestimmten Instanz an.

Dies bedeutet, dass nur eine Instanz eines staticFelds vorhanden ist [1], selbst wenn Sie eine Million Instanzen der Klasse erstellen oder keine. Es wird von allen Instanzen geteilt.

Da staticMethoden auch nicht zu einer bestimmten Instanz gehören, können sie nicht auf Instanzmitglieder verweisen. Weiß im angegebenen Beispiel mainnicht, auf welche Instanz der HelloKlasse (und damit auf welche Instanz der ClockKlasse) sie sich beziehen soll. staticMitglieder können sich nur auf staticMitglieder beziehen . Instanzmitglieder können natürlich auf staticMitglieder zugreifen .

Randnotiz: Natürlich statickönnen Mitglieder über eine Objektreferenz auf Instanzmitglieder zugreifen .

Beispiel:

public class Example {
    private static boolean staticField;
    private boolean instanceField;
    public static void main(String[] args) {
        // a static method can access static fields
        staticField = true;

        // a static method can access instance fields through an object reference
        Example instance = new Example();
        instance.instanceField = true;
    }

[1]: Abhängig von den Laufzeitmerkmalen kann es eine pro ClassLoader oder AppDomain oder Thread sein, aber das ist nebensächlich.

Mehrdad Afshari
quelle
5
In .NET können Sie dieses Verhalten auch mithilfe des Attributs [ThreadStatic] ändern, mit dem die statische Aufladung für bestimmte Threads lokalisiert wird.
TheSoftwareJedi
4
Ich weiß, dass dies ein alter Beitrag ist, aber für Anfänger wie mich kann dies hilfreich sein. stackoverflow.com/questions/7026507/…
user3526905
Würden Sie nicht auf instance.instanceField zugreifen können, da es sich um eine private Variable handelt? Oder ist es gültig, weil Sie das Objekt innerhalb seiner eigenen Klasse instanziiert haben? Klingt für mich nach einem rekursiven Albtraum, aber ich bin ein Java-Neuling.
Matt Corby
Wenn das statische Element einer Klasse von zwei verschiedenen Threads referenziert wird, wie viele Instanzen gibt es dann von diesem statischen Element? Ich habe das Gefühl, es ist 2, aber wenn Sie dieselbe Instanz über Threads hinweg möchten, muss das flüchtige Schlüsselwort verwendet werden. Ist das korrekt?
Dan
..und bleibt der Wert erhalten, wenn keine Instanzen der Klasse mehr vorhanden sind?
McKenzm
130

Dies bedeutet, dass es in Hello nur eine Instanz von "clock" gibt, nicht eine für jede einzelne Instanz der "Hello" -Klasse, oder mehr, dass es unter allen Instanzen von eine gemeinsame "clock" -Referenz gibt die "Hallo" Klasse.

Wenn Sie also irgendwo in Ihrem Code ein "neues Hallo" machen würden: A- Im ersten Szenario (vor der Änderung, ohne "statisch" zu verwenden) würde jedes Mal, wenn ein "neues Hallo" aufgerufen wird, eine neue Uhr erstellt. Aber B- im zweiten Szenario (nach der Änderung mit "statisch") würde jede "neue Hallo" -Instanz weiterhin die ursprüngliche und dieselbe "Uhr" -Referenz gemeinsam nutzen und verwenden, die zuerst erstellt wurde.

Wenn Sie nicht irgendwo außerhalb der Hauptleitung eine "Uhr" benötigen, funktioniert dies genauso gut:

package hello;
public class Hello
{
    public static void main(String args[])
    {
      Clock clock=new Clock();
      clock.sayTime();    
    }
}
Paul Tomblin
quelle
Dies ist die üblichere Methode. Die main()Routine sollte in sich geschlossen sein.
Jason S
1
In der zweiten Instanz würde jedes Mal, wenn die Hauptmethode aufgerufen wird, eine neue Instanz von Clock erstellt, oder?
Klicken Sie auf Upvote
2
In der zweiten Instanz, der statischen Uhr, wird sie nur einmal erstellt. In meinem Beispiel, in dem sich die Uhr innerhalb der Hauptleitung befindet, wird sie bei jedem Aufruf der Hauptleitung neu erstellt. Aber normalerweise wird main beim Programmstart nur einmal aufgerufen, und wenn es beendet wird, ist alles frei.
Paul Tomblin
Ich kann nicht verstehen, wie es möglich ist, eine neue Uhr in der Hauptmethode zu erstellen. Wie Sie sagen, würde es jedes Mal neu erstellt, wenn main aufgerufen wird, aber es gibt nur eine Hauptmethode. Wie kann sich diese Hauptmethode auf verschiedene Uhrinstanzen beziehen? Es ist ein wenig schwierig zu verstehen, wie es möglich ist, eine neue Instanz der Uhr in der Hauptinstanz zu erstellen und die Methode sayTime () zu verwenden, aber es ist nicht möglich, die Instanz aus der Hauptinstanz zu erstellen und sayTime () zu verwenden. Wie ist alles frei, wenn main einmal aufgerufen wird? @ PaulTomblin
ShakibaZar
@ user5621266 Ich habe die mainMethode nur verwendet , weil das OP dies tat. Wenn es sich stattdessen um eine öffentliche Methode handelte, die von einer anderen Stelle aufgerufen wurde, und die Hello-Klasse mehr als einmal instanziiert wurde, konnte für jede Hello-Instanz eine Clock-Instanz erstellt werden, sofern diese nicht clockstatisch war.
Paul Tomblin
97

Das staticSchlüsselwort bedeutet, dass etwas (ein Feld, eine Methode oder eine verschachtelte Klasse) eher mit dem Typ als mit einer bestimmten Instanz des Typs zusammenhängt. So ruft man beispielsweise Math.sin(...)ohne Instanz der MathKlasse auf, und tatsächlich kann man keine Instanz der MathKlasse erstellen .

Weitere Informationen finden Sie im entsprechenden Teil des Java-Tutorials von Oracle .


Randnotiz

Mit Java können Sie leider auf statische Mitglieder zugreifen, als wären sie Instanzmitglieder, z

// Bad code!
Thread.currentThread().sleep(5000);
someOtherThread.sleep(5000);

Das sieht so aus, als wäre sleepes eine Instanzmethode, aber es ist tatsächlich eine statische Methode - der aktuelle Thread wird immer in den Ruhezustand versetzt. Es ist besser, dies im aufrufenden Code klar zu machen:

// Clearer
Thread.sleep(5000);
Jon Skeet
quelle
1
Ein weiteres Beispiel: System.out.println () sieht aus wie eine Klassenmethode, ist aber tatsächlich eine Instanzmethode. Da out eine PrintStream-Instanz in der Systemklasse ist.
Jiahui Zhang
@LeslieCheung: Nein, es sieht für mich nicht nach einer Klassenmethode aus, da mir ein Typname System.outnicht gefällt.
Jon Skeet
42

Das staticSchlüsselwort in Java bedeutet, dass die Variable oder Funktion von allen Instanzen dieser Klasse gemeinsam genutzt wird, da sie zum Typ gehört , nicht von den tatsächlichen Objekten selbst.

Wenn Sie also eine Variable haben: private static int i = 0;und sie i++in einer Instanz inkrementieren ( ), wird die Änderung in allen Instanzen wiedergegeben.iwird jetzt in allen Fällen 1 sein.

Statische Methoden können verwendet werden, ohne ein Objekt zu instanziieren.

geowa4
quelle
4
"Zwischen allen Instanzen geteilt" vermittelt den falschen Eindruck, IMO - es deutet darauf hin, dass Sie dies tun müssen eine Instanz des Objekts haben.
Jon Skeet
1
(Während es wirklich keine Instanzen geben muss, weil das statische Feld usw. zum Typ gehört .)
Jon Skeet
@ Jon Skeet statisch gehört zum Typ, nicht zum Objekt? Können Sie mehr Details erzählen? Typ wie Datentyp: int, double, ...?
Truongnm
@truongnm: Geben Sie wie in der Klasse ein, die die Variable / Methode deklariert.
Jon Skeet
26

Grundlegende Verwendung statischer Elemente ...

public class Hello
{
    // value / method
    public static String staticValue;
    public String nonStaticValue;
}

class A
{
    Hello hello = new Hello();
    hello.staticValue = "abc";
    hello.nonStaticValue = "xyz";
}

class B
{
    Hello hello2 = new Hello(); // here staticValue = "abc"
    hello2.staticValue; // will have value of "abc"
    hello2.nonStaticValue; // will have value of null
}

Auf diese Weise können Sie Werte für alle Klassenmitglieder freigeben, ohne die Klasseninstanz Hello an eine andere Klasse zu senden. Und mit statischer Aufladung müssen Sie keine Klasseninstanz erstellen.

Hello hello = new Hello();
hello.staticValue = "abc";

Sie können statische Werte oder Methoden einfach nach Klassennamen aufrufen:

Hello.staticValue = "abc";
Vasil Valchev
quelle
22

Statisch bedeutet, dass Sie keine Instanz der Klasse erstellen müssen, um die der Klasse zugeordneten Methoden oder Variablen zu verwenden. In Ihrem Beispiel könnten Sie anrufen:

Hello.main(new String[]()) //main(...) is declared as a static function in the Hello class

direkt statt:

Hello h = new Hello();
h.main(new String[]()); //main(...) is a non-static function linked with the "h" variable

Innerhalb einer statischen Methode (die zu einer Klasse gehört) können Sie nicht auf Mitglieder zugreifen, die nicht statisch sind, da ihre Werte von Ihrer Instanziierung der Klasse abhängen. Ein nicht statisches Clock-Objekt, das ein Instanzmitglied ist, hat für jede Instanz Ihrer Hello-Klasse einen anderen Wert / eine andere Referenz. Daher können Sie nicht über den statischen Teil der Klasse darauf zugreifen.

Elie
quelle
Tolle Erklärung für den statischen Kontext :)
Abdel-Raouf
20

Statisch in Java:

Static ist ein Modifikator ohne Zugriff. Das statische Schlüsselwort gehört zur Klasse als Instanz der Klasse. kann verwendet werden, um eine Variable oder Methode an eine Klasse anzuhängen.

Das statische Schlüsselwort kann verwendet werden mit:

Methode

Variable

Klasse in einer anderen Klasse verschachtelt

Initialisierungsblock

Kann nicht verwendet werden mit:

Klasse (nicht verschachtelt)

Konstrukteur

Schnittstellen

Methode Lokale innere Klasse (Differenz dann verschachtelte Klasse)

Methoden der inneren Klasse

Instanzvariablen

Lokale Variablen

Beispiel:

Stellen Sie sich das folgende Beispiel mit einer Instanzvariablen namens count vor, die im Konstruktor inkrementiert wurde:

package pkg;

class StaticExample {
    int count = 0;// will get memory when instance is created

    StaticExample() {
        count++;
        System.out.println(count);
    }

    public static void main(String args[]) {

        StaticExample c1 = new StaticExample();
        StaticExample c2 = new StaticExample();
        StaticExample c3 = new StaticExample();

    }
}

Ausgabe:

1 1 1

Da die Instanzvariable zum Zeitpunkt der Objekterstellung den Speicher erhält, verfügt jedes Objekt über die Kopie der Instanzvariablen. Wenn sie inkrementiert wird, wird sie nicht auf andere Objekte übertragen.

Wenn wir nun die Anzahl der Instanzvariablen in eine statische ändern, erzeugt das Programm eine andere Ausgabe:

package pkg;

class StaticExample {
    static int count = 0;// will get memory when instance is created

    StaticExample() {
        count++;
        System.out.println(count);
    }

    public static void main(String args[]) {

        StaticExample c1 = new StaticExample();
        StaticExample c2 = new StaticExample();
        StaticExample c3 = new StaticExample();

    }
}

Ausgabe:

1 2 3

In diesem Fall erhält die statische Variable den Speicher nur einmal. Wenn ein Objekt den Wert der statischen Variablen ändert, behält es seinen Wert bei.

Statisch mit Finale:

Die globale Variable, die als endgültig und statisch deklariert ist, bleibt für die gesamte Ausführung unverändert. Denn statische Elemente werden im Klassenspeicher gespeichert und in der gesamten Ausführung nur einmal geladen. Sie sind allen Objekten der Klasse gemeinsam. Wenn Sie statische Variablen als endgültig deklarieren, kann keines der Objekte seinen Wert ändern, da er endgültig ist. Daher werden als endgültig und statisch deklarierte Variablen manchmal als Konstanten bezeichnet. Alle Felder von Schnittstellen werden als Konstanten bezeichnet, da sie standardmäßig endgültig und statisch sind.

Geben Sie hier die Bildbeschreibung ein

Bildressource: Endgültig statisch

Affy
quelle
15

Lassen Sie mich mit einem Bild versuchen, um vorhandene Antworten zu ergänzen:

Auf ALLE Sparkonten wird ein Zinssatz von 2% angewendet. Daher ist es statisch .

Ein Gleichgewicht sollte individuell sein , damit es nicht statisch ist.

Geben Sie hier die Bildbeschreibung ein

Andrejs
quelle
13

Diese Diskussion hat bisher Überlegungen zum Klassenladeprogramm ignoriert. Genau genommen werden statische Java-Felder von allen Instanzen einer Klasse für einen bestimmten Klassenladeprogramm gemeinsam genutzt .

Julien Chastang
quelle
1
Dies wurde von Apocalisp in den Kommentaren zu Merhdads Antwort erwähnt.
Zach Langley
1
Guter Punkt. Viele Leute wissen das nicht, aber sobald Sie anfangen, sich mit Klassenladern zu beschäftigen, wird es sehr wichtig.
Sleske
2
Dies ist alles wahr, aber es beantwortet die Frage nicht. Es sollte als Kommentar gepostet worden sein.
Marquis von Lorne
7

Ein Feld kann entweder der Klasse oder einer Instanz einer Klasse zugewiesen werden. Standardmäßig sind Felder Instanzvariablen. Durch die Verwendung staticdes Feldes wird eine Klassenvariable, daher gibt es nur eine clock. Wenn Sie Änderungen an einer Stelle vornehmen, ist diese überall sichtbar. Instanzvariablen werden unabhängig voneinander geändert.

sblundy
quelle
6

Das Schlüsselwort staticwird verwendet, um ein Feld oder eine Methode als zur Klasse selbst und nicht zur Instanz gehörend zu bezeichnen. Wenn das Objekt unter Verwendung Ihres Codes Clockstatisch ist, Helloteilen alle Instanzen der Klasse dieses ClockDatenelement (Feld) gemeinsam. Wenn Sie es nicht statisch machen, kann jede einzelne Instanz von Helloein eindeutiges ClockFeld haben.

Das Problem ist, dass Sie Ihrer Klasse eine Hauptmethode hinzugefügt haben Hello, damit Sie den Code ausführen können. Das Problem hierbei ist, dass die Hauptmethode statisch ist und sich daher nicht auf nicht statische Felder oder darin enthaltene Methoden beziehen kann. Sie können dies auf zwei Arten lösen:

  1. Machen Sie alle Felder und Methoden der HelloKlasse statisch, damit auf sie im Hauptverzeichnis verwiesen werden kann werden kann. Dies ist wirklich keine gute Sache (oder der falsche Grund, ein Feld und / oder eine Methode statisch zu machen)
  2. Erstellen Sie eine Instanz Ihrer HelloKlasse in der Hauptmethode und greifen Sie auf alle Felder und Methoden so zu, wie sie ursprünglich vorgesehen waren.

Für Sie bedeutet dies die folgende Änderung Ihres Codes:

package hello;

public class Hello {

    private Clock clock = new Clock();

    public Clock getClock() {
        return clock;
    }

    public static void main(String args[]) {
        Hello hello = new Hello();
        hello.getClock().sayTime();
    }
}
hfontanez
quelle
6

In Java kann das staticSchlüsselwort einfach als Hinweis auf Folgendes angesehen werden:

"ohne Rücksicht oder Beziehung zu einer bestimmten Instanz"

Wenn Sie so denken static, wird es einfacher, seine Verwendung in den verschiedenen Kontexten zu verstehen, in denen es anzutreffen ist:

  • Ein staticFeld ist ein Feld, das eher zur Klasse als zu einer bestimmten Instanz gehört

  • Eine staticMethode ist eine Methode, von der keine Ahnung hat this; Es ist in der Klasse definiert und kennt keine bestimmte Instanz dieser Klasse, es sei denn, eine Referenz wird an sie übergeben

  • Eine staticMitgliedsklasse ist eine verschachtelte Klasse ohne Vorstellung oder Kenntnis einer Instanz ihrer umschließenden Klasse (es sei denn, ihr wird ein Verweis auf eine umschließende Klasseninstanz übergeben).

Scottb
quelle
5

Static macht das Clock-Mitglied zu einem Klassenmitglied anstelle eines Instanzmitglieds. Ohne das statische Schlüsselwort müssten Sie eine Instanz der Hello-Klasse erstellen (die eine Clock-Member-Variable hat) - z

Hello hello = new Hello();
hello.clock.sayTime();
Stephen Doyle
quelle
5

Statische Methoden verwenden keine Instanzvariablen der Klasse, in der sie definiert sind. Eine sehr gute Erklärung des Unterschieds finden Sie auf dieser Seite

Marc Novakowski
quelle
5

Ich habe eine Vorliebe für statische Methoden (nur wenn möglich) in "Helfer" -Klassen entwickelt.

Die aufrufende Klasse muss keine weitere Mitgliedsvariable (Instanzvariable) der Hilfsklasse erstellen. Sie rufen einfach die Methoden der Hilfsklasse auf. Außerdem wird die Hilfsklasse verbessert, da Sie keinen Konstruktor mehr benötigen und keine Mitgliedsvariablen (Instanzvariablen) benötigen.

Es gibt wahrscheinlich andere Vorteile.

javaguy
quelle
4
//Here is an example 

public class StaticClass 
{
    static int version;
    public void printVersion() {
         System.out.println(version);
    }
}

public class MainClass 
{
    public static void main(String args[]) {  
        StaticClass staticVar1 = new StaticClass();
        staticVar1.version = 10;
        staticVar1.printVersion() // Output 10

        StaticClass staticVar2 = new StaticClass();
        staticVar2.printVersion() // Output 10
        staticVar2.version = 20;
        staticVar2.printVersion() // Output 20
        staticVar1.printVersion() // Output 20
    }
}
Mohammad Parvez
quelle
3

Kann auch an statische Mitglieder denken, die keinen "this" -Zeiger haben. Sie werden von allen Instanzen gemeinsam genutzt.

kal
quelle
3

Statische Konzepte verstehen

public class StaticPractise1 {
    public static void main(String[] args) {
        StaticPractise2 staticPractise2 = new StaticPractise2();
        staticPractise2.printUddhav(); //true
        StaticPractise2.printUddhav(); /* false, because printUddhav() is although inside StaticPractise2, but it is where exactly depends on PC program counter on runtime. */

        StaticPractise2.printUddhavsStatic1(); //true
        staticPractise2.printUddhavsStatic1(); /*false, because, when staticPractise2 is blueprinted, it tracks everything other than static  things and it organizes in its own heap. So, class static methods, object can't reference */

    }
}

Zweite Klasse

public class StaticPractise2 {
    public static void printUddhavsStatic1() {
        System.out.println("Uddhav");
    }

    public void printUddhav() {
        System.out.println("Uddhav");
    }
}
Uddhav Gautam
quelle
2

main() ist eine statische Methode, die zwei grundlegende Einschränkungen aufweist:

  1. Die statische Methode kann kein nicht statisches Datenelement verwenden oder eine nicht statische Methode direkt aufrufen.
  2. this()und super()kann nicht im statischen Kontext verwendet werden.

    class A {  
        int a = 40; //non static
        public static void main(String args[]) {  
            System.out.println(a);  
        }  
    }

Ausgabe: Kompilierungszeitfehler

Bharthan
quelle
1

Auf statische Variablen kann nur mit statischen Methoden zugegriffen werden. Wenn wir also die statischen Variablen deklarieren, sind diese Getter- und Setter-Methoden statische Methoden

Statische Methoden sind eine Klassenebene, auf die wir über den Klassennamen zugreifen können

Das Folgende ist ein Beispiel für statische Variablen Getter und Setter:

public class Static 
{

    private static String owner;
    private static int rent;
    private String car;
    public String getCar() {
        return car;
    }
    public void setCar(String car) {
        this.car = car;
    }
    public static int getRent() {
        return rent;
    }
    public static void setRent(int rent) {
        Static.rent = rent;
    }
    public static String getOwner() {
        return owner;
    }

    public static void setOwner(String owner) {
        Static.owner = owner;
    }

}
Bala Krishna
quelle
1

Eine Frage wurde gefragt , hier über die Wahl des Wortes ‚statisch‘ für dieses Konzept. Es wurde auf diese Frage getäuscht, aber ich glaube nicht, dass die Etymologie klar angesprochen wurde. Damit...


Dies liegt an der Wiederverwendung von Schlüsselwörtern, beginnend mit C.

Betrachten Sie Datendeklarationen in C (innerhalb eines Funktionskörpers):

    void f() {
        int foo = 1;
        static int bar = 2;
         :
    }

Die Variable foo wird beim Eingeben der Funktion auf dem Stapel erstellt (und beim Beenden der Funktion zerstört). Im Gegensatz dazu ist die Bar immer vorhanden, daher ist sie im Sinne des üblichen Englisch "statisch" - sie führt nirgendwo hin.

Java und ähnliche Sprachen haben dasselbe Konzept für Daten. Daten können entweder pro Instanz der Klasse (pro Objekt) oder einmal für die gesamte Klasse zugewiesen werden. Da Java eine vertraute Syntax für C / C ++ - Programmierer anstrebt, ist hier das Schlüsselwort 'static' angemessen.

    class C {
        int foo = 1;
        static int bar = 2;
         :
    }

Zuletzt kommen wir zu Methoden.

    class C {
        int foo() { ... }
        static int bar() { ... }
         :
    }

Konzeptionell gibt es für jede Instanz der Klasse C eine Instanz von foo (). Es gibt nur eine Instanz von bar () für die gesamte Klasse C. Dies ist parallel zu dem Fall, den wir für Daten besprochen haben, und verwendet daher 'static' 'ist wieder eine vernünftige Wahl, insbesondere wenn Sie Ihrer Sprache keine reservierteren Schlüsselwörter hinzufügen möchten.

user13068046
quelle