ตัวระบุการเข้าถึงเริ่มต้นใน Java คืออะไร?


108

ฉันเพิ่งเริ่มอ่านหนังสือ Java และสงสัยว่า ตัวระบุการเข้าถึงใดเป็นค่าเริ่มต้นหากไม่มีการระบุ


คำที่ถูกต้องคือ 'access modifier' คำว่า 'ตัวระบุ' ไม่ปรากฏใน JLS
Marquis of Lorne

คำตอบ:


116

การมองเห็นเริ่มต้นเรียกว่า "package-private" (แม้ว่าคุณจะไม่สามารถใช้สิ่งนี้ได้อย่างชัดเจน) ซึ่งหมายความว่าจะสามารถเข้าถึงฟิลด์นี้ได้จากภายในแพ็กเกจเดียวกันกับคลาสที่เป็นสมาชิก

ดังที่ mdma ชี้ให้เห็นมันไม่เป็นความจริงสำหรับสมาชิกอินเทอร์เฟซซึ่งค่าเริ่มต้นคือ "สาธารณะ"

ดูตัวระบุการเข้าถึงของ Java


25
ไม่ถูกต้อง - ไม่เป็นความจริงสำหรับสมาชิกอินเทอร์เฟซ จากนั้นการเข้าถึงเริ่มต้นจะเป็นแบบสาธารณะ
mdma

2
เรียกได้ว่าเป็น 'แพ็คเกจส่วนตัว' จริงๆ เว็บไซต์ของบุคคลที่สามไม่ใช่การอ้างอิงเชิงบรรทัดฐาน คุณควรอ้างถึง JLS เท่านั้น
Marquis of Lorne

81

ตัวระบุเริ่มต้นขึ้นอยู่กับบริบท

สำหรับคลาสและการประกาศอินเทอร์เฟซค่าดีฟอลต์คือแพ็กเกจส่วนตัว สิ่งนี้อยู่ระหว่างการป้องกันและไพรเวตอนุญาตให้เฉพาะคลาสในการเข้าถึงแพ็กเกจเดียวกัน (การป้องกันเป็นเช่นนี้ แต่ยังอนุญาตให้เข้าถึงคลาสย่อยภายนอกแพ็คเกจด้วย)

class MyClass   // package private
{
   int field;    // package private field

   void calc() {  // package private method

   }
}

สำหรับสมาชิกอินเทอร์เฟซ (ฟิลด์และวิธีการ) การเข้าถึงเริ่มต้นจะเป็นแบบสาธารณะ แต่โปรดทราบว่าการประกาศอินเทอร์เฟซนั้นมีค่าเริ่มต้นเป็นแพ็กเกจส่วนตัว

interface MyInterface  // package private
{
   int field1;         // static final public

   void method1();     // public abstract
}

ถ้าเรามีคำประกาศ

public interface MyInterface2 extends MyInterface
{

}

จากนั้นคลาสที่ใช้ MyInterface2 จะเห็น field1 และ method1 จาก super interface เนื่องจากเป็นแบบสาธารณะแม้ว่าจะไม่เห็นการประกาศ MyInterface ก็ตาม


1
"แพคเกจส่วนตัว" (บางครั้งเขียนในแหล่งที่เป็น/* pp */) เป็นเพียงชื่อที่สะดวกสำหรับการเข้าถึงเริ่มต้น ไม่ใช่ชื่อ JLS
Tom Hawtin - แท

10
@Tom - ถูกต้อง JLS ใช้ "การเข้าถึงเริ่มต้น" ฉันสามารถเขียน "ค่าเริ่มต้นคือการเข้าถึงเริ่มต้น" แต่ดูเหมือนจะไม่เป็นประโยชน์เลย!
mdma

16

หากไม่มีการระบุตัวระบุการเข้าถึงเป็นการเข้าถึงระดับแพ็กเกจ (ไม่มีตัวระบุที่ชัดเจนสำหรับสิ่งนี้) สำหรับคลาสและสมาชิกคลาส วิธีการเชื่อมต่อเป็นแบบสาธารณะโดยปริยาย


9

การเปิดเผยเริ่มต้น (ไม่มีคีย์เวิร์ด) คือ แพ็กเกจซึ่งหมายความว่าจะสามารถใช้ได้กับทุกคลาสที่อยู่ในแพ็กเกจเดียวกัน

ข้อสังเกตที่น่าสนใจคือการป้องกันไม่ได้ จำกัด การมองเห็นเฉพาะคลาสย่อย แต่ยังรวมถึงคลาสอื่น ๆ ในแพ็คเกจเดียวกันด้วย


8

มันขึ้นอยู่กับว่าสิ่งนั้นคืออะไร

  • ประเภทระดับบนสุด (นั่นคือคลาส enums อินเทอร์เฟซและประเภทคำอธิบายประกอบที่ไม่ได้ประกาศไว้ในประเภทอื่น) เป็นแพ็กเกจส่วนตัวตามค่าเริ่มต้น ( JLS §6.6.1 )

  • ในคลาสสมาชิกทั้งหมด (ซึ่งหมายถึงเขตข้อมูลวิธีการและการประกาศชนิดที่ซ้อนกัน) และตัวสร้างจะเป็นแพ็กเกจส่วนตัวตามค่าเริ่มต้น ( JLS §6.6.1 )

    • เมื่อชั้นเรียนได้ประกาศอย่างชัดเจนไม่มีคอนสตรัคคอมไพเลอร์แทรกเริ่มต้นตัวสร้างศูนย์การโต้แย้งซึ่งมีระบุการเข้าถึงเช่นเดียวกับชั้นเรียน ( JLS §8.8.9 ) ตัวสร้างเริ่มต้นมักจะระบุผิดพลาดเหมือนเป็นสาธารณะเสมอ แต่ในบางกรณีที่ไม่สามารถเทียบเท่าได้
  • ใน enums ตัวสร้างเป็นแบบส่วนตัวโดยค่าเริ่มต้น อันที่จริงผู้ควบคุม enum ต้องเป็นแบบส่วนตัวและเป็นข้อผิดพลาดในการระบุว่าเป็นสาธารณะหรือได้รับการคุ้มครอง ค่าคงที่ของ Enum เป็นแบบสาธารณะเสมอและไม่อนุญาตให้ใช้ตัวระบุการเข้าถึงใด ๆ สมาชิกอื่น ๆ ของ enums เป็นแพ็กเกจส่วนตัวตามค่าเริ่มต้น ( JLS §8.9 )

  • ในอินเทอร์เฟซและประเภทคำอธิบายประกอบสมาชิกทั้งหมด (อีกครั้งนั่นหมายถึงฟิลด์วิธีการและการประกาศประเภทที่ซ้อนกัน) เป็นสาธารณะโดยค่าเริ่มต้น อันที่จริงสมาชิกของอินเทอร์เฟซและประเภทคำอธิบายประกอบต้องเป็นสาธารณะและเป็นข้อผิดพลาดในการระบุว่าเป็นส่วนตัวหรือได้รับการป้องกัน ( JLS §9.3ถึง 9.5 )

  • คลาสโลคัลเป็นชื่อคลาสที่ประกาศภายในเมธอดตัวสร้างหรือบล็อกตัวเริ่มต้น พวกเขาถูกกำหนดขอบเขตไว้ที่{.. }บล็อกที่มีการประกาศและไม่อนุญาตตัวระบุการเข้าถึงใด ๆ ( JLS §14.3 ) การใช้การสะท้อนคุณสามารถสร้างอินสแตนซ์คลาสโลคัลจากที่อื่นได้และเป็นแบบแพ็กเกจส่วนตัวแม้ว่าฉันจะไม่แน่ใจว่ารายละเอียดนั้นอยู่ใน JLS หรือไม่

  • คลาสแบบไม่ระบุชื่อคือคลาสแบบกำหนดเองที่สร้างขึ้นโดยnewระบุเนื้อหาคลาสโดยตรงในนิพจน์ ( JLS §15.9.5 ) ไวยากรณ์ของพวกเขาไม่อนุญาตตัวระบุการเข้าถึงใด ๆ การใช้การไตร่ตรองคุณสามารถสร้างอินสแตนซ์คลาสที่ไม่ระบุตัวตนจากที่อื่นได้และทั้งสองและตัวสร้างที่สร้างขึ้นนั้นเป็นแพ็คเกจส่วนตัวแม้ว่าฉันจะไม่แน่ใจว่ารายละเอียดนั้นอยู่ใน JLS หรือไม่

  • อินสแตนซ์และบล็อกตัวเริ่มต้นแบบคงที่ไม่มีตัวระบุการเข้าถึงที่ระดับภาษา ( JLS §8.6 & 8.7 ) แต่บล็อกตัวเริ่มต้นแบบคงที่ถูกนำไปใช้เป็นวิธีการที่ชื่อ<clinit>( JVMS §2.9 ) ดังนั้นเมธอดจะต้องมีตัวระบุการเข้าถึงภายใน ผมตรวจสอบการเรียนการรวบรวมโดย javac และคอมไพเลอร์ของ Eclipse ใช้ Hex Editor และพบว่าทั้งสองวิธีการสร้างเป็นแพคเกจและเอกชน อย่างไรก็ตามคุณไม่สามารถเรียก<clinit>()ภายในภาษาได้เนื่องจาก<และ>อักขระไม่ถูกต้องในชื่อเมธอดและเมธอดการสะท้อนถูกเดินสายเพื่อปฏิเสธการมีอยู่ของมันดังนั้นตัวระบุการเข้าถึงที่มีประสิทธิภาพจึงไม่สามารถเข้าถึงได้ VM เท่านั้นที่สามารถเรียกเมธอดได้ในระหว่างการเริ่มต้นคลาสบล็อกตัวเริ่มต้นอินสแตนซ์ไม่ได้รวบรวมเป็นวิธีการแยกต่างหาก รหัสของพวกเขาจะถูกคัดลอกไปยังตัวสร้างแต่ละตัวดังนั้นจึงไม่สามารถเข้าถึงทีละตัวได้แม้จะเป็นการสะท้อน


