ภาษา Java มีตัวดัดแปลงมากมาย ซึ่งส่วนใหญ่แบ่งออกเป็นสองประเภทดังต่อไปนี้:
โมดิฟายเออร์ใช้เพื่อกำหนดคลาส วิธีการ หรือตัวแปร และมักจะวางไว้ด้านหน้าคำสั่ง เราอธิบายสิ่งนี้ผ่านตัวอย่างต่อไปนี้:
public class className { // ... } private boolean myFlag; static final double weeks = 9.5; protected static final int BOXWIDTH = 42; public static void main(String[] arguments) { // 方法体}
ใน Java การควบคุมการเข้าถึงสามารถใช้เพื่อป้องกันการเข้าถึงคลาส ตัวแปร เมธอด และคอนสตรัคเตอร์ Java รองรับสิทธิ์การเข้าถึงที่แตกต่างกัน 4 แบบ
ค่าดีฟอลต์หรือที่เรียกว่าค่าดีฟอลต์ สามารถมองเห็นได้ภายในแพ็คเกจเดียวกันและไม่ได้ใช้ตัวแก้ไขใดๆ
ส่วนตัว ระบุด้วยตัวแก้ไขส่วนตัว ซึ่งมองเห็นได้ภายในคลาสเดียวกัน
สาธารณะ ระบุด้วยตัวแก้ไขสาธารณะ มองเห็นได้กับทุกชั้นเรียน
Protected ซึ่งระบุด้วย modifier ที่มีการป้องกัน จะมองเห็นได้สำหรับคลาสและคลาสย่อยทั้งหมดในแพ็คเกจเดียวกัน
ตัวแปรและเมธอดที่ประกาศด้วยตัวดัดแปลงการเข้าถึงเริ่มต้นจะมองเห็นได้โดยคลาสในแพ็คเกจเดียวกัน ตัวแปรในอินเทอร์เฟซได้รับการประกาศโดยปริยายว่าเป็น public static final
ในขณะที่วิธีการในอินเทอร์เฟซมีสิทธิ์การเข้าถึงของ public
ตามค่าเริ่มต้น
ตัวอย่าง:
ดังที่แสดงในตัวอย่างต่อไปนี้ ตัวแปรและวิธีการสามารถประกาศได้โดยไม่ต้องมีตัวดัดแปลงใดๆ
String version = "1.5.1"; boolean processOrder() { return true; }
ตัวแก้ไขการเข้าถึงส่วนตัวเป็นระดับการเข้าถึงที่เข้มงวดที่สุด ดังนั้นเมธอด ตัวแปร และตัวสร้างที่ประกาศให้เป็นส่วนตัวสามารถเข้าถึงได้โดยคลาสที่เป็นเจ้าของเท่านั้น และคลาสและอินเทอร์เฟซไม่สามารถประกาศให้เป็นส่วนตัวได้
ตัวแปรที่ประกาศเป็นประเภทการเข้าถึงส่วนตัวสามารถเข้าถึงได้โดยคลาสภายนอกผ่านวิธี getter สาธารณะในคลาสเท่านั้น
การใช้ตัวแก้ไขการเข้าถึงส่วนตัวส่วนใหญ่จะใช้เพื่อซ่อนรายละเอียดการใช้งานของคลาสและปกป้องข้อมูลของคลาส
คลาสต่อไปนี้ใช้ตัวแก้ไขการเข้าถึงส่วนตัว:
public class Logger { private String format; public String getFormat() { return this.format; } public void setFormat(String format) { this.format = format; } }
ในตัวอย่าง ตัวแปรรูปแบบในคลาส Logger เป็นตัวแปรส่วนตัว ดังนั้นคลาสอื่นจึงไม่สามารถรับและตั้งค่าของตัวแปรได้โดยตรง เพื่อให้คลาสอื่นสามารถดำเนินการกับตัวแปรนี้ได้ จึงมีการกำหนดวิธี public
สองวิธี: getFormat()
(ส่งคืนค่าของรูปแบบ) และ setFormat(String)
(ตั้งค่าของรูปแบบ)
คลาส เมธอด ตัวสร้าง และอินเทอร์เฟซที่ประกาศเป็นสาธารณะสามารถเข้าถึงได้โดยคลาสอื่น
หากคลาสสาธารณะหลายคลาสที่เข้าถึงซึ่งกันและกันมีการกระจายในแพ็คเกจที่แตกต่างกัน คุณจะต้องนำเข้าแพ็คเกจที่มีคลาสสาธารณะที่เกี่ยวข้องตั้งอยู่ เนื่องจากการสืบทอดคลาส วิธีการสาธารณะและตัวแปรทั้งหมดของคลาสจึงสามารถสืบทอดโดยคลาสย่อยของมันได้
ฟังก์ชั่นต่อไปนี้ใช้การควบคุมการเข้าถึงสาธารณะ:
public static void main(String[] arguments) { // ... }
เมธอด main() ของโปรแกรม Java จะต้องตั้งค่าเป็นสาธารณะ มิฉะนั้น ล่าม Java จะไม่สามารถเรียกใช้คลาสได้
ตัวแปร วิธีการ และตัวสร้างที่ประกาศเป็นการป้องกันสามารถเข้าถึงได้โดยคลาสอื่น ๆ ในแพ็คเกจเดียวกัน หรือโดยคลาสย่อยในแพ็คเกจที่แตกต่างกัน
ตัวดัดแปลงการเข้าถึงที่ได้รับการป้องกันไม่สามารถแก้ไขคลาสและอินเทอร์เฟซได้ วิธีการและตัวแปรสมาชิกสามารถประกาศการป้องกันได้ แต่ตัวแปรสมาชิกและวิธีการสมาชิกของอินเทอร์เฟซไม่สามารถประกาศการป้องกันได้
คลาสย่อยสามารถเข้าถึงเมธอดและตัวแปรที่ประกาศด้วยตัวดัดแปลงที่ได้รับการป้องกัน ดังนั้นจึงป้องกันคลาสที่ไม่เกี่ยวข้องจากการใช้วิธีการและตัวแปรเหล่านี้
คลาสพาเรนต์ต่อไปนี้ใช้ตัวแก้ไขการเข้าถึงที่ได้รับการป้องกัน และคลาสย่อยจะแทนที่เมธอด openSpeaker() ของคลาสพาเรนต์
class AudioPlayer { protected boolean openSpeaker(Speaker sp) { // 实现细节} } class StreamingAudioPlayer extends AudioPlayer { boolean openSpeaker(Speaker sp) { // 实现细节} }
หากมีการประกาศเมธอด openSpeaker() ส่วนตัว คลาสอื่นที่ไม่ใช่ AudioPlayer จะไม่สามารถเข้าถึงเมธอดนี้ได้
หาก openSpeaker() ถูกประกาศเป็นสาธารณะ ทุกคลาสจะสามารถเข้าถึงวิธีนี้ได้
ถ้าเราต้องการให้เมธอดปรากฏแก่คลาสย่อยของคลาสเท่านั้น ให้ประกาศเมธอดนั้นว่าได้รับการป้องกัน
โปรดทราบกฎต่อไปนี้สำหรับการสืบทอดวิธีการ:
วิธีการประกาศให้เป็นแบบสาธารณะในชั้นเรียนหลักจะต้องเป็นแบบสาธารณะในชั้นเรียนย่อยด้วย
วิธีการที่ประกาศว่ามีการป้องกันในคลาสพาเรนต์จะถูกประกาศให้เป็นแบบมีการป้องกันหรือเปิดเผยต่อสาธารณะในคลาสย่อย ไม่สามารถประกาศเป็นส่วนตัวได้
เมธอดที่ประกาศเป็นไพรเวตในคลาสพาเรนต์ไม่สามารถสืบทอดได้
เพื่อที่จะใช้งานฟังก์ชันอื่นๆ Java ยังมีตัวดัดแปลงที่ไม่สามารถเข้าถึงได้อีกมากมาย
ตัวแก้ไขแบบคงที่ใช้เพื่อสร้างวิธีการเรียนและตัวแปรคลาส
ตัวแก้ไขขั้นสุดท้ายใช้เพื่อแก้ไขคลาส วิธีการ และตัวแปร คลาสที่แก้ไขโดยขั้นสุดท้ายไม่สามารถสืบทอดได้ วิธีการแก้ไขไม่สามารถกำหนดใหม่โดยคลาสที่สืบทอดมา และตัวแปรที่ถูกแก้ไขจะเป็นค่าคงที่และไม่สามารถแก้ไขได้
ตัวดัดแปลงนามธรรมใช้เพื่อสร้างคลาสนามธรรมและวิธีการนามธรรม
โมดิฟายเออร์แบบซิงโครไนซ์และแบบระเหยส่วนใหญ่จะใช้สำหรับการเขียนโปรแกรมเธรด
ตัวแปรคงที่:
คำหลักแบบคงที่ใช้ในการประกาศตัวแปรแบบคงที่ที่ไม่ขึ้นอยู่กับวัตถุ ไม่ว่าคลาสจะสร้างอินสแตนซ์จำนวนเท่าใดก็ตาม จะมีเพียงสำเนาเดียวของตัวแปรแบบคงที่เท่านั้น ตัวแปรคงที่เรียกอีกอย่างว่าตัวแปรคลาส ไม่สามารถประกาศตัวแปรท้องถิ่นเป็นตัวแปรคงที่ได้
วิธีการคงที่:
คำหลักแบบคงที่ใช้ในการประกาศวิธีการแบบคงที่โดยไม่ขึ้นอยู่กับวัตถุ วิธีการแบบคงที่ไม่สามารถใช้ตัวแปรที่ไม่คงที่ของคลาส วิธีการคงที่รับข้อมูลจากรายการพารามิเตอร์แล้วคำนวณข้อมูล
การเข้าถึงตัวแปรคลาสและวิธีการสามารถเข้าถึงได้โดยตรงโดยใช้ classname.variablename
และ classname.methodname
ดังที่แสดงในตัวอย่างต่อไปนี้ ตัวดัดแปลงแบบคงที่ถูกใช้เพื่อสร้างวิธีการเรียนและตัวแปรคลาส
public class InstanceCounter { private static int numInstances = 0; protected static int getCount() { return numInstances; } private static void addInstance() { numInstances++; } InstanceCounter() { InstanceCounter.addInstance(); } public static void main(String[] arguments) { System.out.println("Starting with " + InstanceCounter.getCount() + " instances"); for (int i = 0; i < 500; ++i){ new InstanceCounter(); } System.out.println("Created " + InstanceCounter.getCount() + " instances"); } }
ผลลัพธ์การแก้ไขของการรันตัวอย่างข้างต้นมีดังนี้:
Started with 0 instances Created 500 instances
ตัวแปรสุดท้าย:
ตัวแปรสุดท้ายสามารถเริ่มต้นได้อย่างชัดเจนและเพียงครั้งเดียวเท่านั้น การอ้างอิงถึงวัตถุที่ประกาศขั้นสุดท้ายไม่สามารถชี้ไปยังวัตถุที่แตกต่างกันได้ แต่ข้อมูลในออบเจ็กต์สุดท้ายสามารถเปลี่ยนแปลงได้ กล่าวอีกนัยหนึ่ง การอ้างอิงของวัตถุสุดท้ายไม่สามารถเปลี่ยนแปลงได้ แต่ค่าภายในสามารถเปลี่ยนแปลงได้
ตัวแก้ไขสุดท้ายมักจะใช้ร่วมกับตัวแก้ไขแบบคงที่เพื่อสร้างค่าคงที่ของคลาส
ตัวอย่าง:
public class Test{ final int value = 10; // 下面是声明常量的实例public static final int BOXWIDTH = 6; static final String TITLE = "Manager"; public void changeValue(){ value = 12; //将输出一个错误} }
วิธีการสุดท้ายในคลาสสามารถสืบทอดโดยคลาสย่อย แต่ไม่สามารถแก้ไขได้โดยคลาสย่อย
วัตถุประสงค์หลักของการประกาศวิธีการขั้นสุดท้ายคือเพื่อป้องกันไม่ให้เนื้อหาของวิธีการถูกแก้ไข
ดังที่แสดงด้านล่าง ประกาศวิธีการโดยใช้ตัวแก้ไขขั้นสุดท้าย
public class Test{ public final void changeName(){ // 方法体} }
คลาสสุดท้ายไม่สามารถสืบทอดได้ และไม่มีคลาสใดที่สามารถสืบทอดคุณลักษณะใดๆ ของคลาสสุดท้ายได้
ตัวอย่าง:
public final class Test { // 类体}
คลาสนามธรรม:
คลาสนามธรรมไม่สามารถใช้เพื่อสร้างอินสแตนซ์ของวัตถุได้ จุดประสงค์เดียวของการประกาศคลาสนามธรรมคือการขยายคลาสในอนาคต
คลาสไม่สามารถแก้ไขได้ด้วยนามธรรมและขั้นสุดท้ายในเวลาเดียวกัน ถ้าคลาสมีเมธอด abstract คลาสนั้นจะต้องถูกประกาศเป็นคลาส abstract มิฉะนั้นจะเกิดข้อผิดพลาดในการคอมไพล์
คลาสนามธรรมสามารถมีวิธีนามธรรมและวิธีที่ไม่ใช่นามธรรม
ตัวอย่าง:
abstract class Caravan{ private double price; private String model; private String year; public abstract void goFast(); //抽象方法public abstract void changeColor(); }
วิธีการเชิงนามธรรมเป็นวิธีการที่ไม่มีการใช้งานใด ๆ การใช้งานเฉพาะของวิธีการนั้นจัดทำโดยคลาสย่อย วิธีการเชิงนามธรรมไม่สามารถประกาศขั้นสุดท้ายและแบบคงที่ได้
คลาสย่อยใดๆ ที่สืบทอดคลาสนามธรรมจะต้องใช้วิธีการนามธรรมทั้งหมดของคลาสพาเรนต์ เว้นแต่คลาสย่อยนั้นจะเป็นคลาสนามธรรมด้วย
หากชั้นเรียนมีวิธีนามธรรมหลายวิธี จะต้องประกาศคลาสนั้นเป็นคลาสนามธรรม คลาสนามธรรมไม่จำเป็นต้องมีวิธีนามธรรม
การประกาศวิธีนามธรรมจะลงท้ายด้วยเครื่องหมายอัฒภาค เช่น public abstract example();
ตัวอย่าง:
public abstract class SuperClass{ abstract void m(); //抽象方法} class SubClass extends SuperClass{ //实现抽象方法void m(){ ......... } }
วิธีการประกาศด้วยคำสำคัญที่ซิงโครไนซ์สามารถเข้าถึงได้โดยเธรดเดียวเท่านั้นในเวลาเดียวกัน ตัวแก้ไข Synchronized สามารถนำไปใช้กับตัวแก้ไขการเข้าถึงสี่ตัว
ตัวอย่าง:
public synchronized void showDetails(){ ....... }
เมื่ออ็อบเจ็กต์ซีเรียลไลซ์มีตัวแปรอินสแตนซ์ที่ถูกแก้ไขโดยชั่วคราว Java Virtual Machine (JVM) จะข้ามตัวแปรนั้นไป
ตัวแก้ไขนี้รวมอยู่ในคำสั่งที่กำหนดตัวแปรและใช้เพื่อประมวลผลชนิดข้อมูลของคลาสและตัวแปรล่วงหน้า
ตัวอย่าง:
public transient int limit = 55; // will not persist public int b; // will persist
แต่ละครั้งที่มีการเข้าถึงตัวแปรสมาชิกที่แก้ไขแล้วระเหยได้โดยเธรด ค่าของตัวแปรสมาชิกจะถูกบังคับให้อ่านซ้ำจากหน่วยความจำแบบแบ่งใช้ นอกจากนี้ เมื่อตัวแปรสมาชิกเปลี่ยนแปลง เธรดจะถูกบังคับให้เขียนค่าที่เปลี่ยนแปลงกลับไปยังหน่วยความจำแบบแบ่งใช้ ด้วยวิธีนี้ เมื่อใดก็ได้ สองเธรดที่แตกต่างกันจะเห็นค่าเดียวกันของตัวแปรสมาชิกเสมอ
การอ้างอิงวัตถุที่ระเหยอาจเป็นโมฆะ
ตัวอย่าง:
public class MyRunnable implements Runnable { private volatile boolean active; public void run() { active = true; while (active) // line 1 { // 代码} } public void stop() { active = false; // line 2 } }
โดยทั่วไปแล้ว เมธอด run() จะถูกเรียกในเธรดหนึ่ง และเมธอด stop() จะถูกเรียกในอีกเธรดอื่น หากใช้ค่าของแอคทีฟในบรรทัดที่ 1 ในบัฟเฟอร์ การวนซ้ำจะไม่หยุดเมื่อแอคทีฟในบรรทัด 2 ถูกตั้งค่าเป็นเท็จ