Effective Java阅读笔记-item12
Dreamhead把他用大把银子买来的“Effective Java”借给我阅读,我真是很感动亚,我只能用行动来感谢Dreamhead了。^_^
从item12~item18讨论的都是单个类或接口的设计技术。
12、使类和成员的可访问能力最小化
作者提出“你应尽可能的是每一个类或成员不被外界访问”
* 顶层类或接口的访问级别
public — 意味着你的类是提供给客户API的一部分,你有义务永远支持它,维护它。
package-private — 如果一个类或接口做成packge-private,那么意味着它实际上已成为包的实现的一个部分,而不是包提供给客户(使用者)的API的一部分。在以后包的维护过程中你对该类进行修改、替换和删除对客户并无影响。
* 类or接口内成员的访问级别
在几乎每一本java教科书中都有,我这里就不浪费文字了。不过书中有几个观点还是值得我们注意的:
- 如果一个方法改写了超类的一个方法,那么子类中该方法的访问级别低于超类中的访问级别是不允许的。这样可确保子类的实例可被用在任何超类实例使用的场合。
- 公有类不应该包含public field,例外情况通过公有的静态final field来暴露类中的常量是可以的。
- 如果类内的一个final field包含一个指向可变对象的引用,那么它具有非final field的一切缺点,虽然引用本身是final的不能被修改,但是它引用的对象却可以被修改,这将是一个很危险的安全漏洞。如果你非要这么做的话,请确保被 public static final field所引用的对象是不可变的。
Considering the following code :
public class TestItem12 {
public static final Integer[] intArray = { 1 , 4 , 5 , 6};//可以看出我们提供该final Integer的意图是其////不被修改,但实际上是可以被修改的。
public static void main(String[] args) {
System.out.println("Before modifying :");
//这是我们的意图,我们要使用static final field的值。
for (Integer i : TestItem12.intArray ){
System.out.println(i);
}
//这可不是我们的意图,但是这样做编译器不会告诉你你的final引用的对象被修改了,you //are in danger
TestItem12.intArray[1] = 11;
TestItem12.intArray[2] = 10;
System.out.println("After modifying :");
for (Integer i : TestItem12.intArray ){
System.out.println(i);
}
}
}
//output:
Before modifying :
1
4
5
6
After modifying :
1
11
10
6
可以看到引用本身并未发生变化但是所引用对象的值发生了变化。我们改变一下:
public class TestItem12 {
public static final Integer[] valuesOfArray(){
return (Integer[])intArray.clone();
}
private static final Integer[] intArray = { 1 , 4 , 5 , 6};
public static void main(String[] args) {
Integer[] ia = TestItem12.valuesOfArray();
for (Integer i : ia ){
System.out.println(i);
}
a[2] = 123;
for (Integer i : TestItem12.valuesOfArray() ){
System.out.println(i);
}
}
}
//output:
1
4
5
6
1
4
5
6
当然这样会牺牲一些性能。^_^在这个过程中顺便谈谈clone()这个方法吧,很有意思的,呵呵,看代码吧。
public class TestItem12 {
public static final Integer[] valuesOfArray(){
return (Integer[])intArray; // remove the clone() method
}
private static final Integer[] intArray = { 1 , 4 , 5 , 6};
public static void main(String[] args) {
Integer[] ia = TestItem12.valuesOfArray();
for (Integer i : ia ){
System.out.println(i);
}
a[2] = 123;
for (Integer i : TestItem12.valuesOfArray() ){
System.out.println(i);
}
}
//output:
1
4
5
6
1
4
123
6
看到上面代码,remove the clone method后,输出了123,也就是说final reference所引用的对象的值被修改了。这样做是十分危险的,因为它直接暴露了类内部的成员。Clone的作用是它重新new了一块内存,并用intArray对其进行了初始化。这样实际上外部的引用就不会和内部的private引用指向同一块memory了。Simple吧.^_^
评论