0
点赞
收藏
分享

微信扫一扫

【Java】--面向对象的编程之千锤百炼大总结


【Java】--面向对象的编程之千锤百炼大总结_后端


 写在前面

【Java】--面向对象的编程之千锤百炼大总结_子类_02

        概述

        导入包中的类

        静态导入

        将类放入包中

        包的访问权限控制

        常见的系统包

  【Java】--面向对象的编程之千锤百炼大总结_子类_02继承

        基本语法

        protected关键字

        更复杂的继承关系

        fina关键字

【Java】--面向对象的编程之千锤百炼大总结_子类_02组合

【Java】--面向对象的编程之千锤百炼大总结_子类_02多态

        向上转型

        动态绑定

        方法重写

        向下转型

        super关键字

        总结

  【Java】--面向对象的编程之千锤百炼大总结_子类_02抽象类

        语法规则

        抽象类的作用

  【Java】--面向对象的编程之千锤百炼大总结_子类_02接口

 写在前面

Java面向对象的编程是Java学习的重点和难点,也是面试重要的考点!语法本身不难,需要我们平时 多加练习,多敲代码去感悟和体会,现在我们开始来学习吧!

 【Java】--面向对象的编程之千锤百炼大总结_子类_02

概述

包是什么?

1.包(packag)是组织类的一种方式

2.目的:使用包的目的是保证类的唯一性。

导入包中的类

Java 中已经提供了很多现成的类供我们使用. 例如

【Java】--面向对象的编程之千锤百炼大总结_java_09

可以使用 java.util.Date 这种方式引入 java.util 这个包中的 Date 类,但是这种写法比较麻烦一些, 可以使用 import 语句导入包

【Java】--面向对象的编程之千锤百炼大总结_java_10

 【Java】--面向对象的编程之千锤百炼大总结_父类_11

 如果需要使用 java.util 中的其他类, 可以使用 import java.util.*

【Java】--面向对象的编程之千锤百炼大总结_开发语言_12

但是我们更建议显式的指定要导入的类名. 否则还是容易出现冲突的情况

【Java】--面向对象的编程之千锤百炼大总结_开发语言_13在这种情况下需要使用完整的类名

【Java】--面向对象的编程之千锤百炼大总结_后端_14

注意事项: import 和 C++ 的 #include 差别很大. C++ 必须 #include 来引入其他文件内容, 但是 Java 不需要. import 只是为了写代码的时候更方便. import 更类似于 C++ 的 namespaceusing 

静态导入

使用 import static 可以导入包中的静态的方法字段

【Java】--面向对象的编程之千锤百炼大总结_后端_15

 使用这种方式可以更方便的写一些代码, 例如

【Java】--面向对象的编程之千锤百炼大总结_子类_16

将类放入包中

基本规则

1.在文件的最上方加上一个 package 语句指定该代码在哪个包中

2.包名需要尽量指定成唯一的名字, 通常会用公司的域名的颠倒形式(例如 com.bit.demo1 )

3.包名要和代码路径相匹配. 例如创建 com.bit.demo1 的包, 那么会存在一个对应的路径 com/bit/demo1 来存 储代码

4.如果一个类没有 package 语句, 则该类被放到一个默认包中

操作步骤

1) 在 IDEA 中先新建一个包: 右键 src -> 新建 -> 包

【Java】--面向对象的编程之千锤百炼大总结_子类_17

2) 在弹出的对话框中输入包名, 例如 com.bit.demo1 

 【Java】--面向对象的编程之千锤百炼大总结_开发语言_18

 3) 在包中创建类, 右键包名 -> 新建 -> 类, 然后输入类名即可

【Java】--面向对象的编程之千锤百炼大总结_后端_19

 4) 此时可以看到我们的磁盘上的目录结构已经被 IDEA 自动创建出来了

 【Java】--面向对象的编程之千锤百炼大总结_开发语言_20

 5) 同时我们也看到了, 在新创建的 Test.java 文件的最上方, 就出现了一个 package 语句

【Java】--面向对象的编程之千锤百炼大总结_开发语言_21

包的访问权限控制

我们已经了解了类中的 public private. private 中的成员只能被类的内部使用. 如果某个成员不包含 publicprivate 关键字, 此时这个成员可以在包内部的其他类使用, 但是不能在包外部的类使 用. 下面的代码给了一个示例. Demo1 和 Demo2 是同一个包中, Test 是其他包中. Demo1.java

Demo1.Java

【Java】--面向对象的编程之千锤百炼大总结_父类_22

 Demo2.Java

【Java】--面向对象的编程之千锤百炼大总结_子类_23

【Java】--面向对象的编程之千锤百炼大总结_java_24

 Test.Java

【Java】--面向对象的编程之千锤百炼大总结_父类_25

 常见的系统包

1. java.lang:系统常用基础类(String、Object),此包从JDK1.1后自动导入。

2. java.lang.reflect:java 反射编程包;

3. java.net:进行网络编程开发包。

4. java.sql:进行数据库开发的支持包。

5. java.util:是java提供的工具程序包。(集合类等) 非常重要

6. java.io:I/O编程开发包。

继承

背景

代码中创建的类, 主要是为了抽象现实中的一些事物(包含属性和方法). 有的时候客观事物之间就存在一些关联关系, 那么在表示成类和对象的时候也会存在一定的关联. 例如, 设计一个类表示动物

注意, 我们可以给每个类创建一个单独的 java 文件. 类名必须和 .java 文件名匹配(大小写敏感).

 【Java】--面向对象的编程之千锤百炼大总结_后端_26

 【Java】--面向对象的编程之千锤百炼大总结_子类_27

 【Java】--面向对象的编程之千锤百炼大总结_父类_28

这个代码我们发现其中存在了大量的冗余代码.

仔细分析, 我们发现 Animal Dog 以及 Bird一级 几个类当中存在一定关系。

这三个类都具备一个相同的 eat 方法, 而且行为是完全一样的

这三个类都具备一个相同的 name 属性, 而且意义是完全一样的

从逻辑上讲,Dog 和 Bird 都是一种 Animal (is - a 语义)

此时我们就可以让 Dog 和 Bird 分别继承 Animal 类, 来达到代码重用的效果.

此时, Animal 这样被继承的类, 我们称为 父类 , 基类 超类, 对于像 Dog 和 Bird 这样的类, 我们称为 子类, 派生类 和现实中的儿子继承父亲的财产类似, 子类也会继承父类的字段和方法, 以达到代码重用的效果

语法规则

基本语法

【Java】--面向对象的编程之千锤百炼大总结_后端_29

使用 extends 指定父类.

Java 中一个子类只能继承一个父类 (而C++/Python等语言支持多继承).

子类会继承父类的所有 public 的字段和方法.

对于父类private 字段和方法, 子类中是无法访问

子类的实例中, 也包含着父类的实例. 可以使用 super 关键字得到父类实例的引用

对于上面的代码, 可以使用继承进行改进. 此时我们让 Dog 和 Bird 继承自 Animal 类, 那么 Dog 在义的时候就不必再 写 name 字段和 eat 方法

【Java】--面向对象的编程之千锤百炼大总结_父类_30

 【Java】--面向对象的编程之千锤百炼大总结_java_31

extends 英文原意指 "扩展". 而我们所写的类的继承, 也可以理解成基于父类进行代码上的 "扩展". 例如我们写的 Bird 类, 就是在 Animal 的基础上扩展出了fly方法。

如果我们把 name 改成 private, 那么此时子类就不能访问了。

【Java】--面向对象的编程之千锤百炼大总结_开发语言_32

 【Java】--面向对象的编程之千锤百炼大总结_java_33

protected 关键字

刚才我们发现, 如果把字段设为 private, 子类不能访问. 但是设成 public, 又违背了我们 "封装" 的初衷,两全其美的办法就是 protected 关键字.

对于类的调用者来说, protected 修饰的字段和方法是不能访问的

对于类的 子类同一个包的其他类 来说, protected 修饰的字段和方法是可以访问的

【Java】--面向对象的编程之千锤百炼大总结_java_34

 对于父类的 protected 字段,子类是可以正确访问

【Java】--面向对象的编程之千锤百炼大总结_父类_35

 【Java】--面向对象的编程之千锤百炼大总结_开发语言_36

小结: Java 中对于字段和方法共有四种访问权限

private: 类内部能访问, 类外部不能访问

默认(也叫包访问权限): 类内部能访问, 同一个包中的类可以访问, 其他类不能访问.

protected: 类内部能访问, 子类和同一个包中的类可以访问, 其他类不能访问.

public : 类内部和类的调用者都能访问

【Java】--面向对象的编程之千锤百炼大总结_开发语言_37

 更复杂的继承关系

刚才我们的例子中, 只涉及到 Animal, Cat(Dog) 和 Bird 三种类. 但是如果情况更复杂一些呢? 针对 Cat 这种情况, 我们可能还需要表示更多种类的猫~

【Java】--面向对象的编程之千锤百炼大总结_java_38

 【Java】--面向对象的编程之千锤百炼大总结_后端_39

 final 关键字

曾经我们学习过 final 关键字, 修饰一个变量或者字段的时候, 表示 常量 (不能修改)

【Java】--面向对象的编程之千锤百炼大总结_开发语言_40

 final 关键字也能修饰类, 此时表示被修饰的类就不能被继承

【Java】--面向对象的编程之千锤百炼大总结_后端_41

final 关键字的功能是 限制 类被继承

"限制" 这件事情意味着 "不灵活". 在编程中, 灵活往往不见得是一件好事. 灵活可能意味着更容易出错

是用 final 修饰的类被继承的时候, 就会编译报错, 此时就可以提示我们这样的继承是有悖这个类设计的初衷的

【Java】--面向对象的编程之千锤百炼大总结_父类_42

 我们平时是用的 String 字符串类, 就是用 final 修饰的, 不能被继承

组合

和继承类似, 组合也是一种表达类之间关系的方式, 也是能够达到代码重用的效果.

例如表示一个学校:

【Java】--面向对象的编程之千锤百炼大总结_父类_43

组合并没有涉及到特殊的语法(诸如 extends 这样的关键字), 仅仅是将一个类的实例作为另外一个类的字段. 这是我们设计类的一种常用方式之一

组合表示 has - a 语义

在刚才的例子中, 我们可以理解成一个学校中 "包含" 若干学生和教师

继承表示 is - a 语义

在上面的 "动物和猫" 的例子中, 我们可以理解成一只猫也 "是" 一种动物

大家要注意体会两种语义的区别!!

多态

【Java】--面向对象的编程之千锤百炼大总结_java_44

向上转型

在刚才我们看到的列子中,我们写了如面的代码

【Java】--面向对象的编程之千锤百炼大总结_后端_45

 这个代码也可以写成这样子

【Java】--面向对象的编程之千锤百炼大总结_后端_46

 或者写成这样子

【Java】--面向对象的编程之千锤百炼大总结_后端_47

此时 Dog 是一个父类 (Animal) 的引用, 指向一个子类 (Bird) 的实例. 这种写法称为 向上转型

向上转型这样的写法可以结合 is - a 语义来理解

例如, 我让我媳妇去喂圆圆, 我就可以说"媳妇你喂小鸟了没?", 或者 "媳妇你喂鹦鹉了没?

因为圆圆确实是一只鹦鹉, 也确实是一只小鸟~~

【Java】--面向对象的编程之千锤百炼大总结_子类_48

 什么时候发生向上转型?需要注意的问题有是什么呢?

话不多说,直接上图!

【Java】--面向对象的编程之千锤百炼大总结_子类_49

 方法传参

【Java】--面向对象的编程之千锤百炼大总结_子类_50

 此时形参 animal 的类型是 Animal (基类), 实际上对应到 Bird (父类) 的实例.

方法返回

【Java】--面向对象的编程之千锤百炼大总结_子类_51

此时方法 findMyAnimal 返回的是一个 Animal 类型的引用, 但是实际上对应到 Bird 的实例

动态绑定

在来看图

【Java】--面向对象的编程之千锤百炼大总结_子类_49

【Java】--面向对象的编程之千锤百炼大总结_后端_53

 注意看父类中有eat方法,子类中也有eat方法

【Java】--面向对象的编程之千锤百炼大总结_子类_54

当子类和父类中同时出现相同的方法的时候动态绑定就发生了,这个时候再来看输出的结果

【Java】--面向对象的编程之千锤百炼大总结_后端_55

 【Java】--面向对象的编程之千锤百炼大总结_子类_56

因此,在 Java 中, 调用某个类的方法, 究竟执行了哪段代码 (是父类方法的代码还是子类方法的代码) , 要看究竟这个引 用指向的是父类对象还是子类对象. 这个过程是程序运行时决定的(而不是编译期), 因此称为 动态绑定

方法重写

针对刚才的 eat 方法来说

子类实现父类的同名方法, 并且参数的类型和个数完全相同, 这种情况称为 覆写/重写/覆盖(Override).

注意事项

重写和重载完全不一样. 不要混淆

普通方法可以重写, static 修饰的静态方法不能重写

重写中子类的方法的访问权限不能低于父类的方法访问权限

重写的方法返回值类型不一定和父类的方法相同(但是建议最好写成相同, 特殊情况除外)

方法权限示例: 将子类的 eat 改成 private

【Java】--面向对象的编程之千锤百炼大总结_父类_57

 【Java】--面向对象的编程之千锤百炼大总结_子类_58

 【Java】--面向对象的编程之千锤百炼大总结_java_59

 另外, 针对重写的方法, 可以使用 @Override 注解来显式指定

【Java】--面向对象的编程之千锤百炼大总结_开发语言_60

有了这个注解能帮我们进行一些合法性校验. 例如不小心将方法名字拼写错了 (比如写成 aet), 那么此时编译器就会发 现父类中没有 aet 方法, 就会编译报错, 提示无法构成重写

我们推荐在代码中进行重写方法时显式加上 @Override 注解

小结: 重载和重写的区别.

【Java】--面向对象的编程之千锤百炼大总结_子类_61

理解多态

上代码!

【Java】--面向对象的编程之千锤百炼大总结_java_62

 【Java】--面向对象的编程之千锤百炼大总结_后端_63

在这个代码中, 分割线上方的代码是 类的实现者 编写的, 分割线下方的代码是 类的调用者 编写的

当类的调用者在编写 drawMap 这个方法的时候, 参数类型为 Shape (父类), 此时在该方法内部并不知道, 也不关注当 前的 shape 引用指向的是哪个类型(哪个子类)的实例. 此时 shape 这个引用调用 draw 方法可能会有多种不同的表现 (和 shape 对应的实例相关), 这种行为就称为 多态

使用多态的好处有什么?

1. 类调用者对类的使用成本进一步降低.

        封装是让类的调用者不需要知道类的实现细节.

        多态能让类的调用者连这个类的类型是什么都不必知道, 只需要知道这个对象具有某个方法即可.

因此, 多态可以理解成是封装的更进一步, 让类调用者对类的使用成本进一步降低.这也贴合了 > 中关于 "管理代码复杂程度" 的初衷。

2.能够降低代码的 "圈复杂度", 避免使用大量的 if - else

        上代码!如果不使用多态那么将会是什么样的?

【Java】--面向对象的编程之千锤百炼大总结_子类_64

 3. 可扩展能力更强.

如果要新增一种新的形状, 使用多态的方式代码改动成本也比较低.

【Java】--面向对象的编程之千锤百炼大总结_父类_65

对于类的调用者来说(drawShapes方法), 只要创建一个新类的实例就可以了, 改动成本很低

而对于不用多态的情况, 就要把 drawShapes 中的 if - else 进行一定的修改, 改动成本更高

       super 关键字

super 表示获取到父类实例的引用,

1) 使用了 super 来调用父类的构造器(这个代码前面已经写过了)

【Java】--面向对象的编程之千锤百炼大总结_子类_66

2) 使用 super 来调用父类的普通方法

【Java】--面向对象的编程之千锤百炼大总结_后端_67

在这个代码中, 如果在子类的 eat 方法中直接调用 eat (不加super), 那么此时就认为是调用子类自己的 eat (也就是递 归了). 而加上 super 关键字, 才是调用父类的方法

