代码改变世界

使类和成员的可访问性最小化

2017-03-26 17:23  ttylinux  阅读(586)  评论(0编辑  收藏  举报
本文涉及到的概念
1.使类和成员的可访问性最低的意义
2.类和成员的几种可访问性
3.其它注意事项
4.最后的原则
 
1.使类和成员的可访问性最低的意义
 
信息隐藏(information hiding),封装(encapsulation)的概念
一个模块对外部模块隐藏其内部数据和其他实现细节,也就是将它对外提供的API与它的实现细节清晰地隔离开来,它与其他模块的只通过API进行通信,其他模块不需要知道该模块内部的工作情况。
 
使用类和成员的可访问性最低的意义
a.可访问性越低,一个类对外暴露的信息就越少,信息隐藏程度越高,与其它类的耦合程度就更低。
b.可访问性越低,也就是封装程度高,具备的意义,跟封装的带来的意义相同。
 
封装的作用
a.解除组成系统的各个模块之间的耦合关系,每个模块只需要关注其他模块对外提供的API,各个模块是面向API编程。各个模块可以独立地开发,测试,优化,使用,理解和修改。它只需要维护好对外提供的API就可以。
b.减轻负担,程序员在使用模块的时候,只需要关注模块的API,其它的无需关注;维护的模块的时候,只需要维护单个的模块,不用考虑其它模块的事情,只需要考虑模块对外提供的API。
c.模块复用,可以将模块移植到其它系统,重复使用
d.优化方便,检测性能瓶颈的时候,只是确定出是哪个模块的问题,于是,只需要专门针对该模块进行优化,不用考虑其它模块,因为模块之间的耦合度低,只是通过API通信。
 
规则:尽可能地使每个类或者成员不被外界访问
 
2.类和成员的几种可访问性
 
a.顶层类(非嵌套)和接口,有两种访问级别,包级私有和公有的
顶层类,如果是包级私有,那么,只有该包中的类才能使用它
接口,有包级私有,只有该包中的类能实现它
package chapterFour;

class OneClass {

}
////////////////////////
package chapterFour;

interface OneInterface {

}
/////////////////////////
package chapterFour;

class TestClass implements OneInterface {

public static void main(String[] args) {

OneClass one = new OneClass();
}
}
“如果类或者接口能够被做成包级私有的,它就应该被做成包级私有。通过把类或者接口做成包级私有,它实际上成了这个包的实现的一部分,而不是该包导出API的一部分,在以后的发行版本中,可以对它进行修改、替换、或者删除,而无需担心会影响到现有的客户端程序。如果你把它做成公有的,你就有责任永远支持它,以保持它们的兼容性。”《Effective Java》
 
私有嵌套类(或者接口)
如果一个包级私有的顶层类(或者接口)只是在某一个类的内部被用到,就应该考虑使它成为唯一使用它的那个类的私有嵌套类(或者接口)。这样可以将它的可访问范围从包中的所有类缩小到了使用它的那个类
”《Effective Java》
 
package chapterFour;

class TestClass {
private interface OneInterface {

}

private class OneClass {

}

private OneInterface oneInterface = new OneInterface(){};
private OneClass oneClass = new OneClass();

}
b.类成员(域,方法,嵌套类和嵌套接口),有四种可访问级别
1).私有的---
2).包级私有的,它也是缺省访问级别,如果没有为成员指定访问修饰符,就采用这个访问级别
3).受保护的----声明该成员的类的子类可以访问这个成员,并且,声明该成员的包内部的任何类也可以访问这个成员
package chapterFour;

class OneClass {

protected String protectedStr = "I am protected String";

}
//////////////////////////////////////////////////////
package chapterFour;

 class ChidOneClass extends OneClass {

public void visit(){
System.out.println(protectedStr);
}
}
///////////////////////////////////////////////
package chapterFour;

class Visiter {

public void Visit() {

OneClass one = new OneClass();
System.out.println(one.protectedStr);
}
}
View Code
4).公有的---在任何地方都可以访问该成员
 
对于接口的成员,只有一种访问级别,公有的。
private interface OneInterface {

public int one = 10;

public void method();
}
3.其它注意事项
 
a.实例域决不能是公有的
“如果域是非final的,或者是一个指向可变对象的final引用,那么一旦使这个域成为公有的,就放弃了对存储在这个域中的值进行限制的能力;这意味着,你也放弃了强制这个域不可变的能力。同时,当这个域被修改的时候,你也失去了对它采取任何行动的能力。”《Effective Java》
它可以被客户端代码从任何地方进行修改。
 
b.公有的静态final域
 
package chapterFour;

public class OneClass {

public static final String CAR_TYPE="HONDA";
//public static final OneInstance one;

}
“假设常量构成了类提供的整个抽象中的一部分,可以通过公有的静态final域来暴露这些常量”《Effective Java》
 
静态final域不能包含可变对象的引用,因为,如果是可变对象的引用,那么,可以通过该引用去修改该对象。这会增加不可控性。
 
d.长度非零的数组总是可变的,可被修改的
“类具有公有的静态final数组域,或者返回这种域的访问方法,这几乎总是错误的。如果类具有这样的域或者访问方法,客户端将能够修改数组中的内容。”
《Effective Java》
package chapterFour;

 class OneClass {

//Potential security hole!
public static final int[] VALUES = { 1, 2, 3 };
private static final float[] VALUES_FLOAT = {1.2f,1.3f};

//Potential security hole!
public static float[] getFloatArray(){
return VALUES_FLOAT;
}

public static void main(String[] args){

OneClass.VALUES[0] = 10;
OneClass .getFloatArray()[0] = 10.2f;

}
}
修改为:
返回数组的的一个拷贝;或者返回一个公有的不可变列表
class OneClass {

private static final int[] VALUES = { 1, 2, 3 };
private static final float[] VALUES_FLOAT = { 1.2f, 1.3f };

// method one ,return an unmodifiableList
public static final List<int[]> values() {
return Collections.unmodifiableList(Arrays.asList(VALUES));
}

  //method two ,return a copy of an array
public static final float[] getFloatArray() {
return VALUES_FLOAT.clone();
}
}

/////////////////////////////////////////////////////////////////////////////////////////

package chapterFour;
import java.util.List;

class TwoClass {

public static void main(String[] args){

List<int[]> one = OneClass.values();
if(one.size() > 0){
int[] oneArray = one.get(0);
for(int i = 0; i < oneArray.length; i++){
oneArray[i] = i*10;
System.out.println(oneArray[i]);
}
}
System.out.println("/////////////////////////////");
float[] oneFloat = OneClass.getFloatArray();
for(int i = 0; i < oneFloat.length; i++){
System.out.println(oneFloat[i]);
}
}
}
4.最后的原则
 
"总而言之,你应该始终尽可能地降低可访问性。你在仔细地设计了一个最小的公有API之后,应该防止把任何散乱的类、接口和成员变成API的一部分。除了公有静态final域的特殊情形之外,公有类都不应该包含公有域。并且要确保公有静态final域所引用的对象都是不可变的。"
 
《Effective Java》