CodeGym /Java Blog /Willekeurig /Vaste waarden in Java: definitief, constanten en onverand...
John Squirrels
Niveau 41
San Francisco

Vaste waarden in Java: definitief, constanten en onveranderlijk

Gepubliceerd in de groep Willekeurig
Hoi! U bent al bekend met het woord "modifier". U bent minimaal toegangsmodifiers (openbaar, privé) en de statische modifier tegengekomen. Vandaag bespreken we een speciale modifier genaamd final . Je zou kunnen zeggen dat de laatste modifier delen van ons programma "cementeert" waar constant, ondubbelzinnig, onveranderlijk gedrag nodig is. Er zijn drie plaatsen in uw programma's waar u het kunt gebruiken: klassen, methoden en variabelen. Vaste waarden in Java: definitief, constanten en onveranderlijk - 2 Laten we ze op volgorde doornemen. Als de laatste modifier wordt gebruikt in een klassedeclaratie, betekent dit dat de klasse niet kan worden geërfd. In voorgaande lessen hebben we een eenvoudig overervingsvoorbeeld gebruikt: we hadden een Animalbovenliggende klas en twee onderliggende klassen: CatenDog

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
}
Als we echter de laatste modifier voor de Animalklasse gebruiken, kunnen de klassen Caten Dogdeze niet overerven.

public final class Animal {

}

public class Cat extends Animal {

   // Error! Cannot inherit from final Animal
}
De compiler genereert onmiddellijk een fout. In Java zijn al veel eindklassen geïmplementeerd. Onder degenen die u vaak gebruikt, Stringis de meest bekende. Bovendien, als een klasse als final wordt gedeclareerd , worden alle methoden van de klasse ook final . Wat betekent dat? Als een methode wordt gedeclareerd met behulp van de laatste modifier, kunt u die methode niet overschrijven. Hier hebben we bijvoorbeeld een Animalklasse die een methode declareert speak(). Maar honden en katten "spreken" zeker op verschillende manieren. Dus we declareren speak() methoden in zowel de Caten Dogklassen, maar we zullen ze anders implementeren.

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!");
   }
}
We hebben ervoor gezorgd dat de klassen Caten Dogde methode overschrijven die in de bovenliggende klasse is gedeclareerd. Nu zal een dier anders spreken, afhankelijk van wat voor soort object het is:

public class Main {

   public static void main(String[] args) {

       Cat cat = new Cat();
       Dog dog = new Dog();
      
       cat.speak();
       dog.speak();
   }
}
Uitvoer: Miauw! Inslag! Als we de methode Animalvan de klasse echter speak()als definitief verklaren, kunnen we deze niet overschrijven in andere klassen:

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!");
   }
}
En onze objecten worden gedwongen om de speak()methode te gebruiken zoals gedefinieerd in de bovenliggende klasse:

public static void main(String[] args) {

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

   cat.speak();
   dog.speak();
}
Uitgang: Hallo! Hallo! Nu, met betrekking tot de laatste variabelen. Ze worden ook wel constanten genoemd . Ten eerste (en het belangrijkste) kan de initiële waarde die aan een constante waarde is toegewezen, niet worden gewijzigd. Het wordt voor eens en voor altijd toegewezen.

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!
   }
}
Een constante hoeft niet onmiddellijk te worden geïnitialiseerd. Dat kan achteraf. Maar de waarde die er aanvankelijk aan is toegewezen, blijft voor altijd hetzelfde.

public static void main(String[] args) {

   final int CONSTANT_EXAMPLE;

   CONSTANT_EXAMPLE = 999;// This is allowed
}
Ten tweede, noteer de naam van onze variabele. Java heeft een andere naamgevingsconventie voor constanten. Het is niet de gebruikelijke camelCase- notatie. Als het een gewone variabele was geweest, hadden we het constantExample genoemd. Maar de namen van constanten worden in hoofdletters geschreven, met onderstrepingstekens tussen woorden (als er meer dan één woord is), bijv. "CONSTANT_EXAMPLE". Waarom hebben we constanten nodig? Ze zijn erg handig als er bijvoorbeeld een vaste waarde is die je regelmatig gebruikt in een programma. Je hebt bijvoorbeeld besloten om geschiedenis te schrijven en het spel "The Witcher 4" zelf te schrijven. De game zal uiteraard regelmatig de naam van de hoofdrolspeler gebruiken: "Geralt of Rivia". Deze string (en de namen van andere helden) kan het beste als een constante worden gedeclareerd: de waarde wordt op één plek opgeslagen en je maakt zeker geen typefout als je hem een ​​miljoen keer invoert.

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");
   }
}
Uitvoer: The Witcher 4 Het is al de vierde Witcher-game, maar Geralt of Rivia kan nog steeds niet beslissen wie hij leuker vindt: Yennefer of Wengerberg of Triss Merigold. Maar als je The Witcher nog nooit hebt gespeeld, beginnen we bij de begin. De naam van de hoofdrolspeler is Geralt van Rivia. Geralt van Rivia is een hekser, een monsterjager. We hebben de namen van de helden als constanten verklaard. Nu zullen we zeker geen typefout maken, en het is niet nodig om ze elke keer met de hand op te schrijven. Nog een pluspunt: als we ooit de waarde van de variabele in het hele programma moeten wijzigen, kun je dat op één plek doen, in plaats van het handmatig in de hele codebasis te wijzigen. :)

