JavaRush /จาวาบล็อก /Random-TH /สุดท้าย ค่าคงที่ และไม่เปลี่ยนรูปใน Java

สุดท้าย ค่าคงที่ และไม่เปลี่ยนรูปใน Java

เผยแพร่ในกลุ่ม
สวัสดี! คำว่า "ตัวแก้ไข" เป็นคำที่คุณคุ้นเคยอยู่แล้ว อย่างน้อยที่สุด คุณจะได้พบกับตัวแก้ไขการเข้าถึง (สาธารณะ ส่วนตัว) และตัวแก้ไขแบบคงที่ วัน นี้เราจะมาพูดถึงตัวแก้ไขพิเศษขั้นสุดท้าย อาจกล่าวได้ว่าเป็นการ "ประสาน" ด้านต่างๆ ของโปรแกรมของเราซึ่งเราต้องการพฤติกรรมที่คงที่ ไม่คลุมเครือ และไม่เปลี่ยนแปลง สามารถใช้งานได้สามส่วนในโปรแกรมของเรา: คลาส วิธีการ และตัวแปร ไม่เปลี่ยนรูปใน Java: สุดท้าย ค่าคงที่ และไม่เปลี่ยนรูป - 2 มาดูกันทีละคน หากการประกาศคลาสมี ตัวแก้ไข ขั้นสุดท้ายหมายความว่าคุณไม่สามารถสืบทอดจากคลาสนี้ได้ ในการบรรยายครั้งก่อน เราเห็นตัวอย่างง่ายๆ ของการสืบทอด: เรามีคลาส parent Animalและคลาสย่อยสองคลาส - CatและDog
public class Animal {
}

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

public class Dog extends Animal {

   //..поля и методы класса Dog
}
อย่างไรก็ตาม หากเราระบุAnimalตัวแก้ไข สำหรับคลาส คลาส finalจะไม่สามารถสืบทอดจากคลาส นั้น Catได้เช่นDogกัน
public final class Animal {

}

public class Cat extends Animal {

   //ошибка! Cannot inherit from final Animal
}
คอมไพเลอร์ทำให้เกิดข้อผิดพลาดทันที มีหลาย -classes ที่ใช้งานอยู่แล้วในfinalJava สิ่งที่มีชื่อเสียงที่สุดที่คุณใช้เป็นประจำStringคือ นอกจากนี้ หากมีการประกาศคลาสเป็น เมธอดfinalทั้งหมดของคลาสก็จะกลายเป็นfinal. มันหมายความว่าอะไร? หากมีการระบุตัวแก้ไขสำหรับ method 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เราได้แทนที่วิธีการของคลาสผู้ปกครอง ตอนนี้สัตว์จะเปล่งเสียงขึ้นอยู่กับว่ามันคือวัตถุคลาสใด:
public class Main {

   public static void main(String[] args) {

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

       cat.voice();
       dog.voice();
   }
}
สรุป: เหมียว! โฮ่ง! อย่างไรก็ตาม หาก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()ตามที่กำหนดไว้ในคลาสพาเรนต์:
public static void main(String[] args) {

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

   cat.voice();
   dog.voice();
}
สรุป: เสียง! เสียง! ตอนนี้เกี่ยวกับfinal-variables มิฉะนั้นจะเรียกว่าค่าคงที่ อันดับแรก (และที่สำคัญที่สุด) ไม่สามารถเปลี่ยนแปลงค่าแรกที่กำหนดให้กับค่าคงที่ได้ มันถูกมอบหมายครั้งเดียวและตลอดไป
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 มีรูปแบบการตั้งชื่อที่แตกต่างกัน นี่ไม่ใช่ CamelCase ที่เราคุ้นเคย ในกรณีของตัวแปรปกติ เราจะเรียกมันว่าค่าคงที่ตัวอย่าง แต่ชื่อของค่าคงที่จะถูกเขียนด้วยตัวพิมพ์ใหญ่ และระหว่างคำ (หากมีหลายคำ) จะมีขีดล่าง - “CONSTANT_EXAMPLE” เหตุใดจึงต้องมีค่าคงที่? ตัวอย่างเช่น มันจะมีประโยชน์หากคุณใช้ค่าคงที่ในโปรแกรมอยู่ตลอดเวลา สมมติว่าคุณตัดสินใจลงไปในประวัติศาสตร์และเขียนเกม "The Witcher 4" เพียงอย่างเดียว เห็นได้ชัดว่าเกมจะใช้ชื่อของตัวละครหลัก - "Geralt of Rivia" อย่างต่อเนื่อง เป็นการดีกว่าที่จะแยกบรรทัดนี้และชื่อของฮีโร่อื่น ๆ ออกเป็นค่าคงที่: ค่าที่คุณต้องการจะถูกเก็บไว้ในที่เดียวและคุณจะไม่ทำผิดพลาดอย่างแน่นอนเมื่อพิมพ์เป็นครั้งที่ล้าน
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 Трисс Меригольд.
Но если вы никогда не играли в Ведьмака — начнем сначала.
Главного героя зовут Геральт из Ривии
Геральт из Ривии — ведьмак, охотник на чудовищ
เราได้แยกชื่อของตัวละครออกเป็นค่าคงที่แล้ว และตอนนี้เราจะไม่สะกดผิดอย่างแน่นอน และไม่จำเป็นต้องเขียนด้วยมือทุกครั้ง ข้อดีอีกประการ: หากในที่สุดเราจำเป็นต้องเปลี่ยนค่าของตัวแปรทั่วทั้งโปรแกรม ก็เพียงพอแล้วที่จะทำในที่เดียว แทนที่จะทำซ้ำด้วยตนเองตลอดทั้งโค้ด :)

ประเภทที่ไม่เปลี่ยนรูป

