JavaRush /Java Blogu /Random-AZ /Java-da Final, Sabitlər və Dəyişməz

Java-da Final, Sabitlər və Dəyişməz

Qrupda dərc edilmişdir
Salam! “Dəyişdirici” sözü sizə artıq tanışdır. Ən azı giriş modifikatorları (ictimai, şəxsi) və statik dəyişdirici ilə rastlaşmısınız. Bu gün biz xüsusi son dəyişdirici haqqında danışacağıq . Proqramımızın daimi, birmənalı, dəyişməz davranışa ehtiyac duyduğumuz sahələri “sementləşdirmək” demək olar. O, proqramımızın üç sahəsində istifadə edilə bilər: siniflər, metodlar və dəyişənlər. Java-da dəyişməz: final, sabitlər və dəyişməz - 2 Gəlin onları bir-bir nəzərdən keçirək. Əgər sinif bəyannaməsi son dəyişdiricidən ibarətdirsə , bu o deməkdir ki, siz bu sinifdən miras ala bilməyəcəksiniz. Əvvəlki mühazirələrdə sadə bir miras nümunəsi gördük: bizim valideyn sinifimiz Animalvə iki uşaq sinifimiz var idi - CatDog
public class Animal {
}

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

public class Dog extends Animal {

   //..поля и методы класса Dog
}
AnimalBununla belə, bir sinif üçün dəyişdirici təyin etsək , siniflər də ondan finalmiras ala bilməyəcəklər . CatDog
public final class Animal {

}

public class Cat extends Animal {

   //ошибка! Cannot inherit from final Animal
}
Kompilyator dərhal xəta yaradır. Java-da artıq tətbiq edilmiş bir çox siniflər var final. Davamlı istifadə etdiyinizlərdən ən məşhuru String. Bundan əlavə, əgər sinif kimi elan edilirsə final, onun bütün metodları da olur final. Bunun mənası nədi? Metod üçün dəyişdirici göstərilibsə final, bu metodu ləğv etmək olmaz. Məsələn, Animalmetodu təyin edən bir sinifimiz var voice(). Bununla belə, itlər və pişiklər fərqli şəkildə "danışırlar". Buna görə də, siniflərin hər birində - CatDog- bir üsul yaradacağıq voice(), lakin biz onu fərqli şəkildə həyata keçirəcəyik.
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!");
   }
}
Dərslərdə CatDogbiz ana sinifin metodunu ləğv etdik. İndi heyvan hansı sinif obyektindən asılı olaraq səslənəcək:
public class Main {

   public static void main(String[] args) {

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

       cat.voice();
       dog.voice();
   }
}
Nəticə: Miyav! vay! Bununla belə, əgər Animalbiz bir sinifdə metodu voice()kimi elan etsək final, onu digər siniflərdə yenidən təyin etmək mümkün olmayacaq:
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!");
   }
}
Sonra obyektlərimiz voice()ana sinifdə müəyyən edildiyi kimi metoddan istifadə etməyə məcbur olacaq:
public static void main(String[] args) {

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

   cat.voice();
   dog.voice();
}
Nəticə: Səs! Səs! İndi final-dəyişənlər haqqında. Əks halda onlara sabitlər deyilir . Birincisi (və ən əsası), sabitə təyin edilmiş ilk dəyər dəyişdirilə bilməz. Bir dəfə və əbədi olaraq təyin olunur.
public class Main {

   private static final int CONSTANT_EXAMPLE = 333;

   public static void main(String[] args) {

       CONSTANT_EXAMPLE = 999;//ошибка! Нельзя присвоить новое meaning final-переменной!
   }
}
Sabitin dərhal işə salınmasına ehtiyac yoxdur. Bu daha sonra edilə bilər. Ancaq ilk təyin olunan dəyər əbədi olaraq qalacaq.
public static void main(String[] args) {

   final int CONSTANT_EXAMPLE;

   CONSTANT_EXAMPLE = 999;//так делать можно
}
İkincisi, dəyişənimizin adına diqqət yetirin. Java sabitləri fərqli adlandırma konvensiyasına malikdir. Bu bizim öyrəşdiyimiz dəvə qutusu deyil. Müntəzəm dəyişən vəziyyətində biz onu daimi Nümunə adlandırardıq, lakin sabitlərin adları böyük hərflərlə yazılır və sözlər arasında (onlardan bir neçəsi varsa) alt xətt qoyulur - “CONSTANT_EXAMPLE”. Niyə sabitlər lazımdır? Məsələn, bir proqramda daim müəyyən bir sabit dəyər istifadə etsəniz, onlar lazımlı olacaq. Tutaq ki, tarixə düşmək və “The Witcher 4” oyununu tək yazmaq qərarına gəldiniz. Oyun açıq şəkildə əsas personajın adından - "Riviyanın Geraltından" istifadə edəcəkdir. Bu sətri və digər qəhrəmanların adlarını sabitliyə ayırmaq daha yaxşıdır: sizə lazım olan dəyər bir yerdə saxlanacaq və milyonuncu dəfə yazarkən mütləq səhv etməyəcəksiniz.
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 + " - ведьмак, охотник на чудовищ");
   }
}
Nəticə:
Ведьмак 4
Это уже четвертая часть Ведьмака, а Геральт из Ривии ниHow не определится, кто ему нравится больше: Йеннифэр из Венгерберга or Трисс Меригольд.
Но если вы никогда не играли в Ведьмака — начнем сначала.
Главного героя зовут Геральт из Ривии
Геральт из Ривии — ведьмак, охотник на чудовищ
Biz personajların adlarını sabitlərə ayırdıq və indi onları mütləq səhv yazmayacağıq və hər dəfə onları əl ilə yazmağa ehtiyac qalmayacaq. Başqa bir artı: əgər nəhayət proqram boyu dəyişənin dəyərini dəyişdirməli olsaq, onu bütün kodda əl ilə təkrar etməkdənsə, bir yerdə etmək kifayətdir :)

