CodeGym /Java blog /Tilfældig /Faste værdier i Java: endelige, konstanter og uforanderli...
John Squirrels
Niveau
San Francisco

Faste værdier i Java: endelige, konstanter og uforanderlige

Udgivet i gruppen
Hej! Du er allerede bekendt med ordet "modifikator". Du har som minimum stødt på adgangsmodifikatorer (offentlige, private) og den statiske modifikator. I dag vil vi diskutere en speciel modifikator kaldet final . Man kan sige, at den sidste modifikator "cementerer" dele af vores program, hvor der er behov for konstant, utvetydig, uforanderlig adfærd. Der er tre steder i dine programmer, du kan bruge det: klasser, metoder og variabler. Faste værdier i Java: endelige, konstanter og uforanderlige - 2 Lad os gennemgå dem i rækkefølge. Hvis den endelige modifikator bruges i en klasseerklæring, betyder det, at klassen ikke kan nedarves. I tidligere lektioner brugte vi et simpelt arveeksempel: vi havde en Animalforældreklasse og to børneklasser: CatogDog

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
}
Men hvis vi bruger den endelige modifikator på Animalklassen, kan klasserne Catog Dogikke arve den.

public final class Animal {

}

public class Cat extends Animal {

   // Error! Cannot inherit from final Animal
}
Compileren genererer straks en fejl. I Java er mange afsluttende klasser allerede implementeret. Blandt dem, du bruger hyppigt, Stringer den mest kendte. Desuden, hvis en klasse erklæres som endelig , bliver alle klassens metoder også endelige . Hvad betyder det? Hvis en metode er erklæret ved hjælp af den endelige modifikator, kan du ikke tilsidesætte denne metode. For eksempel har vi her en Animalklasse, der erklærer en speak()metode. Men hunde og katte "taler" bestemt på forskellige måder. Så vi vil erklære speak() metoder i både klasserne Catog Dog, men vi implementerer dem anderledes.

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!");
   }
}
Vi fik klasserne Catog Dogtil at tilsidesætte den metode, der blev erklæret i den overordnede klasse. Nu vil et dyr tale anderledes, afhængigt af hvilken type genstand det er:

public class Main {

   public static void main(String[] args) {

       Cat cat = new Cat();
       Dog dog = new Dog();
      
       cat.speak();
       dog.speak();
   }
}
Output: Mjau! Puha! Men hvis vi erklærer Animalklassens speak()metode som endelig, kan vi ikke tilsidesætte den i andre klasser:

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!");
   }
}
Og vores objekter vil blive tvunget til at bruge speak()metoden som defineret i den overordnede klasse:

public static void main(String[] args) {

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

   cat.speak();
   dog.speak();
}
Output: Hej! Hej! Nu angående endelige variabler. De er også kendt som konstanter . For det første (og vigtigst af alt) kan den initiale værdi, der er tildelt en konstant værdi, ikke ændres. Det tildeles én gang for alle.

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!
   }
}
En konstant behøver ikke initialiseres med det samme. Det kan gøres senere. Men den værdi, der oprindeligt blev tildelt den, forbliver den samme for evigt.

public static void main(String[] args) {

   final int CONSTANT_EXAMPLE;

   CONSTANT_EXAMPLE = 999;// This is allowed
}
For det andet, noter vores variabels navn. Java har en anden navngivningskonvention for konstanter. Det er ikke den sædvanlige camelCase- notation. Hvis det havde været en almindelig variabel, ville vi have kaldt den konstantEksempel. Men navnene på konstanter er skrevet med store bogstaver, med understregninger mellem ordene (hvis der er mere end ét ord), f.eks. "CONSTANT_EXAMPLE". Hvorfor har vi brug for konstanter? De er meget nyttige, hvis der for eksempel er en fast værdi, du jævnligt bruger i et program. For eksempel har du besluttet dig for at skrive historie og selv skrive spillet "The Witcher 4". Spillet vil naturligvis jævnligt bruge hovedpersonens navn: "Geralt of Rivia". Denne streng (og andre heltes navne) er bedst erklæret som en konstant: dens værdi vil blive gemt ét sted, og du vil bestemt ikke lave en tastefejl, når du indtaster den en million gange.

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");
   }
}
Output: The Witcher 4 Det er allerede det fjerde Witcher-spil, men Geralt fra Rivia kan stadig ikke bestemme, hvem han kan lide mere: Yennefer fra Wengerberg eller Triss Merigold Men hvis du aldrig har spillet The Witcher før, starter vi fra starten. Hovedpersonens navn er Geralt af Rivia Geralt af Rivia er en hekser, en monsterjæger. Vi har erklæret heltenes navne som konstanter. Nu laver vi bestemt ikke en tastefejl, og der er ingen grund til at skrive dem ud i hånden hver gang. Et andet plus: Hvis vi nogensinde har brug for at ændre variablens værdi på tværs af hele programmet, kan du gøre det ét sted i stedet for manuelt at ændre det på tværs af hele kodebasen. :)

