CodeGym /Blog Java /rawak /Nilai tetap dalam Java: akhir, pemalar dan tidak boleh di...
John Squirrels
Tahap
San Francisco

Nilai tetap dalam Java: akhir, pemalar dan tidak boleh diubah

Diterbitkan dalam kumpulan
Hai! Anda sudah biasa dengan perkataan "pengubah suai". Sekurang-kurangnya, anda telah menemui pengubah suai akses (awam, peribadi) dan pengubah suai statik. Hari ini kita akan membincangkan pengubah suai khas yang dipanggil final . Anda boleh mengatakan bahagian "simen" pengubah terakhir dalam program kami di mana tingkah laku yang berterusan, tidak jelas dan tidak berubah diperlukan. Terdapat tiga tempat dalam program anda yang boleh anda gunakan: kelas, kaedah dan pembolehubah. Nilai tetap dalam Java: akhir, pemalar dan tidak boleh diubah - 2 Mari kita jalani mereka dengan teratur. Jika pengubahsuai akhir digunakan dalam pengisytiharan kelas, ini bermakna kelas itu tidak boleh diwarisi. Dalam pelajaran sebelumnya, kami menggunakan contoh warisan mudah: kami mempunyai Animalkelas induk dan dua kelas anak: CatdanDog

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
}
Walau bagaimanapun, jika kita menggunakan pengubah suai akhir pada Animalkelas, kelas Catdan Dogtidak boleh mewarisinya.

public final class Animal {

}

public class Cat extends Animal {

   // Error! Cannot inherit from final Animal
}
Pengkompil segera menjana ralat. Di Jawa, banyak kelas akhir telah dilaksanakan. Antara yang kerap anda gunakan, Stringadalah yang paling terkenal. Selain itu, jika kelas diisytiharkan sebagai muktamad , semua kaedah kelas juga menjadi muktamad . Apakah maksudnya? Jika kaedah diisytiharkan menggunakan pengubah suai terakhir , anda tidak boleh mengatasi kaedah itu. Sebagai contoh, di sini kita mempunyai Animalkelas yang mengisytiharkan speak()kaedah. Tetapi, anjing dan kucing pasti "bercakap" dengan cara yang berbeza. Jadi, kami akan mengisytiharkan kaedah speak() dalam kedua-dua kelas Catdan Dog, tetapi kami akan melaksanakannya secara berbeza.

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!");
   }
}
Kami membuat kelas Catdan Dogmengatasi kaedah yang diisytiharkan dalam kelas induk. Kini, haiwan akan bercakap secara berbeza, bergantung pada jenis objeknya:

public class Main {

   public static void main(String[] args) {

       Cat cat = new Cat();
       Dog dog = new Dog();
      
       cat.speak();
       dog.speak();
   }
}
Keluaran: Meow! woof! Walau bagaimanapun, jika kami mengisytiharkan kaedah Animalkelas speak()sebagai muktamad, maka kami tidak boleh mengatasinya dalam kelas lain:

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!");
   }
}
Dan objek kami akan dipaksa untuk menggunakan speak()kaedah seperti yang ditakrifkan dalam kelas induk:

public static void main(String[] args) {

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

   cat.speak();
   dog.speak();
}
Keluaran: Hello! hello! Sekarang, mengenai pembolehubah akhir . Ia juga dikenali sebagai pemalar . Pertama (dan yang paling penting), nilai awal yang diberikan kepada nilai malar tidak boleh diubah. Ia ditugaskan sekali dan untuk semua.

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!
   }
}
Pemalar tidak perlu dimulakan dengan segera. Itu boleh dilakukan kemudian. Tetapi, nilai yang pada mulanya diberikan kepadanya akan kekal selama-lamanya.

public static void main(String[] args) {

   final int CONSTANT_EXAMPLE;

   CONSTANT_EXAMPLE = 999;// This is allowed
}
Kedua, perhatikan nama pembolehubah kami. Java mempunyai konvensyen penamaan yang berbeza untuk pemalar. Ia bukan notasi camelCase yang biasa . Jika ia adalah pembolehubah biasa, kami akan memanggilnya constantExample. Tetapi, nama pemalar ditulis dalam semua huruf besar, dengan garis bawah antara perkataan (jika terdapat lebih daripada satu perkataan), cth "CONSTANT_EXAMPLE". Mengapa kita memerlukan pemalar? Mereka sangat berguna jika, sebagai contoh, terdapat nilai tetap yang anda kerap gunakan dalam program. Sebagai contoh, anda telah memutuskan untuk mencipta sejarah dan menulis permainan "The Witcher 4" sendiri. Permainan ini jelas akan kerap menggunakan nama protagonis: "Geralt of Rivia". Rentetan ini (dan nama wira lain) paling baik diisytiharkan sebagai pemalar: nilainya akan disimpan di satu tempat, dan anda pastinya tidak akan membuat kesilapan apabila memasukkannya berjuta kali.

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 Ia sudah menjadi permainan Witcher keempat, tetapi Geralt of Rivia masih tidak dapat memutuskan siapa yang lebih disukainya: Yennefer of Wengerberg atau Triss Merigold Tetapi, jika anda tidak pernah bermain The Witcher sebelum ini, kita akan bermula dari permulaan. Nama protagonis ialah Geralt of Rivia Geralt of Rivia ialah ahli sihir, pemburu raksasa Kami telah mengisytiharkan nama wira sebagai pemalar. Kini kami pasti tidak akan membuat kesilapan menaip, dan tidak perlu menulisnya dengan tangan setiap kali. Tambahan lain: jika kita perlu menukar nilai pembolehubah merentas keseluruhan program, anda boleh melakukannya di satu tempat, dan bukannya mengubah suainya secara manual merentas keseluruhan pangkalan kod. :)

