CodeGym/Java блог/Случаен/Фиксирани стойности в Java: окончателни, константи и неиз...
John Squirrels
Ниво
San Francisco

Фиксирани стойности в Java: окончателни, константи и неизменни

Публикувано в групата
здрасти Вече сте запознати с думата "модификатор". Като минимум сте срещали модификатори за достъп (публичен, частен) и статичния модификатор. Днес ще обсъдим специален модификатор, наречен final . Може да се каже, че крайният модификатор „циментира“ части от нашата програма, където са необходими постоянни, недвусмислени, непроменливи поведения. Във вашите програми можете да го използвате на три места: класове, методи и променливи. Фиксирани стойности в Java: окончателни, константи и неизменни - 2 Нека ги прегледаме по ред. Ако крайният модификатор се използва в декларация на клас, това означава, че класът не може да бъде наследен. В предишните уроци използвахме прост пример за наследяване: имахме Animalродителски клас и два дъщерни класа: CatиDog
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
}
Въпреки това, ако използваме финалния модификатор на Animalкласа, класовете Catand Dogне могат да го наследят.
public final class Animal {

}

public class Cat extends Animal {

   // Error! Cannot inherit from final Animal
}
Компилаторът веднага генерира грешка. В Java много финални класове вече са внедрени. Сред тези, които използвате често, Stringе най-известният. Освен това, ако даден клас е деклариран като final , всички методи на класа също стават final . Какво означава това? Ако даден метод е деклариран с помощта на финалния модификатор, не можете да отмените този метод. Например, тук имаме Animalклас, който декларира speak()метод. Но кучетата и котките определено "говорят" по различни начини. Така че ще декларираме методите speak() и в двата класа Catи Dog, но ще ги имплементираме по различен начин.
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!");
   }
}
Направихме класовете Catи Dogда заместват метода, деклариран в родителския клас. Сега едно животно ще говори по различен начин в зависимост от вида на обекта:
public class Main {

   public static void main(String[] args) {

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

       cat.speak();
       dog.speak();
   }
}
Изход: мяу! Уф! Въпреки това, ако декларираме метода Animalна класа speak()като окончателен, тогава не можем да го заменим в други класове:
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!");
   }
}
И нашите обекти ще бъдат принудени да използват speak()метода, Howто е дефиниран в родителския клас:
public static void main(String[] args) {

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

   cat.speak();
   dog.speak();
}
Изход: Здравейте! Здравейте! Сега по отношение на крайните променливи. Те са известни също като константи . Първо (и най-важното), първоначалната стойност, присвоена на постоянна стойност, не може да бъде променена. Назначава се веднъж завинаги.
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!
   }
}
Константата не трябва да се инициализира незабавно. Това може да стане по-късно. Но първоначално присвоената му стойност ще остане същата завинаги.
public static void main(String[] args) {

   final int CONSTANT_EXAMPLE;

   CONSTANT_EXAMPLE = 999;// This is allowed
}
Второ, забележете името на нашата променлива. Java има различна конвенция за именуване на константи. Това не е обичайната нотация с камилски регистър . Ако беше обикновена променлива, щяхме да я наречем constantExample. Но имената на константите се пишат изцяло с главни букви, с долна черта между думите (ако има повече от една дума), напр. "CONSTANT_EXAMPLE". Защо се нуждаем от константи? Те са много полезни, ако например има фиксирана стойност, която редовно използвате в програма. Например, вие сте решor да направите история и да напишете играта "The Witcher 4" сами. Играта очевидно ще използва редовно името на главния герой: "Geralt of Rivia". Този низ (и имената на други герои) е най-добре да се декларира като константа: стойността му ще се съхранява на едно място и определено няма да направите печатна грешка, когато го въвеждате мorони пъти.
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");
   }
}
Резултат: The Witcher 4 Това вече е четвъртата игра на Witcher, но Гералт от Ривия все още не може да реши кой харесва повече: Йенефер от Венгерберг or Трис Мериголд. Но ако никога преди не сте играли The Witcher, ще започнем от начало. Името на главния герой е Гералт от Ривия Гералт от Ривия е вещица, ловец на чудовища Обявихме имената на героите като постоянни. Сега определено няма да направим печатна грешка и няма нужда да ги пишете на ръка всеки път. Друг плюс: ако някога се наложи да променим стойността на променливата в цялата програма, можете да го направите на едно място, instead of да я модифицирате ръчно в цялата codeова база. :)