注意 super 和 this 功能有些相似, 但是还是要注意其中的区别

【Java】--面向对象的编程之千锤百炼大总结_子类_68

总结

多态是面向对象程序设计中比较难理解的部分. 我们会在后面的抽象类和接口中进一步体会多态的使用. 重点是多态带 来的编码上的好处

另一方面, 如果抛开 Java, 多态其实是一个更广泛的概念, 和 "继承" 这样的语法并没有必然的联系

C++ 中的 "动态多态" 和 Java 的多态类似. 但是 C++ 还有一种 "静态多态"(模板), 就和继承体系没有关系了.

Python 中的多态体现的是 "鸭子类型", 也和继承体系没有关系.

Go 语言中没有无论是哪种编程语言, 多态的核心都是让调用者不必关注对象的具体类型. 这是降低用户使用成本的一种重要方式. "继承" 这样的概念, 同样也能表示多态

无论是哪种编程语言, 多态的核心都是让调用者不必关注对象的具体类型. 这是降低用户使用成本的一种重要方式.

抽象类

什么是抽象类?我们需要注意什么?如何去编写?话不多说直接先上图!【Java】--面向对象的编程之千锤百炼大总结_父类_69

 语法规则

【Java】--面向对象的编程之千锤百炼大总结_子类_70

draw 方法前加上 abstract 关键字, 表示这是一个抽象方法. 同时抽象方法没有方法体(没有 { },不能执行具体代码)。

对于包含抽象方法的类, 必须加上 abstract 关键字表示这是一个抽象类

注意事项

1) 抽象类不能直接实例化

【Java】--面向对象的编程之千锤百炼大总结_父类_71

 2) 抽象方法不能是 private 的

【Java】--面向对象的编程之千锤百炼大总结_java_72

 3) 抽象类中可以包含其他的非抽象方法, 也可以包含字段. 这个非抽象方法和普通方法的规则都是一样的, 可以被重写, 也可以被子类直接调用

【Java】--面向对象的编程之千锤百炼大总结_java_73

 抽象类的作用

抽象类存在的最大意义就是为了被继承

抽象类本身不能被实例化, 要想使用, 只能创建该抽象类的子类. 然后让子类重写抽象类中的抽象方法.

接口

接口是抽象类的更进一步. 抽象类中还可以包含非抽象方法, 和字段. 而接口中包含的方法都是抽象方法, 字段只能包含 静态常量

语法规则

【Java】--面向对象的编程之千锤百炼大总结_父类_74

使用 interface 定义一个接口

接口中的方法一定是抽象方法, 因此可以省略 abstract

接口中的方法一定是 public, 因此可以省略 public

Cycle 使用 implements 继承接口. 此时表达的含义不再是 "扩展", 而是 "实现"

在调用的时候同样可以创建一个接口的引用, 对应到一个子类的实例.

接口不能单独被实例化

多个接口的实现

直接上代码!

【Java】--面向对象的编程之千锤百炼大总结_java_75

 【Java】--面向对象的编程之千锤百炼大总结_开发语言_76

 【Java】--面向对象的编程之千锤百炼大总结_后端_77

 【Java】--面向对象的编程之千锤百炼大总结_java_78

 接口使用实例

1.Comparable接口

【Java】--面向对象的编程之千锤百炼大总结_开发语言_79

 【Java】--面向对象的编程之千锤百炼大总结_java_80

【Java】--面向对象的编程之千锤百炼大总结_子类_81

 注意!

如果自定义数据类型进行大小比较,一定要实现,可以比较的接口

Comparable 这个接口有很大的缺点:对类的侵入性非常强,一旦写好,不易改动

为了让能够更好的改动,所以我们还可以使用Comparator接口

Comparator接口

【Java】--面向对象的编程之千锤百炼大总结_后端_82

 【Java】--面向对象的编程之千锤百炼大总结_子类_83

 【Java】--面向对象的编程之千锤百炼大总结_子类_84

 【Java】--面向对象的编程之千锤百炼大总结_java_85

                           小生不才,表达能力有限,希望各位老铁点个赞哈!!


举报

相关推荐

0 条评论