Uforanderlige typer

Efterhånden som du har arbejdet med Java, har du sikkert allerede vænnet dig til tanken om, at programmører har næsten fuldstændig kontrol over tilstanden af ​​alle objekter. Hvis du vil oprette et Catobjekt, kan du. Hvis du vil omdøbe den, kan du. Hvis du vil ændre dens alder eller noget andet, kan du. Men Java har flere datatyper, der har en særlig egenskab. De er uforanderlige . Hvis en klasse er uforanderlig, kan dens objekters tilstand ikke ændres. Vil du have nogle eksempler? Det kan måske overraske dig, men den mest kendte uforanderlige klasse er String! Så vi kan virkelig ikke ændre en strengs værdi? Nå, lad os prøve det:

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
}
Output: Jeg elsker Java Jeg elsker Java Efter at vi skrev

str1 = "I love Python";
strengobjektet "I love Java"ændrede sig ikke eller gik nogen steder. Den eksisterer heldigvis stadig og har nøjagtig samme tekst som før. Koden

str1 = "I love Python";
simpelthen oprettet et andet objekt, som str1 nu peger på. Men vi kan tilsyneladende ikke have nogen effekt på "I love Java"-strengobjektet. Okay, lad os prøve noget andet! Klassen Stringer fuld af metoder, og nogle af dem ser ud til at ændre objektets tilstand! For eksempel er der en replace()metode. Lad os ændre ordet "Java" til "Python" i vores streng!

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);
}
Output: Jeg elsker Java Jeg elsker Java Det virkede ikke igen! Måske udskiftningsmetoden ikke virker? Lad os prøve noget andet. For eksempel substring(). Det returnerer en understreng baseret på tegnindekser, der er sendt som argumenter. Lad os skære de første 10 tegn af vores streng:

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);
}
Output: Jeg elsker Java Jeg elsker Java Faste værdier i Java: endelige, konstanter og uforanderlige - 3 Intet ændret. Og det burde den ikke have. Som vi sagde tidligere, er strenge uforanderlige. Så hvad er der med alle metoderne i klassen String? De kan trods alt afkorte strenge, ændre tegn og meget mere. Hvad er meningen, hvis der ikke sker noget? De kan faktisk gøre disse ting! Men de returnerer en ny streng hver gang. Det er meningsløst at skrive

str1.replace("Java", "Python");
fordi du ikke kan ændre det originale objekt. Men hvis du skriver metodens resultat til en ny referencevariabel, vil du straks se forskellen!

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 Stringmetoder fungerer på denne måde. Intet kan gøres ved objektet "I love Java". Du kan bare oprette et nyt objekt og skrive: "<nyt objekt> = resultatet af manipulation af "I love Java" object ". Hvilke andre typer er uforanderlige? Nogle, som du helt sikkert skal huske med det samme, er alle indpakningsklasserne for de primitive typer. Integer, Byte, Character, Short, Boolean, Long, Double, Float: alle disse klasser opretter immutableobjekter (vi taler om dem i kommende lektioner). Dette inkluderer klasser, der bruges til at oprette store tal, såsom BigIntegerog BigDecimal. Vi har for nylig dækket undtagelser og berørt stak-sporet . , gæt hvad, java.lang.StackTraceElementobjekter er også uforanderlige. Dette giver mening: Hvis nogen kunne ændre vores staks data, ville det gøre det hele meningsløst. Forestil dig, at nogen gennemgår stak-sporingen og ændrer en OutOfMemoryError til en FileNotFoundException . Og så bruger du den stak til at finde årsagen til fejlen. Men programmet bruger ikke engang filer. :) Så de gjorde disse objekter uforanderlige, for en sikkerheds skyld. Okay, så det giver mere eller mindre mening for StackTraceElement . Men hvorfor skulle nogen have brug for at gøre Strings uforanderlige? Hvorfor skulle det være et problem at ændre deres værdier? Det ville nok endda være mere bekvemt. :/ Det er der flere grunde til. For det første sparer det hukommelse. Uforanderlige strenge kan placeres i strengebassinet, så strenge kan genbruges i stedet for at oprette nye. For det andet for sikkerheden. For eksempel er brugernavne og adgangskoder strenge i næsten alle programmer. At gøre det muligt at ændre dem kan resultere i autorisationsproblemer. Der er andre grunde, men vores undersøgelse af Java har ikke dækket dem endnu, så vi vender tilbage til dem senere.
Kommentarer
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION