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吧.^_^

© 2004, bigwhite. 版权所有.

Related posts:

  1. Effective Java阅读笔记-item4、6
  2. Effective Java阅读笔记-item1
  3. Java 5.0新特性研究(一)
  4. Java 5.0新特性研究(二)
  5. C++ Advanced Training(二)