Onveranderlijke typen

Omdat je met Java hebt gewerkt, ben je waarschijnlijk al gewend geraakt aan het idee dat programmeurs bijna volledige controle hebben over de status van alle objecten. Als je een object wilt maken Cat, kan dat. Als je het wilt hernoemen, kan dat. Als je zijn leeftijd of iets anders wilt veranderen, kan dat. Maar Java heeft verschillende gegevenstypen die een speciale eigenschap hebben. Ze zijn onveranderlijk . Als een klasse onveranderlijk is, kan de status van de objecten niet worden gewijzigd. Wil je wat voorbeelden? Het zal je misschien verbazen, maar de meest bekende onveranderlijke klasse is String! Dus we kunnen de waarde van een String echt niet veranderen? Nou, laten we het proberen:

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
}
Uitvoer: Ik hou van Java Ik hou van Java Nadat we schreven

str1 = "I love Python";
het "I love Java"tekenreeksobject is niet veranderd of is nergens heen gegaan. Het bestaat nog steeds gelukkig en heeft exact dezelfde tekst als voorheen. De code

str1 = "I love Python";
creëerde gewoon een ander object, waar str1 nu naar verwijst. Maar het lijkt erop dat we geen enkel effect hebben op het tekenreeksobject "I love Java". Oké, laten we iets anders proberen! De Stringklasse zit vol met methoden, en sommige lijken de status van het object te veranderen! Er is bijvoorbeeld een replace()methode. Laten we het woord "Java" veranderen in "Python" in onze string!

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);
}
Uitvoer: Ik hou van Java Ik hou van Java Het werkte weer niet! Misschien werkt de vervangmethode niet? Laten we iets anders proberen. Bijvoorbeeld, substring(). Het retourneert een subtekenreeks op basis van tekenindexen die als argumenten zijn doorgegeven. Laten we de eerste 10 tekens van onze string afsnijden:

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);
}
Uitvoer: Ik hou van Java Ik hou van Java Vaste waarden in Java: definitief, constanten en onveranderlijk - 3 Er is niets veranderd. En dat zou niet moeten. Zoals we al eerder zeiden, Strings zijn onveranderlijk. Dus, wat is er met alle methoden in de Stringklas? Ze kunnen immers strings afkappen, karakters veranderen en meer. Wat heeft het voor zin als er niets gebeurt? Ze kunnen deze dingen echt! Maar ze retourneren elke keer een nieuwe string. Het is zinloos om te schrijven

str1.replace("Java", "Python");
omdat je het originele object niet kunt veranderen. Maar als u het resultaat van de methode naar een nieuwe referentievariabele schrijft, ziet u meteen het verschil!

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 werken op deze manier. Aan het object kan niets worden gedaan "I love Java". U kunt gewoon een nieuw object maken en schrijven: "<nieuw object> = het resultaat van het manipuleren van de "I love Java" object ". Welke andere typen zijn onveranderlijk? Sommige die u zeker meteen moet onthouden, zijn alle wrapper-klassen voor de primitieve typen. Integer, Byte, Character, Short, Boolean, Long, Double, Float: al deze klassen maken immutableobjecten (we zullen er in komende lessen over praten). Dit omvat klassen die worden gebruikt om grote getallen te maken, zoals BigIntegeren . We hebben onlangs uitzonderingen behandeld en de stacktraceringBigDecimal besproken . , raad eens, java.lang.StackTraceElementobjecten zijn ook onveranderlijk. Dit is logisch: als iemand de gegevens van onze stapel zou kunnen veranderen, zou het hele ding zinloos worden. Stel je voor dat iemand de stacktracering doorloopt en een OutOfMemoryError verandert in een FileNotFoundException . En dan gebruik je die stapel om de oorzaak van de fout te vinden. Maar het programma gebruikt niet eens bestanden. :) Dus maakten ze deze objecten onveranderlijk, voor het geval dat. Oké, dus het is min of meer logisch voor StackTraceElement . Maar waarom zou iemand Strings onveranderlijk moeten maken? Waarom zou het veranderen van hun waarden een probleem zijn? Het zou waarschijnlijk zelfs handiger zijn. :/ Daar zijn verschillende redenen voor. Ten eerste bespaart het geheugen. Onveranderlijke strings kunnen in de stringpool worden geplaatst, waardoor tekenreeksen kunnen worden hergebruikt in plaats van nieuwe te maken. Ten tweede, voor de veiligheid. Gebruikersnamen en wachtwoorden zijn bijvoorbeeld Strings in bijna elk programma. Het mogelijk maken om ze te wijzigen kan leiden tot autorisatieproblemen. Er zijn andere redenen, maar onze studie van Java heeft ze nog niet behandeld, dus we komen er later op terug.
Opmerkingen
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION