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

Private
— ตัวแก้ไขการเข้าถึงที่เข้มงวดที่สุด มันจำกัดการมองเห็นข้อมูลและวิธีการภายในคลาสเดียว คุณรู้จักตัวดัดแปลงนี้จากการบรรยายเกี่ยวกับ 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
. 
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)
. 
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()
ฯลฯ
GO TO FULL VERSION