7

defaultคือคีย์เวิร์ดที่ใช้เป็นตัวแก้ไขการเข้าถึงสำหรับเมธอดและตัวแปร
การใช้ตัวแก้ไขการเข้าถึงนี้จะทำให้คลาสตัวแปรวิธีการหรือตัวสร้างของคุณสามารถเข้าถึงได้จากคลาสหรือแพ็กเกจของตัวเองมันจะถูกตั้งค่าด้วยหากไม่มีตัวปรับการเข้าถึงอยู่

  Access Levels
    Modifier    Class   Package Subclass  EveryWhere
    public        Y        Y       Y         Y
    protected     Y        Y       Y         N
    default       Y        Y       N         N
    private       Y        N       N         N

หากคุณใช้ค่าเริ่มต้นในอินเทอร์เฟซคุณจะสามารถใช้วิธีการดังตัวอย่างนี้ได้

public interface Computer {    
    default void Start() {
        throw new UnsupportedOperationException("Error");
    }    
}

อย่างไรก็ตามมันจะใช้งานได้จากเวอร์ชัน 8 Java เท่านั้น

เอกสารอย่างเป็นทางการ

Access Modifiers ใน Java


3

ดูที่นี่สำหรับรายละเอียดเพิ่มเติม ค่าเริ่มต้นคือไม่มีส่วนบุคคล / สาธารณะ / ป้องกัน แต่เป็นข้อกำหนดการเข้าถึงที่แตกต่างกันโดยสิ้นเชิง ไม่ได้ใช้กันอย่างแพร่หลายและฉันต้องการเจาะจงมากขึ้นในคำจำกัดความการเข้าถึงของฉัน


3

ตัวระบุการเข้าถึงเริ่มต้นคือแพ็กเกจชั้นเรียนสามารถเข้าถึงสมาชิกของคลาสอื่น ๆ ในแพ็กเกจเดียวกัน แต่ภายนอกแพ็กเกจจะปรากฏเป็นส่วนตัว


