×

消息

EU e-Privacy Directive

This website uses cookies to manage authentication, navigation, and other functions. By using our website, you agree that we can place these types of cookies on your device.

View e-Privacy Directive Documents

You have declined cookies. This decision can be reversed.

这节比较简单,都是各种面试考烂了的东西。

类和属性的访问控制应尽可能严格

访问控制是Java语言中最重要的概念之一,它使得对数据的封装成为可能。好的数据封装可以有效分隔一个系统中的不同模块,增加系统可靠性,便于维护,而且使各模块的开发和重构完全独立,实现细节上的改动不会影响对外开放的API。

对于类,有两个访问级别:package-private和public。其中前者是默认的,如果一个类没有被声明为public,那么它就是package-private,也就是说,它只在其自己所在的软件包内可见。这两个级别的选择没什么复杂的:只有要作为API开放的类,才声明为public,其余实现的细节,则尽可能都声明为package-private。如果一个非public类只被另外一个类使用,那么它应该被定义成使用者的私有内嵌类(private nested class),这样可以进一步减小它的可见范围,使其更好地被保护。

对于类的属性,则有四个访问级别:

private:仅所在类内可见

package-private:同一软件包内可见

protected:子类和同一软件包内可见

public:完全开放

四个级别的含义很简单,无需赘言。值得一提的,是一些小细节。

1. 对于public类的属性,从package到protected是可见性上的一种巨大提升。原因在于,一个package级别的属性,只能算实现的一部分,可以被开发者随意改动,而一旦它被开放为protected,就变成了API的一部分,需要被长期维护,任何与其有关的改动都会破坏用户代码,同时它也会向用户泄露API实现细节的信息。真正需要protected属性的时候并不多,所以尽可能不要声明这一级别的属性。

2. 根据Java语言规范,如果子类覆盖了父类的一个方法,那么被覆盖方法的可见性只能放宽而不能收紧。这是为保证在任何父类对象可用的场景,子类对象都同样可用。这一规则由编译器强化,如有违反,会有编译错误出现。

3. 对象属性永远不能是public的。原因显而易见:如果public对象属性不是immutable或者final,那么用户可以轻易改变其属性或者引用,对这样的改变,开发者无法控制,而这很容易破坏程序的实现。即便public对象属性是final而且immutable,它同样影响开发者对程序的维护,对这一属性的修改有可能破坏用户代码。这一规则同样适用于静态(static)属性,但有一个特例:常量,也就是public static final而且immutable的属性,可以存在。这种情况下常量名要全部大写,并用下划线连接各单词。

基于上面第三条规则,由于非空数组一定是mutable的,所以任何类都不应该有public static final的数组属性,或者返回这种属性的getter。这是一种最常见的安全漏洞的来源:

// Potential security hole!
public static final Thing[] VALUES = { ... };

有两种替代方案可以避免这个问题:

private static final Thing[] PRIVATE_VALUES = { ... };

public static final List<Thing> VALUES =
	Collections.unmodifiableList(Arrays.asList(PRIVATE_VALUES));

或者:

private static final Thing[] PRIVATE_VALUES = { ... };

public static final Thing[] values() {
	return PRIVATE_VALUES.clone();
}

可以依用户需求和使用习惯做出选择。

提交评论


安全码
刷新