为什么子类不能访问基类的private成员?为什么要这样设计?

  看到很多朋友提问“为什么子类不能访问基类的private成员”?随后看到很多朋友回答“这是规范”“这是封装的特性”类似这样的回答。我觉得大家都是对的。但是有时候您需要关注提问的重点在于why?为什么Java要这样设计private?或者是Object Oriented为啥要这样设计这样的机制?

 

  • 封装性:首先,private成员具有良好的封装性(encapsulation)。这个性质对于良好的设计来说是个重要的要素。因为良好的封装性会减小耦合的。服务代码可以定义public函数给客户代码。这样一来客户代码可以和服务代码并行开发。更重要的是,如果修改服务代码的内部实现也不需要改动客户代码。

 

  • 子类也是客户代码:对于客户代码的理解最直接的就是调用这个类的代码,这个很好理解。更深入的理解就可以把客户代码延伸到这个类的子类。从这一点来说子类就是基类的客户代码。你定义了一个class,在里面写了些通用的方法,甚至申明了abstract方法要求别人来继承。这个时候基类里面的protect成员就是对外的API,因为这些方法对子类来说是可见的,你不能随意改动。这个时候如果这个成员是public或者protected就可能造成麻烦。对于API来说你不能随意改动。你能设想JDK里面的有些类的API改动的情况吗?至少我会抓狂的:)

 

  • 访问权限扩大原则:延伸话题来说,还有就是Java对override的时候访问权限的限制。大家都知道Java的访问权限从小到大是:private-> default->  protected-> public。如果要override一个基类里面的方法,那么子类的这个方法的权限不能比被override的函数权限小。这样就导致一个隐性的问题:如果你的基类有public方法,那么它的子类里面都有这个方法的public属性。你不能把基类的这个方法private化。换句话说一旦定义了public函数,它的子类都要维护这个public方法。所以就算是方法也要小心地把它设为public。

 

  当然如果这个基类到最终的子类都是你维护,或者这个类本身就是个非public的类,那么原则可以放宽。

 

  顺便说一下,Eclipse有自动生成标准get/set函数的功能,所以生成get/set是很容易的事情,不要为了方便把成员都变成public。

 

  譬如写了个基类Base,然后有人继承了Base:

public class Base { public String[] data; } class Sub extends Base{ public void show(){ System.out.println(Arrays.toString(this.getData())); } } 

可是有一天你发觉用ArrayList更好,你就把Base改成:

public class Base { //public String[] data; public ArrayList data; } 

然后所有Base的子类都无法编译,直接调用到子类data域的类也无法编译。这就是噩梦,客户端程序员会用眼光追杀你:)

回过头来想,如果当初Base的data域是private,由get/set来访问,那么你可以轻松的修改Base, 子类无需改动:

public class Base { //private String[] data; private ArrayList data; public String[] getData() { return (String[]) data.toArray(); } public void setData(String[] data) { this.data = new ArrayList(Arrays.asList(data)); } } 作者:卢声远

你可能感兴趣的:(为什么子类不能访问基类的private成员?为什么要这样设计?)