Java:跨包的受保护访问

Java:跨包的受保护访问,java,inheritance,packages,protected,Java,Inheritance,Packages,Protected,我想了解下面的示例中发生了什么(通过子类从包外部访问受保护的成员) 我知道对于包外的类,子类只能通过继承看到受保护的成员 有两个包:package1和package2 package1:ProtectedClass.java package org.test.package1; public class ProtectedClass { protected void foo () { System.out.println("foo"); } } packag

我想了解下面的示例中发生了什么(通过子类从包外部访问受保护的成员)

我知道对于包外的类,子类只能通过继承看到受保护的成员

有两个包:
package1
package2

  • package1
    ProtectedClass.java

    package org.test.package1;
    
    public class ProtectedClass {
    
        protected void foo () {
            System.out.println("foo");
        }
    }
    
    package org.test.package2;
    
    import org.test.package1.ProtectedClass;
    
    public class ExtendsprotectedClass  extends ProtectedClass {
    
        public void boo() {
            foo(); // This works, 
                   // since protected method is visible through inheritance
        }
    
        public static void main(String[] args) {
            ExtendsprotectedClass epc = new ExtendsprotectedClass();
            epc.foo(); // Why is this working? 
                       // Since it is accessed through a reference,
                       // foo() should not be visible, right?
        }
    }
    
    package org.test.package2;
    
    public class UsesExtendedClass {
    
        public static void main(String[] args) {
            ExtendsprotectedClass epc = new ExtendsprotectedClass();
            epc.foo(); // CompilationError: 
                       // The method foo() from the type ProtectedClass
                       // is not visible
        }
    }
    
  • package2
    ExtendsprotectedClass.java

    package org.test.package1;
    
    public class ProtectedClass {
    
        protected void foo () {
            System.out.println("foo");
        }
    }
    
    package org.test.package2;
    
    import org.test.package1.ProtectedClass;
    
    public class ExtendsprotectedClass  extends ProtectedClass {
    
        public void boo() {
            foo(); // This works, 
                   // since protected method is visible through inheritance
        }
    
        public static void main(String[] args) {
            ExtendsprotectedClass epc = new ExtendsprotectedClass();
            epc.foo(); // Why is this working? 
                       // Since it is accessed through a reference,
                       // foo() should not be visible, right?
        }
    }
    
    package org.test.package2;
    
    public class UsesExtendedClass {
    
        public static void main(String[] args) {
            ExtendsprotectedClass epc = new ExtendsprotectedClass();
            epc.foo(); // CompilationError: 
                       // The method foo() from the type ProtectedClass
                       // is not visible
        }
    }
    
  • package2
    UsesExtendedClass.java

    package org.test.package1;
    
    public class ProtectedClass {
    
        protected void foo () {
            System.out.println("foo");
        }
    }
    
    package org.test.package2;
    
    import org.test.package1.ProtectedClass;
    
    public class ExtendsprotectedClass  extends ProtectedClass {
    
        public void boo() {
            foo(); // This works, 
                   // since protected method is visible through inheritance
        }
    
        public static void main(String[] args) {
            ExtendsprotectedClass epc = new ExtendsprotectedClass();
            epc.foo(); // Why is this working? 
                       // Since it is accessed through a reference,
                       // foo() should not be visible, right?
        }
    }
    
    package org.test.package2;
    
    public class UsesExtendedClass {
    
        public static void main(String[] args) {
            ExtendsprotectedClass epc = new ExtendsprotectedClass();
            epc.foo(); // CompilationError: 
                       // The method foo() from the type ProtectedClass
                       // is not visible
        }
    }
    
  • 可以理解的是,
    ExtendsprotectedClass
    中的
    boo()
    方法可以访问
    foo()
    ,因为受保护的成员只能通过继承来访问


    我的问题是,为什么通过
    main()中的引用访问
    foo()
    方法时工作正常
    extendedsprotectedclass
    的方法,但当通过
    UsesExtendedClass
    中的
    epc
    引用访问时,该方法将不起作用。

    允许
    extendedsprotectedclass
    类中的代码通过类型的引用访问
    ProtectedClass
    的受保护成员
    ExtendsprotectedClass
    。从:

    对象的受保护成员或构造函数可以从包的外部访问,在包中它只能由负责该对象实现的代码声明

    设C为声明受保护成员m的类。仅允许在C的子类S的主体内访问。此外,如果Id表示实例字段或实例方法,则:

    • 如果访问是通过限定名称Q.Id进行的,其中Q是ExpressionName,则当且仅当表达式Q的类型是S或S的子类时才允许访问。[……]
    UsesExtendedClass
    不负责实现
    extendedsprotectedclass
    ,因此最终调用失败


    编辑:这背后的原因是
    protected
    access旨在帮助子类实现它们所需的功能,从而提供比通常可用的更多的对超类内部的访问。如果所有代码都可以使用该方法,那么该方法将非常接近于公开。基本上,信任子类不会破坏封装;它们在自己类型的对象中被赋予了更多的功能。公共API不应该公开这些细节,但受保护的API只是为了给子类提供更多的机会;UseStendedClass不从ProtectedClass继承,并且根据定义为“受保护”成员只能在声明/定义它们的类中访问,或者在从声明或定义它们的类继承的类中访问。

    在第一种情况下有效,因为它是从同一个类调用的,即使方法是通过引用访问的。您甚至可以通过同一主方法中的引用调用
    ExtendsprotectedClass
    private
    方法。

    从以下位置查看此图片:


    很明显,类的受保护成员可以通过子类访问。

    根据定义--“受保护”成员只能在声明/定义它们的类中访问。我不太同意这一点,因为受保护的成员可以从同一个包中的其他类访问,而无需继承。@Jon谢谢。我知道子类的类成员可以访问受保护的成员(如
    boo()
    method中所示)。但是我很好奇为什么只允许在子类方法中通过子类的引用访问受保护的成员?它背后的任何理由都是有效的,因为受保护的方法是由它自己类的指针访问的。这应该失败:
    public static void ExtendsprotectedClass.main(String[]args){ProtectedClass epc=new ExtendsprotectedClass();//upcast
    epc.foo();//应该是编译错误吗?
    }@Jon:完全同意
    protected
    访问旨在帮助子类实现所需的功能。这就是为什么我添加了一段代码
    boo()
    调用
    foo()
    。也就是说,子类代码可以使用受保护的
    foo()
    或重写基类的
    foo()
    。但我仍然不明白的是,为什么允许它通过引用直接访问
    ExtendsprotectedClass epc=new ExtendsprotectedClass();epc.foo()。它不应该像第二种情况那样,对吗?为什么它只允许通过实现基类的类中的引用访问受保护的方法
    foo()
    ?@JWhiz:因为这意味着该类中的代码能够轻松地处理自身的实例,比如比较,静态工厂方法等。仅仅为了能够访问特定成员而编写实例方法可能是一件非常痛苦的事情。同样,子类的代码应该知道它在做什么。@Jon:你能提供指向示例代码的指针吗?在示例代码中,同一类的私有/受保护方法通过它们实现基类的同一类的引用进行访问。我接受了这个答案,谢谢。现在我明白了为什么它可以通过引用访问它<代码>+1
    用于它。但是,不应该允许通过对象引用调用
    private
    方法,对吗?这是否违背了将其私有化的目的?允许这样做的具体原因是什么?@JWhiz java访问修饰符在类而不是实例级别工作。因此,私有方法对于类是私有的,而不是实例。如果private在实例上工作,那么如果有两个实例,则必须将更多变量和方法公开