Jenis tidak berubah

Memandangkan anda telah bekerja dengan Java, anda mungkin sudah terbiasa dengan idea bahawa pengaturcara mempunyai kawalan yang hampir sepenuhnya ke atas keadaan semua objek. Jika anda ingin membuat Catobjek, anda boleh. Kalau nak tukar nama pun boleh. Jika anda ingin menukar umurnya atau sesuatu yang lain, anda boleh. Tetapi Java mempunyai beberapa jenis data yang mempunyai sifat istimewa. Mereka tidak berubah . Jika kelas tidak boleh diubah, maka keadaan objeknya tidak boleh diubah. Mahu beberapa contoh? Ia mungkin mengejutkan anda, tetapi kelas tidak berubah yang paling terkenal ialah String! Jadi, kita benar-benar tidak boleh menukar nilai String? Nah, mari cuba:

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: Saya suka Java Saya suka Java Selepas kami menulis

str1 = "I love Python";
objek "I love Java"rentetan tidak berubah atau pergi ke mana-mana. Ia masih wujud dengan gembira dan mempunyai teks yang sama seperti sebelumnya. Kod itu

str1 = "I love Python";
hanya mencipta objek lain, yang kini ditunjukkan oleh str1 . Tetapi, kami nampaknya tidak mempunyai sebarang kesan pada objek rentetan "Saya suka Java". Okay, jom cuba yang lain! Kelas ini Stringpenuh dengan kaedah, dan sebahagian daripadanya kelihatan mengubah keadaan objek! Sebagai contoh, terdapat replace()kaedah. Mari tukar perkataan "Java" kepada "Python" dalam rentetan kami!

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: Saya suka Java Saya suka Java Ia tidak berfungsi lagi! Mungkin kaedah ganti tidak berfungsi? Mari cuba sesuatu yang lain. Contohnya, substring(). Ia mengembalikan subrentetan berdasarkan indeks aksara yang diluluskan sebagai argumen. Mari kita potong 10 aksara pertama rentetan kami:

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: Saya suka Java Saya suka Java Nilai tetap dalam Java: muktamad, pemalar dan tidak berubah - 3 Tiada apa-apa yang berubah. Dan ia tidak sepatutnya. Seperti yang kami katakan sebelum ini, Strings tidak boleh diubah. Jadi, ada apa dengan semua kaedah dalam Stringkelas? Lagipun, mereka boleh memotong rentetan, menukar aksara dan banyak lagi. Apa gunanya jika tiada apa yang berlaku? Mereka sebenarnya boleh melakukan perkara-perkara ini! Tetapi, mereka mengembalikan String baharu setiap kali. Tak guna menulis

str1.replace("Java", "Python");
kerana anda tidak boleh menukar objek asal. Tetapi, jika anda menulis hasil kaedah kepada pembolehubah rujukan baharu, anda akan melihat perbezaannya serta-merta!

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);
}
Semua Stringkaedah berfungsi dengan cara ini. Tiada apa yang boleh dilakukan terhadap "I love Java"objek itu. Anda hanya boleh mencipta objek baharu dan menulis: "<objek baharu> = hasil memanipulasi "I love Java" object ". Apakah jenis lain yang tidak boleh diubah? Beberapa yang anda pasti perlu ingat segera ialah semua kelas pembalut untuk jenis primitif. Integer, Byte, Character, Short, Boolean, Long, Double, Float: semua kelas ini mencipta immutableobjek (kita akan membincangkannya dalam pelajaran akan datang). Ini termasuk kelas yang digunakan untuk mencipta nombor besar, seperti BigIntegerdan BigDecimal. Kami baru-baru ini membincangkan pengecualian dan menyentuh jejak tindanan . Nah , rasa apa, java.lang.StackTraceElementobjek juga tidak berubah. Ini masuk akal: jika seseorang boleh menukar data timbunan kami, ia akan menjadikan semuanya sia-sia. Bayangkan seseorang melalui jejak tindanan dan menukar OutOfMemoryError kepada FileNotFoundException . Dan kemudian anda menggunakan timbunan itu untuk mencari punca ralat. Tetapi program ini tidak menggunakan fail. :) Jadi, mereka menjadikan objek ini tidak berubah, untuk berjaga-jaga. Okay, jadi lebih kurang masuk akal untuk StackTraceElement . Tetapi, mengapa sesiapa perlu membuat Strings tidak berubah? Mengapa mengubah nilai mereka menjadi masalah? Ia mungkin lebih mudah. :/ Terdapat beberapa sebab untuk ini. Pertama, ia menjimatkan memori. Rentetan tidak berubah boleh diletakkan di dalam kolam rentetan, membenarkan rentetan digunakan semula dan bukannya mencipta yang baharu. Kedua, untuk keselamatan. Sebagai contoh, nama pengguna dan kata laluan adalah String dalam hampir setiap program. Memungkinkan untuk menukarnya boleh mengakibatkan masalah keizinan. Terdapat sebab-sebab lain, tetapi kajian Java kami belum meliputinya lagi, jadi kami akan kembali kepada mereka kemudian.
Komen
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION