CodeGym/Java-Blog/Random-DE/Feste Werte in Java: endgültig, konstant und unveränderli...
Autor
Aditi Nawghare
Software Engineer at Siemens

Feste Werte in Java: endgültig, konstant und unveränderlich

Veröffentlicht in der Gruppe Random-DE
Hallo! Sie kennen das Wort „Modifikator“ bereits. Zumindest sind Sie auf Zugriffsmodifikatoren (öffentlich, privat) und den statischen Modifikator gestoßen. Heute besprechen wir einen speziellen Modifikator namens final. Man könnte sagen, der letzte Modifikator „zementiert“ Teile unseres Programms, in denen konstante, eindeutige und unveränderliche Verhaltensweisen erforderlich sind. Es gibt drei Stellen in Ihren Programmen, an denen Sie es verwenden können: Klassen, Methoden und Variablen. Feste Werte in Java: endgültig, konstant und unveränderlich – 2 Lassen Sie uns sie der Reihe nach durchgehen. Wenn der letzte Modifikator in einer Klassendeklaration verwendet wird, bedeutet dies, dass die Klasse nicht vererbt werden kann. In den vorherigen Lektionen haben wir ein einfaches Vererbungsbeispiel verwendet: Wir hatten eine Animalübergeordnete Klasse und zwei untergeordnete Klassen: CatundDog
public class Animal {
}



public class Cat extends Animal {
   // Fields and methods of the Cat class
}


public class Dog extends Animal {

   // Fields and methods of the Dog class
}
Wenn wir jedoch den finalen Modifikator für die AnimalKlasse verwenden, können die Klassen Catund Dogihn nicht erben.
public final class Animal {

}

public class Cat extends Animal {

   // Error! Cannot inherit from final Animal
}
Der Compiler generiert sofort einen Fehler. In Java sind viele finale Klassen bereits implementiert. Unter denen, die Sie häufig verwenden, Stringist die bekannteste. Wenn außerdem eine Klasse als final deklariert wird , werden auch alle Methoden der Klasse zu final . Was bedeutet das? Wenn eine Methode mit dem finalen Modifikator deklariert wird, können Sie diese Methode nicht überschreiben. Hier haben wir zum Beispiel eine AnimalKlasse, die eine Methode deklariert speak(). Aber Hunde und Katzen „sprechen“ definitiv auf unterschiedliche Weise. Wir deklarieren also sowohl in den Klassen Catals auch speak()-Methoden Dog, implementieren sie jedoch unterschiedlich.
public class Animal {

   public void speak() {
       System.out.println("Hello!");
   }
}

public class Cat extends Animal {

   @Override
   public void speak() {
       System.out.println("Meow!");
   }
}

public class Dog extends Animal {

   @Override
   public void speak() {
       System.out.println("Woof!");
   }
}
Wir haben dafür gesorgt, dass die Klassen Catund Dogdie in der übergeordneten Klasse deklarierte Methode überschreiben. Nun wird ein Tier unterschiedlich sprechen, je nachdem, um welche Art von Objekt es sich handelt:
public class Main {

   public static void main(String[] args) {

       Cat cat = new Cat();
       Dog dog = new Dog();

       cat.speak();
       dog.speak();
   }
}
Ausgabe: Miau! Schuss! Wenn wir jedoch die Methode Animalder Klasse speak()als final deklarieren, können wir sie in anderen Klassen nicht überschreiben:
public class Animal {

   public final void speak() {
       System.out.println("Hello!");
   }
}


public class Cat extends Animal {

   @Override
   public void speak() {// Error! A final method can't be overridden!
       System.out.println("Meow!");
   }
}
Und unsere Objekte werden gezwungen, die speak()in der übergeordneten Klasse definierte Methode zu verwenden:
public static void main(String[] args) {

   Cat cat = new Cat();
   Dog dog = new Dog();

   cat.speak();
   dog.speak();
}
Ausgabe: Hallo! Hallo! Nun zu den endgültigen Variablen. Sie werden auch als Konstanten bezeichnet . Erstens (und am wichtigsten) kann der einem konstanten Wert zugewiesene Anfangswert nicht geändert werden. Es wird ein für alle Mal vergeben.
public class Main {

   private static final int CONSTANT_EXAMPLE = 333;