Dəyişməz növlər

Java-da işlədiyiniz müddətdə, yəqin ki, proqramçının bütün obyektlərin vəziyyətini demək olar ki, tamamilə idarə etdiyinə artıq öyrəşmisiniz. İstənilən - obyekt yaratdı Cat. İstəsəm adını dəyişdim. İstəsəydi, yaşını dəyişdi, ya başqa bir şey. Lakin Java-da xüsusi vəziyyətə malik bir neçə məlumat növü var. Onlar dəyişməz və ya dəyişməzdirlər . Bu o deməkdir ki, əgər sinif dəyişməzdirsə, onun obyektlərinin vəziyyəti dəyişdirilə bilməz. Nümunələr? Siz təəccüblənə bilərsiniz, amma Dəyişməz sinifin ən məşhur nümunəsi String! Deyəsən, bir sətirin dəyərini dəyişə bilmərik? Gəlin cəhd edək:
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
}
Nəticə: Mən Java-nı sevirəm Java-nı sevirəm Yazdıqdan sonra:
str1 = "I love Python";
"I love Java" sətirli obyekt dəyişməyib və heç yerə getməyib. O, təhlükəsiz şəkildə mövcuddur və içərisində əvvəlki kimi eyni mətnə ​​malikdir. Kod:
str1 = "I love Python";
sadəcə başqa obyekt yaratdı və indi dəyişən str1ona işarə edir. Lakin biz “I love Java” obyektinə heç bir şəkildə təsir edə bilmərik. Tamam, fərqli şəkildə cəhd edək! Sinif Stringüsullarla doludur və onlardan bəziləri cərgənin vəziyyətini dəyişdirir! Məsələn, bir üsul var replace(). Gəlin sətirimizdəki “Java” sözünü “Python” sözü ilə dəyişək!
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);
}
Nəticə: Java-nı sevirəm Java-nı sevirəm. Yenə alınmadı! Bəlkə əyri üsul işləmir? Gəlin başqa birini sınayaq. Misal üçün, substring(). Ötürülmüş simvolların nömrələri əsasında sətri kəsir. İlk 10 simvolumuzu kəsək:
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);
}
Nəticə: Mən Java-nı sevirəm Mən Java-nı sevirəm Java-da dəyişməz: final, sabitlər və dəyişməz - 3 . Heç nə dəyişməyib. Və olmamalıdır. Dediyimiz kimi, obyektlər Stringdəyişməzdir. Bəs bütün bu sinif metodları nədir String? Onlar xətti kəsə, içindəki simvolları dəyişdirə və s. Heç bir şey olmadıqda onlar niyə lazımdır? Onlar bacarar! Lakin onlar hər dəfə yeni sətir obyekti qaytarırlar. Yazmağın faydası yoxdur:
str1.replace("Java", "Python");
- orijinal obyekti dəyişməyəcəksiniz. Ancaq metodun nəticəsini yeni bir istinad dəyişəninə yazsanız, fərqi dərhal görəcəksiniz!
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);
}
Bütün bu üsulların işlədiyi yeganə yol budur String. "I love Java" obyekti ilə heç nə edə bilməzsiniz . Sadəcə yeni obyekt yaradın və yazın: “Yeni obyekt = “Mən Java-nı sevirəm” obyekti ilə bəzi manipulyasiyaların nəticəsi .” Başqa hansı növlər Dəyişməzdir? İndi mütləq xatırlamalı olduğunuz şeydən - primitiv növlər üzərindəki bütün sarğı sinifləri dəyişməzdir. Integer, Byte, Character, Short, Boolean, Long, Double, Float- bütün bu siniflər Dəyişməz obyektlər yaradır. Buraya böyük ədədlər yaratmaq üçün istifadə olunan siniflər də daxildir - BigIntegerBigDecimal. Bu yaxınlarda istisnalardan keçdik və onlara toxunduq StackTrace. Beləliklə: java.lang.StackTraceElement sinifinin obyektləri də dəyişməzdir. Bu məntiqlidir: əgər kimsə yığınımızdakı məlumatları dəyişdirə bilsəydi, onunla bütün işləri inkar edə bilər. Təsəvvür edin ki, kimsə StackTrace- ə daxil olur və OutOfMemoryError-u FileNotFoundException- a dəyişir . Və siz bu yığınla işləməli və xətanın səbəbini axtarmalısınız. Proqram isə ümumiyyətlə fayllardan istifadə etmir :) Buna görə də təhlükəsiz tərəfdə olmaq üçün bu obyektlər dəyişməz hala salınıb. Yaxşı, StackTraceElement ilə bu az və ya çox aydındır. Niyə kimsə simləri dəyişməz etmək istəyir? Onların dəyərlərini dəyişmək mümkün olsaydı nə problem olardı. Yəqin ki, daha rahat olardı :/ Bunun bir neçə səbəbi var. Birincisi, yaddaşa qənaət. Dəyişməz sətirlər yerləşdirilə bilər String Poolvə hər dəfə yeniləri yaratmaq əvəzinə eyni olanlar istifadə edilə bilər. İkincisi, təhlükəsizlik. Məsələn, hər hansı bir proqramda əksər giriş və şifrələr sətirlərdir. Onları dəyişdirmək imkanı avtorizasiya ilə bağlı problemlərə səbəb ola bilər. Başqa səbəblər də var, lakin Java-nı öyrənərkən hələ onlara çatmamışıq – sonra qayıdacayıq.
Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION