ITEEDU

Java Gossip: 被保护的(protected)成员

在之前您的数据成员都预设为"private"成员,也就是私用成员,私用成员只能在类别对象中使用,不能直接透过对象来呼叫使用,而即使是扩充了该类别的衍生类别也是如此,您只能透过该类别所提供的"public"方法成员来呼叫或设定私用成员。

然而有些时候,您希望扩充了基底类别的衍生类别,能够直接存取呼叫基底类别中的成员,但不是透过"public"方法成员,也不是将它宣告为"public",因为您仍不希望这些成员被对象直接呼叫使用。

可以宣告这些成员为「被保护的成员」(protected),保护的意思表示存取它有条件限制以保护该成员,当您将类别成员宣告为受保护的成员之后,继承它的类别就可以直接使用这些成员,但这些成员仍然受到对象范围的保护,不可被对象直接呼叫使用。

要宣告一个成员成为受保护的成员,就使用"protected"关键词,下面这个程序是个实际的例子,您将数据成员宣告为受保护的成员,扩充它的类别就可以直接使用,而不用透过"public"方法成员来呼叫:

Rectangle.java
public class Rectangle {
	// 受保护的member
	protected int x, y;
	protected int width, height;
	public Rectangle() {
		x = y = 0;
		width = height = 0;
	}
	public Rectangle(int x, int y, int width, int height) {
		this.x = x;?this.y = y;
		this.width = width;?this.height = height;
	}
	public int getX() { return x; }
	public int getY() { return y; }
	public int getWidth() { return width; }
	public int getHeight() { return height; }
	public int getArea() { return width*height; }
}
Cubic.java
public class Cubic extends Rectangle {
	protected int z;
	protected int length;
	public Cubic() {
		z = 0;?length = 0;
	}
	public Cubic(int x, int y, int z,
	int length, int width, int height) {
		super(x, y, width, height);
		this.z = z;
		this.length = length;
	}
	public int getLength() { return length; }
	public int getVolumn() { return length*width*height; }
} f
UseProtected.java
public class UseProtected {
	public static void main(String[] args) {
		Cubic c1 = new Cubic(0, 0, 0, 10, 20, 30);
		System.out.println("c1 volumn: " + c1.getVolumn());
	}
}

执行结果:

c1 volumn: 6000

在这个例子中,您可以看到直接使用继承下来的受保护成员确实比较方便,方法成员也可以宣告为受保护的成员,对象通常是仅适用于 类别中使用的一些内部处理方法,这些方法对类别外部来说,可能是呼叫它并没有意义或是有危险性,但您在衍生类别中仍可能使用到这些方法,所以通常会将之 宣告为受保护的成员。

一个例子就是在窗口事件处理时,设定事件发生时的呼叫函式,它可以被继承,以自订一些窗口组件,这些方法在事件发生时才会被呼叫,您在类 别外直接呼叫这些方法并没有意义,甚至某些条件没有成立就呼叫它,对整个程序的执行会造成错误,这些方法成员通常就会宣告为受保护的成员。

在设计上有一个考虑,就是对对象内部的field成员最好不要直接呼叫,而仍然透过方法呼叫,例如下面的方式有时不被鼓励:

public class SomeClass {
	private int someInt;
	.....
	public void someMethod() {
		int i = someInt;
		.....
		someInt = 1234;
		....
	}
}

直接在someMethod()中使用field成员,有时会使得someMethod()失去一些弹性,有时建议使用这样的方式:

public class SomeClass {
private int someInt;

.....

private int getSomeInt() {
return someInt;
}

private void setSomeInt(int someInt) {
this.someInt = someInt;
}

public void someMethod() {
int i = getSomeInt();
.....
setSomeInt(1234);
....
}
}

这样作的好处是,您可以在存取field成员前作一些额外的处理(这些处理可能原先您要在someMethod()中进行),当然何时要使用,以及 setter、getter要宣告为"public 、"protected"或是"private",则视您的程序需求而定了。

事实上,对于同一个 套件(package) 下的类别,可以直接呼叫彼此的protected成员,而对于不同套件(package)下的成员,不能呼叫彼此的protected成员。

如果在定义成员时没有设定任何的存取修饰,则为预设(default)的存取权限,预设存取权限可以在同一个套件(package)中的其它类别直接存取,但在子类别中不能被直接存取。