เหตุใดจึงไม่สามารถกำหนดคลาสให้เป็นการป้องกันได้


91

ทำไมเราไม่สามารถกำหนดคลาสเป็นไฟล์ protected ?

ฉันรู้ว่าเราทำไม่ได้ แต่ทำไม? ควรมีเหตุผลเฉพาะบางอย่าง


3
จะทำอย่างไรถ้าคุณประกาศว่าคลาสได้รับการปกป้อง

1
ฉันคิดว่านี่คือสิ่งที่คุณกำลังมองหา: stackoverflow.com/questions/2534733/java-protected-classes : D
dewijones92

2
สมมติว่าทำไมชั้นนอกไม่สามารถป้องกันได้? ชั้นในสามารถป้องกันได้
Number945

คำตอบ:


102

เพราะมันไม่มีเหตุผล

สมาชิกคลาสที่ได้รับการป้องกัน (วิธีการหรือตัวแปร) เหมือนกับแพ็กเกจส่วนตัว (การมองเห็นเริ่มต้น) ยกเว้นว่าสามารถเข้าถึงได้จากคลาสย่อย
เนื่องจากไม่มีแนวคิดเช่น 'subpackage' หรือ 'package-inheritance' ใน Java การประกาศคลาสที่มีการป้องกันหรือแพ็กเกจส่วนตัวจึงเป็นสิ่งเดียวกัน

คุณสามารถประกาศคลาสที่ซ้อนกันและชั้นในเป็นแบบป้องกันหรือแบบส่วนตัวได้


> เนื่องจากไม่มีแนวคิดเช่น 'subpackage' หรือ 'package-inheritance' ใน Java การประกาศคลาสที่ได้รับการป้องกันหรือแพ็กเกจส่วนตัวจึงเป็นสิ่งเดียวกัน เหตุใดคลาสที่ได้รับการป้องกันจึงมีการมองเห็นเหมือนกับแพ็กเกจส่วนตัว ไม่เหมือนกับที่สาธารณะ? ขอบคุณ.
yaromir

@Nikita Ryback คุณช่วยอธิบายได้ไหมว่า subPackage หรือ package-inheritance คืออะไรฉันยังไม่ชัดเจนว่าทำไมจึงใช้การป้องกันในระดับบนสุดหากคุณอธิบายด้วยตัวอย่างจะดีมาก
App Kart

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

@kelgwiin ฉันเชื่อว่าคุณไม่ควรผสมตัวปรับการเข้าถึงของคลาสและของสมาชิก เพราะทั้งสองมีความแตกต่างกัน ในขณะที่คลาสอนุญาตให้แก้ไขตัวเองเป็นสาธารณะหรือค่าเริ่มต้นสมาชิกสามารถแก้ไขเป็นสาธารณะส่วนตัวได้รับการป้องกันและค่าเริ่มต้น
sharhp

2
"เพราะมันไม่มีเหตุผล" - นั่นเป็นคำพูดที่ค่อนข้างชัดเจน มันไม่ได้กำหนดไว้ใน Java แต่สิ่งที่คล้ายกันไม่อยู่; เช่นopenใน Kotlin ซึ่งอนุญาตให้มีคลาสย่อยนอกแพ็กเกจปัจจุบัน (เราสามารถจินตนาการได้protectedใน Java ป้องกันสิ่งนั้นโดยมีค่าดีฟอลต์ตรงกันข้าม)
Raphael

41

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

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

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


3
"ตอนนี้การทำให้คลาสที่ได้รับการป้องกันสามารถมองเห็นได้ภายนอกแพ็กเกจ (คลาสย่อย) นั้นค่อนข้างสับสนและยุ่งยากชั้นเรียนใดที่ควรได้รับอนุญาตให้สืบทอดคลาสที่ได้รับการป้องกันของเราและหากคลาสทั้งหมดได้รับอนุญาตให้คลาสย่อยมันจะคล้ายกับตัวระบุการเข้าถึงสาธารณะ" ช่วยให้ฉันเข้าใจปัญหาจริงๆว่าทำไมคลาสที่ได้รับการป้องกันจึงไม่สมเหตุสมผล :)
user1338998


3

คำตอบของ @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 ตัวในระดับบนสุด:

