ใน Java ทำไมสมาชิกที่ได้รับความคุ้มครองทำให้เข้าถึงคลาสของแพ็คเกจเดียวกันได้


14

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

แพ็คเกจ Class Class ย่อย 
YYYY สาธารณะ 
ป้องกัน YYYN 
ไม่มีตัวแก้ไข YYNN 
YNNN ส่วนตัว 

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

อะไรคือสาเหตุของการนำไปใช้นี้?

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

package some.package;
public class A {
 protected void protectedMethod(){
  // do something
 }
}

package another.package;
public class B extends A{
 public void someMethod(){
  // accessible because B is a subclass of A
  protectedMethod();
 }
} 

package some.package;
public class C {
 public void anotherMethod(){
  // accessible because C is in the same package as A
  protectedMehtod();
 }
}

คำตอบ:


4

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

สำหรับฉันแล้วกรณีการใช้งานดังกล่าวค่อนข้างทั่วไปกว่าเฉพาะและมันเกิดจากการตั้งค่าของฉันไปที่:

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

จากด้านบนฉันสามารถเริ่มออกแบบสำหรับวัตถุของฉันด้วยตัวดัดแปลงการเข้าถึงเริ่มต้น (ฉันจะเริ่มต้นด้วยprivateแต่นั่นจะทำให้การทดสอบหน่วยซับซ้อน):

public class Example {
    public static void main(String [] args) {
        new UnitTest().testDoSomething(new Unit1(), new Unit2());
    }

    static class Unit1 {
        void doSomething() {} // default access
    }
    static class Unit2 {
        void doSomething() {} // default access
    }

    static class UnitTest {
        void testDoSomething(Unit1 unit1, Unit2 unit2) {
            unit1.doSomething();
            unit2.doSomething();
        }
    }
}

บันทึก Side ในตัวอย่างข้างต้นUnit1, Unit2และUnitTestมีการซ้อนกันภายในExampleสำหรับความเรียบง่ายของงานนำเสนอ แต่ในโครงการจริงผมน่าจะมีชั้นเรียนเหล่านี้ในแฟ้มที่แยกต่างหาก (และUnitTestแม้กระทั่งในไดเรกทอรีที่แยกต่างหาก )

จากนั้นเมื่อมีความจำเป็นเกิดขึ้นฉันจะลดการควบคุมการเข้าถึงจากค่าเริ่มต้นเป็นprotected:

public class ExampleEvolved {
    public static void main(String [] args) {
        new UnitTest().testDoSomething(new Unit1(), new Unit2());
    }

    static class Unit1 {
        protected void doSomething() {} // made protected
    }
    static class Unit2 {
        protected void doSomething() {} // made protected
    }

    static class UnitTest {
        // ---> no changes needed although UnitTest doesn't subclass
        // ...and, hey, if I'd have to subclass... which one of Unit1, Unit2?
        void testDoSomething(Unit1 unit1, Unit2 unit2) {
            unit1.doSomething();
            unit2.doSomething();
        }
    }
}

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

ต้องการการเปลี่ยนแปลงน้อยลง => การปรับเปลี่ยนที่ปลอดภัยยิ่งขึ้น; หลังจากทั้งหมดที่ฉันเปลี่ยนเพียงแค่ตัวดัดแปลงการเข้าถึงและฉันไม่ได้แก้ไขวิธีการUnit1.doSomething()และสิ่งที่Unit2.doSomething()ทำดังนั้นจึงเป็นเรื่องปกติที่จะคาดว่ารหัสการทดสอบหน่วยจะทำงานต่อไปโดยไม่มีการดัดแปลง


5

ฉันว่านี่มีสองส่วน:

  1. ค่าเริ่มต้น "แพ็คเกจ" การเข้าถึงมีประโยชน์ในหลากหลายกรณีเนื่องจากคลาสไม่ได้เป็นหน่วยการห่อหุ้มที่ดีเสมอไป วัตถุประกอบหลายอย่างที่วัตถุบางอย่างทำหน้าที่เป็นชุดของวัตถุอื่น ๆ แต่รายการนั้นจะต้องไม่สามารถแก้ไขได้ในที่สาธารณะเนื่องจากมีค่าคงที่บางส่วนในคอลเลกชันทั้งหมด C ++ มีเพื่อน ๆ Java มีการเข้าถึงแพ็คเกจ
  2. ตอนนี้ขอบเขตการเข้าถึง "แพ็คเกจ" นั้นไม่ขึ้นอยู่กับขอบเขต "subclass" (ป้องกัน) ดังนั้นคุณต้องมีตัวระบุการเข้าถึงเพิ่มเติมสำหรับแพ็คเกจเท่านั้นคลาสย่อยเท่านั้นและแพ็คเกจและคลาสย่อย ขอบเขต "แพ็คเกจ" ถูก จำกัด มากขึ้นเนื่องจากชุดของคลาสในแพคเกจมักจะมีความชัดเจนในขณะที่คลาสย่อยอาจปรากฏที่ใดก็ได้ ดังนั้นเพื่อให้สิ่งต่าง ๆ ง่ายขึ้น Java เพียงรวมการเข้าถึงแพ็คเกจไว้ในการเข้าถึงที่ได้รับการป้องกันและไม่มีตัวระบุพิเศษสำหรับคลาสย่อย - แต่ - ไม่ใช่แพ็คเกจ ถึงแม้ว่าคุณควรคิดprotectedเช่นนั้นเสมอ