ในช่วงเวลาที่คุณทำงานใน Java คุณอาจคุ้นเคยกับความจริงที่ว่าโปรแกรมเมอร์ควบคุมสถานะของวัตถุทั้งหมดเกือบทั้งหมดแล้ว ต้องการ-สร้างวัตถุCat. ถ้าฉันต้องการฉันก็เปลี่ยนชื่อมัน หากเขาต้องการเขาก็เปลี่ยนอายุหรืออย่างอื่น แต่ใน Java มีข้อมูลหลายประเภทที่มีสถานะพิเศษ พวกมันไม่เปลี่ยนรูปหรือไม่เปลี่ยนรูป ซึ่งหมายความว่าหากคลาสไม่เปลี่ยนรูป สถานะของอ็อบเจ็กต์จะไม่สามารถเปลี่ยนแปลงได้ ตัวอย่าง? คุณอาจจะแปลกใจ แต่ตัวอย่างที่มีชื่อเสียงที่สุดของคลาส 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";
วัตถุที่มีสตริง"ฉันรัก Java"ไม่มีการเปลี่ยนแปลงและไม่ได้หายไปไหน มันมีอยู่อย่างปลอดภัยและมีข้อความเหมือนกันทุกประการอยู่ข้างในเหมือนเมื่อก่อน รหัส:
str1 = "I love Python";
เพิ่งสร้างวัตถุอื่นและตอนนี้ตัวแปรชี้str1ไปที่มัน แต่ เราไม่สามารถมีอิทธิพลต่อวัตถุ"ฉันรัก Java" แต่อย่างใด เอาล่ะ เรามาลองอย่างอื่นกันดีกว่า! ชั้นเรียน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 ไม่มีอะไรเปลี่ยนแปลง และมันก็ไม่ควรมี อย่างที่เราพูดไปแล้ว วัตถุนั้นStringไม่เปลี่ยนรูป แล้ววิธีการเรียนทั้งหมดนี้คืออะไรString? พวกเขาสามารถตัดแต่งเส้น เปลี่ยนตัวละครในนั้น ฯลฯ ทำไมพวกเขาถึงต้องการถ้าไม่มีอะไรเกิดขึ้น? พวกเขาสามารถ! แต่จะส่งคืนวัตถุสตริงใหม่ทุกครั้ง ไม่มีประโยชน์ที่จะเขียน:
str1.replace("Java", "Python");
- คุณจะไม่เปลี่ยนวัตถุดั้งเดิม แต่ถ้าคุณเขียนผลลัพธ์ของวิธีการลงในตัวแปรอ้างอิงใหม่ คุณจะเห็นความแตกต่างทันที!
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ใช้ได้ คุณไม่สามารถทำอะไรกับ วัตถุ "ฉันรัก Java" เพียงสร้างวัตถุใหม่และเขียน: “วัตถุใหม่ = ผลลัพธ์ของการยักย้ายบางอย่างด้วย วัตถุ “ ฉันรัก Java”ประเภทอื่น ๆ ที่ไม่เปลี่ยนรูปมีอะไรบ้าง? จากสิ่งที่คุณต้องจำไว้ตอนนี้ - คลาส wrapper ทั้งหมดเหนือประเภทดั้งเดิมนั้นไม่เปลี่ยนรูป Integer, Byte, Character, Short, Boolean, Long, Double, Float- คลาสทั้งหมดเหล่านี้สร้างวัตถุที่ไม่เปลี่ยนรูป รวมถึงคลาสที่ใช้สร้างตัวเลขจำนวนมาก - BigIntegerและBigDecimal. เมื่อเร็วๆ นี้เราได้ผ่านข้อยกเว้นและได้ดำเนินการStackTraceแล้ว ดังนั้น: อ็อบเจ็กต์ของ คลาส java.lang.StackTraceElementก็ไม่เปลี่ยนรูปเช่นกัน นี่เป็นตรรกะ: หากมีใครสามารถเปลี่ยนแปลงข้อมูลในสแต็กของเราได้ ก็อาจทำให้การทำงานในนั้นกลายเป็นโมฆะได้ ลองนึกภาพใคร บางคนเข้าไปในStackTraceและเปลี่ยนOutOfMemoryErrorเป็นFileNotFoundException และคุณควรทำงานกับสแต็กนี้และค้นหาสาเหตุของข้อผิดพลาด และโปรแกรมไม่ได้ใช้ไฟล์เลย :) ดังนั้นเพื่อความปลอดภัย วัตถุเหล่านี้จึงถูกทำให้ไม่เปลี่ยนรูป ด้วยStackTraceElementมันชัดเจนไม่มากก็น้อย ทำไมทุกคนถึงอยากให้สตริงไม่เปลี่ยนรูป? จะเกิดปัญหาอะไรขึ้นหากสามารถเปลี่ยนค่านิยมได้ คงจะสะดวกกว่านี้อีก :/ มีสาเหตุหลายประการ ประการแรก การบันทึกหน่วยความจำ สามารถวางสตริงที่ไม่เปลี่ยนรูปได้String Poolและสามารถใช้สตริงเดียวกันในแต่ละครั้งแทนการสร้างสตริงใหม่ ประการที่สองความปลอดภัย ตัวอย่างเช่น ข้อมูลเข้าสู่ระบบและรหัสผ่านส่วนใหญ่ในโปรแกรมใดๆ จะเป็นสตริง ความเป็นไปได้ในการเปลี่ยนแปลงอาจนำไปสู่ปัญหาเกี่ยวกับการอนุญาตได้ มีเหตุผลอื่นๆ อีก แต่เรายังไม่เข้าใจเหตุผลเหล่านั้นในการเรียนรู้ Java เราจะกลับมาใหม่ในภายหลัง
ความคิดเห็น
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION