zoukankan      html  css  js  c++  java
  • 11-面向对象4

    1. 类与类之间的关系

    1.1 依赖

    对象之间最弱的一种关联方式,是临时性的关联。代码中一般指由局部变量、函数参数、返回值建立的对于其他对象的调用关系。

    1.2 关联

    对象之间一种引用关系,比如客户类与订单类之间的关系。这种关系通常使用类的属性表达,关联可以有方向,即导航。

    一般不作说明的时候,导航是双向的,不需要在线上标出箭头

    关联表示类之间的“持久”关系,这种关系一般表示一种重要的业务之间的关系,需要保存的,或者说需要“持久化”的,保存到数据库中。另外,依赖表示类之间的是 一种“临时、短暂”关系,这种关系是不需要保存的。

    1.3 聚合

    聚合(关联关系的一种):表示“has-a”的关系。与关联关系一样,聚合关系也是通过实例变量来实现这样关系的。“关联关系”和“聚合关系”来语法上是没办法区分的,从语义上才能更好的区分两者的区别。

    如汽车类与引挚类,轮胎类之间的关系就是整体与个体的关系。与“关联关系”一样,“聚合关系”也是通过「实例变量」来实现的。

    关联和聚集(聚合)的区别:

    • “关联关系”所涉及的两个对象是处在同一个层次上的。比如人和自行车就是一种“关联关系”,而不是“聚合关系”,因为人不是由自行车组成的。
    • “聚合关系”涉及的两个对象处于不平等的层次上,一个代表“整体”,一个代表“部分”。比如电脑和它的显示器、键盘、主板以及内存就是“聚集关系”,因为主板是电脑的组成部分。

    1.4 组合

    对象 A 包含对象 B,对象 B 离开对象 A 没有实际意义,是一种更强的关联关系。比如,人的结构包含手, 手离开人的躯体就失去了它应有的作用。

    表示 contains-a 的关系,是一种强烈的包含关系。组合类负责被组合类的生命周期。组合也使用 [属性] 表达组合关系,是“关联关系”的一种,是比“聚合关系”强的关系。

    1.5 继承

    Generalization,又称为泛化,is-a 的关系。如:类与类的继承关系,类与接口的实现关系。

    场景:父与子、动物与人、植物与树

    2. 继承

    2.1 继承概述

    • 为什么要有继承?
      • 多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中, 那么多个类无需再定义这些属性和行为,只要继承那个类即可
      • 举例(可以理解为:"子类 is a 父类")
      • 子类继承了父类,就继承了父类的方法和属性;在子类中,可以使用父类中定义的方法和属性,也可以创建新的属性和方法
    • 类继承语法规则:class Subclass extends SuperClass {...}
      • Subclass:子类、派生类
      • Superclass:父类、基类、超类
    • 作用
      • 减少了代码冗余,提高了代码的复用性
      • 更有利于功能的扩展
      • 继承的出现让类与类之间产生了关系,提供了多态的前提
    • 注意
      • 不要仅为了获取其他类中某个功能而去继承
      • Java 中的继承反应的是我们现实世界中的继承关系吗?
        • 不是!Java 中的继承,反应的是“一般到特殊的关系”
        • 在 Java 中,继承的关键字用的是“extends”,即子类不是父类的子集,而是对父类的"扩展"。

    2.2 继承的规则

    1. 子类不能直接访问父类中私有的(private) 的成员变量和方法

    • 【继承性】父类的私有成员在“物理上”已经被继承过来了
    • 【封装性】只不过逻辑和语法上设置的不允许被访问

    2. Java 只支持类的单继承和多层继承,不允许多重继承。

    • 单继承就是一个类只能有一个父类;多继承就是一个类可以有多个父类
    • 一个父类可以派生出多个子类
    • 子类直接继承的父类,称为“直接父类”;由于多层继承而拥有的父类,称为“间接父类”。子类继承父类之后,就获取了“直接父类”以及“所有间接父类”中声明的属性和方法。

    2.3 Object 类基本特性

    当创建一个类时,总是在继承;Object 类是所有 Java 类的根基类,也就意味着所有的 Java 对象都拥有 Object 类的属性和方法。因此,除非已明确指出要从其它类中继承,否则就是在隐式地从 Java 的标准根类 java.lang.Object 进行继承。

    4. 方法重写/覆盖

    4.1 定义

    在子类中可以根据需要对从父类中继承来的 (!static) 方法进行改造,也称为方法的重置、覆盖。在程序执行时,子类的方法将覆盖父类的方法。

    • 属性没有“覆盖”这一说
    • 父类中「私有方法」不能被重写,就算方法声明相同,那这俩也互不相干
    • 方法重写是实现“多态”的必要条件

    4.2 要求

    • 子类重写的方法必须和父类被重写的方法具有相同的方法名称、参数列表
    • 子类重写的方法使用的访问权限 ≥ 父类被重写的方法的访问权限(子类不能重写父类中声明为private权限的方法)
    • 子类重写的方法的返回值类型 ≤ 父类被重写的方法的返回值类型(被重写方法若是void/基本类型,重写方法必须是void/基本类型)
    • 子类重写的方法抛出的异常 ≤ 父类被重写方法的异常

    4.3 补充

    1. 子类在继承父类时,对于方法而言,存在 2 种关系

    • override(覆盖):这是对实例方法(instance method) 而言的;子类与父类中形构相同的方法会 override 父类中的那个方法。
    • hide(隐藏):这是对类方法(class method) 即 static 方法而言的;如果子类中定义了静态方法,则它会隐藏父类中形构相同的所有方法。

    2. static、private 修饰的父类方法不能覆盖

    “覆盖”只有在某方法是基类的接口的一部分时才会出现。即,必须能将一个对象向上转型为它的基类型并调用相同的方法。如果某方法为 private,他就不是基类的接口的一部分,它仅是一些隐藏于类中的程序代码,只不过是具有相同的名称而已。但如果在导出类中以相同的名称生成一个 public、protected 或包访问权限方法的话,此时你并没有覆盖该方法,仅是生成了一个新的方法。由于 private 方法无法触及而且能有效隐藏,所以除了把它看作是因为它所归属的类的组织结构的原因而存在外,其他任何事物都不需要考虑到它。

    根据上面的规定,“覆盖”的前提是「实例方法」,只有「实例方法」在继承时才会出现 override 情况。 如果是 static 方法,在继承时出现的现象根本就不能用 override 这个词描述,如果 static 方法在父类和子类中形构一致,则被隐藏。那什么是隐藏呢?

    隐藏 :child 隐藏了 parent 的变量和方法,那么,child 实例就不能访问 parent 中被隐藏的变量或者方法,但是,将 child 实例向上提升转换成 parent,可以访问 parent 中被隐藏的变量或者方法了。我的理解是被隐藏的东西就是只和类绑定的东西。当子类继承父类,在子类对象中是访问不到父类中的被隐藏的东西的。因为这些东西只和父类绑定了。

    5. 测试4种权限修饰符

    • 同包下的不同类
      • protected 也提供包访问权限,也就是说,相同包内的其他类可以访问 protected 元素
      • 同一个包中的其他类,不可以访问 Order 类中的 private 成员
      • 不同包下的其他类,只能访问 Order 类中的 public 成员
    • 不同包下的子类
      • 在不同包的子类中,不能调用 private 和缺省的成员
      • 此时唯一可以访问的成员就是源包的 public 成员。但有时,基类的创建者会希望有某个特定成员,把对它的访问权限赋予派生类而不是所有类。这就需要 protected 来完成这一工作

    6. super 关键字

    6.1 super 概述

    有些人认为 super 和 this 引用是类似的概念,实际上,这样类比并不太恰当。这是因为 super 并不是一个对象的引用,不能将 super 赋给另一个对象变量,它只是一个指示编译器调用超类属性和方法的特殊关键字。super 代表的是 父类存储空间的标识

    使用 super 来调用父类中的指定操作:① 访问父类中定义的成员;② 在子类构造器中调用父类的构造器

    • super 不能出现在静态方法中(static 是没有 this 的方法,既然没有 this,也就不会有 super)
    • 尤其当子父类出现同名成员时,可以用 super 表明调用的是父类中的成员
    • super 的追溯不仅限于直接父类,还有间接父类

    6.2 调用父类构造器细节

    • 子类中所有的构造器默认都会访问父类中空参的构造器 // 子类初始化之前,一定要先完成父类结构的初始化
    • 子类的构造器中,通过 "this(参数列表)" 或者 "super(参数列表)" 指定调用本类或者父类中相应的构造器。同时,只能 "二选一",且必须放在构造器的首行
      • 如果子类构造器这两种都想用,可以先调用 "this(参数列表)",再在子类带参构造器中调用 "super(参数列表)"
      • 在一个类中的多个构造器,至少有一个构造器是使用了 "super(参数列表)" 的
    • 如果子类构造器中既未显式调用父类或本类的构造器,且父类中又没有无参的构造器,则编译出错

    创建子类对象时并没有同时创建一个父类对象?可构造器首行为什么要隐式调用 super()?而且子类继承过来的父类属性,又都是存放在哪的?

    7. 子类对象实例化过程

    • 从结果上来看(继承性)
      • 子类继承父类之后,就获取了父类中声明的属性或方法
      • 创建子类对象,在堆空间中,就会加载所有父类中声明的属性
    • 从过程上来看
      • 当我们通过子类构造器创建子类对象时,一定会直接或间接地调用父类构造器,而父类构造器又会直接或间接地调用它父类的构造器 ... 直到调用 java.lang.Object 的构造器为止 // 继承的层次结构
      • 分层初始化(必须先初始化父类,再初始化子类)
    • 摘自《Java编程思想》
  • 相关阅读:
    使用mongodb保存爬取豆瓣电影的数据
    使用scrapy爬取阳光热线问政平台
    使用scrapy爬取手机版斗鱼主播的房间图片及昵称
    使用selenium + chrome爬取中国大学Mooc网的计算机学科的所有课程链接
    使用scrapy爬取腾讯社招,获取所有分页的职位名称及chaolia、类型、人数、工作地点、发布日期超链接
    python2使用bs4爬取腾讯社招
    使用python2爬取百度贴吧指定关键字和分页帖子楼主所发的图片
    提问的智慧
    深刻理解系统架构师和系统分析师定义
    Redis基础数据结构与核心原理
  • 原文地址:https://www.cnblogs.com/liujiaqi1101/p/12997055.html
Copyright © 2011-2022 走看看