CodeGym/Blog Java/Random-PL/Stałe wartości w Javie: ostateczne, stałe i niezmienne
Autor
Aditi Nawghare
Software Engineer at Siemens

Stałe wartości w Javie: ostateczne, stałe i niezmienne

Opublikowano w grupie Random-PL
Cześć! Znasz już słowo „modyfikator”. Jako minimum napotkałeś modyfikatory dostępu (publiczne, prywatne) i modyfikator statyczny. Dzisiaj omówimy specjalny modyfikator o nazwie final . Można powiedzieć, że ostateczny modyfikator „scementuje” części naszego programu, w których potrzebne są stałe, jednoznaczne, niezmienne zachowania. Istnieją trzy miejsca w twoich programach, w których możesz go używać: klasy, metody i zmienne. Stałe wartości w Javie: ostateczne, stałe i niezmienne - 2 Przejrzyjmy je po kolei. Jeśli modyfikator final jest używany w deklaracji klasy, oznacza to, że klasa nie może być dziedziczona. W poprzednich lekcjach użyliśmy prostego przykładu dziedziczenia: mieliśmy Animalklasę nadrzędną i dwie klasy podrzędne: CatiDog
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
}
Jeśli jednak użyjemy modyfikatora final w Animalklasie, klasy Cati Dognie mogą go dziedziczyć.
public final class Animal {

}

public class Cat extends Animal {

   // Error! Cannot inherit from final Animal
}
Kompilator natychmiast generuje błąd. W Javie zaimplementowano już wiele klas końcowych . Wśród tych, których często używasz, Stringjest najbardziej znany. Co więcej, jeśli klasa jest zadeklarowana jako final , wszystkie metody klasy również stają się final . Co to znaczy? Jeśli metoda jest zadeklarowana przy użyciu modyfikatora final , nie można jej zastąpić. Na przykład tutaj mamy Animalklasę, która deklaruje speak()metodę. Ale psy i koty zdecydowanie „mówią” na różne sposoby. Tak więc zadeklarujemy metody speak() zarówno w klasach Catjak i Dog, ale zaimplementujemy je w inny sposób.
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!");
   }
}
Sprawiliśmy, że klasy Cati Dognadpisują metodę zadeklarowaną w klasie nadrzędnej. Teraz zwierzę będzie mówić inaczej, w zależności od rodzaju obiektu:
public class Main {

   public static void main(String[] args) {

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

       cat.speak();
       dog.speak();
   }
}
Wyjście: Miau! Wątek! Jeśli jednak zadeklarujemy metodę Animalklasy speak()jako final, to nie możemy jej przesłonić w innych klasach:
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!");
   }
}
A nasze obiekty będą zmuszone do użycia speak()metody zdefiniowanej w klasie nadrzędnej:
public static void main(String[] args) {

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

   cat.speak();
   dog.speak();
}
Wyjście: Cześć! Cześć! A teraz odnośnie zmiennych końcowych . Są one również znane jako stałe . Po pierwsze (i najważniejsze), wartość początkowa przypisana do wartości stałej nie może zostać zmieniona. Jest przypisany raz na zawsze.
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!
   }
}
Stała nie musi być natychmiast inicjowana. To można zrobić później. Ale początkowo przypisana mu wartość pozostanie taka sama na zawsze.
public static void main(String[] args) {

   final int CONSTANT_EXAMPLE;

   CONSTANT_EXAMPLE = 999;// This is allowed
}
Po drugie, zanotuj nazwę naszej zmiennej. Java ma inną konwencję nazewnictwa dla stałych. To nie jest zwykła notacja camelCase . Gdyby była to zwykła zmienna, nazwalibyśmy ją fixedExample. Ale nazwy stałych są pisane wielkimi literami, z podkreśleniami między słowami (jeśli występuje więcej niż jedno słowo), np. "CONSTANT_EXAMPLE". Dlaczego potrzebujemy stałych? Są bardzo przydatne, jeśli na przykład istnieje stała wartość, której regularnie używasz w programie. Na przykład zdecydowałeś się przejść do historii i sam napisać grę „Wiedźmin 4”. Gra oczywiście będzie regularnie używać imienia głównego bohatera: „Geralt z Rivii”. Ten ciąg (i imiona innych bohaterów) najlepiej zadeklarować jako stałą: jego wartość będzie przechowywana w jednym miejscu i na pewno nie popełnisz literówki wpisując go milion razy.
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");
   }
}
Produkcja: Wiedźmin 4 To już czwarta gra o Wiedźminie, ale Geralt z Rivii nadal nie może się zdecydować, kogo bardziej lubi: Yennefer z Wengerbergu czy Triss Merigold Ale jeśli nigdy wcześniej nie grałeś w Wiedźmina, zaczniemy od początek. Bohater ma na imię Geralt z Rivii Geralt z Rivii jest wiedźminem, łowcą potworów Imiona bohaterów zadeklarowaliśmy jako stałe. Teraz na pewno nie popełnimy literówki i nie ma potrzeby za każdym razem wpisywać ich ręcznie. Kolejny plus: jeśli kiedykolwiek będziemy musieli zmienić wartość zmiennej w całym programie, możesz to zrobić w jednym miejscu, zamiast ręcznie modyfikować ją w całej bazie kodu. :)

