首页 回顾 protected 访问修饰符
文章
取消

回顾 protected 访问修饰符

使用 protected 访问控制符

这是基础内容了,但是不能轻视,越基础越要清晰理解。

Protected Access

这是用于演示 protected 关键字的代码包图。

image-20191102082917612

image-20191102204121667

首先创建一个 Bird 类并将其成员设置为 protected

1
2
3
4
5
6
7
package pond.shore;
public class Bird {
    protected String text = "floating";		// protected 访问
    protected void floatInWater() {			// protected 访问
        System.out.println(text);
    } 
}

接着我们创建一个子类:

1
2
3
4
5
6
7
8
package pond.goose;
import pond.shore.Bird;		// 在不同的包
public class Gosling extends Bird {		// 创建子类
    public void swim() {
        floatInWater();		// 调用 protected 成员
        System.out.println(text);	// 调用 protected 成员
    }
}

运行以上代码,会打印 floating 两次,一次因为调用 floatInWater() 另一次因为 swim() 里面的 println()。 因为 GoslingBird 的子类,它可以访问这些成员,即使不在同一个包。 记住 protected 允许所有默认访问权限所允许的。(Remember protected also gives us access to everything that default access does.) 意味着与 Bird 在同一个包的类可以访问它的 protected 成员。

1
2
3
4
5
6
7
8
package pond.shore;			// 与 Bird 在同一个包
public class BirdWatcher {
    public void watchBird() {
        Bird bird = new Bird();
        bird.floatInWater();	// 调用 protected 成员
        System.out.println(bird.text);	// 调用 protected 成员
    }
}

现在我们尝试在不同的包做同样的操作:

1
2
3
4
5
6
7
8
package pond.inland;			// 与 Bird 不在同一个包
public class BirdWatcherFromAfar {
    public void watchBird() {
        Bird bird = new Bird();
        bird.floatInWater();	// 不能通过编译
        System.out.println(bird.text);	// 不能通过编译
    }
}

BirdWatcherFromAfarBird 不在同一个包,且不是 Bird 的子类,所以无法访问 Birdprotected 成员。

好了,现在看看下面这个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package pond.swan;
import pond.shore.Bird;			// 与 Bird 不在同一个包
public class Swan extends Bird {	// 但是 Bird 的子类
    public void swim() {
        floatInWater();		// 包访问父类
        System.out.println(text);	// 包访问父类
    }
    public void helpOtherSwanSwim() {
        Swan other = new Swan();
        other.floatInWater();	// 包访问父类
        System.out.println(other.text);		// 包访问父类
    }
    public void helpOtherBirdSwim() {
        Bird other = new Bird();
        other.floatInWater();	// 不能通过编译
        System.out.println(other.text);		// 不能通过编译
    }
}

上面代码,helpOtherBirdSwim() 方法里面 other.floatInWater()System.out.println(other.text) 不能通过编译是因为引用变量 other 的类型是 Bird。 如果通过引用变量访问一个成员,能否访问取决于引用的变量的类型

再看看下面这个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package pond.goose;
import pond.shore.Bird;			
public class Goose extends Bird {	
    public void helpGooseSwim() {
        Goose other = new Goose();
        other.floatInWater();	
        System.out.println(other.text);		
    }
    public void helpOtherGooseSwim() {
        Bird other = new Goose();
        other.floatInWater();	// 不能通过编译
        System.out.println(other.text);		// 不能通过编译
    }
}

上面代码中,在第二个方法 helpOtherGooseSwim() 有问题,尽管创建的是一个 Goose 对象,但是 other 保存的引用类型是 Bird。因为 GooseBird 不在同一个包,而且 Bird 不是 Goose 的子类,所以不允许访问 Bird 的成员。

在看多一个例子:

1
2
3
4
5
6
7
8
package pond.duck;
import pond.goose.Goose;
public class GooseWatcher {
    public void watch() {
        Goose goose = new Goose();
        goose.floatInWater();	// 不能通过编译
    }
}

代码不能通过编译的原因是我们不在 Goose 类里面。 floatInWater() 方法是 Bird 类中声明的。 GooseWatcherBird 不在同一个包,而且不是 Bird 的子类。Goose 继承自 Bird 只是允许 Goose 访问 floatInWater() ,而不是 Goose 的调用者。

本文由作者按照 CC BY 4.0 进行授权