【问题标题】:Java access control for protected field outside package [duplicate]包外受保护字段的Java访问控制[重复]
【发布时间】:2016-10-17 06:53:35
【问题描述】:

我收到了一个问题,以确定以下访问是否合法。

package SomePack;

public class A1 {
    ...
protected int y1;
}

///////////

package Whatever;
class B2 extends A1 {
    void h(SomePack.A1 x) {
        x.y1 = 3; // Is this line legal?
    }
}

我认为这大概是合法的,因为 1. y1 字段为protected 2. B2 extends A1 所以 B2 是 A1 的子类型。 3.访问控制基于静态类型,x的静态类型为A1。

但是面试官说这个答案应该是非法的。任何人都可以帮助解释这一点吗?非常感谢。

【问题讨论】:

标签: java


【解决方案1】:

一个对象的protected 成员或构造函数可以从包的外部访问,在该包中它仅由负责实现该对象的代码声明。

https://docs.oracle.com/javase/specs/jls/se8/html/jls-6.html#jls-6.6.1

示例 6.6-1。访问控制:

package points;
public class Point {
    protected int x, y;
    public void move(int dx, int dy) { x += dx; y += dy; }
    public int getX() { return x; }
    public int getY() { return y; }
}

字段 x 和 y 被声明为受保护,并且只能在类 Point 的子类中在包点外访问,并且仅当它们是由正在访问它们的代码实现的对象的字段时。

所以在B2类中,它可以访问自己的y1B2的对象,但不能访问SomePack.A1 xy1或任何其他A1的子类的对象。

【讨论】:

  • 谢谢。这句话怎么解读:and only when they are fields of objects that are being implemented by the code that is accessing them. ?
  • @FongTinyik 表示xy 可以在包外访问,如果使用xy 的代码也是实现相应子类的代码。
  • 实现corresponding subclass的代码也只能访问corresponding subclass的(对象)xy
  • 所以在SubPoint内部我们只能访问this.x或其他实例的xSubPoint。对吗?
  • @FongTinyik 是的。但无法访问Point.xSubPoint2.x
【解决方案2】:

protected 修饰符用于继承,对于包的可见性只使用不使用修饰符。

以下是对不同可见性的用途的简要说明

public 修饰符用于任何地方都需要可见性:

public void someMethod(){
    //user code here
}

protected 修饰符用于当您希望通过继承访问类的内容时:

protected void someMethod(){
    //user code here
}

仅当您想要包可见性时不使用修饰符:

void someMethod(){
    //user code here
}

最后,private 用于您不希望可见性并且只想在内部使用它的情况。

private void someMethod(){
    //user code here
}

以上更详细的解释可以参考:Controlling Access to Members of a Class

【讨论】:

    【解决方案3】:
    • protected 成员只能在子类中的包外部访问。
    • 如果需要访问包外的protected成员变量,只需要通过继承访问即可。
    • 如果需要使用引用变量访问,则需要在同一个包中。

    下面的例子在上面详细说明。

    当您将成员变量修改为protected 时,该受保护的成员变量只能通过继承在包外部访问。

    声明x.y1 = 3; 它试图使用引用变量进行访问,这在包外是不可能的。

    如果您想访问它,只需输入y1 = 3

    使用下面的代码应该可以让您访问 y1

    package whatever;
    
    import somepack.A1;
    
    class B2 extends A1 {
        void h(somepack.A1 x) {
            System.out.println(y1);
            y1 = 3; 
            System.out.println(y1);
    
        }
    
        public static void main(String args[]){
            B2 obj = new B2();
            obj.h(new A1());
        }
    }
    

    这将打印在下面。

    0
    3
    

    如您所见,我们可以仅使用继承直接将值分配给受保护的成员。

    现在让我们看看如何使用引用变量类型进行访问,即不使用继承。

    package somepack;
    
    
    public class A1 {
        protected int y1;
    
    }
    class C{
        public static void main(String args[]){
            A1 obj = new A1();
            System.out.println(obj.y1);
        }
    
    }
    

    【讨论】:

    • 如果我想更改x的y1字段怎么办?
    • 我们已经在这样做了。请检查更新的代码。
    • 感谢 Prasad 并祝贺您达到 10k。但是我的问题是为什么不能访问xy1字段,而不是如何访问thisy1
    • 因为java语言就是这样设计的:)
    • package P1; public class C1 { protected int M; } package P2; class C2 extends C1 { void f(P1.C1 x) { x.M = 3; } 这个合法吗?
    猜你喜欢
    • 2012-05-26
    • 1970-01-01
    • 2015-05-09
    • 1970-01-01
    • 2014-11-18
    • 2010-10-18
    • 2013-02-03
    • 2011-04-02
    • 2023-03-25
    相关资源
    最近更新 更多