java中不同包的受保护成员访问-好奇心[重复]

Posted

技术标签:

【中文标题】java中不同包的受保护成员访问-好奇心[重复]【英文标题】:Protected member access from different packages in java - a curiosity [duplicate] 【发布时间】:2011-07-30 13:43:23 【问题描述】:
package packageOne;
public class Base

    protected void display()
        System.out.println("in Base");
    



package packageTwo;
public class Derived extends packageOne.Base 
    public void show()
        new Base().display(); //this is not working throws compilation error that display() from the type Base is not visible
        new Derived().display(); //is working
        display(); //is working
    

这两个包位于两个不同的文件中。但是为什么会有这种行为呢?

【问题讨论】:

【参考方案1】:

protected 允许从子类从同一包中的其他类访问。这就是为什么任何Derived 类实例都可以访问Base 中受保护的方法。

另一行创建了一个Base 实例(不是Derived 实例!!)。并且仅允许从同一包的对象访问该实例的受保护方法。


display();

-> 允许,因为调用者,Derived 的实例可以访问其子类的受保护成员和字段,即使它们位于不同的包中

new Derived().display();

-> 允许,因为您在Derived 的实例上调用该方法,并且该实例可以访问其子类的受保护方法

new Base().display();

-> 不允许 因为调用者的(this 实例)类没有像Base 类定义在同一个包中,所以this 无法访问受保护的方法.正如我们所看到的,当前的子类是该包中的一个类,这并不重要。 后门已关闭;)

【讨论】:

Derived 是 Base 的子类。 @abson - 等一下,理解你的问题,仍在编辑并试图解释;) 我发现逻辑被破坏了,为什么在具有包私有访问权限的基类的情况下,即使它们位于不同的包中,它也可以为其子级提供受保护的方法级访问。不明白为什么在这种情况下类也不应该被标记为受保护的(就像抽象,其中 min 1 抽象方法强制类被标记为抽象),或者至少是公共的以避免混淆。一般规则是首先是类级别的访问权限,然后是成员级别的访问权限。【参考方案2】:

http://java.sun.com/docs/books/jls/third_edition/html/names.html#6.6

class C
    protected member;

// in a different package

class S extends C 

    obj.member; // only allowed if type of obj is S or subclass of S

动机大概如下。如果objS,则S 类对其内部有足够的了解,它有权操纵其成员,并且可以安全地做到这一点。

如果obj 不是S,它可能是C 的另一个子类S2S 不知道。 S2 可能在编写S 时还没有出生。对于S 来操作S2 的受保护内部结构是非常危险的。如果允许这样做,从S2 的角度来看,它不知道谁会篡改其受保护的内部结构以及如何篡改,这使得S2 的工作很难推理自己的状态。

现在如果objDD extends S,那么S 访问obj.member 是否危险?并不真地。 S 如何使用memberS 及其所有子类(包括D)的共享知识。 S作为超类有定义行为的权利,D作为子类有接受和遵从的义务。

为了更容易理解,该规则实际上应该被简化为要求obj 的(静态)类型恰好是S。毕竟,子类D 出现在S 中是非常不寻常和不合适的。即使发生这种情况,obj 的静态类型是D,我们的简化规则可以通过向上转换轻松处理:((S)obj).member

【讨论】:

嘿,我有一个好奇心。为什么obj的类型不能是'C'?答案可能很简单,但我无法得到它。请解释!谢谢 @ShashankAgarwal 你的问题得到答案了吗?【参考方案3】:

受保护的访问有一些特殊规则,详见Java Language Specification:

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

【讨论】:

【参考方案4】:

首先想到的是你可以在任何软件中使用protectedObject,但只有不同的包非子类不能从其他类访问受保护的成员。这意味着您不能直接使用它。首先你得到那个 obj 然后使用。

    package Demos;

    public class AB
    
        public    int a = 14;
        protected int b = 13;   
    

我们还有另一个类

package Example;

import Demos.AB;

public class Ex1 extends AB

    public static void main(String[] args)
    
        AB obj = new AB();          // obj of AB                OR
                                    // AB obj = new Ex1(); object of Ex1 but referance of AB
                                    // cant use protacted member

        System.out.println(obj.a);
        System.out.println(obj.b);  //You can't use 


        Ex1 obj1 = new Ex1();       // you have to make obj of sub-class referance of Ex1
        System.out.println(obj1.a);
        System.out.println(obj1.b);  // Now You can use
    

在这件事上,你必须扩展受保护成员的类,然后使用你不能直接使用 is。

【讨论】:

【参考方案5】:
new Base().display();

它创建一个 Base 对象,然后尝试调用它的 display()。 显然它不会起作用,因为 Base 上的 display() 是受保护的。

【讨论】:

但是我从一个扩展它的类中调用它,所以它应该可以正常工作不是吗? @abson: super.display() 很好。但在示例中,它创建了一个新对象,然后通过它调用。因此,除非它们在同一个包中,否则它不会起作用。【参考方案6】:

这是预期的行为。 protected 表示继承的类和相同的包类可以看到该方法。所以,这就是你所看到的。

【讨论】:

【参考方案7】:

这可能是对您问题的直接回答,但我认为您没有理由致电 new Base().display();。也许您在super.display(); 中的意思。

在这种情况下,你实际上是在使用继承的方法,但仅仅因为你继承了一个类,并不意味着你访问了受保护的方法(根据定义,仅对超类可见)。

不同之处在于您尝试从您继承的类的实例访问受保护的方法(您的示例)。在我的示例中,您可以通过继承访问受保护的方法。

总结:可以通过继承上下文访问方法。

为什么?

它让程序员可以灵活地决定哪些功能只能由直系后代使用或扩展。

【讨论】:

【参考方案8】:

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

【讨论】:

【参考方案9】:

display 不是 Base 中的静态方法。所以,你必须先创建一个 Base 的实例,然后调用 display。

Base base = new Base();
base.display();

【讨论】:

基础基础 =new Base();基地.显示;等同于 new Base().display(); 这是 OP 的相同代码。(-1) 是的,你是对的!这是一个疏忽!

以上是关于java中不同包的受保护成员访问-好奇心[重复]的主要内容,如果未能解决你的问题,请参考以下文章

无法访问基类中的受保护成员 [重复]

C#访问派生类中的受保护成员[重复]

访问不同程序集中的受保护成员

C# 中实例成员的受保护访问? [复制]

.Net中受保护的内部意味着啥[重复]

C#:基类中的受保护方法;无法使用来自另一个类的派生类对象进行访问[重复]