3

นี่คือคำพูดเกี่ยวกับการมองเห็นระดับแพ็กเกจจากบทสัมภาษณ์ของ James Gosling ผู้สร้าง Java:

Bill Venners : Java มีระดับการเข้าถึงสี่ระดับ ค่าเริ่มต้นคือแพ็คเกจ ฉันสงสัยมาตลอดว่าการทำให้การเข้าถึงแพ็กเกจเป็นค่าเริ่มต้นนั้นสะดวกหรือไม่เพราะคำหลักสามคำที่ผู้คนจาก C ++ รู้อยู่แล้วนั้นเป็นแบบส่วนตัวได้รับการป้องกันและสาธารณะ หรือหากคุณมีเหตุผลบางอย่างที่คุณคิดว่าการเข้าถึงแพ็กเกจควรเป็นค่าเริ่มต้น

เจมส์กอสลิง : โดยทั่วไปแล้วแพคเกจคือชุดของสิ่งต่างๆที่เขียนร่วมกัน โดยทั่วไปฉันสามารถทำหนึ่งในสองสิ่งได้ อย่างหนึ่งคือบังคับให้คุณใส่คำหลักที่ให้โดเมนแก่คุณเสมอ หรือฉันอาจมีค่าเริ่มต้น คำถามคืออะไรทำให้ค่าเริ่มต้นที่สมเหตุสมผล? และฉันมักจะไปหาสิ่งที่อันตรายน้อยที่สุด

สาธารณะคงเป็นเรื่องแย่มากที่จะตั้งค่าเริ่มต้น ส่วนตัวอาจเป็นเรื่องไม่ดีที่จะทำให้ผิดนัดถ้าเพียงเพราะคนไม่ได้เขียนวิธีการส่วนตัวบ่อยๆ และสิ่งเดียวกันกับการป้องกัน และจากการดูโค้ดจำนวนมากที่ฉันมีฉันตัดสินใจว่าสิ่งที่พบบ่อยที่สุดที่ปลอดภัยพอสมควรอยู่ในแพ็คเกจ และ C ++ ไม่มีคีย์เวิร์ดสำหรับสิ่งนั้นเนื่องจากไม่มีแนวคิดเกี่ยวกับแพ็คเกจ

แต่ฉันชอบมันมากกว่าความคิดเรื่องเพื่อนเพราะกับเพื่อนคุณต้องระบุว่าเพื่อนของคุณเป็นใครดังนั้นหากคุณเพิ่มคลาสใหม่ลงในแพ็กเกจโดยทั่วไปแล้วคุณจะต้องไปที่ทั้งหมด เรียนในแพ็คเกจนั้นและอัปเดตเพื่อนของพวกเขาซึ่งฉันมักจะพบว่าปวดก้นอย่างสมบูรณ์

แต่รายชื่อเพื่อนเองทำให้เกิดปัญหาการกำหนดเวอร์ชัน ดังนั้นจึงมีแนวคิดเกี่ยวกับชนชั้นที่เป็นมิตรนี้ และสิ่งที่ดีที่ฉันทำให้เป็นค่าเริ่มต้น - ฉันจะแก้ปัญหาแล้วคำหลักควรเป็นอย่างไร

ในขณะที่มีคำหลักที่เป็นมิตรจริงๆ แต่เนื่องจากตัวอื่น ๆ ทั้งหมดขึ้นต้นด้วย "P" จึงเป็น "เพื่อน" พร้อมกับ "PH" แต่นั่นเป็นเพียงแค่วันเดียวเท่านั้น

http://www.artima.com/intv/gosling2P.html


2

อัปเดตการใช้คีย์เวิร์ดJava 8default : ดังที่คนอื่น ๆ สังเกตเห็นการมองเห็นเริ่มต้น (ไม่มีคีย์เวิร์ด)

คุณสามารถเข้าถึงฟิลด์นี้ได้จากภายในแพ็กเกจเดียวกันกับคลาสนั้น ๆ