ที่ระดับบนสุด - สาธารณะหรือแพ็กเกจส่วนตัว (ไม่มีตัวแก้ไขที่ชัดเจน)


3

การกำหนดฟิลด์ที่ได้รับการป้องกันทำให้ฟิลด์นั้นสามารถเข้าถึงได้ภายในแพ็กเกจและภายนอกแพ็กเกจผ่านการสืบทอดเท่านั้น

ดังนั้นหากเราได้รับอนุญาตให้สร้างคลาสที่ได้รับการป้องกันเราก็สามารถเข้าถึงมันภายในแพ็กเกจได้อย่างง่ายดาย แต่สำหรับการเข้าถึงคลาสนั้นนอกแพ็คเกจก่อนอื่นเราต้องขยายเอนทิตีนั้นซึ่งคลาสนี้ถูกกำหนดซึ่งเป็นแพ็กเกจของมัน

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

สำหรับข้อมูลเพิ่มเติมโปรดอ่านเหตุใดคลาส Java ภายนอกจึงไม่สามารถเป็นส่วนตัวหรือป้องกันได้


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

1

ได้รับการคุ้มครองไม่เหมือนกับสาธารณะ 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
}

0

พฤติกรรมของ“ ป้องกัน” = พฤติกรรมของ“ ค่าเริ่มต้น” +“ ใช้ในคลาสย่อยในแพ็คเกจใดก็ได้”

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


0

มีการป้องกัน : มองเห็นได้เฉพาะในระดับแพ็คเกจ *

คลาสถูกกำหนดป้องกัน ---> ไม่สามารถขยายได้จากแพ็คเกจภายนอกได้ (มองไม่เห็น)

และหากไม่สามารถขยายได้ก็จะไม่มีความหมายที่จะรักษาไว้เป็นความคุ้มครองเพราะจะกลายเป็นค่าเริ่มต้นเข้าถึงซึ่งได้รับอนุญาต

เช่นเดียวกันกับคลาสที่กำหนดไว้ส่วนตัว

หมายเหตุ:คลาสที่ซ้อนกันหรือชั้นในสามารถกำหนดป้องกันหรือเป็นส่วนตัวได้

* : สำรวจคำหลักที่มีการป้องกันสำหรับคำตอบนี้ฉันทำให้มันรวบรัด


0

คำตอบจาก @ Akash5288 ไม่สมเหตุสมผลสำหรับฉัน:

หากคลาสทั้งหมดได้รับอนุญาตให้คลาสย่อยมันจะคล้ายกับตัวระบุการเข้าถึงสาธารณะ

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

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

คำตอบ "คุณไม่สามารถขยายชั้นเรียนที่คุณไม่สามารถเข้าถึง / ดูได้" มีเหตุผลมากกว่า


0

สิ่งที่สมเหตุสมผลสำหรับคำถามนี้คือ JVM เขียนด้วยภาษา C (Sun JVM) และ C ++ (oracle JVM) ดังนั้นในระหว่างการคอมไพล์เราจะสร้างไฟล์. class จากไฟล์ java ของเราและถ้าเราประกาศคลาสด้วยคีย์เวิร์ดที่ได้รับการป้องกัน จากนั้น JVM จะไม่สามารถเข้าถึงได้

คำตอบว่าทำไมคลาสที่ได้รับการป้องกันจะไม่สามารถเข้าถึงได้โดย JVM ก็คือเนื่องจากฟิลด์ที่ได้รับการป้องกันนั้นสามารถเข้าถึงได้ภายในแพ็คเกจเดียวกันหรือไปยังแพ็กเกจที่แตกต่างกันผ่านการสืบทอดเท่านั้นและ JVM ไม่ได้เขียนในลักษณะที่จะสืบทอดคลาส หวังว่าจะตอบโจทย์คำถามนี้ :)

ในทำนองเดียวกันคลาสระดับบนสุดต้องไม่เป็นส่วนตัว คำอธิบายด้านล่าง:

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

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


0

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

ตัวอย่าง:

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 
}

0

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

คลาสชั้นนอกที่ได้รับการป้องกันจึงเหมือนกันกับคลาสนอก (ค่าเริ่มต้น)!

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.