มันจะไม่ง่ายกว่าprotectedนี้หรือไม่ถ้าเป็นคลาสย่อยเท่านั้น สุจริตเป็นเวลานานฉันอยู่ภายใต้ความประทับใจที่เป็นพฤติกรรม
jramoyo

@jramoyo: ไม่เพราะคุณยังคงต้องการให้มีพฤติกรรมแบบรวมที่ใช้ได้ซึ่งหมายความว่าตัวระบุอื่น
Jan Hudec

6
@jramoyo - ใน C # protectedเป็นคลาสและคลาสย่อยเท่านั้นและinternalเป็นไลบรารี่/ แพ็กเกจกว้าง นอกจากนี้ยังมีprotected internalซึ่งเป็นเทียบเท่ากับของ protectedJava
Bobson

@Bobson - ขอบคุณการติดตั้ง C # ดูเหมือนจะเป็นทางเลือกที่ดีกว่า
jramoyo

5

IMHO นี่เป็นการตัดสินใจออกแบบที่ไม่ดีใน Java

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

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

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

มีหลายสิ่งหลายอย่างที่ฉันเป็นส่วนตัวระหว่างฉันและลูก ๆ ของฉันและเราไม่แบ่งปันกับเพื่อนบ้าน มีน้อยมากที่ฉันรักษาความเป็นส่วนตัวระหว่างฉันและเพื่อนบ้านและไม่แบ่งปันกับลูก ๆ ของฉัน :-)


0

ตัวอย่างที่ดีที่นึกได้ทันทีคือคลาสยูทิลิตี้ที่ใช้บ่อยในแพ็คเกจ แต่คุณไม่ต้องการการเข้าถึงแบบสาธารณะ .) แทนที่จะทำให้ทุกอย่าง [เทียบเท่า Java friend access modifier or idiomในC++] ของคลาสอื่น ๆ ทุกอย่างพร้อมใช้งานโดยอัตโนมัติ


1
คลาสยูทิลิตี้เป็นตัวอย่างของคลาสที่อยู่ภายในโดยรวมมากกว่าสมาชิก
Jan Hudec

0

กรณีการใช้งานสำหรับโมดิฟายเออร์ป้องกัน / แพ็กเกจการเข้าถึงจะคล้ายกับเคสสำหรับโมดิฟายเออร์สำหรับเพื่อนใน C ++

กรณีการใช้งานหนึ่งคือเมื่อการดำเนินการตามรูปแบบของที่ระลึก

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

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


1
ไม่วัตถุที่ระลึกไม่ต้องการและไม่ควรมีการเข้าถึงวัตถุใด ๆ มันเป็นวัตถุที่ทำให้อนุกรมเป็นของที่ระลึกและ deserializes อีกครั้ง และของที่ระลึกเองก็เป็นเพียงถุงสมบัติที่โง่ ไม่ควรมีสิทธิ์เข้าถึงแบบสาธารณะมากกว่าอีกแบบ
Jan Hudec

@JanHudec ผมกล่าวอย่างแท้จริง"เป็น -> หนึ่ง <- วิธีที่เป็นไปได้เพื่อให้บรรลุรูปแบบของที่ระลึก"
Tulains Córdova

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

-1

สมมาตร?

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


1
ขอบคุณคุณมีตัวอย่างไหม เสียงเหมือนที่สามารถทำได้โดย "เริ่มต้น" การเข้าถึงมากกว่า "การป้องกัน"
jramoyo

-1

ลำดับชั้นการห่อหุ้มของ Java ถูกกำหนดไว้อย่างดี:

ชั้น -> แพคเกจ -> มรดก

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

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

มันทำให้รู้สึกจากมุมมองแนวคิดที่จะมีบางสิ่งบางอย่างใน java.util ที่จะ "เป็นมิตร" กับชั้นเรียนอื่นในแพคเกจกว่าสิ่งที่อยู่ใน com.example.foo.bar ที่ subclassing มัน ในกรณีก่อนหน้าคลาสมีแนวโน้มที่จะถูกเขียนโดยผู้เขียนคนเดียวกันหรืออย่างน้อยผู้เขียนโค้ดจากองค์กรเดียวกัน


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