JavaRush /Java блогу /Random-KY /Final, Constants and Immutable in Java

Final, Constants and Immutable in Java

Группада жарыяланган
Салам! "Модификатор" деген сөз сизге мурунтан эле тааныш. Жок дегенде, сиз кирүү өзгөрткүчтөрүн (коомдук, жеке) жана статикалык өзгөрткүчтү кезиктирдиңиз. Бүгүн биз атайын акыркы өзгөрткүч жөнүндө сүйлөшөбүз . Бул биздин программанын туруктуу, ачык-айкын, өзгөрүлбөс жүрүм-турумга муктаж болгон жерлерин «цементтеди» деп айтууга болот. Аны биздин программанын үч тармагында колдонсо болот: класстар, методдор жана өзгөрмөлөр. Javaда өзгөрүлгүс: акыркы, константалар жана өзгөрүлгүс - 2 Келгиле, аларды бир-бирден карап чыгалы. Эгерде класс декларациясында акыркы модификатор камтылса , бул сиз бул классты мурастай албайсыз дегенди билдирет. Мурунку лекцияларда биз мурастын жөнөкөй мисалын көрдүк: бизде ата-энелер классы Animalжана эки бала классы бар болчу - CatжанаDog
public class Animal {
}

public class Cat extends Animal {
   //..поля и методы класса Cat
}

public class Dog extends Animal {

   //..поля и методы класса Dog
}
AnimalБирок, класс үчүн модификаторду көрсөтсө , класстар андан да finalмурастай алbyte . CatDog
public final class Animal {

}

public class Cat extends Animal {

   //ошибка! Cannot inherit from final Animal
}
Компилятор дароо ката чыгарат. Javaда буга чейин ишке ашырылган көптөгөн класстар бар final. Сиз дайыма колдонгондордун эң белгилүүсү String. Кошумчалай кетсек, эгерде класс катары жарыя кылынса final, анын бардык ыкмалары да болуп калат final. Бул эмнени билдирет? Эгерде метод үчүн өзгөрткүч көрсөтүлгөн болсо final, бул ыкманы жокко чыгарууга болбойт. Мисалы, бизде Animalметодду аныктаган класс бар voice(). Бирок, иттер менен мышыктар так башкача "сүйлөшөт". Ошондуктан, ар бир класста - Catжана Dog- методун түзөбүз voice(), бирок аны башкача ишке ашырабыз.
public class Animal {

   public void voice() {
       System.out.println("Voice!");
   }
}

public class Cat extends Animal {

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

public class Dog extends Animal {

   @Override
   public void voice() {
       System.out.println("Woof!");
   }
}
Класстарда Catжана Dogбиз ата-энелер классынын ыкмасын жокко чыгардык. Эми жаныбар кайсы класс an objectисине жараша үн чыгарат:
public class Main {

   public static void main(String[] args) {

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

       cat.voice();
       dog.voice();
   }
}
Жыйынтык: Мия! Woof! Бирок, класстагы Animalметодду деп жарыяласак , аны башка класстарда кайра аныктоо мүмкүн эмес: voice()final
public class Animal {

   public final void voice() {
       System.out.println("Voice!");
   }
}


public class Cat extends Animal {

   @Override
   public void voice() {//ошибка! final-метод не может быть переопределен!
       System.out.println("Meow!");
   }
}
voice()Ошондо биздин an objectтер ата-эне класста аныкталгандай ыкманы колдонууга аргасыз болушат :
public static void main(String[] args) {

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

   cat.voice();
   dog.voice();
}
Жыйынтык: Voice! Voice! Эми final-өзгөрмөлөр жөнүндө. Болбосо алар константалар деп аталат . Биринчиден (жана эң негизгиси), туруктууга ыйгарылган биринчи маанини өзгөртүүгө болбойт. Ал бир жолу жана түбөлүккө дайындалат.
public class Main {

   private static final int CONSTANT_EXAMPLE = 333;