Неизменни типове

Тъй като сте работor с Java, вероятно вече сте свикнали с идеята, че програмистите имат почти пълен контрол върху състоянието на всички обекти. Ако искате да създадете Catобект, можете. Ако искате да го преименувате, можете. Ако искате да промените възрастта му or нещо друго, можете. Но Java има няколко типа данни, които имат специално свойство. Те са неизменни . Ако един клас е неизменен, тогава състоянието на неговите обекти не може да бъде променено. Искате ли примери? Може да ви изненада, но най-известният неизменен клас е 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 = "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
}
Резултат: Обичам Java Обичам Java След като написахме
str1 = "I love Python";
низовият "I love Java"обект не се промени or отиде никъде. Все още щастливо съществува и има абсолютно същия текст като преди. Кодът
str1 = "I love Python";
просто създаде друг обект, към който сега сочи str1 . Но изглежда не можем да окажем ниHowво влияние върху низовия обект „I love Java“. Добре, нека опитаме нещо друго! Класът Stringе пълен с методи и някои от тях изглежда променят състоянието на обекта! Например, има replace()метод. Нека променим думата "Java" на "Python" в нашия низ!
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);
}
Резултат: Обичам Java Обичам Java Отново не работи! Може би методът за замяна не работи? Нека опитаме нещо друго. Например substring(),. Той връща подниз въз основа на индекси на знаци, предадени като аргументи. Нека отрежем първите 10 знака от нашия низ:
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);
}
Резултат: Обичам Java Обичам Java Фиксирани стойности в Java: окончателни, константи и неизменни - 3 Нищо не е променено. И не трябваше. Както казахме по-рано, низовете са неизменни. И така, Howво става с всички методи в Stringкласа? В края на краищата те могат да съкращават низове, да променят символи и много други. Какъв е смисълът, ако нищо не се случи? Те наистина могат да правят тези неща! Но те връщат нов низ всеки път. Безсмислено е да се пише
str1.replace("Java", "Python");
защото не можете да промените оригиналния обект. Но ако запишете резултата от метода в нова референтна променлива, веднага ще видите разликата!
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);
}
Всички Stringметоди работят по този начин. Нищо не може да се направи на "I love Java"обекта. Можете просто да създадете нов обект и да напишете: "<нов обект> = резултатът от манипулирането на "I love Java" object ". Какви други типове са неизменни? Някои, които определено ще трябва да запомните веднага, са всички класове обвивки за примитивните типове. Integer, Byte, Character, Short, Boolean, Long, Double, Float: всички тези класове създават immutableобекти (ще говорим за тях в предстоящите уроци). Това включва класове, използвани за създаване на големи числа, като BigIntegerи BigDecimal. Наскоро разгледахме изключенията и засегнахме проследяването на стека . Добре , познайте Howво, java.lang.StackTraceElementобектите също са неизменни. Това има смисъл: ако някой може да промени данните на нашия стек, това ще направи всичко безсмислено. Представете си, че някой преминава през проследяването на стека и променя OutOfMemoryError на FileNotFoundException . И след това използвате този стек, за да намерите причината за грешката. Но програмата дори не използва файлове. :) И така, направиха тези обекти неизменни, за всеки случай. Добре, така че повече or по-малко има смисъл за StackTraceElement . Но защо някой ще трябва да прави Strings неизменни? Защо промяната на техните ценности би била проблем? Сигурно дори би било по-удобно. :/ Има няколко причини за това. Първо, спестява памет. Неизменните низове могат да бъдат поставени в пула от низове, позволявайки низовете да се използват повторно, instead of да се създават нови. Второ, за сигурност. Например, потребителските имена и паролите са низове в почти всяка програма. Възможността за промяната им може да доведе до проблеми с оторизацията. Има и други причини, но нашето изследване на Java все още не ги е обхванало, така че ще се върнем към тях по-късно.
Коментари
  • Популярен
  • Нов
  • Стар
Трябва да сте влезли, за да оставите коментар
Тази страница все още няма коментари