Niezmienne typy

Pracując z Javą, prawdopodobnie przyzwyczaiłeś się już do myśli, że programiści mają prawie całkowitą kontrolę nad stanem wszystkich obiektów. Jeśli chcesz utworzyć Catobiekt, możesz. Jeśli chcesz zmienić jego nazwę, możesz to zrobić. Jeśli chcesz zmienić jego wiek lub coś innego, możesz. Ale Java ma kilka typów danych, które mają specjalną właściwość. Są niezmienne . Jeśli klasa jest niezmienna, stan jej obiektów nie może zostać zmieniony. Chcesz kilka przykładów? Może cię to zaskoczyć, ale najbardziej znaną niezmienną klasą jest String! Więc naprawdę nie możemy zmienić wartości ciągu znaków? Cóż, spróbujmy:
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
}
Wyjście: Kocham Javę Kocham Javę Po tym, jak napisaliśmy
str1 = "I love Python";
obiekt "I love Java"string nie zmienił się ani nie poszedł nigdzie. Nadal szczęśliwie istnieje i ma dokładnie ten sam tekst co poprzednio. Kod
str1 = "I love Python";
po prostu stworzył kolejny obiekt, na który teraz wskazuje str1 . Ale wydaje się, że nie możemy mieć żadnego wpływu na obiekt łańcuchowy „Kocham Javę”. Dobra, spróbujmy czegoś innego! Klasa Stringjest pełna metod, a niektóre z nich wydają się zmieniać stan obiektu! Na przykład istnieje replace()metoda. Zmieńmy słowo „Java” na „Python” w naszym łańcuchu!
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);
}
Wynik: Kocham Javę Kocham Javę Znowu nie zadziałało! Może metoda zamiany nie działa? Spróbujmy czegoś innego. na przykład substring(). Zwraca podłańcuch na podstawie indeksów znaków przekazanych jako argumenty. Odetnijmy pierwsze 10 znaków naszego ciągu:
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);
}
Wynik: Kocham Javę Kocham Javę Stałe wartości w Javie: ostateczne, stałe i niezmienne - 3 Nic się nie zmieniło. A nie powinno. Jak powiedzieliśmy wcześniej, łańcuchy są niezmienne. Więc o co chodzi ze wszystkimi metodami w Stringklasie? W końcu mogą obcinać ciągi znaków, zmieniać znaki i nie tylko. Jaki jest sens, jeśli nic się nie dzieje? Oni naprawdę potrafią takie rzeczy! Ale za każdym razem zwracają nowy ciąg. Nie ma sensu pisać
str1.replace("Java", "Python");
ponieważ nie możesz zmienić oryginalnego obiektu. Ale jeśli zapiszesz wynik metody do nowej zmiennej referencyjnej, natychmiast zobaczysz różnicę!
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);
}
Wszystkie Stringmetody działają w ten sposób. Nic nie można zrobić z "I love Java"obiektem. Możesz po prostu utworzyć nowy obiekt i napisać: „<nowy obiekt> = wynik manipulowania "I love Java" object ". Jakie inne typy są niezmienne? Niektóre, o których zdecydowanie musisz od razu pamiętać, to wszystkie klasy opakowujące dla typów pierwotnych. Integer, Byte, Character, Short, Boolean, Long, Double, Float: wszystkie te klasy tworzą immutableobiekty (porozmawiamy o nich w następnych lekcjach). Obejmuje to klasy używane do tworzenia dużych liczb, takich jak BigIntegeri BigDecimal. Niedawno omówiliśmy wyjątki i dotknęliśmy śladu stosu . Cóż , zgadnij co, java.lang.StackTraceElementobiekty są również niezmienne. Ma to sens: gdyby ktoś mógł zmienić dane naszego stosu, cała sprawa byłaby bezcelowa. Wyobraź sobie, że ktoś przegląda ślad stosu i zmienia OutOfMemoryError na FileNotFoundException . A następnie używasz tego stosu, aby znaleźć przyczynę błędu. Ale program nawet nie używa plików. :) Tak więc, na wszelki wypadek, uczynili te obiekty niezmiennymi. Okej, więc mniej więcej ma to sens dla StackTraceElement . Ale dlaczego ktoś miałby czynić ciągi niezmiennymi? Dlaczego zmiana ich wartości miałaby być problemem? Pewnie byłoby to nawet wygodniejsze. :/ Jest ku temu kilka powodów. Po pierwsze oszczędza pamięć. Niezmienne ciągi można umieścić w puli ciągów, umożliwiając ponowne użycie ciągów zamiast tworzenia nowych. Po drugie, dla bezpieczeństwa. Na przykład nazwy użytkowników i hasła są ciągami znaków w prawie każdym programie. Umożliwienie ich zmiany mogłoby spowodować problemy z autoryzacją. Istnieją inne powody, ale nasze badania nad Javą jeszcze ich nie omówiły, więc wrócimy do nich później.
Komentarze
  • Popularne
  • Najnowsze
  • Najstarsze
Musisz się zalogować, aby dodać komentarz
Ta strona nie ma jeszcze żadnych komentarzy