   public static void main(String[] args) {

       CONSTANT_EXAMPLE = 999;//ошибка! Нельзя присвоить новое meaning final-переменной!
   }
}
Туракты дароо инициализациялоонун кереги жок. Муну кийинчерээк жасоого болот. Бирок биринчи берилген баа түбөлүккө калат.
public static void main(String[] args) {

   final int CONSTANT_EXAMPLE;

   CONSTANT_EXAMPLE = 999;//так делать можно
}
Экинчиден, биздин өзгөрмөнүн атына көңүл буруңуз. Java константаларында башка ат коюу конвенциясы бар. Бул биз көнгөн төө эмес. Регулярдуу өзгөрмө болсо, биз аны константалууМысалы деп атамакпыз, бирок константалардын аттары баш тамгалар менен жазылат жана сөздөрдүн ортосунда (эгерде алардын бир нечеси болсо) астынкы сызык бар - “ТУРАК_МИСАЛ”. Эмне үчүн туруктуулар керек? Мисалы, программада кандайдыр бир туруктуу маанини дайыма колдонсоңуз, алар пайдалуу болот. Тарыхта калууну чечип, жалгыз “The Witcher 4” оюнун жазууну чечти дейли. Оюн дайыма башкы каармандын атын колдонот - "Ривиянын Геральты". Бул сапты жана башка баатырлардын атын константага бөлүп койгон жакшы: сизге керектүү маани бир жерде сакталат жана аны миллионунчу жолу терүүдө ката кетирбейсиз.
public class TheWitcher4 {

   private static final String GERALT_NAME = "Геральт из Ривии";
   private static final String YENNEFER_NAME = "Йеннифэр из Венгерберга";
   private static final String TRISS_NAME = "Трисс Меригольд";

   public static void main(String[] args) {

       System.out.println("Ведьмак 4");
       System.out.println("Это уже четвертая часть Ведьмака, а " + GERALT_NAME + " ниHow не определится кто ему" +
               " нравится больше: " + YENNEFER_NAME + " or " + TRISS_NAME);

       System.out.println("Но если вы никогда не играли в Ведьмака - начнем сначала.");
       System.out.println("Главного героя зовут " + GERALT_NAME);
       System.out.println(GERALT_NAME + " - ведьмак, охотник на чудовищ");
   }
}
Жыйынтык:
Ведьмак 4
Это уже четвертая часть Ведьмака, а Геральт из Ривии ниHow не определится, кто ему нравится больше: Йеннифэр из Венгерберга or Трисс Меригольд.
Но если вы никогда не играли в Ведьмака — начнем сначала.
Главного героя зовут Геральт из Ривии
Геральт из Ривии — ведьмак, охотник на чудовищ
Каармандардын атын константаларга бөлүп койдук, эми аларды сөзсүз ката кетирбейбиз, ар бир жолу кол менен жазуунун кереги жок болот. Дагы бир плюс: эгер биз программанын ичинде өзгөрмөнүн маанисин өзгөртүүгө туура келсе, аны бүт code боюнча кол менен кайра жасоонун ордуна, аны бир жерде жасоо жетиштүү :)

Өзгөрбөс түрлөрү