   public static void main(String[] args) {

       CONSTANT_EXAMPLE = 999;// Error! You can't assign a new value to a final variable!
   }
}
Eine Konstante muss nicht sofort initialisiert werden. Das kann man später machen. Der ihm ursprünglich zugewiesene Wert bleibt jedoch für immer derselbe.
public static void main(String[] args) {

   final int CONSTANT_EXAMPLE;

   CONSTANT_EXAMPLE = 999;// This is allowed
}
Zweitens notieren Sie sich den Namen unserer Variablen. Java hat eine andere Namenskonvention für Konstanten. Es handelt sich nicht um die übliche CamelCase- Notation. Wäre es eine gewöhnliche Variable gewesen, hätten wir sie „constantExample“ genannt. Die Namen von Konstanten werden jedoch in Großbuchstaben geschrieben, mit Unterstrichen zwischen den Wörtern (wenn mehr als ein Wort vorhanden ist), z. B. „CONSTANT_EXAMPLE“. Warum brauchen wir Konstanten? Sie sind sehr nützlich, wenn es beispielsweise einen festen Wert gibt, den Sie regelmäßig in einem Programm verwenden. Du hast zum Beispiel beschlossen, Geschichte zu schreiben und das Spiel „The Witcher 4“ selbst zu schreiben. Das Spiel wird natürlich regelmäßig den Namen des Protagonisten verwenden: „Geralt von Riva“. Diese Zeichenfolge (und die Namen anderer Helden) wird am besten als Konstante deklariert: Ihr Wert wird an einem Ort gespeichert, und Sie werden definitiv keinen Tippfehler machen, wenn Sie ihn millionenfach eingeben.
public class TheWitcher4 {

   private static final String GERALT_NAME = "Geralt of Rivia";
   private static final String YENNEFER_NAME = "Yennefer of Wengerberg";
   private static final String TRISS_NAME = "Triss Merigold";

   public static void main(String[] args) {

       System.out.println("The Witcher 4");
       System.out.println("It's already the fourth Witcher game, but " + GERALT_NAME + " still can't decide who" +
               " he likes more: " + YENNEFER_NAME + " or " + TRISS_NAME);

       System.out.println("But, if you've never played The Witcher before, we'll start from the beginning.");
       System.out.println("The protagonist's name is " + GERALT_NAME);
       System.out.println(GERALT_NAME + " is a witcher, a monster hunter");
   }
}
Ausgabe: The Witcher 4 Es ist bereits das vierte Witcher-Spiel, aber Geralt von Rivia kann sich immer noch nicht entscheiden, wen er mehr mag: Yennefer von Wengerberg oder Triss Merigold. Wenn Sie jedoch noch nie The Witcher gespielt haben, beginnen wir mit dem Anfang. Der Name des Protagonisten ist Geralt von Rivia. Geralt von Rivia ist ein Hexer, ein Monsterjäger. Wir haben die Namen der Helden zu Konstanten erklärt. Jetzt werden wir definitiv keinen Tippfehler mehr machen und es ist nicht nötig, sie jedes Mal von Hand aufzuschreiben. Ein weiterer Pluspunkt: Wenn wir jemals den Wert der Variablen im gesamten Programm ändern müssen, können Sie dies an einer Stelle tun, anstatt ihn manuell in der gesamten Codebasis zu ändern. :) :)

Unveränderliche Typen

Da Sie mit Java gearbeitet haben, haben Sie sich wahrscheinlich bereits an die Vorstellung gewöhnt, dass Programmierer nahezu vollständige Kontrolle über den Zustand aller Objekte haben. Wenn Sie ein Objekt erstellen möchten Cat, können Sie dies tun. Wenn Sie es umbenennen möchten, können Sie dies tun. Wenn Sie das Alter oder etwas anderes ändern möchten, können Sie dies tun. Aber Java verfügt über mehrere Datentypen, die über eine besondere Eigenschaft verfügen. Sie sind unveränderlich . Wenn eine Klasse unveränderlich ist, kann der Status ihrer Objekte nicht geändert werden. Möchten Sie einige Beispiele? Es mag Sie überraschen, aber die bekannteste unveränderliche Klasse ist String! Wir können den Wert eines Strings also wirklich nicht ändern? Naja, probieren wir es mal:
public static void main(String[] args) {

   String str1 = "I love Java";

   String str2 = str1;// Both reference variables point to the same string.
   System.out.println(str2);

   str1 = "I love Python";// but changing str1 has no impact on str2
   System.out.println(str2);// str2 continues to point to the "I love Java" string, but str1 now points to a different object
}
Ausgabe: Ich liebe Java. Ich liebe Java. Nachdem wir geschrieben haben
str1 = "I love Python";
Das "I love Java"String-Objekt hat sich nicht geändert oder ist nirgendwo hingegangen. Es existiert glücklicherweise immer noch und hat genau den gleichen Text wie zuvor. Der Code
str1 = "I love Python";
habe einfach ein weiteres Objekt erstellt, auf das str1 nun zeigt. Aber wir können anscheinend keinen Einfluss auf das String-Objekt „I love Java“ haben. Okay, lass uns etwas anderes ausprobieren! Die StringKlasse ist voller Methoden und einige von ihnen scheinen den Zustand des Objekts zu ändern! Es gibt zum Beispiel eine replace()Methode. Lassen Sie uns in unserem String das Wort „Java“ in „Python“ ändern!
public static void main(String[] args) {

   String str1 = "I love Java";

   String str2 = str1;// Both reference variables point to the same string.
   System.out.println(str2);

   str1.replace("Java", "Python");// We try to change the state of str1 by swapping the word "Java" with "Python"
   System.out.println(str2);
}
Ausgabe: Ich liebe Java. Ich liebe Java. Es hat wieder nicht funktioniert! Vielleicht funktioniert die Ersetzungsmethode nicht? Versuchen wir etwas anderes. Zum Beispiel substring(). Es gibt eine Teilzeichenfolge zurück, die auf als Argumenten übergebenen Zeichenindizes basiert. Schneiden wir die ersten 10 Zeichen unserer Zeichenfolge ab:
public static void main(String[] args) {

   String str1 = "I love Java";

   String str2 = str1;// Both reference variables point to the same string.
   System.out.println(str2);

   str1.substring(10);// Truncate the original String
   System.out.println(str2);
}
Ausgabe: Ich liebe Java. Ich liebe Java. Feste Werte in Java: endgültig, konstant und unveränderlich – 3 Es hat sich nichts geändert. Und das hätte auch nicht der Fall sein sollen. Wie wir bereits sagten, sind Strings unveränderlich. Was ist also mit all den Methoden in der StringKlasse? Schließlich können sie Zeichenfolgen abschneiden, Zeichen ändern und mehr. Was nützt es, wenn nichts passiert? Sie können diese Dinge tatsächlich tun! Sie geben jedoch jedes Mal einen neuen String zurück. Es ist sinnlos zu schreiben
str1.replace("Java", "Python");
weil Sie das ursprüngliche Objekt nicht ändern können. Wenn Sie jedoch das Ergebnis der Methode in eine neue Referenzvariable schreiben, werden Sie den Unterschied sofort sehen!
public static void main(String[] args) {

   String str1 = "I love Java";

   String str2 = str1;// Both reference variables point to the same string.
   System.out.println(str2);

   String str1AfterReplacement =  str1.replace("Java", "Python");
   System.out.println(str2);

   System.out.println(str1AfterReplacement);
}
Alle StringMethoden funktionieren auf diese Weise. Am "I love Java"Objekt kann nichts gemacht werden. Sie können einfach ein neues Objekt erstellen und schreiben: „<neues Objekt> = das Ergebnis der Manipulation von "I love Java" object ". Welche anderen Typen sind unveränderlich? Einige, die Sie sich unbedingt sofort merken müssen, sind alle Wrapper-Klassen für die primitiven Typen. IntegerByte, Character, Short, Boolean, Long, Double, Float: Alle diese Klassen erstellen immutableObjekte (wir werden in den kommenden Lektionen darüber sprechen). Dazu gehören Klassen, die zum Erstellen großer Zahlen verwendet werden, wie z. B. BigIntegerund. Wir haben kürzlich Ausnahmen behandelt und den Stack-TraceBigDecimal angesprochen . Nun raten Sie mal, java.lang.StackTraceElementObjekte sind ebenfalls unveränderlich. Das macht Sinn: Wenn jemand die Daten unseres Stacks ändern könnte, würde das die ganze Sache sinnlos machen. Stellen Sie sich vor, jemand geht den Stack-Trace durch und ändert einen OutOfMemoryError in einen FileNotFoundException . Und dann verwenden Sie diesen Stapel, um die Fehlerursache zu finden. Aber das Programm verwendet nicht einmal Dateien. :) Also haben sie diese Objekte für alle Fälle unveränderlich gemacht. Okay, für StackTraceElement macht es also mehr oder weniger Sinn . Aber warum sollte jemand Strings unveränderlich machen müssen? Warum sollte es ein Problem sein, ihre Werte zu ändern? Es wäre wahrscheinlich sogar bequemer. :/ Dafür gibt es mehrere Gründe. Erstens spart es Speicherplatz. Im String-Pool können unveränderliche Strings platziert werden, sodass Zeichenfolgen wiederverwendet werden können, anstatt neue zu erstellen. Zweitens aus Sicherheitsgründen. Beispielsweise sind Benutzernamen und Passwörter in fast jedem Programm Strings. Die Möglichkeit, sie zu ändern, könnte zu Berechtigungsproblemen führen. Es gibt noch andere Gründe, aber unsere Java-Studie hat sie noch nicht abgedeckt, deshalb werden wir später darauf zurückkommen.
Kommentare
  • Beliebt
  • Neu
  • Alt
Du musst angemeldet sein, um einen Kommentar schreiben zu können
Auf dieser Seite gibt es noch keine Kommentare