เพื่อไม่ให้สับสนกับคุณลักษณะใหม่ของJava 8 ( วิธีการเริ่มต้น ) ที่อนุญาตให้อินเทอร์เฟซจัดเตรียมการนำไปใช้งานเมื่อมีป้ายกำกับด้วยdefaultคีย์เวิร์ด

ดู: เข้าถึงตัวปรับแต่ง


1

มีตัวแก้ไขการเข้าถึงที่เรียกว่า "ค่าเริ่มต้น" ใน JAVA ซึ่งอนุญาตให้สร้างอินสแตนซ์โดยตรงของเอนทิตีนั้นภายในแพ็คเกจนั้นเท่านั้น

นี่คือลิงค์ที่มีประโยชน์:

Java Access Modifiers / Specifiers


-2

ก่อนอื่นให้ฉันพูดสิ่งหนึ่งที่ไม่มีคำว่า "Access specifier" ใน java เราควรเรียกทุกอย่างว่า "Modifiers" ดังที่เราทราบว่าขั้นสุดท้ายคงที่ซิงโครไนซ์ระเหย .... ถูกเรียกว่าเป็นโมดิฟายเออร์แม้แต่ Public, private, protected, default, abstract ก็ควรเรียกว่าเป็นโมดิฟายเออร์ ค่าดีฟอลต์คือโมดิฟายเออร์ที่ไม่มีการดำรงอยู่ทางกายภาพ แต่ไม่มีการวางโมดิฟายเออร์จึงควรถือว่าเป็นโมดิฟายเออร์เริ่มต้น

เพื่อให้เหตุผลนี้ใช้ตัวอย่างเดียว:

public class Simple{  
    public static void main(String args[]){  
     System.out.println("Hello Java");  
    }  
}  

ผลลัพธ์จะเป็น: Hello Java

ตอนนี้เปลี่ยน public เป็น private และดูข้อผิดพลาดของคอมไพเลอร์ที่คุณได้รับ: มันแจ้งว่า "Modifier private is not allowed here" ข้อสรุปคือบางคนอาจผิดหรือบทช่วยสอนบางอย่างอาจผิด แต่คอมไพเลอร์ไม่สามารถผิดได้ ดังนั้นเราจึงสามารถพูดได้ว่าไม่มีตัวระบุการเข้าถึงคำศัพท์ใน java ทุกอย่างเป็นตัวปรับเปลี่ยน


ประโยคแรกเป็นแบบเฉพาะจุด แต่ความจริงที่ว่าคลาสภายนอกไม่สามารถเป็นส่วนตัวได้ไม่ได้พิสูจน์ว่าไม่มีสิ่งที่เรียกว่าตัวระบุการเข้าถึงใน Java
Marquis of Lorne

@EJP นี่เป็นเพียงตัวอย่างเท่านั้น สิ่งที่ฉันกำลังพูดคือตัวระบุการเข้าถึงคำถูกใช้ในภาษาอื่นเช่น c, dot net เป็นต้น แต่คำศัพท์ทางเทคนิคใน java สำหรับสิ่งนี้คือตัวปรับแต่ง หากคุณใช้ eclipse หรือ IDE อื่น ๆ คุณจะเห็นได้ว่าในช่วงเวลาของการสร้างคลาสใหม่เราถูกขอให้ระบุชื่อตัวดัดแปลงและในรายการพวกเขาระบุสาธารณะส่วนตัวนามธรรม ฯลฯ
Sagar Raut

ในตัวอย่างของฉันสิ่งที่ฉันพยายามจะบอกว่าคอมไพเลอร์ให้ข้อความแสดงข้อผิดพลาด: ไม่อนุญาตให้ใช้ตัวปรับแต่งส่วนตัวมันไม่ได้ให้ข้อความเช่นไม่อนุญาตให้ใช้ตัวระบุการเข้าถึงส่วนตัว ดังนั้นคำศัพท์ทางเทคนิคที่เราควรพูดคือ modifiers ใน java not access specifier ใน java
Sagar Raut
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.