第六章 封装、继承、多态
封装
- 在类中定义属性的时候,一般需要把属性隐藏起来。
如果外界需要访问这个属性,那么就提供公共方法对其访问 - 访问属性:获取属性值,设置属性值。
- 对于私有属性的修改:直接赋值,或,通过构造器赋值。
- 私有的方法和属性不能在其他类中调用。
- 私有属性,只允许在当前类中访问,出了这个类的范围,就不能访问
- 私有方法,只允许在当前类中调用,出了这个类的范围,就不能调用
- 可维护性:当修改了方法内部的逻辑后,不会影响到方法的调用。
- 封装的优点:
\1. 提高代码的安全性,重要信息可以私有化,不对外暴露
\2. 提高代码的复用性,常用的代码或者功能封装到方法中,可以在其他地方反复调用
\3. 封装代码的实现细节,便于修改内部代码,提高可维护性
\4. 简化外部的调用,便于调用者使用 - 其实,我们在定义一个类的时候,就是在完成封装的过程。
方法重载
- 类中有多个方法,具有相同的方法名,但是方法的参数各不相同,这种情况被称为方法的重载
(overload) - println 并不是一个方法,而是有很多个 println 方法,这些方法分别可以处理不同的情况,因
为它们的参数列表是不一样的,就是重载。 - 方法的重载,必须是在同一个类中,并且要求如下:
\1. 方法的名字必须相同
\2. 方法的参数列表必须不同
参数的类型不同
参数的个数不同
参数的顺序不同
\3. 方法的修饰符、返回类型、抛出异常这些地方没有限制(可以相同,也可以不同,但一般都是相同的) - 注意:
- public void method(int num){} //编译异常,类中有重复方法
- public int method(int num){} // t.method() ,分不清调用哪个
- 重载方法的调用:
- 优先匹配类型相同的方法
- 没有匹配类型参数可以实现自动类型转换,【就近原则】
- 注意,当参数无法完全精确匹配到方法的时候,参数会尝试做自动转换,然后再去尝试匹配方法
- 重载方法中,参数类型也会发生类型提升的操作。
- 小类型 --> 大类型
- 就近原则
创建和初始化对象
- new Student(),该代码完成了俩个过程,对象的创建和初始化。
- new关键字,给对象申请/分配内存空间,并将对象中的属性进行默认值的初始化。
- 如果在代码中,还给这些属性进行了显示赋值,那么就会用这个显示赋的值,把之前的默认值给覆盖掉。
- 调用类中的构造器,在构造器中也可以对属性进行赋值,这个赋值会把之前默认值或者显示赋值给覆盖掉
- new, 开辟内存。
- 对象中属性赋值的方式和顺序:
- 通过new开辟内存,赋默认初始值
- 通过代码进行显式赋值 (所有对象的属性将会使用同一个值)
- 通过构造器对属性赋值 (推荐使用有参构造器)
- 通过指定set方法对属性进行赋值(推荐)
- 如果是private属性,那么就需要使用对应的setXxx方法进行属性值的的设置。(推荐)
构造器
- 构造器的作用:
- 使用new关键字来创建对象的时候,后面跟的必须是类中存在的构造器
- 构造器中的代码,在对象创建后会被调用,从而可以完成对象的初始化工作
- 定义了有参构造器,会覆盖掉当前类中的无参构造器。
- 通过显式定义无参构造器,防止被覆盖掉。
- 注意:当类中定义有参构造器时,为了防止无参构造器被覆盖掉,推荐显式的定义出无参构造器
- 构造器相互调用:
- 使用 this()
- 一般使用无参调用有参构造器
- 少参调用多参
- 默认构造器:
即使在类中没有定义构造器,那么在编译之后,也会自动的生成一个无参构造器,并且构造器中不执行任何代码。这个无参构造器就被称为默认的构造器。 - 注意:如果我们在类中定义了一个构造器,那么系统就不在为该类生成无参的默认构造器
了。
继承
-
类和类之间的关系有很多中,继承就是其中一种关系,除此之外还有依赖、组合、聚合等
-
继承描述的是事物之间的所属关系,这种关系是: is-a 的关系。
-
父类更通用,子类更具体。
-
子类可以直接访问父类中的非私有的属性和方法。( id ,method() )
父类中的私有属性和方法,子类中不能直接访问。
-
注意,父类中的构造器,子类是不能继承的。
-
继承的好处:
- 提高代码的复用性。
- 类与类之间产生了关系(is a),这是使用多态特性的前提。
-
子类可以直接访问到父类及其间接父类中非私有的属性和方法。(A --> B --> C --> Object)
-
任何类都有父类,错,object类没有父类。【Object类是一个根类】
- 任何类都是Object类的子类或间接子类。
-
注意:Object类中没有属性。
-
默认继承了Object,编译后会自动生成 extends Object 的代码语句
-
子类继承父类,创建子类对象的时候,会先默认调用父类的无参构造器
-
构造器执行顺序:先调用父类构造器,再调用子类构造器。
-
子类继承父类,会继承父类的属性和方法,那么就需要先调用父类的构造器对父类中的属性进行初始化,初始化完成后再给子类使用。
-
构造器的作用之一就是进行初始化
-
为什么创造子类对象时,需要先调用父类的构造器?
因为子类可以访问父类的属性,父类属性在使用前需要初始化,要通过父类构造器实现。
-
super关键字
-
在子类中,使用super关键字一般做以下事情:
- 访问父类中的属性
- 调用父类中的方法
- 调用父类中的构造器
-
没有显式写出super时,就近原则。
-
当子类和父类属性名相同时,通过super关键字区分。
-
子类构造器中隐式调用父类无参构造器。
-
子类构造器会默认调用父类中的无参构造器。
-
子类对象的创建,一定会调用父类无参构造器。
-
-
可以使用super关键字来指定调用的父类构造器。
-
super和this调用构造器时,要求必须定义在构造器的第一行。
( 导致super和this不能同时使用 )
- 这是因为this调用构造器的语句和super调用构造器的语句,都要求自己是第一句代码,但是构造器中的第一句代码只能有一个,所以它们俩个不能同时出现。
- 如果this和super不是都要调用构造器,那么同时出现就没有问题。
-
通过子类的构造器传值实现父类属性的赋值。
方法重写
- 如果子类和父类中出现了相同的方法,这种情况就叫做方法重写 (Override)。
- 注意,方法重载是发生在同一个类中,方法重写发生在子父类之间
- 方法的重写:
- 方法名必须相同
- **参数列表必须相同!! **
- 权限不能被缩小 ( public > protected > default > private)
- 异常范围不能被扩大
- 返回类型可以相同,也可以不同
- 如果父类的返回类型是引用类型,子类重写后的方法返回类型可以和父类方法的返回类型保持一致,也可以是父类方法返回类型的子类型
- 如果父类的返回类型是基本类型,那么子类重写后的返回类型必须和父类的保持一致
- 注意:大多数情况下,子类中重写的方法 会和 父类中的方法 完全保持一致,只有方法的实现不同。(也就是大括号中代码不一样)
- 父类中哪些方法不能被重写:
- 父类中的静态方法不能被子类重写 (可以通过编译,没有实现重写的效果)
- 父类中的私有方法不能被子类重写
- 子类继承父类,在调用方法的时候,如果子类中没用重写,那么调用的是从父类继承的方法,如果子类重写了这个方法,那么将会调用到子类中重写后的方法。
非常重要
- 子类继承父类,继承了父类中的方法,但是父类中的方法并不一定能满足子类中的功能需要,所以子类中需要把方法进行重写。
- String类继承了Object,并且重写了Object类中的toString、equals等方法,所以,在调用String对象的toString、equals等方法时候,其实调用的是子类String中重写后的方法!
多态
-
相同类型的不同对象,调用同一个方法,最终执行结果是不同的
-
多态:父类的引用可以指向任意的子类对象。
-
注意,一个父类型的引用,可以指向它的任何一个子类对象
-
多态的前提:
重要
- 子类继承父类
- 子类重写父类中的方法
- 父类的引用指向子类对象
-
成员变量,静态方法看左边;(静态方法不重写,编译和运行都看左边。)
非静态方法:编译看左边,运行看右边。
-
父类中的静态方法不能被重写。
-
父类类型引用无法调用子类中独有的方法。(可以通过强制转换)
-
多态:编译看左边,运行看右边。
- 当父类的引用指向子类的对象时,
- 编译时,引用调用的方法为当前类中定义的方法及父类的方法。无法调用子类中特有的方法。
- 运行时,输出结果由等号右边指向的子类对象决定,如果没有重写父类方法,则输出父类方法的内容。如果重写了父类的方法,则输出重写后的方法内容。
- 他的非静态方法,在编译时是与父类一致的,运行时却与子类一致(发生了复写)。
- 编译时候,看左边的对象有没有该方法,左边的没有该方法则不能进行调用。运行时候结果看new的对象时谁,就调用谁的方法。
-
可以看出,这时候想新增一个球类游戏,并且去运行它,几乎不需要修改什么代码,只需要新增这个类即可。(用父类ball的引用指向子类球类。)
-
定义方法的参数设为父类类型,接收传过来的参数,任意子类参数。
-
重写toString()方法:将一个对象转换为字符串的表现形式。
instanceof
- instanceof,判断当前父类的引用,到底是指向的哪一个子类对象。
- 进行强制类型转换:可能导致ClassCastException,通过加入instanceof判断两者是否有关系
- 【卫语句】,单独的if语句
引用类型的转换
- 多态中的转型分为向上转型与向下转型两种:
- 向上转型(子类转父类)
多态本身就是将子类的对象赋值给父类的引用,这就是一个自动向上转型的过程(类型自动转换) - 向下转型(父类转子类)
父类类型向子类类型转换,是向下转换的过程。(类型强制转换)
- 向上转型(子类转父类)
- 在使用多态的情况下,父类引用是无法调用到子类中独有的方法的。
快捷键
- shift + tab :整体向前移动
- tab : 整体向后移动