JavaRush /จาวาบล็อก /Random-TH /ตัวดัดแปลงการเข้าถึง ส่วนตัว ได้รับการป้องกัน ค่าเริ่มต้น...

ตัวดัดแปลงการเข้าถึง ส่วนตัว ได้รับการป้องกัน ค่าเริ่มต้น สาธารณะ

เผยแพร่ในกลุ่ม
สวัสดี! ในการบรรยายวันนี้ เราจะมาทำความคุ้นเคยกับแนวคิดของ “ access modifiers ” และดูตัวอย่างการทำงานกับพวกมัน ตัวดัดแปลงการเข้าถึง  ส่วนตัว, ได้รับการป้องกัน, ค่าเริ่มต้น, สาธารณะ - 1แม้ว่าคำว่า "มาทำความรู้จักกันเถอะ" จะไม่ถูกต้องทั้งหมด แต่คุณคุ้นเคยกับคำเหล่านี้ส่วนใหญ่จากการบรรยายครั้งก่อนแล้ว เผื่อว่าเราจะรีเฟรชความทรงจำเกี่ยวกับสิ่งสำคัญกัน Access Modifiersมักเป็นคีย์เวิร์ดที่ควบคุมระดับการเข้าถึงส่วนต่างๆ ของโค้ดของคุณ ทำไม "บ่อยที่สุด"? เนื่องจากหนึ่งในนั้นถูกตั้งค่าตามค่าเริ่มต้นและไม่ได้ระบุด้วยคำหลัก :) มีตัวแก้ไขการเข้าถึงทั้งหมดสี่ตัวใน Java เราแสดงรายการตามลำดับที่เข้มงวดที่สุดไปจนถึง "นุ่มนวล" ที่สุด:
  • ส่วนตัว;
  • มีการป้องกัน;
  • ค่าเริ่มต้น (มองเห็นแพ็คเกจ);
  • สาธารณะ.
ลองดูแต่ละรายการตัดสินใจว่าเมื่อใดจะมีประโยชน์สำหรับเราและยกตัวอย่าง :)

ตัวแก้ไขส่วนตัว

ตัวดัดแปลงการเข้าถึง  ส่วนตัว, ได้รับการป้องกัน, ค่าเริ่มต้น, สาธารณะ - 2Private— ตัวแก้ไขการเข้าถึงที่เข้มงวดที่สุด มันจำกัดการมองเห็นข้อมูลและวิธีการภายในคลาสเดียว คุณรู้จักตัวดัดแปลงนี้จากการบรรยายเกี่ยวกับ getters และ setters จำตัวอย่างนี้ได้ไหม?
public class Cat {

   public String name;
   public int age;
   public int weight;

   public Cat(String name, int age, int weight) {
       this.name = name;
       this.age = age;
       this.weight = weight;
   }

   public Cat() {
   }

   public void sayMeow() {
       System.out.println("Meow!");
   }
}

public class Main {

   public static void main(String[] args) {

       Cat cat = new Cat();
       cat.name = "";
       cat.age = -1000;
       cat.weight = 0;
   }
}
เราดูมันในบทความหนึ่งก่อนหน้านี้ ที่นี่เราทำผิดพลาดร้ายแรง: เราเปิดข้อมูลของเราซึ่งเป็นผลมาจากการที่เพื่อนโปรแกรมเมอร์สามารถเข้าถึงฟิลด์คลาสได้โดยตรงและเปลี่ยนค่าของพวกเขา ยิ่งไปกว่านั้น ค่าเหล่านี้ถูกกำหนดโดยไม่มีการตรวจสอบด้วยเหตุนี้จึงเป็นไปได้ที่จะสร้างแมวที่มีอายุ -1,000 ปี ชื่อ "" และน้ำหนัก 0 ในโปรแกรมของเรา เพื่อแก้ไขปัญหานี้ เรา ใช้getters และ settersและยังจำกัดการเข้าถึงข้อมูลโดยใช้ตัวprivateแก้ไข
public class Cat {

   private String name;
   private int age;
   private int weight;

   public Cat(String name, int age, int weight) {
       this.name = name;
       this.age = age;
       this.weight = weight;
   }

   public Cat() {
   }

   public void sayMeow() {
       System.out.println("Meow!");
   }

   public String getName() {
       return name;
   }

   public void setName(String name) {
       // checking the input parameter
       this.name = name;
   }

   public int getAge() {
       return age;
   }

   public void setAge(int age) {
       // checking the input parameter
       this.age = age;
   }

   public int getWeight() {
       return weight;
   }