Javaда иштеген убактыңызда, балким, программист бардык an objectтердин абалын дээрлик толугу менен көзөмөлдөп турганына көнүп калгандырсыз. Wanted - түзүлгөн an object Cat. Кааласам атын өзгөртүп койдум. Кааласа жашын өзгөрттү, же башкасын. Бирок Javaда өзгөчө абалга ээ болгон бир нече маалымат түрлөрү бар. Алар өзгөрүлгүс же өзгөрүлгүс . Бул класс өзгөрүлгүс болсо, анын an objectтеринин абалын өзгөртүү мүмкүн эмес дегенди билдирет. Мисалдар? Сиз таң калышыңыз мүмкүн, бирок Immutable классынын эң белгилүү мисалы String! Биз саптын маанисин өзгөртө албайбыз окшойт? Келгиле, аракет кылалы:
public static void main(String[] args) {

   String str1 = "I love Java";

   String str2 = str1;//обе переменные-ссылки указывают на одну строку.
   System.out.println(str2);

   str1 = "I love Python";//но поведение str1 ниHow не влияет на str2
   System.out.println(str2);//str2 продолжает указывать на строку "I love Java", хотя str1 уже указывает на другой an object
}
Жыйынтык: Мен Java-ны жакшы көрөм Мен Java-ны жакшы көрөм, биз жазгандан кийин:
str1 = "I love Python";
"I love Java" саптары менен an object өзгөргөн жок жана эч жакка кеткен жок. Ал аман-эсен бар жана ичинде мурункудай эле текст бар. Код:
str1 = "I love Python";
жөн гана башка an object түздү жана азыр өзгөрмө str1аны көрсөтөт. Бирок биз "Мен Javaны сүйөм" an objectине эч кандай таасир бере албайбыз. Макул, келгиле, башкача аракет кылалы! Класста Stringметоддор толтура, алардын айрымдары катардын абалын өзгөрткөндөй! Мисалы, бир ыкмасы бар replace(). Сапыбыздагы “Java” сөзүн “Python” сөзүнө алмаштыралы!
public static void main(String[] args) {

   String str1 = "I love Java";

   String str2 = str1;//обе переменные-ссылки указывают на одну строку.
   System.out.println(str2);

   str1.replace("Java", "Python");//попробуем изменить состояние str1, заменив слово "Java" на “Python”
   System.out.println(str2);
}
Жыйынтык: Мен Java-ны жакшы көрөм Мен Java-ны жакшы көрөм. Бул кайра ишке ашкан жок! Балким ийри ыкмасы иштебейт? Келгиле, дагы бир аракет кылалы. Мисалы, substring(). Өткөрүлгөн символдордун сандарына негизделген сапты кырктырат. Келгиле, өзүбүздүн символубузду биринчи 10 белгиге чейин кыскарталы:
public static void main(String[] args) {

   String str1 = "I love Java";

   String str2 = str1;//обе переменные-ссылки указывают на одну строку.
   System.out.println(str2);

   str1.substring(10);//обрезаем исходную строку
   System.out.println(str2);
}
Жыйынтык: Мен Java сүйөм Мен Java сүйөм Javaда өзгөрүлгүс: акыркы, константалар жана өзгөрүлгүс - 3 Эч нерсе өзгөргөн жок. Жана андай болбошу керек. Биз айткандай, an objectтер Stringөзгөрүлгүс. Бул класстык методдор деген эмне String? Алар сызыкты кыркып, андагы каармандарды өзгөртө алат ж.б. Эч нерсе болбосо, алар эмне үчүн керек? Алар мүмкүн! Бирок алар ар бир жолу жаңы сап an objectисин кайтарышат. Жазгандан пайда жок:
str1.replace("Java", "Python");
- сиз баштапкы an objectти өзгөртпөйсүз. Бирок, эгерде сиз методдун натыйжасын жаңы шилтеме өзгөрмөсүнө жазсаңыз, анда айырманы дароо көрөсүз!
public static void main(String[] args) {

   String str1 = "I love Java";

   String str2 = str1;//обе переменные-ссылки указывают на одну строку.
   System.out.println(str2);

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

   System.out.println(str1AfterReplacement);
}
Бул ыкмалардын бардыгы ушундай гана Stringиштейт. "I love Java" an objectи менен эч нерсе кыла албайсыз . Жөн гана жаңы an object түзүп, жазыңыз: "Жаңы an object = "I love Java" an objectи менен кээ бир манипуляциялардын натыйжасы ." Дагы кандай түрлөрү өзгөрүлгүс? Сиз азыр эстен чыгарбашыңыз керек болгон нерседен - примитивдүү түрлөрдүн үстүнөн бардык орогуч класстары өзгөрүлбөйт. Integer, Byte, Character, Short, Boolean, Long, Double, Float- бул класстардын баары Өзгөрбөс an objectтерди түзөт. Бул ошондой эле чоң сандарды түзүү үчүн колдонулган класстарды камтыйт - BigIntegerжана BigDecimal. Биз жакында эле өзгөчөлүктөрдөн өтүп, аларга токтолдук StackTrace. Ошентип: java.lang.StackTraceElement классынын an objectтери да өзгөрүлбөйт. Бул логикалуу: эгерде кимдир бирөө биздин стектеги маалыматтарды өзгөртө алса, анда ал аны менен иштөөнү жокко чыгарышы мүмкүн. Элестеткиле, кимдир бирөө StackTraceге кирип , OutOfMemoryError ды FileNotFoundException деп өзгөртөт . Жана сиз бул стек менен иштеп, катанын себебин издешиңиз керек. Ал эми программа файлдарды такыр колдонбойт :) Ошондуктан, коопсуз тарапта болуу үчүн, бул an objectтер өзгөрүлгүс кылып жасалган. Ооба, StackTraceElement менен бул аздыр-көптүр түшүнүктүү. Эмне үчүн кимдир бирөө саптарды өзгөрүлгүс кылгысы келет? Алардын баалуулуктарын өзгөртүүгө мүмкүнчүлүк болгондо кандай көйгөй болмок. Бул, балким, андан да ыңгайлуу болмок :/ Мунун бир нече себептери бар. Биринчиден, эстутум сактоо. Өзгөрбөс саптарды жайгаштырса болот String Poolжана ошол эле саптарды ар бир жолу жаңысын түзүүнүн ордуна колдонсо болот. Экинчиден, коопсуздук. Мисалы, каалаган программадагы логиндердин жана сырсөздөрдүн көбү саптар. Аларды өзгөртүү мүмкүнчүлүгү авторизацияга байланыштуу көйгөйлөргө алып келиши мүмкүн. Башка себептер бар, бирок биз Java тorн үйрөнүүдө аларга азырынча жете элекпиз — кийинчерээк кайтып келебиз.
Комментарийлер
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION