【作者前言】:13年入圈,分享些本人工作中遇到的点点滴滴那些事儿,17年刚开始写博客,高手勿喷!以分享交流为主,欢迎各路豪杰点评改进!
[1]
🔥知识点内容
🔓1. 编程思想 [2]
把客观事物封装成抽象的类
,并且类可以把自己的数据和方法只让可信的类或者对象操作
,对不可信的进行信息隐藏
。在一个对象内部,某些代码或某些数据可以是私有的,不能被外界访问。通过这种方式,现实世界可以被描绘成一系列完全自治、封装的对象,这些对象通过一个受保护的接口访问其他对象eg:
设计一个类 银行卡:卡号、身份证号、钱数
image.png
image.png
通过案例观察,发现当前类的设计并不是很安全!!!
需要将属性进行私有化处理 --- 添加访问修饰符 --- private
属性通过私有化之后,没有办法直接进行访问了,如果我还是想修改属性,只能调用方法
image.png
image.png
🔓2.封装的好处 [3]
封装把过程和数据包围起来,对数据的访问只能通过已定义的接口。面向对象编程始于这个基本概念。即现实世界可以被描绘成一系列完全自治、封装的对象,这些对象通过一个受保护的接口访问其他对象。
封装是一种信息隐藏技术,在Java中
通过控制成员的访问权限实现封装,即 使用方法将类的数据隐藏起来,控制用户对类的修改和访问数据的程度。
适当的封装可以让代码更容易理解和维护,也加强了代码的安全性。``
🔓3.封装的过程 [4]
1、创建好类
2、将属性进行私有化处理private 数据类型 变量名
3、添加构造方法(多个构造方法)无参构造方法一定要添加
4、添加get set方法
get(获取):一般来说是为了获取数据
set(设置):用来修改数据
5、编写自定义方法
🔓4.快捷键说明(开发时使用) [5]
当类编写好属性之后,
shift+alt+s(相当于点击了工具中的 source)
image.png
image.png
image.png
🔓5. 继承(重用、扩展) [6]
继承是一种连接类的层次模型,并且允许和鼓励类的重用,它提供了一种明确表述共性的方法
一个新类可以从现有的类中派生
,这个过程称为类继承
,新类继承了原始类的特性
,新类
称为原始类的派生类
(子类
),而原始类
称为新类的基类
(父类
)
派生类可以从它的基类那里继承方法和实例变量,并且类可以修改或增加新的方法使之更适应特殊的需要
🔓6. 继承的意义 [7]
从现实生活中的继承,可以理解为儿子继承了父亲的财产,即财产重用;
面向对象程序设计中的继承,则是代码重用
;
继承是利用现有的类创建新类的过程,现有的类作为基类(父类),创建的新类称作派生类(子类)
复用代码是Java众多引人注目的功能之一。但要想称为极具革命性的语言,仅仅能够复制代码并对之加以改变是不够的,它还必须能够做更多的事情。尽可能的复用代码是程序员一直在追求的,继承
就是一种复用代码的方式,也是Java的三大特性之一
继承是Java面向对象编程技术的一块基石,因为它允许创建分等级层次的类
继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为
继承是使用已存在的类的定义作为基础建立新类的技术,新类的定义可以增加新的数据或新的功能
,也可以用父类的功能,通过使用继承我们能够非常方便地复用以前的代码,能够大大的提高开发效率
🔓7. Java派生类定义 [8]
在Java中,使用
extends
关键字描述类与类之间的继承关系
,其基本用法是:
【访问权限修饰符】【修饰符】子类名 extends 父类名 {
子类体
}
由于Java是单亲继承体系,因此在描述类与类的继承关系时,extends关键字后面只能是一个名字,而不能是一个列表(后续接口继承的情况,extends 后面可以是一个列表)
父类↓
image.png
派生类1↓
image.png
派生类2↓
image.png
测试使用↓
image.png
🔓8. Extends继承 [9]
继承定义了类如何相互关联,共享特性。对于若干个相同或者相识的类,我们可以抽象出他们共有的行为或者属相并将其定义成一个父类或者超类,然后用这些类继承该父类,他们不仅可以拥有父类的属性、方法还可以定义自己独有的属性或者方法。
子类拥有父类的的属性和方法
(private成员由于权限关系因此不能访问
)
子类可以拥有自己属性和方法
,即子类可以对父类进行扩展
子类可以用自己的方式实现父类的方法
(后续介绍)
综上所述,使用继承确实有许多的优点,除了将所有子类的共同属性放入父类,实现代码共享,避免重复外,还可以使得修改扩展继承而来的实现比较简单
。
🔓9. 构造方法与继承 [10]
通过前面我们知道子类可以继承父类的属性和方法
但是有一样是子类继承不了的
:构造方法
对于构造方法
而言,它只能够被调用
,而不能被继承
image.png
当构建子类对象时会优先隐式自动调用父类的无参构造方法
,而且这个构建调用过程是从父类“向外”递归
扩散的,也就是从父类开始向子类一级一级地完成构建,即如果C继承自B,而B继承自A,那么构建C的对象时,会先调用A的构造方法,然后调用B的构造方法,最后调用C的构造方法,以此类推
image.png
父类使用private
修饰构造方法,子类就会报错,子类无法构建父类
image.png
根据上述示例,对于继承而已,子类会默认调用父类的无参构造方法,也就是说子类必须能够访问父类的一个构造方法,并且一定会调用
🔓10. super [11]
image.png
java.lang.NullPointerException
:表示空指针异常,使用对象调用方法,但是对象是null
那么,如果父类不具备无参的构造方法怎么办呢?
Java 语言中,要求子类有责任保证它所继承的父类尽快进入到一个稳定、完整的状态中。如果没有这个约束,那么子类的某个继承自父类的方法可能会使用到父类中的一些变量,而这些变量并没有进行初始化,从而产生一些难以预料的后果
如果没有无参的父类构造方法
,子类
必须要显式的调用父类的构造方法
,而且必须是在子类构造器中做的第一件事
通过super
关键字可以在子类构造方法中
显式调用父类的构造方法
,该调用必须位于子类构造方法的第一行
super
调用其他的方法
super | this |
---|---|
表示父类引用 | 表示当前对象引用 |
super可以调用父类构造 | 调用当前对象构造方法 |
不能当成参数返回值使用 引用不能传递 | 当成参数或者返回值使用,可以传递 |
image.png
🔓11. 继承-小结【5-11】 [12]
- 类的继承由关键字
extends
确定,Java语言为单亲继承
,即一个子类只有一个父类,而一个父类可以有多个子类
- 子类可以重写父类中的某一个方法,称为方法覆盖,也称方法重写,是继承中非常重要的知识点。如果
子类需要修改从父类继承到的方法的方法体,就可以使用方法覆盖
image.png
image.png
image.png
当创建子类对象时会优先隐式自动调用父类的无参构造方法,而且这个构建调用过程是从父类"向外"递归扩散的,也就是从父类开始向子类一级一级地完成构建,即如果C继承自B,而B继承自A,那么构建C的对象时,会先调用A的构造方法,然后调用B的构造方法,最后调用C的构造方法,以此类推
如果没有无参的父类构造方法,子类必须要使用super显式的调用父类的构造方法,而且必须是在子类构造器中做的第一件事
this引用对象自身,调用自己的构造方法,而super调用父类定义的成员变量、方法或构造方法,super不能当做引用传递给其他的调用者,而this可以
🔓 12. 方法的重写 与 方法的重载 有何区别? [13]
方法的重写(Override) | 方法的重载(Overload) |
---|---|
在继承父类的子类中 | 在同一个类中 |
方法名称、参数列表一致 | 方法名称相同、参数列表不同 |
返回值也要一致 | 与返回值类型无关 |
-
方法重载
方法重载:同一个类中,方法名相同、参数列表不同(类型、个数、顺序)、返回类型可以相同或不同、访问权限可以相同或不同的方法 -
方法重写
继承的作用就是复用,即子类直接使用父类的属性和方法
然而,有些时候,子类希望修改父类的方法的方法体,可以怎么做呢?
第一种做法是子类创建一个不同名字的新方法,实现新的逻辑,然而,这种做法会导致子类依然包含父类中的那个方法,却不应该使用,破坏封装性
我们希望子类中的方法依然和父类方法的声明形式一样,但是具体方法体却不同,这种做法就叫做方法覆盖/方法重写 -
对比方法重写与重载
发生方法覆盖
的两个方法的方法名
、参数列表
必须完全一致
(子类重写父类的方法
) ,方法返回值如果是基本数据类型,则返回值应该保持一致
,如果返回值是类,则子类覆盖方法的返回值必须是父类方法返回值或其的子类(协变返回类型)
子类抛出的异常不能超过父类相应方法抛出的异常(子类异常不能大于父类异常
) (异常处理后面详细介绍)
子类方法的访问级别不能低于父类相应方法的访问级别(子类访问级别不能低于父类访问级别
)
13. 多态 [14]
Animal a; //定义了一个引用类型a
a = new Animal(); // 实例化一个Animal对象给引用a
引用类型 与 实例化类型 一致
指着老虎说 这是什么动物, 将老虎当成了动物
Animal a = new Tiger();
总结:
1、子类引用可以存放到父类引用中
2、把子类对象当成父类对象看待 (把老虎 当成 动物)
3、对象的数据类型不变
java.lang.ClassCastException
:
类型转换异常
变量名 instanceof 类名 :判断变量(引用) 是否是属于 后面类型 属于 true 不属于 false
image.png
4、子类引用存放到父类引用中,引用只能调用其引用类型声明的方法,并且调用的方法是子类覆盖父类的方法
image.png
image.png
image.png
14. 对象向上造型 [15]
简而言之:白马是马,马非白马的问题
在继承关系中,
继承者可以完全替换被继承者,反之则不可以
eg:
人类是人类,男人女人都是人类,一个人是男人,一定也是人,所以向上转型不需要强制,但是一个人是人,但不一定是男人,所以需要强制转换
从实例上来看:
Person p = new Man(); //是合理的
Man m = new Person();//则不合理
所谓的对象向上造型,就是父类的引用(栈中)指向子类的对象(堆中)
image.png
父类引用指向子类对象
子类引用不能指向父类对象
15. 编译期与运行期 [16]
在进行对象造型时,用来
声明引用的父类类型
我们称为编译期类型
,而实际用于构建对象的子类类型
我们称为运行期类型
image.png
那么这个时候直接使用bird对象调用成员变量和成员方法究竟应该调用编译器类型中声明的还是调用运行期类型中重写的呢?
引用变量在编译阶段只能调用其编译时类型所具有的方法,但运行时则执行它运行时类型所具有的方法
因此,编写Java代码时,引用只能调用编译器类型里包含的成员
例如,通过Object p =new Persion()代码定义一个变量p,则这个p只能调用Object类的方法,而不能调用Persion类里定义的方法
16. 对象向下造型 [17]
对象在满足条件的情况下也能进行向下造型,即显式的将父类引用指向的对象转换为子类类型向下造型的要求是:进行向下造型的对象的运行期类型必须是子类或以子类为根的继承树中的其他类型(Ostrich extends Bird)
image.png
17. 多态环境下对属性和方法的调用特点 [18]
Java代码中的数据和行为(变量和方法)在进行绑定(即通过对象调用成员变量或方法时究竟调用哪个版本,如覆盖后的方法)的时候划分为两种类型:
静态绑定
动态绑定
静态绑定发生在编译时期,动态绑定发生在运行时
类的成员变量
(属性
)都是静态绑定的
(编译时
),也就是说,类中声明的成员变量不能被子类中的同名属性覆盖
,通过该类的引用调用成员,始终调用该类自身中声明的属性(即始终调用编译期类型中的属性)
image.png
image.png
image.png
对于Java中的方法而言,除了final
(后续详细介绍
),static
(后续详细介绍
),private
和构造方法
是静态绑定外,其他的方法全部为动态绑定,这就意味着方法调用将动态使用运行期类型版本)
- 由上述特点可以看出:
重载方法中具体调用哪个版本是通过静态绑定在编译期就决定了的
重写覆盖的方法调用哪个版本是通过动态绑定在运行期决定的
18. 多态的应用 [19]
将多态作为方法参数、返回值进行应用
-
方法参数
案例:动物园管理员 喂食动物------(参数是一个父类 只要是子类 都可以传递进来
)
image.png
image.png
image.png
image.png
-
方法返回值
案例:动物管理员,有一个小女儿,想养一只小动物,养什么动物 根据你有多少钱---(返回值类型是父类类型 子类得任何对象都可以作为返回值进行返回
)
image.png
19. 多态的可变参数 [20]
image.png
20. 多态参数的使用 [21]
如果将方法的
形参参数声明为父类类型
,结合前面介绍的方法参数的功能(即调用方法代码前会隐式执行形参和实参之间的赋值操作),由于子类的对象赋值给父类的引用是合法的,那么在调用方法时,实参
就可以是以形参类型为根的继承树中的任意类型
此时形参对应的运行期类型和传进来的实参运行期类型保持一致
21. instanceof [22]
实参可能是形参的任意子孙类,某些时候需要在方法中明确究竟参数的运行期类型是什么,那么
instanceof
运算符提供了一种解决方法
运算符instanceof
用来判断对象是否属于某个类的实例
,具体语法如下:
对象 instanceof 类
该表达式为一个boolean表达式,如果对象的类型是后面提供的类或其子类
,则返回true
,反之返回false
22. 多态的总结 [23]
//多态在执行期间判断所引用对象的实际类型,根据其实际的类型调用其相应的方法
多态存在的三个必要条件
· 继承
· 重写覆盖
· 对象向上造型-父类引用指向子类对象
多态的好处:
· 可替换性(substitutability)
多态对已存在代码具有可替换性
· 可扩充性(extensibility)
多态对代码具有可扩充性。增加新的子类不影响已存在类的多态性、继承性,以及其他特性的运行和操作。实际上新加子类更容易获得多态功能
· 接口性(interface-ability)
多态是超类通过方法签名,向子类提供了一个共同接口,由子类来完善或者覆盖它而实现的
· 灵活性(flexibility)
它在应用中体现了灵活多样的操作,提高了使用效率
· 简化性(simplicity)
多态简化对应用软件的代码编写和修改过程,尤其在处理大量对象的运算和操作时,这个特点尤为突出和重要
🔥2.应用场景:
🔥3.实现目标:
🔥4.代码实现:
-
🔥【知识点回顾·简介】 ↓↓↓
↩ -
🔑[编程思想] ↩
-
🔑[封装的好处] ↩
-
🔑[封装的过程] ↩
-
🔑[快捷键说明] ↩
-
🔑[继承(重用、扩展)] ↩
-
🔑[继承的意义] ↩
-
🔑[Java派生类 定义] ↩
-
🔑[Extends继承] ↩
-
🔑[构造方法与继承] ↩
-
🔑[super] ↩
-
🔑[继承-小结] ↩
-
🔑[方法的重写 与 方法的重载 有何区别?] ↩
-
🔑[多态] ↩
-
🔑[多态-对象向上造型] ↩
-
🔑[编译期与运行期] ↩
-
🔑[对象向下造型] ↩
-
🔑[多态环境下对属性和方法的调用特点] ↩
-
🔑[多态的应用] ↩
-
🔑[多态的可变参数] ↩
-
🔑[多态参数的使用] ↩
-
🔑[instanceof] ↩
-
🔑[多态的总结] ↩