   public void setWeight(int weight) {
       // checking the input parameter
       this.weight = weight;
   }
}
ที่จริงแล้วการจำกัดการเข้าถึงฟิลด์และการใช้งาน getters-setters เป็นตัวอย่างการใช้งานที่พบบ่อยที่สุดprivateในการทำงานจริง นั่นคือการนำการห่อหุ้มไปใช้ในโปรแกรมคือจุดประสงค์หลักของตัวปรับแต่งนี้ สิ่งนี้ไม่เพียงแต่ใช้กับฟิลด์เท่านั้น ลองนึกภาพว่าในโปรแกรมของคุณมีวิธีการที่ใช้ฟังก์ชันการทำงานที่ซับซ้อนมากบางอย่าง เพื่อเป็นตัวอย่าง... สมมติว่าวิธีการของคุณreadDataFromCollider()ใช้ที่อยู่ที่มีข้อมูลเป็นอินพุต อ่านข้อมูลจาก Large Hadron Collider ในรูปแบบไบต์ แปลงข้อมูลนี้เป็นข้อความ เขียนลงในไฟล์ และพิมพ์ออกมา แม้แต่คำอธิบายของวิธีการก็ดูน่าขนลุกนับประสาอะไรกับโค้ด :) เพื่อเพิ่มความสามารถในการอ่านโค้ดจะเป็นการดีที่จะไม่เขียนตรรกะที่ซับซ้อนของวิธีการในที่เดียว แต่ในทางกลับกันเพื่อทำลายฟังก์ชันการทำงาน ออกเป็นวิธีการแยกกัน ตัวอย่างเช่น วิธีการนี้readByteData()มีหน้าที่ในการอ่านข้อมูลconvertBytesToSymbols()แปลงข้อมูลที่อ่านจากคอลไลเดอร์ให้เป็นsaveToFile()ข้อความ บันทึกข้อความผลลัพธ์ลงในไฟล์ และprintColliderData()พิมพ์ไฟล์ข้อมูลของเรา วิธีการreadDataFromCollider()จะง่ายกว่ามาก:
public class ColliderUtil {

   public void readDataFromCollider(Path pathToData) {
       byte[] colliderData = readByteData(pathToData);
       String[] textData = convertBytesToSymbols(colliderData);
       File fileWithData = saveToFile(textData);
       printColliderData(fileWithData);
   }

   public byte[] readByteData(Path pathToData) {

       // reads data in bytes
   }

   public String[] convertBytesToSymbols(byte[] colliderDataInBytes) {

       // convert bytes to characters
   }

   public File saveToFile(String[] colliderData) {

       // save the read data to a file
   }

   public void printColliderData(File fileWithColliderData) {

       // print data from file
   }
}
อย่างไรก็ตาม ดังที่คุณจำได้จากการบรรยายเกี่ยวกับอินเทอร์เฟซ ผู้ใช้จะสามารถเข้าถึงอินเทอร์เฟซสุดท้ายเท่านั้น และทั้ง 4 วิธีของเราไม่ได้เป็นส่วนหนึ่งของมัน เป็นส่วนเสริม : เราสร้างขึ้นเพื่อปรับปรุงความสามารถในการอ่านโค้ดและเพื่อหลีกเลี่ยงการยัดเยียดงานที่แตกต่างกันสี่งานให้อยู่ในวิธีเดียว ไม่จำเป็นต้องให้ผู้ใช้เข้าถึงวิธีการเหล่านี้ได้ หากผู้ใช้สามารถเข้าถึงวิธีการนี้เมื่อทำงานกับ Collider convertBytesToSymbols()เขามักจะไม่เข้าใจว่าวิธีนี้คืออะไรและทำไมจึงจำเป็น ไบต์ใดที่ถูกแปลง? พวกเขามาจากไหน? ทำไมต้องแปลงเป็นข้อความ? ตรรกะที่ทำงานในวิธีนี้ไม่ได้เป็นส่วนหนึ่งของอินเทอร์เฟซผู้ใช้ เฉพาะวิธีการเท่านั้นreadDataFromCollider()ที่เป็นส่วนหนึ่งของอินเทอร์เฟซ จะทำอย่างไรกับวิธี "ภายใน" ทั้งสี่นี้ ขวา! จำกัดการเข้าถึงด้วยตัวprivateแก้ไข วิธีนี้ทำให้พวกเขาสามารถทำงานภายในชั้นเรียนได้อย่างง่ายดาย และไม่ทำให้ผู้ใช้สับสนซึ่งไม่ต้องการตรรกะของแต่ละคนแยกกัน
public class ColliderUtil {

   public void readDataFromCollider(Path pathToData) {
       byte[] colliderData = readByteData(pathToData);
       String[] textData = convertBytesToSymbols(colliderData);
       File fileWithData = saveToFile(textData);
       printColliderData(fileWithData);
   }

