| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> Java知识库 -> ??【Java】你真的会“面向对象编程“吗? 小白零基础入门 ??(万字图文解析,建议收藏) -> 正文阅读 |
|
[Java知识库]??【Java】你真的会“面向对象编程“吗? 小白零基础入门 ??(万字图文解析,建议收藏) |
目录前言看完本章文,你会学习到 包,继承,多态思想,抽象类,接口,具体看目录即可。 本文全文 3.7w字数可收藏下拉慢慢看。 一、包
为什么要组织类?? 你在公司的一个工程上面创建了一个TestDemo类,要是你同事也创建一个叫做TestDemo类,就会发现创建不了。 所以为了解决上面的问题,我们就引入了一个 包 这个概念,所以也就是说,在直观来看包就是一个文件夹而已。 我们平时已经使用过包,比如:使用Scanner的时候,必须导入包含Scanner这个类的一个包(如果,没有导入就会报错),类似C语言的头文件。 导入包中的类上面说到没有导入Scanner的包就会报错,那么我们怎么知道要导入什么包呢?这里提供一下方法
这里可以看见: Scanner.class是存放在java.util.Scanner; 这里我们可以尝试一下这个导包
* 代表通配符 那就有个问题了,这么多类,我们没有使用到岂不是浪费了??? 诶,老乡这你就不懂了 这里在java中是你使用到谁才会导谁,比如现在就使用到了Scanner ,它只会导入Scanner,随用随取 还有个问题我们平时使用的String也没有导入包啊 怎么可以正常使用呢? 我们发现还有一种导包的方法:比如下面需要使用Date这个方法 这里我们可不可以不使用import,当然可以!!
但是在日常使用,大家也没有看见多少人这样导包吧,所以还是尽量使用import 但是下面有个情况:使用util* 和java.sql.*就会报错 发现有两个下面都有… 这个情况下我们可以使用
静态导入该节了解即可: 我们平时写输出 但是大家要是不想写system那就使用下面的方法即可省略 也不推荐这样写,大家也不这样写。 但是这样有个好处就是看下面代码:
将类放到包中好了上面讲了那么多,其实就是证明文件在文件夹下面,现在我们需要解决一开始的问题,回到根本我们要开始创建package了 大家注意一定是在scr这个文件夹下创建,因为java程序只会找scr这里的东西
比如 www.baidu.com 我们写成:最后你可以取个有意义的名称com.baidu.TestDemo1 有些同学不一样,这里我们可以设置一下,看起来更有层次感 注意包名要小写,且最好是公司域名的逆置 在最下面的com里面创建一个class,对应的文件夹也存在这个class,避免了文件名冲突。 大家可以看见这个使用包创建的文件,这个java文件会使用package关键字跟上当前java文件的全路径,注意不要删除掉。 我们在src上面输入类名 编译器也会方便让我们区分 包的访问权限控制我们已经了解了类中的 public 和 private. private 中的成员只能被类的内部使用 但是要是都不包含private 和public呢?我们在com包下创建了TetsDemo2并且里面 三个属性:其中sex是没有被任何访问符修饰,这个时候sex就是包访问权限:也就是当前com包下所有成员可以访问的到 我们试试去src的TestDemo下访问看看:只有age 没有sex
二、继承我们经常听见继承封装多态他们其实都是面向对象的一个基本特征(不是某一个语言的特征,上面向对象的特征,不单单指某一个语言) 1.什么是继承?? 来代码举例: 只需要看注释的字
大家可以看见上面,我们定义了动物类型 动物有名字,和可以吃东西的行为,而我们的Cat类型,和Bird类型也会有名字,和吃东西的行为,这样的话代码就有重复的了,让我们的代码变的冗余了,我们可以看见既然动物了有这些相似的,那么我们可以直接继承Animal类,让它的东西给其他的类使用,这样就完成了我们继承的一个过程了。是不是十分简单。 小总结: 这三个类都具备一个相同的 eat 方法, 而且行为是完全一样的.
语法规则基本语法:
注意:
解析: 我们要记住子类继承父类,需要先帮助父类来构造 在Cat构造前,我们已经继承了Animal,Animal先有 而且参数是String类型的我们父类也是String类型的所以使用Super就先给父类赋值了,就符合了上面说的话了。 使用快捷键 Alt+enter 我们以前不写为什么不报错呢??因为会默认生成一个没有参数的方法 super和this的区别
大家有没有发现为什么子类没有的字段方法可以被调用出来字段: 现在我们来修改代码一下看看:使用继承
protected 关键字刚才我们发现, 如果把字段设为 private, 子类不能访问. 但是设成 public, 又违背了我们 “封装” 的初衷.
小结: Java 中对于字段和方法共有四种访问权限
范围表:default (什么修饰符都不写) 什么时候下用哪一种呢? 我们希望类要尽量做到 “封装”, 即隐藏内部实现细节, 只暴露出 必要 的信息给类的调用者. 因此我们在使用的时候应该尽可能的使用 比较严格 的访问权限. 例如如果一个方法能用 private, 就尽量不要用public. 另外, 还有一种 简单粗暴 的做法: 将所有的字段设为 private, 将所有的方法设为 public. 不过这种方式属于是对访问权限的滥用, 还是更希望同学们能写代码的时候认真思考, 该类提供的字段方法到底给 “谁” 使用(是类内部自己用, 还是类的调用者使用, 还是子类使用) 更加复杂的继承要是父类有个字段,我们子类继承父类也有一个一样的字段,那么输出是谁的呢? 要是父类,还继承了个父类,然后子类输出的是谁的呢? 上面的情况可以衍生出继承很多。
如刚才这样的继承方式称为多层继承, 即子类还可以进一步的再派生出新的子类. 注意: 时刻牢记, 我们写的类是现实事物的抽象. 而我们真正在公司中所遇到的项目往往业务比较复杂, 可能会涉及到一系列复杂的概念, 都需要我们使用代码来表示, 所以我们真实项目中所写的类也会有很多. 类之间的关系也会更加复杂. 但是即使如此, 我们并不希望类之间的继承层次太复杂. 一般我们不希望出现超过三层的继承关系. 如果继承层次太多, 就需要考虑对代码进行重构了. 如果想从语法上进行限制继承, 就可以使用 final 关键字 final 关键字曾经我们学习过 final 关键字, 修饰一个变量或者字段的时候, 表示 常量 (不能修改).
final 关键字也能修饰类, 此时表示被修饰的类就不能被继承.
组合什么叫组合?? 例如表示一个学校:
组合表示 has - a 语义 继承表示 is - a 语义 大家要注意体会两种语义的区别. 三、多态多态是面向对象的第三大特征,它的实现实质上是由向上转型(Upcasting)也称为(向上映射)和动态绑定的机制结合完成的,只有理解了这两个机制,才能明白多态的意义。 向上转型的概念及方法调用
向上转型是安全的,这是因为任何子类都继承了并接受了父类的方法,子类与父类的继承关系是is-a的关系。猫属动物,动物并不只是猫。 向上转型发生的时机:
函数的参数是Animal,传过去了一个animal ,传过去的animal还是指向animal所指的对象 new Dog(),这也叫做上向转型。 还可以暴力点:这也是向上转型
还有一种情况:return的是Dog,使用Animal接收 下一步 静态绑定和动态绑定什么是绑定?将一个方法调用同一个方法所在的类关联在一起就是绑定,绑定分为
接下来使用代码列子来解释一下两种绑定: 静态绑定:有如下方法和成员变量 Dog对象调用类中的成员方法,这种调用方式是在代码里指定的,编译时编译器就知道dog调用的是Dog的eat()。
动态绑定:代码稍微修改了下 看下面图: 新增了一个Dog2: main方面的改动:有一个数组,然后随机数随机向上转型 结果: 也可以这样来看: 动态绑定
向上转型需要注意的地方:
为什么呢?·因为这个引用类型是Animal,所以只可以调用Animal特有的方法和属性。 结论:通过父类引用 调用方法或者成员变量的时候 , 只能调用父类的特有方法或者成员 但是上面的话我们下图的结果既然是Dog的eat方法,那岂不是和上面的冲突了? 方法重写针对刚才的 eat 方法来说: 子类实现父类的同名方法, 并且参数的类型和个数完全相同, 这种情况称为 覆写/重写/覆盖(Override) 1.我们先来看一下重载(overload)和重写(override)的区别 重载:
重写:顾名思义重新写一份
我们来看看刚刚的eat代码: Animal类 Dog类 有一个图很形象的表达出来他们的区别:
注解针对重写的方法, 可以使用 @Override 注解来显式指定 在要重写的方法上加一个@Override 有了这个注解能帮我们进行一些合法性校验. 例如不小心将方法名字拼写错了 (比如写成 aet), 那么此时编译器就会发现父类中没有 aet 方法, 就会编译报错, 提示无法构成重写 向下转型向上转型是子类对象转成父类对象, 向下转型就是父类对象转成子类对象. 相比于向上转型来说, 向下转型没那么常见,但是也有一定的用途. 先来看一下什么是向下转型 首先我们来看代码:dog指向animal 调用eat 运行一下:报错了 ,说Animal不可以转换为 Dog 前提:向下转型 一定要先发生向上转型 可以看出向下转型是不安全的,因为不知道那个Dog要转换的类有没有关系 这个时候我们可以使用一个关键字 这样就不会报错了,所以正是因为这样的不安全,我们平时不经常使用,不过上面认识即可。 在构造方法中调用重写的方法(一个坑)一段有坑的代码. 在父类构造方法调用eat 运行结果: main函数: 运行结果: 为什么会这样呢? 解析: 理解多态有了面的向上转型, 动态绑定, 方法重写之后, 我们就可以使用 多态(polypeptide) 的形式来设计程序了.
在这个代码中, 分割线上方的代码是 类的实现者 编写的, 分割线下方的代码是 类的调用者 编写的 . 当类的调用者在编写 drawMap 这个方法的时候, 参数类型为 Shape (父类), 此时在该方法内部并不知道, 也不关注当前的 shape 引用指向的是哪个类型(哪个子类)的实例. 此时 shape 这个引用调用 draw 方法可能会有多种不同的表现(和 shape 对应的实例相关), 这种行为就称为 多态 使用多态的好处是什么? 1.类调用者对类的使用成本进一步降低.
2 能够降低代码的 “圈复杂度”, 避免使用大量的 if - else 例如我们现在需要打印的不是一个形状了, 而是多个形状. 如果不基于多态, 实现代码如下:
如果使用使用多态, 则不必写这么多的 if - else 分支语句, 代码更简单
对于类的调用者来说(drawShapes方法), 只要创建一个新类的实例就可以了, 改动成本很低. 四、抽象类语法规则在刚才的打印图形例子中, 我们发现, 父类 Shape 中的 draw 方法好像并没有什么实际工作, 主要的绘制图形都是由Shape 的各种子类的 draw 方法来完成的. 像这种没有实际工作的方法, 我们可以把它设计成一个 抽象方法(abstractmethod), 包含抽象方法的类我们称为 抽象类(abstract class) 语法规则
注意事项
final
如果想要不重写方法 可以使用abstract 抽象类的作用上面说到抽象类不可以被继承,那么它还有什么作用呢?
确实如此. 但是使用抽象类相当于多了一重编译器的校验. 使用抽象类的场景就如上面的代码, 实际工作不应该由父类完成, 而应由子类完成. 那么此时如果不小心误用成父类了,
五、接口
语法规则及语法实现
5.接口当中的
为什么可以实现多个接口?
这个时候要是有其他类来implementsD,需要重写D,A,B的方法(这个时候E的功能就很强大)
现在我们通过类来表示一组动物 另外我们再提供一组接口, 分别表示 “会飞的”, “会跑的”, “会游泳的” 接下来我们创建一个具体的动物 青蛙, 既能跑, 又能游(两栖动物) 上面的代码展示了 Java 面向对象编程中最常见的用法: 一个类继承一个父类, 同时实现多种接口 猫是一种动物, 具有会跑的特性. 为什么要搞这么多接口呢?不可以全部放在Animal类里面吗?? 答:因为动物不一定都会飞,不一定多会游泳,我们可以继承他们都有的特征,具体一下行为可以使用接口来实现,而且接口,就是给我们达到多继承的效果的。
比如:只要实现了我的接口 都可以发生向上转型,都可以发生动态绑定,都可以发生多态 接口使用实例comparable 接口刚才的例子比较抽象, 我们再来一个更能实际的例子. 给对象数组排序 给定一个学生类
那么comparable是什么东西呢?根据一路找下来,我们发现这个是个接口
那么我们这里写什么呢??写一个比较规则
所以这个comparable接口有什么用,其实就是对于 sort 方法来说, 需要传入的数组的每个对象都是 “可比较” 的, 需要具备 compareTo 这样的能力. 通过重写 compareTo 方法的方式, 就可以定义比较规则.(让类也有可比较的能力) 让哪一个类具备了这样的能力(可比较性)转换的都是student类 上面的列子就说明了,一旦一个类实现了接口就具备了某种能力 那么这个接口有什么不好的地方呢?? 这样想,要是我们不想按照年龄排序,需要按照名字排序呢?那么我们的规则就需要修改一下: 那我们想分数排序:修改规则 运行结果: 大家发现了没有,这玩意一点不灵活啊,老是要修改规则 麻烦死了
为了解决comparable接口的缺陷 我们有一个新的接口 Comparator接口 Comparator接口现在我们来这个接口来比较,假如我们想使用age来比较,我们来写一个类,让这个类实现Comparator
我们来看一下sort的源码:是一个接口类型的参数 运行结果: 好了,现在我们换一个场景,使用name排序,那么也是一样的写一个类: main 我们一般把Comparator叫做比较器 那么他们的区别在哪里呢?
Clonable 接口Java 中内置了一些很有用的接口, Clonable 就是其中之一. Object 类中存在一个 clone 方法, 调用这个方法可以创建一个对象的 “拷贝”. 但是要想合法调用 clone 方法, 必须要先 Clonable接口里面什么都没有(空接口) 这里存在一个面试问题:这个空接口有什么用?? 空接口有个术语叫做(标记接口),实现的类证明可以被克隆的 重写克隆方法代码如下: main: 运行结果: 克隆的深拷贝和浅拷贝首先我们先来看一段代码: Main函数: 输出结果: 我们来分析一下main的内存空间样子,为什么不会影响person,因为下面是2个空间使用并不会影响到 main方法:一步一步来 如果我修改了12.5 是不是person 和 person2都被修改了?(因为克隆只是克隆了蓝框框 它们里面所指money 还是那一个) main函数: 我们有个思路:把money也克隆一份 变成黄色的部分那样 让一个另外一个person指向黄色部分,这样修改黑色部分就不会受影响了,这样也达到了我们深拷贝的效果 那么我们怎么做呢?? money要克隆,我们让它实现克隆接口 重写克隆方法 在person类里面写 运行结果: 总结:抽象类和接口都是 Java 中多态的常见使用方式. 都需要重点掌握. 同时又要认清两者的区别 核心区别: 抽象类中可以包含普通方法和普通字段, 这样的普通方法和字段可以被子类直接使用(不必重写), 而接口中不 以上就是全部内容了如果有帮助可以点个大拇指,收藏一下 |
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/23 17:17:38- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |