区分一个组件设计的好不好,唯一的评价因素就是看对于外界组件,能不能隐藏起来细节,只通过API进行通信,每个模块不知道其他模块的细节实现,这就是封装或者信息隐藏的概念。封装一个非常大的好处就是可以接触组件之间的耦合,也就是解耦。解耦使组件之间可以独立的开发,测试,优化,使用和修改。这些组件并行化的开发,加快了开发的速度。
封装的工具:访问控制机制,也就是类,方法,成员的可访问性(public,protect,default,private)
封装的规则:尽可能的使每个类或成员不被外界访问。也就是对每个类要赋予尽可能最小的访问级别。
私有的成员外界无法访问,因此改变只会影响这个类的内在。如果把某个类,方法,成员设置成public,那以后一定要维护这个类的兼容性。
继承时访问权限的限制:子类的访问权限一定不能低于超类的访问权限。例如:
public class Person {
protected void testAcessable(){
System.out.println("this is parent and the accessalbe is protected");
}
}
public class Child extends Person {
//至少是protected级别的否则无法编译,这里就无法编译
private void testAcessable(){
System.out.println("this is child and the accessable level is private");
}
}
公有类的实例域绝不能是公有的,一旦成为公有,这个类就失去了对这个域的限制,而且这也很容易造成线程不安全。静态域也是同样的限制,只有一种情况例外,那就是通过静态公有final域来暴露某些常量。
要注意final修饰数组的时候并不是说数组不可变,而是数组引用不可变,如果想要实现一个不可变的数组可以使用List代替,Collections.unmodifiableList(Arrays.asList(array));另一种实现不可变数组的情况是使用数组的浅拷贝,返回一个本数组的地址引用
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class FINALARRAY {
private static final Integer[] array = new Integer[10];
//也可以使用克隆返回一个唯一的final地址引用。
public static final Integer[] values(){
return array.clone();
}
public static void main(String[] args) {
Integer[] array = FINALARRAY.array;
array[2] = 3;
array[4] =5;
System.out.println(array.toString());
final List<Integer> finalList = Collections.unmodifiableList(Arrays.asList(array));
finalList.set(2, 4);
System.out.println(finalList.toString());
}
}
}
/*
[Ljava.lang.Integer;@6e0be858
Exception in thread "main" java.lang.UnsupportedOperationException
at java.util.Collections$UnmodifiableList.set(Collections.java:1313)
at item15.FINALARRAY.main(FINALARRAY.java:14)
*/
总结:应该始终尽可能降低元素的访问级别,仔细设计一个具有最小公有API之后,应该防止把任何散乱的类,接口或者成员变成API的一部分,除了公有静态final域的特殊情况外(充当常量),共有类不应该包含公有域,而且要保证公有静态final域所引用的对象都是不可变的。