   private byte[] readByteData(Path pathToData) {
       // reads data in bytes
   }

   private String[] convertBytesToSymbols(byte[] colliderDataInBytes) {
       // convert bytes to characters
   }

   private File saveToFile(String[] colliderData) {
       // save the read data to a file
   }

   private void printColliderData(File fileWithColliderData) {
       // print data from file
   }
}

มีการป้องกันตัวแก้ไข

ตัวแก้ไขการเข้าถึงที่จำกัดลำดับถัดไปคือprotected. ตัวดัดแปลงการเข้าถึง  ส่วนตัว, ได้รับการป้องกัน, ค่าเริ่มต้น, สาธารณะ - 3 ฟิลด์และวิธีการที่กำหนดด้วยตัวแก้ไขการเข้าถึงprotectedจะมองเห็นได้:
  • ภายในทุกคลาสที่อยู่ในแพ็คเกจเดียวกันกับของเรา
  • ภายในคลาสที่สืบทอดทั้งหมดของคลาสของเรา
เป็นเรื่องยากที่จะจินตนาการได้ทันทีว่าสิ่งนี้อาจจำเป็นเมื่อใด อย่าแปลกใจ: protectedมีกรณีการสมัครน้อยกว่าprivateและมีความเฉพาะเจาะจง มาก ลองนึกภาพว่าเรามีคลาสนามธรรมAbstractSecretAgentที่แสดงถึงสายลับของหน่วยข่าวกรองบางแห่ง เช่นเดียวกับแพ็คเกจtop_secretที่ประกอบด้วยคลาสนี้และผู้สืบทอด คลาสที่เป็นรูปธรรม - FBISecretAgent, MI6SecretAgentฯลฯMossadSecretAgent- ได้รับการสืบทอดมาจากคลาสนั้น ภายในคลาสนามธรรมเราต้องการใช้ตัวนับตัวแทน เมื่อมีการสร้างอ็อบเจ็กต์เอเจนต์ใหม่ขึ้นที่ไหนสักแห่งในโปรแกรม ออบเจ็กต์จะเพิ่มขึ้น
package top_secret;

public abstract class AbstractSecretAgent {

   public static int agentCount = 0;
}
แต่ตัวแทนของเราเป็นความลับ! ซึ่งหมายความว่ามีเพียงพวกเขาและไม่มีใครควรรู้เกี่ยวกับหมายเลขของพวกเขา เราสามารถเพิ่มตัวแก้ไขลงprotectedในฟิลด์ ได้อย่างง่ายดาย agentCountจากนั้นอ็อบเจ็กต์ของคลาสสายลับอื่น ๆ หรือคลาสที่อยู่ในแพ็คเกจ "ความลับ" ของเรา ก็สามารถรับค่าของมันtop_secretได้
public abstract class AbstractSecretAgent {

   protected static int agentCount = 0;
}
มันมีไว้สำหรับงานเฉพาะที่จำเป็นต้องมีตัวดัดแปลงprotected:)

ตัวแก้ไขแพ็คเกจที่มองเห็นได้

ถัดไปในรายการของเราคือตัวแก้ไขdefaultหรือที่เรียกกันว่าpackage visible. ไม่ได้ระบุด้วยคีย์เวิร์ดเนื่องจากมีการตั้งค่าเริ่มต้นใน Java สำหรับทุกฟิลด์และวิธีการ หากคุณเขียนโค้ดของคุณ -
int x = 10;
... ตัวแปรxจะมีpackage visibleสิทธิ์เข้าถึง แบบเดียวกันนี้ ถ้าเมธอด (หรือตัวแปร) ไม่ได้ถูกทำเครื่องหมายด้วยตัวแก้ไขใดๆ จะถือว่าถูกทำเครื่องหมายด้วย "ตัวแก้ไขเริ่มต้น" ตัวแปรหรือเมธอดที่มีตัวปรับแต่ง (เช่น ไม่มีเลย) จะปรากฏแก่ทุกคลาสของแพ็คเกจที่มีการประกาศตัวแปรเหล่านั้น และสำหรับพวกเขาเท่านั้น การใช้งานมีจำกัด เช่นเดียวกับตัวprotectedแก้ไข ส่วนใหญ่มักdefaultจะใช้ -access ในแพ็คเกจที่มีคลาสยูทิลิตี้บางคลาสที่ไม่ได้ใช้ฟังก์ชันการทำงานของคลาสอื่นทั้งหมดในแพ็คเกจนี้ ลองยกตัวอย่าง ลองจินตนาการว่าเรามีแพ็คเกจ " บริการ " ภายในมีคลาสต่างๆ ที่ทำงานกับฐานข้อมูล ตัวอย่างเช่น มีคลาสUserServiceที่อ่านข้อมูลผู้ใช้จากฐานข้อมูล คลาสCarServiceที่อ่านข้อมูลเกี่ยวกับรถยนต์จากฐานข้อมูลเดียวกัน และคลาสอื่นๆ ซึ่งแต่ละคลาสทำงานกับออบเจ็กต์ประเภทของตัวเองและอ่านข้อมูลเกี่ยวกับรถยนต์จากฐานข้อมูล
package services;

