`

为什么子类不能访问基类的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:

 

[java] view plaincopy
 
  1. public class Base {  
  2.    public String[] data;  
  3. }  
  4. class Sub extends Base{  
  5.     public void show(){  
  6.         System.out.println(Arrays.toString(this.getData()));  
  7.     }  
  8. }  

 

 

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

 

[java] view plaincopy
 
  1. public class Base {  
  2.    //public String[] data;  
  3.    public ArrayList data;  
  4. }  

 

 

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

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

 

 

[java] view plaincopy
 
  1. public class Base {  
  2.     //private String[] data;  
  3.     private ArrayList<String> data;  
  4.       
  5.     public String[] getData() {  
  6.         return  (String[]) data.toArray();  
  7.     }  
  8.       
  9.     public void setData(String[] data) {  
  10.         this.data = new ArrayList<String>(Arrays.asList(data));  
  11.     }  
  12. }  
分享到:
评论

相关推荐

    一个具有对象计数功能的基类

    More Effective C++的Item M26:限制某个类所能产生的对象数量,里面有一个模板类可作为基类,可作为参考学习内容,如果使用VS2005对模板类进行编译,注意类声明和定义如果分开写在.h和.cpp,子类不能只#include ...

    c.c++找工作面试重点结构图-mindmanager

    公有继承的特点是基类的公有成员和保护成员作为派生类的成员时,它们都保持原有的状态,而基类的私有成员仍然是私有的,不能被这个派生类的子类所访问。 (1) 基类成员对其对象的可见性: 公有成员可见,其他不可见...

    Python面向对象编程:私有成员,保护成员和普通成员;抽象基类与继承

    保护成员变量: _foo:以单下划线开头的表示的是 protected 类型的变量,即保护类型只能允许其本身与子类进行访问,不能用于 from module import * 普通成员变量:foo 类外可访问。 私有方法:__private_method...

    C++上机实验报告-实验五.docx

    采用类的派生的方法,利用基类派生出子类,子类继承基类的属性,从而在已有基类的基础上设计新的派生类,模式如下: class 派生类名:继承方式 基类名1,继承方式 基类名2,…,继承方式 基类名n { 派生类成员声明;...

    net学习笔记及其他代码应用

    11.用.net做B/S结构的系统,您是用几层结构来开发,每一层之间的关系以及为什么要这样分层? 答:一般为3层 数据访问层,业务层,表示层。 数据访问层对数据库进行增删查改。 业务层一般分为二层,业务表观层...

    c#学习笔记——学习心得

    密封类:密封类不能作为基类被继承,但可以继承别的类或接口,密封类中不能声明受保护的成员或虚成员,密封类不能声明为抽象的,声明密封类用sealed.密封方法只能用于对基类的虚方法进行实现,声明密封方法时同时...

    C++/JAVA/C#子类调用父类函数情况总结

    —–基类有默认构造函数时,可以在子类不写,则隐式调用 —–基类无/有默认构造函数时,在子类构造函数初始化列表处调用,则显示调用 基类类名(参数) class Base { public: Base(int b) : m_b(b) { } private...

    C++纯虚数和抽象类

    //可定义公有基类的一个指针,即可达到程序的要求。 CTriangle tir(4,6); cout(); pshape=&tir; cout&lt;&lt;pshape-&gt;area(); CCircle cir(7); cout(); pshape=&cir; cout&lt;&lt;pshape-&gt;area(); }

    leetcode添加元素使和等于-KnowledgeCollection:整理计算机笔试面试知识

    私有继承(private):私有继承的特点是基类的公有成员和保护成员都作为派生类的私有成员,并且不能被这个派生类的子类所访问。 保护继承(protected):保护继承的特点是基类的所有公有成员和保护成员都成为派生类...

    C++中的三种继承public,protected,private详细解析

    我们已经知道,在基类以private方式被继承时,其public和protected成员在子类中变为private成员。然而某些情况下,需要在子类中将一个或多个继承的成员恢复其在基类中的访问权限

    JAVA复习资料

    10、基类的公有成员在派生类中的访问权限由_基类___决定。 11、用static修饰的方法,称为静态方法。它们不是对象的方法,而是整个类的方法。静态方法只能处理用关键字_static___修饰的数据。 12、在Java中有...

    PHP面向对象程序设计继承用法简单示例

    本文实例讲述了PHP面向对象程序设计继承用法。...//如果$name是protected,private访问权限,那么将不能在类外被直接访问。 //如果$name是private访问权限,那么将只能在自身类里访问。 //如果$name是protecte

    JAVA面试题最全集

    修饰符(关键字)如果一个类被声明为final,意味着它不能再派生出新的子类,不能作为父类被继承。因此一个类不能既被声明为 abstract的,又被声明为final的。将变量或方法声明为final,可以保证它们在使用中不被...

    【04-面向对象(上)】

     –方法不能独立执行,必须要有调用者.(如:类.方法、对象.方法)  –方法不能独立定义,只能定义在类里.  –方法要么属于一个类,要么属于一个对象 方法的参数传递机制 传递方式只有一种:值传递. 形参...

    Java面向对象程序设计杨晓燕面向对象基本原则和模式.pptx

    子类型能够替换基类型原则 子类型能够替换基类型原则也叫里氏代换原则(Liskov Substitution Principle ,简称LSP),里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现,且程序运行正常。 特

    在一小时内学会 C#(txt版本)

    2. 你不能在 C# 中访问一个“挂起”指针。 3. 超出数组边界的表达式索引值同样不可访问。 4. C# 中没有全局变量或全局函数,取而代之的是通过静态函数和静态变量完成的。 数据类型 所有 C# 的类型都是从 object 类...

    java 面试题 总结

    为什么要有GC?  GC是垃圾收集的意思(Gabage Collection),内存处理是编程人员容易出现问题的地方,忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃,Java提供的GC功能可以自动监测对象是否超过作用域...

    超级有影响力霸气的Java面试题大全文档

    为什么要有GC?  GC是垃圾收集的意思(Gabage Collection),内存处理是编程人员容易出现问题的地方,忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃,Java提供的GC功能可以自动监测对象是否超过作用域...

    java基础.txt

    · 用protected修饰的属性和方法,父类和子类不在同一包下不能继承 子类又称派生类,父类又称基类和超类 super:关键字,对父类对象的引用,可以调用本类的属性和方法 super(); 对父类对象构造的调用,如果...

Global site tag (gtag.js) - Google Analytics