面向对象编程:封装、继承、多态学习

系列文章目录

JavaSE
基础知识、数据类型学习万年历项目代码逻辑训练习题
代码逻辑训练习题方法、数组学习图书管理系统项目
面向对象编程:封装、继承、多态学习封装继承多态习题常用类、包装类、异常处理机制学习
集合学习IO流、多线程学习仓库管理系统JavaSE项目
员工管理系统、多表查询、反射实现DBHelper学习DML、DDL、数据库对象学习
JavaWeb
网络编程、各种标签、CSS学习ECMAScript、BOM学习DOM、jQuery学习
Servlet、JSP、Cookie、Ajax学习融资管理系统JavaWeb项目
框架
MyBatis框架学习逆向工程、Spring框架IOC、AOP学习SpringMVC框架学习
SpringBoot框架学习招聘网站框架项目Vue介绍、窗体内操作、窗体间操作学习
Vue路由配置、网络请求访问框架项目、element组件介绍学习标准管理系统Vue项目
微服务
Linux安装、Nginx反向代理、负载均衡学习Docker学习Jenkins学习
Nexus学习Spring Security学习RabbitMQ学习
Redis学习MongoDB学习MongoDB学习
Nacos学习Spring Session学习Spring Gateway学习
JSR 303学习OpenFeign学习Hystrix学习


前言

本文主要讲述Java面向对象编程的封装-继承-多态,以及其相关知识及关键字。在下攸攸太上,其实在下乃非地球人,是宇宙ൠ♄§星派来的先遣官。


一、面向对象编程

1.面向对象总介绍

面向对象:英文名为Object Oriented。
直到之前,我们编程形式还是采用面向过程编程的思维:要实现一个功能,我们辛辛苦苦从零开始自己编写
现在,我们要尽量改掉我们之前的编码思维,改成面向过程编程的思维:要实现一个功能,我们先想有没有类能组合起来实现这个功能
改用人来举个例子:以前我们要搬砖,我们要自己一块一块亲手搬;
现在应该考虑:我能不能找人来搬这些砖,找那些人能来替我搬砖
可以发现以前我们是打工人 ,现在我们翻身当老板 啦!
(面向过程考虑怎么做
面向对象考虑找谁来做)
哼,想起来就好笑,以后工作管着我的人以为自己是老板,他却没想到,我是我自己代码的老板,精神胜利赛高!!!

2.具体如何叫面向对象?

虽然说我们翻身当老板,但现在还不知道老板该怎么当不是,接下来我将教你当老板的思路:
1、分析当前项目中涉及到的都有谁(不仅限人类,还有可乐,绵羊,这个项目涉及到的一切)
2、分析涉及到的人应该具备的行为或者能力。(方法)
3、分析涉及到的人应该提供的属性。(属性)
有同学可能会问:方法我知道,类要实现的功能,这个属性是啥啊?是类似怪物的数值叫属性吗?
诶,你还真别说,真是这样的,属性就类似于你定义的变量,能给他赋值,能对他进行应用。
为什么是类似而不是相同呢?
一会儿会讲啦!

3.面向对象实现步骤

使用面向对象方式解决问题的步骤:
A、面向对象分析:OOA(Analysis)
B、面向对象设计:OOD(Design)
C、面向对象编程:OOP(Programming)

4.面向对象编码的编码,解决问题的步骤

以下为创建类
A、将参与者向上提取,抽象化,成为一个类。例如:学生类,人类,哺乳动物类(定义类)
B、确定参与者应该具备的行为(定义方法)
C、确定参与者应该具备的信息(定义属性)
以下为根据类创建对象
D、让参与者完成该做的行为(调用方法)(对象.方法())

对象.属性=(赋值)
OOP的最终目的:使用“对象.方法()”来解决问题,而不是我们自己写一个方法来解决问题。当然大部分时候还是要自己创建类—>创建对象—>对象.方法()来解决问题。

二、多文件编写程序

之前我们都是在一个类(文件)里实现所有功能的,但是从本章开始,我们要使用多个文件来实现一个功能,所以,会涉及类之间互相调用资源的情况。
举例:
之前是一个人蛮干,所有活都自己揽下来;现在要一个团队分工,共同完成一个目标,这是组员的沟通交流,过程中另一个组员需要的文件也需要在组内互相传递。
此时包的作用就体现出来了,可以分开不同的项目

1.局部变量和属性的区别

声明在方法里的叫局部变量
声明在类里方法外的属性(成员变量)
区别:
位置不同: 局部变量在方法里;属性在方法外

初始值不同: 局部变量没有默认值;属性有默认值(String-null,int-0,double-0.0)(数组初始化给默认值,是赋给他默认值,所以没问题)

作用域不同: 局部变量从声明开始,到包裹的大括号结束;属性在本类下(拿名直接用)和其他类(对象名.成员对象名)都可以使用

位置不同: 局部变量:栈内存(栈里不稳定,随时清空);属性:堆内存

生命周期: 局部变量从声明变量开始,到当前方法执行完;属性从所依附的对象的创建开始,到对象被销毁或程序执行结束
同名的局部变量和属性,在同一个作用域内,局部变量的优先级更高
当前对象能.属性的都是属性:解释this.属性(this.age = age)

2.构造方法

构造方法:!!没有返回值!!
什么是构造方法?
用来创建对象[实例化:把类创建成对象(实例)]和为对象的属性赋初始值[初始化:为对象的属性赋的第一个值]
总结:作用是初始化,实例化

构造方法的使用:
如果程序员没有构造一个构造方法,java程序会给你提供一个无参,方法体为空的构造方法

构造方法的特点:
构造方法名与类名相同,没有返回值
如果用户创建了构造方法,系统不会再提供构造方法
可以重载

不能用对象名.构造方法,不能类名.构造方法,只能new来调用

3. 内存的组成

栈(局部变量)

堆(new出来的对象)

常量池(常量,静态static资源)相同的信息不会创建第二个

方法区(方法)

4. this关键字

代表当前自身对象。

通过this来[区分]同名的局部变量和属性
this.属性
this.方法
this.构造方法(不能有参无参两边一起this构造方法,会构成无限循环)

this是一个指针吗?
this算是一个指针,是用与存地址的,但java里不叫他指针

是每创建一个新的对象时在存this的地方把新对象的地址赋给this指针吗?
建造新对象时,对象内自动产生一个this参数,每个对象一个this,不是全局只有一个

this是存在方法区在它属于的方法里吗?
不是在方法区里,是跟对象走的,对象创建时包含一个this指针指向自己,在对象里

5. static关键字

特点:
1、当前类下的所有static(静态)资源,都会提前(类声明时,main方法未执行时)加载到内存的常量池里
2、静态的是脱离对象的,是当前类下所有对象共用的可以通过对象名.静态方法调用,或类名.静态方法调用
非静态只能通过对象名.静态方法调用
2.5、静态资源归类所有,所有在使用的时候,可以通过类名.静态资源来使用
3、静态资源只加载一次

6. 包

1、分门别类进行功能代码的存储java.util(工具类)java.lang(这个工具类不需要导入这个包,因为自动导了包)
2、区分同名类
3、阿里规约‘项目中不存在不在包里的类’

使用包步骤:
1、创建包 new package

2、命名包名 包名由小写字母组成,无大写,
包的包含关系使用.来代替
一般来说,包名时项目部署后,访问域名的倒写

3、导包 import 包名.类名;(全局限定名)
import 包名.;将包下的所有类都导进来
import static 包名.类名.
;(只有静态的能使用,静态导入,待会儿使用方法时可以不用类名.(如果有同名方法,可能出错))

4、导包的时候包之间没有包含关系,在Show Option Menu 下选择ShowMember

7. 代码块

定义:一个大括号内的所有代码

大括号的作用:划分作用域

代码块的分类:
普通代码块
位置:方法内的代码块

构造代码块
位置:构造函数内,创建对象时会用到的

静态代码块
位置:static{
只执行一次,第一次加载这个类时执行
}

同步代码块
位置:方法内

执行顺序:静态->构造->普通

8. final关键字

1、修饰变量
基本数据类型变量:int、char等。数值不可以发生变化
引用数据类型变量:Scanner、String等。变量的值可以继续变;但内存地址最终;因为引用数据类型存堆里,栈里存它的地址,被传值时,是传走地址
总结:final只管栈区不能变,不管其他区

2、修饰方法
方法体是最终的,所以子类继承后不可以对final方法进行重写

3、修饰类
该类不能有子类,不可以被继承

4、思考
final修饰的父类方法可以重载嘛?
可以重载,在重载的两个方法,一个无参的被final修饰了,有参的没被final修饰;
在子类中:能重写父类的有参方法嘛?
能重写有参方法

9. 类和类之间的关系

继承关系:父类与子类,extends
实现关系:接口与实现类,implements
依赖关系:一个类作为另一个类方法的参数
关联关系:一个类是另一个类的属性
聚集关系:关联关系包含聚集关系:聚集关系是可分离的关联关系
组合关系:关联关系包含组合关系:一个类是另一个类的组成部分

三、面向对象三部曲

封装继承多态,先详细解释下各个词语的意义

1. 封装:

封装的目的是安全
通过公有的方法,间接访问/操作私有的属性,就叫封装

2.继承:

继承的目的是重用

2.1继承的前提条件

1、当前项目中有多个参与者
2、多个参与者属于一类(具有相同属性和共同行为的一组对象。这样的类之间可以通过继承实现代码的重用)
…继承: 人类 黑猩猩 红毛猩猩
…不继承: 鸟 飞机 超人(有相同的属性和行为,但无法归类到同一个大类中)

实现步骤:
1、找到不同类中相同的属性和行为,提取出来,放到单独的类里,这个单独的类,叫父类
2、各个类中特有的属性和行为,分别存放在各自的类里,这些各自的类,称为子类
3、借助关键字extends,子类可以继承父类,实现继承(子类对象.父类资源)

继承的特性: 单根性 传递性
…单根性:只能有一个父类
…传递性:A继承B,B继承C,A能使用C的

隐式继承: 类名(无extends)(继承Object类:根基类)(所有没写extends的都是继承object)
显式继承: 类名 extends 父类

子类不可以继承父类的哪些资源:
构造方法(但是子类可以调用)

子类可以使用继承父类的那些资源:

权限从大到小 本类下         同包子类           不同包子类
public      ✔             ✔                    ✔
protected   ✔             ✔                    ✔
默认的      ✔              ✔                   ❌
private     ✔             ❌                  ❌

思考:父类的private型属性子类为什么能应用呢?是在调用父类构造方法同时这些private属性也构造了嘛?
当一个子类被实例化的时候,默认会先调用父类的构造方法对父类进行初始化,即在内存中创建一个父类对象,
然后再父类对象的外部放上子类独有的属性,两者合起来成为一个子类的对象。
子类继承了父类的所有属性和方法或子类拥有父类的所有属性和方法是对的,只不过父类的私有属性和方法,子类是无法直接访到的。
即只是拥有,但是无法使用,但可以叫他爸用。

2.2方法的重写

子类需要对继承过来的方法,做一些方法体的改变。父类方法不适合解决子类的问题,子类需要对该方法做修改,修改的行为叫做方法的重写

重写的定义:
子类中,方法名相同,参数列表相同,返回值相同或缩小;(void也不行)
访问修饰符相同或扩大的方法叫重写

2.3 super关键字

父类也叫超类,基类;子类也叫派生类
super代指父类对象;(为什么是父类对象,而不是父类)
在构造子类对象时,如果程序发现这个子类有父类,他会去调用父类的构造方法,一路调用到Object的构造方法,
相当于,构造子类对象不仅构造他自己,也构造他的父类,他的祖先
所以有他的父类对象

this代指自身对象:
与super相同都是为了区分同名资源,(反过来说,只要没有同名,不用也行)
super可以修饰属性,可以修饰方法,可以修饰构造方法

思考:super是直接去父类找,父类没找到会回来找本类还是找父类的父类?
如果在父类中找到了对应的成员,则直接使用该成员。
如果在父类中没有找到对应的成员,它不会回来找本类,而是继续向上查找父类的父类,直到找到该成员或者到达继承结构的最顶层。
这个过程被称为继承链的向上搜索。它会沿着继承层次结构从子类到父类依次查找成员。
如果在整个继承链中都找不到对应的成员,那么编译器会报错,指示无法找到该成员。
总结起来,super关键字会从当前类开始向上查找父类的成员,直到找到该成员或者到达继承结构的最顶层。如果找不到,则会报错。

思考:构造方法不用改成set?
因为构造方法比较特殊,他就是初始赋值的方法,所以一般不用set,但用也可以

继承条件下,子类构造方法的执行顺序:
1、Teacher t1 = new Teacher();
teacher父类为human,程序流程在这段代码的执行流程为:
先执行父类构造,再执行子类构造
如果程序员没有手动调用父类构造方法的话,那么程序自动帮忙调用父类的无参构造方法
(如果父类没有无参构造方法,程序自动调用谁)
调用不了,因为没有无参构造,所以子类必须手动调用父类的有参构造
(为什么不往上走到object)
如果父类还有父类,找到顶级父类,再一层层往下执行,object也执行了,但我们看不到
2、在子类的构造方法里,第一行必须是调用父类构造方法
可以手动调用有参或无参,也可以程序帮忙调用无参

2.4抽象类

设置父类为抽象类:abstract
关键字限制他使用构造器
原因:该类创建出来的对象,在程序中,没有存在的必要

子类还是会去进行构造抽象父类的构造方法
尽量所有自定义的父类都设为抽象 (提示:Object 不抽象)

一个类如果有抽象方法,那么该类必须是抽象类,
但是一个类是抽象类,可以没有抽象方法

抽象方法: 可以有参数不能有方法体

原因: 父类需要强迫子类重写该方法,父类只需要把该方法设置为抽象方法即可

最基础格式 abstract 返回值类型 方法名();【不能有方法体】

2.5接口

接口的作用:
解决了java的单继承问题,因为接口可以多实现,(接口约等于抽象父类)

java是单继承的,相当于只能有一个父类(父亲),有时父类的方法是不够用的,所以我们可以用接口(师傅),师傅的东西不能继承,只能实现
没有任何需要重写方法的接口称为标记接口

如何使用接口:
1、定义一个接口interface
2、使用这个接口implements

接口与抽象父类的异同
同:都不能实例化对象(接口没有构造方法)
异:
接口没有构造方法抽象父类有但不能用,关键字不同,接口没有变量(只有静态常量,程序会默认给所有变量判定为静态常量)
接口中大部分都是抽象方法。(接口用于定规则)(程序会自动抽象所有方法)

接口用到的关键字是implements
如果有父类有接口:继承父类在前、实现接口在后
接口中除了抽象方法外,还可以写static,default修饰的,带有方法体的非抽象方法
接口能多实现,父类只能单继承
抽象的所有子类都有的放在父类里,不是所有其他子类也需要的就放在接口里
接口中的方法,尽量保持单一性,为了防止"接口污染

接口的方法最好写个简单的方法体,要不然实现类必须重写

2.6内部类

为了解决java的单继承问题
1成员内部类:在类里的类
2静态内部类:在类里的类,修饰符为静态static
3局部内部类:在类里的方法里的类
4匿名内部类:

2.6单例模式

目前有32个经典设计模式,有单例模式,工厂模式,代理模式
模式就是解决方案。
单例模式解决的问题是:当前这一类,有且只能有一个私有静态对象
单例模式构造方法是私有的,私有静态对象是在自己类下创建的
有一个共有的方法是其他类对这个对象的访问
饿汉式单例模式:
线程安全,浪费资源
懒汉式单例模式:
线程不安全,节省资源
静态内部类单例模式:几乎不用

3. 多态

多态的作用是扩展
同一个父类下,不同的子类使用同一个方法,有不同的表现形式

继承父类/接口->重写->声明父类 = new 子类;(向上类型转换)
声明父类 = new 子类的例子:Animal animal = new Dog();
声明 接口 = new 实现类();

多态的作用: 极大地提高了代码的扩展性

多态的两种表现形式 (都一定会涉及到自动类型转换,都出现在第二条业务线里)
1、父类/接口做参数—>代码的扩展性能达到极致
2、父类/接口做返回值—>提高了扩展性,但还没有达到最好
需要创建多种不同的子类对象(if里)

补充:
多态的效果:在编码期,以父类作参数(这样该方法适合所有的子类对象,扩展性达到最好)
在方法运行期,会根据实际传入的子类对象,动态调用对应的重写方法(只能重写)
重载是静态绑定,静态多态

多态的使用场合:
两条业务线,其中一条是继承的业务线,
另一条业务线一定有一个方法是继承线的父类在里面作参数或做返回值
方法体中,传入的实际参数调用重写的方法
多态环境下,涉及两种类型转换

4. 基本数据类型转换

java中数据类型分类基本数据类型、引用数据类型
基本:
1、整数(byte1、short2、int4、long8)、浮点(float4 double8)、字符char2、布尔boolean1位
2、java中boolean类型不参与类型转换
3、byte、short、char三者之间不进行类型转换,三者都是最小类型。
4、从小到大排列如下:(byte、short、char)、int、long、float、double
5、小类型转大类型是自动类型转换
6、大类型转小类型需要进行强制类型转换:小类型 变量名 = (小类型) 大类型变量;

5. 引用数据类型类型转换

引用:
1、不是所有的引用数据类型都有必要做数据类型转换
2、引用数据类型只有两种:

向上类型转换: 一般只发生在多态(声明父类 = new 子类)

弊端: 不能调用自己特有的方法,只能调用继承的和重写的

向下类型转换: 可以解决向上转型的弊端:(小类型) 大类型变量,就可以调用子类特有的方法

隐患: 可能存在类型转换错误的问题,程序会报错,必须用instanceof来判断

例子:

f (animal instanceof Doggy){
           Doggy dog = (Doggy)animal;
           dog.toothmove();
       }

instanceof关键字
使用方法: 对象 instanceof 类型
这个对象是这个类型或这个类型的子类。可以向上判断,不能向下判断。
例如我是大连人,他问我是衡水区的吗?不是,我是甘井子区的吗?是,我是大连人吗?是。我是地球人吗?是。
以此推出对象 instanceof Object的话,返回值一定是true。
父类对象 instanceof 子类 返回false
子类对象 instanceof 父类/本类 返回true
对象 instanceof 不相关的类 编译时出错

有一种特殊的情况:
我们假设一种情况,猪类、狗类、鸟类继承父类动物类,我们使用饲养员类的参数是动物类 的方式实现多态,这时候我们在饲养员类如此判断

System.out.println(animal instanceof Doggy);

会发现如果实际传入的是狗类,返回值为true,如果实际传入的是猪类或鸟类,返回值为false。

这时问题如下:
猪类跟狗类没有直接联系,唯一的关系是共同父类,这时程序返回不应该为报错吗?为什么是返回false呢?

原因:
程序认为animal对象有可能是Doggy类,所以不会在编译时报错,程序在运行时才反应过来,这家伙不是Doggy类,但为时已晚,只能默默说出false。

比喻:
正常来说,炸弹(硫磺、硝石加木炭)是不允许带上飞机的,这是有个乘客,带了硫磺、硝石,警报人员认为这两种材料没法构成炸弹,就让他上飞机了,等飞机起飞了才发现“我靠,这厮可以用飞机燃油代替木炭”,这时候反应过来已经晚了,只能报告了。

工厂设计模式:
不仅可以使用父类做方法的形参,还可以使用父类做方法的返回值类型,真实返回的对象可以是该类的任意一个子类对象。

标准的实体类:(以后所有类都要这么建)
1、所有属性私有化
2、提供get/set方法【身份证只能get,不能set】
3、构造方法:无参和全参构造都要有
4、成员方法

(参与者类也叫实体类)


总结

本文主要讲述了面向对象编程的步骤以及概念,封装、继承、重写的意义及作用,面向对象编程的前置知识,以及以后会常用的关键字。这些重要的知识请牢记于心,若本文能帮到客官一点小忙,在下喜色于心。欢迎各位客官在评论区发表高见!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

攸攸太上

感谢支持

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值