Statische Methoden, Klassen-Variable, Konstante
1. Überblick
Bisher waren alle Elemente, die auf oberster Ebene der Klassendefinition stehen (Attribute, Methoden), jeweils an ein einzelnes, zur Laufzeit erzeugtes Objekt gebunden – entweder an das gerade aktive Objekt (explizit oder implizit mit this
erreichbar) oder an die Objektreferenz eines anderen Objekts gebunden.
Zum Aktivieren schreibt man bekanntlich objektReferenz.attributName
oder objektReferenz.methodenName(..)
, wobei objektReferenz
entweder der Rückgabewert von new Klassenname(..)
, einer Objektvariablen, eines Methodenaufrufes oder im Falle von Strings "… irgendein Text …" sein kann.
Es gibt jedoch Bedarf an Funktionalitäten, die NICHT an ein Objekt gebunden sind.
Für diesen Fall existieren
-
statische Methoden (auch Klassen-Methoden genannt)
-
statische Variable (auch Klassen-Variable genannt)
-
KONSTANTE als wichtige Variation von Klassen-Variablen.
Markant ist das Wort static
am Beginn der Deklaration.
Wichtig für später: Statische Methoden und Variablen sind NICHT Teil des Vererbungskonzepts!
Zugriff von außen erhält man durch Angabe des Klassennamens:
-
MeineKlasse.klassenMethode(..)
-
MeineKlasse.klassenVariable
-
MeineKlasse.KONSTANTE
Innerhalb der selben Klasse ist kein Voranstellen nötig.
Es ist syntaktisch erlaubt, aber sehr schlechter Stil, statische Methoden an Objekten der passenden Klasse aufzurufen.
Ergänzend werden als Abschluss auch die Wrapper-Klassen zu den primitiven Datentypen behandelt.
in Arbeit ...
2. Statische Methoden
Diese können ohne Benutzung einer Objektreferenz aufgerufen werden, können aber logischerweise auch nicht auf Attribute eines Objekts zugreifen, da ja zu keinem einzelnen Objekt eine besondere Bindung besteht – welches individuelle Attribut sollte dann genutzt werden? Stattdessen werden sie an der Klasse aufgerufen: Math.sqrt(9) // liefert 3
Viele solche statischen Methoden finden sich z.B. in der Klasse java.lang.Math, die Berechnungen und Funktionalitäten unterschiedlichster Art bereitstellt – z.B.
static double Math.sqrt(double val)
(Quadratwurzel),
static double Math.sin(double alpha)
(Erklärung siehe z.B. Sinus und Kosinus – Wikipedia) und viele weitere.
3. Main-Methode
"Prominenteste" statische Methode ist vermutlich die Main-Methode.
Sie nimmt eine im Sprach-Design festgelegte Sonderstellung ein:
Sie ist der Ausgangspukt des Progammlaufes (außerhalb von BlueJ!) auf Kommandozeile und in "normalen" IDEs und Programmier-Editoren wie IntelliJ, Eclipse, Netbeans, VisualStudioCode.
Da zu Beginn noch kein Objekt verfügbar ist, muss die main
-Methode statisch sein!
Ihre Signatur ist:
public static void main(String[] args) { /* Methodenrumpf */ }
Programme liefern immer einen numerischen Rückgabewert.
4. Klassen-Variable
Klassenvariable (oder Statische Variable) existieren im Gegensatz zu Instanz-Variablen (für jede Instanz individuell) nur als ein einziger Speicherplatz für die gesamte Klasse. Jede Instanz kann sie gleichermaßen nutzen. Damit können auch Daten zwischen verschiedenen Instanzen der selben Klasse geteilt werden.
Einsatzbereich ist z.B. Instanzen-Erzeugungs-Zählen (im Konstruktor nach Nutzung um 1 erhöhen) oder (analog) Vergabe fortlaufender Nummern.
Weiteres Beispiel: Gemeinsame Nutzung eines externen Objekts durch alle Instanzen einer Klasse.
Sehr sinnvoll ist es auch, Utility-Klassen wie unsere oft genutzte Klasse Util (dzt. v.a. für kompaktere Ausgabe-Methoden (siehe "Utility"-Klassen) als statische Variable zu definieren: private static Util u = new Util();
.
Eine weitere Nutzung ist das Sicherstellen, dass nur ein einziges Objekt einer Klasse verfügbar ist – Singleton-Pattern (Stoff für später).
5. Konstante
Eine Variation des Konzepts der Klassenvariablen sind die Konstanten. Durch Verwendung eines neuen Schlüsselwortes (das auch in anderen ähnlich gearteten Zusammenhängen verwendet wird) final wird die Variable zur Konstanten. D.h. die Wert-Zuweisung muss direkt bei der Deklaration (oder innerhalb eines "Static Initializer" – Stoff für später) erfolgen.
Zur leichten Erkennbarkeit werden sie in ausschließlich Großbuchstaben (ab der 2. Stelle auch Ziffern) benannt. Zur Teilwort-Trennung wird der Unterstrich '_'
verwendet.
Sehr häufig werden Konstante als public
deklariert – sie sind nicht durch "inkompetente Änderung von außen" gefährdet, da sie ja unveränderbar (final
) sind.
Beispiel:
public class Demo1 {
private static Util u = new Util();
public static final String URL_ORF_AT = "https://orf.at";
// oder alternativ:
public static final String URL_SPENGERGASSE; // OHNE sofortige Zuweisung
static { // Static Initializer -
// wird beim Laden der *Klasse* ins Laufzeitsystem ausgeführt
// v.a. für komplexere Initialisierungen
// quasi ein "Konstruktor" für Klassenvariablen
URL_SPENGERGASSE = "https://www.spengergasse.at";
}
public Demo1() {
// Konstruktor-Arbeiten ...
}
public void verwendung() {
u.prn("ORF-Website: " + Demo1.URL_ORF_AT); // 'Demo1.' in eigener Kl. optional!
u.prn("Spengergassen-Website: " + URL_SPENGERGASSE);
u.prn("Die Kreis-Zahl π: " + Math.PI);
}
// ...
}
6. Wrapper-Klassen zu den primitiven Datentypen
Oft wird mehr "Intelligenz" beim Verwenden von Werten benötigt oder bestimmte Datenstrukturen können keine primitiven Datentypen aufnehmen, sondern benötigen Objekte als Inhalt.
Daher gibt es in Java zu jedem "primitiven" Datentyp eine Klasse Wrapper-Klasse (Hüll-Klasse).
Diese Hüll-Klassen (Wrapper-Classes) heißen ähnlich wie die zugeordneten primitiven Typen:
-
int
…Integer
-
long
…Long
-
short
…Short
-
byte
…Byte
-
char
…Character
-
boolean
…Boolean
-
float
…Float
-
double
…Double
Sehr oft kann der Compiler bei Bedarf automatisch zwischen primitivem Typ und Wrapper-Objekt konvertieren. Das heißt für primitiv → Wrapper: "Autoboxing", für Wrapper → primitiv: "Unboxing". Die genauen Regeln muss man nicht unbedingt auswendig wissen, man sieht es beim Probieren an Compiler-Fehlermeldungen, wenn es nicht klappt.
Es gibt beispielsweise auch Konstante für den kleinsten und größten darstellbaren Wert: Integer.MIN_VALUE
, Short.MAX_VALUE
.
Achtung: bei float
, double
ist MIN_VALUE nicht der negativste Wert, sondern der kleinste von 0 unterscheidbare POSITIVE Wert (also ganz nahe bei 0)
Er wäre daher in Bereichsangaben oft unbeabsichtigt dabei!
Daher z.B. zur Festlegung eines EMPTY_VAL
entweder Float.MAX_VALUE oder – wenn er negativ sein soll – MINUS davor, also:
float mostNegative = -Float.MAX_VALUE;
!
Wrapperklassen bieten auch einige statische Hilfsmethoden, beispielsweise
Umwandlung einer Zahl in einen String:
String intTxt = Integer.toString(42);
Sie bieten auch Möglichkeiten, textuelle Repräsentationen von Zahlen in die binäre, für das Laufzeutsystem direkt verwendbare Form zu konvertieren:
int z = Integer.parseInt("42")
Auch Umwandlung in String-Repräsentation für andere Zahlenbasis:
Integer.toString(int i, int radix); // radix ist Ausgabe-Zahlenbasis