ทำไมเราไม่สามารถกำหนดคลาสเป็นไฟล์ protected
?
ฉันรู้ว่าเราทำไม่ได้ แต่ทำไม? ควรมีเหตุผลเฉพาะบางอย่าง
ทำไมเราไม่สามารถกำหนดคลาสเป็นไฟล์ protected
?
ฉันรู้ว่าเราทำไม่ได้ แต่ทำไม? ควรมีเหตุผลเฉพาะบางอย่าง
คำตอบ:
เพราะมันไม่มีเหตุผล
สมาชิกคลาสที่ได้รับการป้องกัน (วิธีการหรือตัวแปร) เหมือนกับแพ็กเกจส่วนตัว (การมองเห็นเริ่มต้น) ยกเว้นว่าสามารถเข้าถึงได้จากคลาสย่อย
เนื่องจากไม่มีแนวคิดเช่น 'subpackage' หรือ 'package-inheritance' ใน Java การประกาศคลาสที่มีการป้องกันหรือแพ็กเกจส่วนตัวจึงเป็นสิ่งเดียวกัน
คุณสามารถประกาศคลาสที่ซ้อนกันและชั้นในเป็นแบบป้องกันหรือแบบส่วนตัวได้
open
ใน Kotlin ซึ่งอนุญาตให้มีคลาสย่อยนอกแพ็กเกจปัจจุบัน (เราสามารถจินตนาการได้protected
ใน Java ป้องกันสิ่งนั้นโดยมีค่าดีฟอลต์ตรงกันข้าม)
อย่างที่คุณทราบดีว่าค่าเริ่มต้นมีไว้สำหรับการเข้าถึงระดับแพ็กเกจและการป้องกันนั้นมีไว้สำหรับระดับแพ็กเกจบวกคลาสที่ไม่ใช่แพ็กเกจ แต่จะขยายคลาสนี้ออกไป (จุดที่ควรสังเกตคือคุณสามารถขยายคลาสได้ก็ต่อเมื่อมองเห็นได้เท่านั้น!) ลองใส่ตามนี้:
เนื่องจากไม่มีวิธีการ จำกัด คลาสนี้ให้เป็นคลาสย่อยโดยคลาสเพียงไม่กี่คลาส (เราไม่สามารถ จำกัด คลาสที่สืบทอดโดยคลาสเพียงไม่กี่คลาสจากคลาสที่มีอยู่ทั้งหมดในแพ็กเกจ / นอกแพ็กเกจ) จึงไม่มีการใช้ตัวระบุการเข้าถึงที่มีการป้องกัน สำหรับชั้นเรียนระดับบนสุด ดังนั้นจึงไม่อนุญาต
public class A
{
protected class B
{
}
}
คำตอบของ @Nikita Rybakมีจุดที่ดี แต่ขาดรายละเอียดฉันไม่สามารถเข้าใจความคิดได้โดยไม่ต้องคิดให้ลึกซึ้งสิ่งต่อไปนี้คือสิ่งที่ฉันคิดและตอนนี้ฉันควรเข้าใจเหตุผลอย่างสมบูรณ์
ตัวปรับการเข้าถึงสี่ตัวสมมติว่าระดับที่ 1 เป็นสาธารณะและระดับ 4 เป็นแบบส่วนตัว (ตามตารางนี้ตามลำดับ) สิ่งแรกที่เราควรทราบคือทำไมคลาสไม่สามารถกำหนดเป็นส่วนตัวในระดับบนสุดได้
ดังนั้นถ้า "private class foo" (สมาชิกที่กำหนดไว้คือคลาสตัวเองเป็นสมาชิก) อนุญาตสิ่งที่อยู่ด้านนอก (ซึ่งมีสมาชิก) คืออะไร? ขอบเขตไฟล์? ไม่ไฟล์ภายนอกไม่มีจุดหมายเนื่องจากแม้หลายคลาสในไฟล์เดียวจะถูกคอมไพล์เป็นไฟล์คลาสแยกกัน ดังนั้นด้านนอกเป็นแพคเกจ แต่ตัวแก้ไขการเข้าถึงเริ่มต้นระดับที่ 3 หมายถึง "package-private " อยู่แล้ว ดังนั้นตัวแก้ไขการเข้าถึงส่วนตัวระดับที่ 4 จะไม่ถูกใช้ / อนุญาต
แต่คลาสส่วนตัวที่ซ้อนกันได้รับอนุญาตเนื่องจากชั้นนอกโดยตรงคือคลาสไม่ใช่แพ็กเกจเช่น :
class PrivateNestedMain {
private static class Inner {
public static void main(String[] args) {
System.out.println("Hello from Inner!");
}
}
}
จะเกิดอะไรขึ้นถ้า "คลาสที่ได้รับการป้องกัน" อนุญาต คุณสมบัติหลักที่ได้รับการป้องกันคือคลาสย่อยดังนั้นชั้นนอก (แพ็กเกจ) จึงควร (เนื่องจากขึ้นอยู่กับขอบเขต แต่ก็ยังคงเป็นทางเลือก) ให้รูปแบบของคลาสย่อยเช่นแพ็กเกจย่อยหรือpackage A extends package B
แต่เราไม่ทราบสิ่งนั้น ดังนั้นการป้องกันจึงไม่สามารถใช้ศักยภาพเต็ม (ขอบเขตหลักคือคลาสย่อย) ในระดับบนสุดซึ่งด้านนอกเป็นแพ็คเกจ (เช่นไม่มีสิ่งที่เป็นแพ็คเกจย่อย) แต่การป้องกันสามารถใช้ศักยภาพเต็มในคลาสที่ซ้อนกันซึ่งด้านนอกเป็นคลาส ( เช่นสามารถเป็นคลาสย่อยได้) :
class ProtectedNestedMain {
protected static class Inner {
public static void main(String[] args) {
System.out.println("Hello from Inner!");
}
}
}
หมายเหตุว่าข้างต้นกล่าวว่า "ไม่สามารถใช้งานได้เต็มศักยภาพ" เนื่องจากมันไม่สามารถเข้าถึง subclass กว้างเพียงเพราะไม่มี subclass นอกว่าเป็นวิธีการป้องกันจริงสามารถช่วยให้ , มันเป็นเพียงแค่เรื่องของการเลือกที่จะหลีกเลี่ยงการทำซ้ำงานของแพคเกจ - ส่วนตัวหากภายนอกไม่สามารถคลาสย่อยได้โปรดดูด้านล่าง
ความสับสนของฉันส่วนใหญ่เกิดจากตารางที่มีชื่อเสียงที่https://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html :
หากอนุญาตระดับที่ 1 (สาธารณะ) และระดับที่ 3 (แพ็กเกจส่วนตัว) จะไม่อนุญาตให้ใช้ระดับที่อยู่ระหว่างระดับ 2 (ป้องกัน) บนโลกได้อย่างไร
คลาสย่อยการสนับสนุนสาธารณะจึงทำให้เข้าใจผิดได้ง่าย วิธีที่ถูกต้องในการอ่านตารางนี้คือ
คลาสย่อยการสนับสนุนสาธารณะหากด้านนอกมีคุณสมบัติคลาสย่อย
การทำให้เข้าใจผิดเช่นเดียวกันนี้ใช้กับ package-private, package-private ไม่รองรับคลาสย่อย ( Nในเซลล์) ไม่ได้หมายความว่าแนวคิด subclass จะใช้กับภายนอก
นั่นหมายความว่าเราควรละเว้นคอลัมน์Subclassหากไม่มีคุณสมบัติ subclass ในด้านนอก:
อย่างที่เราเห็นตอนนี้ทั้งแบบป้องกันและแบบแพ็กเกจเป็นระดับเดียวกันในขณะนี้ ( YYN ) ไม่ต้องสับสนอีกต่อไปว่าเหตุใดจึงไม่อนุญาตให้อยู่ระหว่างระดับ โดยรวมแล้ว Java เลือกเฉพาะแพ็กเกจส่วนตัวที่ได้รับการป้องกันเพื่อหลีกเลี่ยงความสับสน ( เป็นเพียงเรื่องของทางเลือกแต่คุณสมบัติหลักที่ได้รับการป้องกันคือคลาสย่อยดังนั้นแพ็กเกจไพรเวตจึงเหนือกว่า) และผลลัพธ์ที่ได้อนุญาตให้ใช้ตัวดัดแปลงการเข้าถึงเพียง 2 ตัวในระดับบนสุด:
ที่ระดับบนสุด - สาธารณะหรือแพ็กเกจส่วนตัว (ไม่มีตัวแก้ไขที่ชัดเจน)
การกำหนดฟิลด์ที่ได้รับการป้องกันทำให้ฟิลด์นั้นสามารถเข้าถึงได้ภายในแพ็กเกจและภายนอกแพ็กเกจผ่านการสืบทอดเท่านั้น
ดังนั้นหากเราได้รับอนุญาตให้สร้างคลาสที่ได้รับการป้องกันเราก็สามารถเข้าถึงมันภายในแพ็กเกจได้อย่างง่ายดาย แต่สำหรับการเข้าถึงคลาสนั้นนอกแพ็คเกจก่อนอื่นเราต้องขยายเอนทิตีนั้นซึ่งคลาสนี้ถูกกำหนดซึ่งเป็นแพ็กเกจของมัน
และเนื่องจากไม่สามารถขยายแพ็กเกจได้ (สามารถอิมพอร์ตได้) การกำหนดคลาสที่ได้รับการป้องกันจะทำให้แพ็กเกจเป็นส่วนตัวอีกครั้งซึ่งคล้ายกับการกำหนดเป็นค่าเริ่มต้นซึ่งเราสามารถทำได้อยู่แล้ว ดังนั้นจึงไม่มีประโยชน์ในการกำหนดคลาสส่วนตัว แต่จะทำให้สิ่งต่างๆคลุมเครือเท่านั้น
สำหรับข้อมูลเพิ่มเติมโปรดอ่านเหตุใดคลาส Java ภายนอกจึงไม่สามารถเป็นส่วนตัวหรือป้องกันได้
ได้รับการคุ้มครองไม่เหมือนกับสาธารณะ Protected มีทั้งการเข้าถึงระดับแพ็กเกจ plus สามารถเข้าถึงได้ภายนอกแพ็กเกจโดยการสืบทอดเท่านั้นถ้าคลาสพูดว่า A นอกแพ็กเกจจะเป็นคลาสจากแพ็กเกจอื่น (ด้วยวิธีการป้องกันโดยใช้ INHERITANCE) จะสามารถเข้าถึงเมธอดของคลาส B นี้ได้ซึ่ง มีวิธีการป้องกัน แต่คลาสย่อยที่ได้รับจากคลาสนี้คือ A ไม่สามารถเข้าถึงวิธีการป้องกันได้ .. สิ่งที่ตรงกันข้ามเกิดขึ้นกับสาธารณะ ..
ตัวอย่าง:
package 2;
class B
{
protected void method1()
{
}
}
package 1;
import 2.B;
class A extends B
{
//can access protected method
}
class C extends A
{
//can't access the protected method
}
พฤติกรรมของ“ ป้องกัน” = พฤติกรรมของ“ ค่าเริ่มต้น” +“ ใช้ในคลาสย่อยในแพ็คเกจใดก็ได้”
อย่างไรก็ตามเรามีตัวปรับการเข้าถึงเริ่มต้นสำหรับคลาสข้อได้เปรียบเดียวที่เราจะได้รับจากตัวแก้ไขการเข้าถึงที่มีการป้องกันคือ: - โดยใช้ในแพ็คเกจใดก็ได้ผ่านคลาสย่อย แต่สำหรับคลาสย่อยการมองเห็นคลาสที่ "ป้องกัน" หลักจะเป็นแบบส่วนตัว เลยเข้าไม่ได้. โดยทั่วไปถ้าคุณมีคลาสระดับบนสุดที่ได้รับการป้องกันจะไม่มีคลาสภายนอกที่สามารถเข้าถึงได้ด้วยคลาสย่อย ดังนั้นการป้องกันสำหรับคลาสระดับบนสุดจึงไม่มีความหมาย
มีการป้องกัน : มองเห็นได้เฉพาะในระดับแพ็คเกจ *
คลาสถูกกำหนดป้องกัน ---> ไม่สามารถขยายได้จากแพ็คเกจภายนอกได้ (มองไม่เห็น)
และหากไม่สามารถขยายได้ก็จะไม่มีความหมายที่จะรักษาไว้เป็นความคุ้มครองเพราะจะกลายเป็นค่าเริ่มต้นเข้าถึงซึ่งได้รับอนุญาต
เช่นเดียวกันกับคลาสที่กำหนดไว้ส่วนตัว
หมายเหตุ:คลาสที่ซ้อนกันหรือชั้นในสามารถกำหนดป้องกันหรือเป็นส่วนตัวได้
* : สำรวจคำหลักที่มีการป้องกันสำหรับคำตอบนี้ฉันทำให้มันรวบรัด
คำตอบจาก @ Akash5288 ไม่สมเหตุสมผลสำหรับฉัน:
หากคลาสทั้งหมดได้รับอนุญาตให้คลาสย่อยมันจะคล้ายกับตัวระบุการเข้าถึงสาธารณะ
เนื่องจากไม่มีวิธีการ จำกัด คลาสนี้ให้เป็นคลาสย่อยโดยคลาสเพียงไม่กี่คลาส (เราไม่สามารถ จำกัด คลาสที่สืบทอดโดยคลาสเพียงไม่กี่คลาสจากคลาสที่มีอยู่ทั้งหมดในแพ็กเกจ / นอกแพ็กเกจ) จึงไม่มีการใช้ตัวระบุการเข้าถึงที่มีการป้องกัน สำหรับชั้นเรียนระดับบนสุด ดังนั้นจึงไม่อนุญาต
จากนั้นคุณสามารถใช้ตรรกะเดียวกันกับวิธีการและตัวแปรที่ได้รับการป้องกันซึ่งจะ "คล้ายกับสาธารณะ" คลาสทั้งหมดที่อยู่นอกแพ็คเกจสามารถขยายคลาสสาธารณะของเราและใช้วิธีการป้องกันได้ เหตุใดการ จำกัด วิธีการและตัวแปรให้เป็นชั้นเรียนเพิ่มเติมจึงเป็นเรื่องปกติ แต่การ จำกัด ทั้งชั้นไม่เป็นผล "คล้ายกับสาธารณะ" ไม่ใช่ "เหมือนกับสาธารณะ" การตีความของฉันคือการอนุญาตคลาสที่ได้รับการป้องกันนั้นเป็นเรื่องปกติดีเพราะอนุญาตให้ใช้วิธีการป้องกันได้
คำตอบ "คุณไม่สามารถขยายชั้นเรียนที่คุณไม่สามารถเข้าถึง / ดูได้" มีเหตุผลมากกว่า
สิ่งที่สมเหตุสมผลสำหรับคำถามนี้คือ JVM เขียนด้วยภาษา C (Sun JVM) และ C ++ (oracle JVM) ดังนั้นในระหว่างการคอมไพล์เราจะสร้างไฟล์. class จากไฟล์ java ของเราและถ้าเราประกาศคลาสด้วยคีย์เวิร์ดที่ได้รับการป้องกัน จากนั้น JVM จะไม่สามารถเข้าถึงได้
คำตอบว่าทำไมคลาสที่ได้รับการป้องกันจะไม่สามารถเข้าถึงได้โดย JVM ก็คือเนื่องจากฟิลด์ที่ได้รับการป้องกันนั้นสามารถเข้าถึงได้ภายในแพ็คเกจเดียวกันหรือไปยังแพ็กเกจที่แตกต่างกันผ่านการสืบทอดเท่านั้นและ JVM ไม่ได้เขียนในลักษณะที่จะสืบทอดคลาส หวังว่าจะตอบโจทย์คำถามนี้ :)
ในทำนองเดียวกันคลาสระดับบนสุดต้องไม่เป็นส่วนตัว คำอธิบายด้านล่าง:
จะเกิดอะไรขึ้นถ้าเราจะกำหนดคลาสส่วนตัวคลาสนั้นจะเข้าถึงได้เฉพาะภายในเอนทิตีที่กำหนดไว้ซึ่งในกรณีของเราคือแพ็กเกจ
ดังนั้นการกำหนดการเข้าถึงคลาสส่วนตัวจะทำให้สามารถเข้าถึงได้ภายในแพ็กเกจเดียวกันซึ่งคีย์เวิร์ดเริ่มต้นทำเพื่อเราอยู่แล้วดังนั้นจึงไม่มีประโยชน์ในการกำหนดคลาสไพรเวต แต่จะทำให้สิ่งต่างๆคลุมเครือเท่านั้น
ได้รับการป้องกันหมายความว่าสมาชิกสามารถเข้าถึงได้โดยคลาสใดก็ได้ในแพ็กเกจเดียวกันและโดยคลาสย่อยแม้ว่าจะอยู่ในแพ็กเกจอื่นก็ตาม
ตัวอย่าง:
package a;
class parent{
protected void p();
}
package b;
import a.p;
class child extends parent{
//you can access method which is protected in the parent in the child
}
class another extends child {
//here you can not access the protected method
}
หากคลาสภายนอกถูกประกาศโดยการป้องกันฉันคิดว่าคุณต้องการให้คลาสสามารถเข้าถึงได้จากแพ็กเกจเดียวกันและคลาสย่อย แต่แพ็กเกจต่างกัน อย่างไรก็ตามไม่มีความเป็นไปได้ที่จะสร้างคลาสย่อยสำหรับคลาสที่ได้รับการป้องกันเนื่องจากเมื่อคุณเขียน "คลาสสุนัขขยายสัตว์" เนื่องจาก "สัตว์" ที่ได้รับการคุ้มครองจะสามารถเข้าถึงได้โดยคลาสย่อยเท่านั้นซึ่งเห็นได้ชัดว่า "สุนัข" ไม่ใช่คลาสย่อย "สัตว์" .
คลาสชั้นนอกที่ได้รับการป้องกันจึงเหมือนกันกับคลาสนอก (ค่าเริ่มต้น)!