public class UserService {
}

package services;

public class CarService {
}
อย่างไรก็ตาม สถานการณ์สามารถเกิดขึ้นได้ง่ายเมื่อข้อมูลในฐานข้อมูลอยู่ในรูปแบบหนึ่ง แต่เราต้องการในรูปแบบอื่น ลองจินตนาการว่าวันเกิดของผู้ใช้ในฐานข้อมูลถูกจัดเก็บในรูปแบบ TIMESTAMP WITH TIME ZONE...
2014-04-04 20:32:59.390583+02
...เราต้องการวัตถุที่ง่ายที่สุดแทน - java.util.Date. เพื่อจุดประสงค์นี้ เราสามารถสร้างservicesคลาสพิเศษ ภายในแพ็คเกจ Mapperได้ เขาจะรับผิดชอบในการแปลงข้อมูลจากฐานข้อมูลเป็นวัตถุ Java ที่เราคุ้นเคย คลาสตัวช่วยง่ายๆ โดยปกติแล้วเราจะสร้างคลาสทั้งหมดเป็นpublic class ClassNameแต่สิ่งนี้ไม่จำเป็น เราสามารถประกาศคลาส helper ของเราได้ง่ายๆ เป็นclass Mapper. ในกรณีนี้ มันยังคงใช้งานได้ แต่ไม่มีใครมองเห็นได้นอกแพ็คเกจservices!
package services;

class Mapper {
}


package services;

public class CarService {

   Mapper mapper;
}
และนี่คือตรรกะที่ถูกต้อง: ทำไมคนภายนอกแพ็คเกจถึงเห็นคลาสเสริมที่ใช้งานได้กับคลาสของแพ็คเกจเดียวกันเท่านั้น?

ตัวแก้ไขสาธารณะ

และสุดท้ายในรายการ แต่ไม่ท้ายสุด - ตัวแก้ไขpublic! คุณพบเขาในวันแรกของการเรียนที่ JavaRush โดยเปิดตัวpublic static void main(String[] args). ตัวดัดแปลงการเข้าถึง  ส่วนตัว, ได้รับการป้องกัน, ค่าเริ่มต้น, สาธารณะ - 4 ตอนนี้คุณได้ศึกษาการบรรยายเกี่ยวกับอินเทอร์เฟซแล้ว จุดประสงค์ของมันก็ชัดเจนสำหรับคุณ :) ท้ายที่สุดpublicมันถูกสร้างขึ้นเพื่อมอบบางสิ่งให้กับผู้ใช้ ตัวอย่างเช่น อินเทอร์เฟซของโปรแกรมของคุณ สมมติว่าคุณเขียนโปรแกรมแปลและสามารถแปลข้อความภาษารัสเซียเป็นภาษาอังกฤษได้ คุณได้สร้างวิธีการtranslate(String textInRussian)ที่ใช้ตรรกะที่จำเป็น คุณทำเครื่องหมายวิธีนี้ด้วยคำว่าpublicและตอนนี้มันจะกลายเป็นส่วนหนึ่งของอินเทอร์เฟซ:
public class Translator {

   public String translate(String textInRussian) {

       // translates text from Russian to English
   }
}
คุณสามารถเชื่อมโยงการโทรเข้ากับวิธีนี้ได้ด้วยปุ่ม "แปล" บนหน้าจอโปรแกรม - เท่านี้ก็เรียบร้อย! ใครๆก็ใช้มันได้ บางส่วนของรหัสที่มีเครื่องหมายตัวแก้ไขpublicนั้นมีไว้สำหรับผู้ใช้ปลายทาง เพื่อเป็นตัวอย่างในชีวิตprivateนี่คือกระบวนการทั้งหมดที่เกิดขึ้นภายในทีวีในขณะที่ทีวีทำงาน และpublicนี่คือปุ่มบนรีโมทคอนโทรลของทีวีที่ผู้ใช้สามารถควบคุมได้ ในขณะเดียวกัน เขาไม่จำเป็นต้องรู้ว่าทีวีทำงานอย่างไรและทำงานอย่างไร รีโมทคอนโทรลเป็นชุดpublicของ -methods: on(), off(), nextChannel(), previousChannel(), increaseVolume(), decreaseVolume()ฯลฯ
ความคิดเห็น
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION