• JavaSE - 深度探讨继承与多态,私有成员是否被继承问题


    目录

    一、继承

    举例

    概念

    语法规则,访问问题。

    有关Java中私有成员到底是否会被继承的问题,

    final关键字

    二、组合

    三、多态

    1、多态实现的条件

    2、向上转型和向下转型

    3. 重写


    一、继承

    举例

    Java - 图书馆管理系统_配的上了吗的博客-CSDN博客

    中的User和Administrator User和GeneralUser就是一种继承关系。 

    概念

    继承:是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特性的基础上进行扩展,增加新功能,这样产生新的类,称派生类。继承呈现了面向对象程序设计的层次结构, 体现了 由简单到复杂的认知过程。继承主要解决的问题是:共性的抽取,实现代码复用。

    简单来说,继承是is--a的关系:管理员用户是一种用户,猫是一种动物,某种特定的销售方式是一种销售方式。

    语法规则,访问问题。

     Java的类只有两种访问修饰限定符:public和什么都不加的默认权限访问。一个Java文件中只能只能有一个public类。 

    ============================================

    实例:

    1. public class Base {
    2. private int pri_num = 0;
    3. public int Same_num;
    4. public int num1 = 0;
    5. public Base(int n) { // 有了自定义的构造函数,编译器就不会自动生成默认构造函数
    6. Same_num = n;
    7. }
    8. // 基类的静态函数,不能被重写,属于类
    9. public static void static_func() {
    10. System.out.println("Base::static_func");
    11. }
    12. // 基类的普通函数
    13. public void func() {
    14. System.out.println("Base::func");
    15. System.out.println(Same_num); // 这里打印的是哪里的Same_num呢?
    16. }
    17. private void private_func() {
    18. System.out.println("Base::private_func");
    19. }
    20. public static void main(String[] args) {
    21. // 这里算是比较有趣的了。
    22. Base base = new Derived();
    23. base.private_func();
    24. }
    25. }
    26. class Derived extends Base {
    27. public int Same_num; // 与基类数据成员同名的数据成员,不会覆盖。
    28. public Derived() { // 需要帮助基类部分初始化,只能一次且必须在第一行。
    29. super(10);
    30. this.Same_num = 22;
    31. super.Same_num = 11;
    32. }
    33. // @Override 静态方法不可以重写,也就是子类和父类中各有一个静态方法
    34. public static void static_func() {
    35. System.out.println("Derived::static_func");
    36. }
    37. @Override // 这个@override可省略,书写目的是让编译器检测类型,返回值部分是否覆盖成功,否则会创建新的函数,构成重载。
    38. public void func() {
    39. System.out.println("Derived::func");
    40. }
    41. // @Override 未覆盖,可能因为程序员大意,所以要写@Override
    42. public void func(int n) {
    43. System.out.println("Derived::unOverrideFunction");
    44. }
    45. // 为了证实基类引用不可以调用派生类独有的函数
    46. public void Derived_func() {
    47. System.out.println("Derived specific func");
    48. }
    49. public void testNum() {
    50. // 测试访问同名的非静态数据成员
    51. System.out.println(Same_num);
    52. System.out.println(super.Same_num);
    53. System.out.println(this.Same_num);
    54. }
    55. public void testStaticFunc() {
    56. // 测试访问静态成员方法,这是不能重写的。
    57. static_func(); //
    58. super.static_func();
    59. Base.static_func();
    60. this.static_func();
    61. Derived.static_func();
    62. }
    63. }
    64. class Main {
    65. public static void main(String[] args) {
    66. Derived derived = new Derived();
    67. System.out.println(derived.Same_num); // 22
    68. derived.testNum(); // 22 11 22
    69. derived.testStaticFunc(); // d b b d d
    70. derived.Derived_func(); //
    71. Base base = new Derived();
    72. base.func(); // d
    73. base.static_func(); // 无法发生动态绑定
    74. }
    75. }

    运行结果:  是与main函数中的注释相同的。

     

     对于这样的语句:Derived derived = new Derived();

     搞清楚内存布局是很关键的。

     实在不想写太多的总结性话语了,其实Java的继承和C++的如出一辙,并无太大变化。上面代码中已经测试了大多数情况了。详细阅读代码即可,且成员命名也比较明确。

    总结:

    1.  子类的实例中, 也包含着父类的实例. 可以使用 super 关键字得到父类实例的引用.

    2.  Java 中一个子类只能继承一个父类 (而C++/Python等语言支持多继承).

    3. 对于父类的 private 的字段和方法, 子类的成员函数中是无法访问的.

    4. 关于继承中的构造函数:子类需要先帮助父类进行构造,再构造自己的成员。且子类的构造函数中默认会调用父类的默认构造函数,即默认有一个super(); 我印象中这是和C++一样的。但是如果子类没有默认构造函数,则需要程序员手动调用合适的基类构造函数,同样是super(....) 的方式。补:super: 父类对象的引用  [不能出现在静态方法当中]                                                  super(xxx);  //调用父类的构造方法
    super.funcO;
    super.data;

    5. 子类的重写函数的访问权限不能低于父类的被重写的函数的访问权限。当然private基类函数也不能被重写,因为父类中不可见。

    有关Java中私有成员到底是否会被继承的问题,

    可以看Base函数的main函数,调用结果为

     

    这里其实发生了动态绑定,并且运行成功了,也成功调用了private_func();函数。这算是比较深的探究了对于Java中的继承。

    java继承关系中,父类private修饰的内容真的不能被继承吗?NO!!_阿亮_1024的博客-CSDN博客_父类的private能不能被继承

    这是一篇针对此问题较为深刻探讨的博客。

    1. 这下果然不报错了,编译可以通过。但是程序的运行结果,却让我大吃一惊。程序运行不但没出错,还输出了:父类private的方法。什么??这是什么情况,为什么可以成功执行,子类中明明没有这个method方法的,为什么可以成功运行???(为了便于后面理解,我将这个问题命名为问题1) 

    2. 但是:运行的时候,是在父类中运行子类的private修饰的方法,那也应该不能成功运行才对,但实际上却成功运行了,这又是为什么?(为了便于后面理解,我将这个问题命名为问题2

    3. 证明了:“在继承关系中,子类从父类中继承下来的方法,它的权限修饰符是针对父类而言的!”,我们就能解释问题2了。被子类继承的private方法,也是只对本类(父类)可见的,所以当然就可以在父类的main方法中运行被子类继承下去的private方法了。
    问题2解决了,那问题1也就解决了,因为子类继承了父类中被private修饰的方法。所以,方法当然可以被正常调用。

    以上三点摘自上方链接处的文章。其实说的就是上方代码中Base类的main函数问题。

    final关键字

    final修饰类,表示此类不能被继承。与abstract相对立,不能同时存在。

    final修饰成员方法时,表示此方法不能被重写。

    二、组合

    和继承类似, 组合也是一种表达类之间关系的方式, 也是能够达到代码重用的效果.

    组合并没有涉及到特殊的语法(诸如 extends 这样的关键字), 仅仅是将一个类的实例作为另外一个类的字段. 这是我们设计类的一种常用方式之一.

    组合表示 has - a 语义 在刚才的例子中, 我们可以理解成一个学校中 "包含" 若干学生和教师.  

    继承表示 is - a 语义 在上面的 "动物和猫" 的例子中, 我们可以理解成一只猫也 "是" 一种动物.

    (1条消息) C++ 图书馆管理系统_配的上了吗的博客-CSDN博客

    这就是一种典型的组合思想的运用。

    三、多态


    多态具体一点就是要去完成某个行为,不同的对象去完成,会产生不同的状态。

    1、多态实现的条件


    (1)必须要在继承的体系下。

    (2)子类对父类中的方法进行重写。

    (3)通过父类引用去调用子类重写的方法。

    多态体现:在代码运行时,当传递不同类对象时,会调用对应类中的方法。

    2、向上转型和向下转型

    向上转型是实现多态的一部分条件,它在继承的体系下。多态中上指的是父类,下指的是子类。向上转型就是子类转型成父类。或者:父类引用,引用子类对象。只要记住父类引用,引用子类对象。这是从小的范围像大的范围转换。

    发生向上转型的三种情况:1. 直接赋值  2. 参数传递  3. 返回值传递  都是用基类引用引用派生类对象。

    向下转型是子类引用,引用父类对象。但是这意味着范围的缩小,所以它不安全。

    如何理解向上转型:家庭中父亲比儿子的地位高,为上者,以下犯上。所以子类对象用父类引用接收即向上转型,地位提高了。

    3. 重写

     实在不想偷了,上面两点是偷的。

    其实这里的重写和C++一样的,看这里的时候简直梦回C++Primer。

    重写的返回值要求相同,但是有一个例外:即方法的返回值是对应类对象的引用时,也可以发生重写。称为协变类型。

    父类的静态的,private的,final的都不能被重写。

    重载被称为编译时多态。而重写称为运行时多态。

    方法的重载是一个类的多态的体现,方法的重写是子类和父类多态的体现。

    ========================

    其实工作中继承用的可能并不多 因为维护的成本偏大。

  • 相关阅读:
    一个自己用的复制对象的工具类
    目标检测一 SSD代码复现
    uni-app、小程序项目对pages.json文件拆分、动态生成pages.json文件、动态生成分包配置pages.json文件的解决方案
    【C++】速通类和对象,看这一篇就够了
    存储数据保护技术——HyperClone克隆与HyperMirror卷镜像技术介绍
    安卓APP源码和报告——学生信息管理系统
    selenium之常用定位
    【附源码】计算机毕业设计JAVA助农脱贫系统
    (WebFlux)004、WebFilter踩坑记录
    js 内存泄露,几种常涉及到的内存泄露
  • 原文地址:https://blog.csdn.net/i777777777777777/article/details/125622610