Java基础教程-05-面向对象

1. 面向过程和面向对象解释

1.1 面向过程

1.1.1 简述

我们回想一下, 前面我们完成一个需求的步骤是怎样的?

  1. 首先是搞清楚我们要做什么.
  2. 然后在分析怎么做.
  3. 最后我们在通过代码一步一步去实现.

上述的每一个步骤, 我们都是参与者, 并且需要面对具体的每一个步骤和过程, 这就是面向过程最直接的体现.

1.1.2 举例

• 生活中的例子: 洗衣服. 想完成洗衣服这个需求, 我们得完成下述的每一个步骤:

  1. 找个盆.
  2. 接点水.
  3. 到洗衣液.
  4. 把衣服放进去浸泡10分钟.
  5. 把衣服揉搓干净.
  6. 漂洗.
  7. 拧干水分.
  8. 晾晒.

注意:

  1. 上述的这些步骤, 但凡有一个我们不会做, 就没有办法完成洗衣服这个需求.
  2. 即: 每一步都需要我们亲自做, 这就是: 面向过程思想.

• 代码举例: 把数组元素按照[11, 22, 33, 44, 55]的格式进行输出.

  1. 定义方法printArray(), 参数列表为: int[] arr, 返回值的类型为String.
  2. 定义字符串变量s, 用来记录数组元素拼接后的结果.
  3. 字符串变量s的初始化值设置为[.
  4. 对数组对象进行判断, 看其是否是合法对象.
    即: 数组对象不为: null
  5. 通过for循环遍历数组, 获取到每一个元素.
  6. 判断当前获取到的元素是否是最后一个元素, 并和字符串变量s进行拼接.
     • 如果是最后一个元素, 则在后边在拼接上]
     • 如果不是最后一个元素, 则在后边在拼接上,
  7. 当for循环执行结束后, 字符串变量s记录的就是拼接后的结果, 将其直接返回即可.

注意: 上述的每一步代码都需要我们编写, 这样做比较繁琐.

1.1.3 总结

面向过程思想其实就是一种编程思想. 所谓的面向过程开发, 指的就是面向着具体的每一个步骤和过程, 把每一个步骤和过程完成, 然后由这些功能方法相互调用, 完成需求.
记忆: 面向过程的代表语言是: C语言.

1.2 面向对象

1.2.1 简述

当需求单一, 或者简单时, 我们一步一步去操作是没问题的, 并且效率也挺高. 可随着需求的更改, 功能的增多, 发现需要面对每一个步骤就很麻烦了, 于是我们就想着, 能不能把这些步骤和功能在进行封装, 封装时根据不同的功能, 进行不同的封装, 功能类似的用一个类封装在一起, 这样结构就清晰了很多. 用的时候, 找到对应的类就可以了. 这就是面向对象的思想.

1.2.2 举例

• 生活中的例子: 洗衣服.

  1. 想完成洗衣服这个需求, 我们可以通过洗衣机 来实现.
  2. 对于我们来讲, 洗衣机就是我们的对象.
  3. 总结: 万物皆对象.

• 代码举例: 把数组元素按照[11, 22, 33, 44, 55]的格式进行输出.
上述的需求, 我们可以通过Arrays类的toString()方法来实现.

Int[] arr  = {11, 22, 33, 44, 55};
sop(Arrays.toString(arr));   -> “[11, 22, 33, 44, 55]”

1.2.3 思想特点

  1. 是一种符合我们思考习惯的思想.
  2. 可以将复杂的事情简单化.
  3. 让我们从执行者变成了指挥者.

1.2.4 总结

面向对象思想是一种编程思想, 它是基于面向过程的, 强调的是以对象为基础完成各种操作.
总结来讲, 万物皆对象.

2. 类和对象

2.1 概述

问题一: 你为什么学习编程语言?
我们学习编程语言, 其实就是为了把现实世界的事物通过代码模拟出来, 实现信息化.
例如:
• 超市的计费系统.
• 银行的核心系统.
• 千亿级数据仓库.

分析PB级数据,为企业提供高效、稳健的实时数据洞察。
采用类似阿里巴巴大数据数仓设计的分层架构思想,使用主流的实时仓库技术Flink、Druid、Kafka。

• 企业级360°全方位用户画像.
360°全方位还原用户画像,实现对个体和群体信息的标签化,实现精准推荐和营销.
• 电商推荐系统.
项目利用Neo4j构建用户和商品的关系图示,基于词向量相似度推荐商品、CTR/CVR点击率预估模型、逻辑斯特回归算法进行CTR点击率预估。

问题二: 我们是如何表示现实世界的事物呢?

  1. 属性.
    – 属性指的就是事物的描述信息(名词).
    – 属性在Java中被称之为成员变量.
  2. 行为.
    – 行为指的就是事物能够做什么.
    – 行为在Java中被称之为成员方法.

例如: 学生
• 属性: 姓名, 年龄, 性别…
• 行为: 学习, 吃饭, 睡觉…

问题三: Java语言是如何表示现实世界的事物呢?

  1. 在Java语言中, 是通过类来体现事物的. Java语言最基本的单位是类, 它是一个抽象的概念, 看不见, 摸不着.
  2. 对象: 对象就是该类事物的具体体现, 实现.

举例:
类 学生 大象
对象 张三, 23 北京动物园叫图图的大象

2.2 类的定义格式

2.2.1 简述

定义类其实就是定义类的成员(成员变量和成员方法)
• 成员变量:

  1. 和以前定义变量是一样的, 只不过位置发生了改变, 写到类中, 方法外
  2. 而且成员变量还可以不用赋值, 因为它有默认值.

• 成员方法:

  1. 和以前定义方法是一样的, 只不过把static关键字去掉.
  2. 这点先记忆即可, 后面我们再讲解static关键字的用法.

2.2.2 格式

public class 类名 {//成员变量//成员方法
}

2.2.3 示例

需求
定义一个学生类.
参考代码

public class Student{//成员变量, 就是属性.String name;   //姓名int age;        //年龄//成员方法, 就是行为.//学习的方法public void study() {System.out.println("键盘敲烂, 月薪过万!...");}//吃饭的方法public void eat() {System.out.println("学习饿了要吃饭!...");}
}

2.3 类的使用

2.3.1 简述

所谓类的使用, 就是使用类中定义的成员(成员变量和成员方法).

2.3.2 格式

  1. 创建该类的对象.

类名 对象名 = new 类名();

  1. 通过对象名.的形式, 调用类中的指定成员即可.

//成员变量
对象名.成员变量

//成员方法
对象名.成员方法(参数列表中各数据类型对应的值…)

2.3.3 示例

需求
使用学生类中的成员.
参考代码

public class StudentTest{public static void main(String[] args) {//1. 创建学生类的对象.Student s = new Student();//2. 访问成员变量.System.out.println(s.name);System.out.println(s.age);//3. 给成员变量赋值.s.name = "张三";s.age = 23;//4. 访问成员变量.System.out.println(s.name);System.out.println(s.age);//5. 访问成员方法. s.study();s.eat();}
}

运行结果为:

null
0
张三
23
好好学习, 天天向上!
为了保持精力, 要按时吃饭.

3. 手机类的定义和使用

3.1 需求

  1. 定义手机类Phone.
    属性: 品牌(brand), 价格(price), 颜色(color)
    行为: 打电话(call), 发短信(sendMessage)
  2. 创建测试类PhoneTest, 在类中定义main方法, 并访问手机类(Phone类)中的成员.

3.2 参考代码

手机类

public class Phone {// 属性: 也叫成员变量, 就是用来描述事物的外在特征的(即: 名词)String brand;           //品牌int price;              //价格String color;           //颜色// 行为: 打电话(call), 发短信(sendMessage)//打电话public void call(String name) {   //夯哥System.out.println("给" + name + "打电话!...");}//发短信public void sendMessage(String name) {System.out.println("给" + name + "发短信!...");}
}

手机类的测试

public class PhoneTest {//main方法是程序的主入口, 所有的代码都是从这里开始执行的.public static void main(String[] args) {//1. 创建手机类的对象.Phone p = new Phone();//2. 设置成员变量值.p.brand = "华为";p.price = 5999;p.color = "黑色";//3. 打印成员变量值.System.out.println(p.brand);System.out.println(p.price);System.out.println(p.color);//4. 调用成员方法p.call("夯哥");p.sendMessage("夯哥");}
}

运行结果为:

华为
5999
黑色
给夯哥打电话!...
给夯哥发短信!...

4. 对象的内存图

4.1 一个对象的内存图

代码

//手机类
public class Phone {//属性, 成员变量String brand; //品牌int price;      //价格String color;   //颜色//行为, 成员方法//打电话public void call(String name) {System.out.println("给" + name + "打电话!...");}//发短信public void sendMessage(String name) {System.out.println("给" + name + "发短信!...");}
}//手机类的测试类
public class PhoneTest {public static void main(String[] args) {//1. 创建手机类的对象.Phone p = new Phone();//2. 设置成员变量值.p.brand = "华为";p.price = 6666;p.color = "黑色";//3. 打印成员变量.System.out.println(p.brand + "--" + p.price + "--" + p.color);//4. 调用成员方法.p.call("夯哥");p.sendMessage("夯哥");}
}

内存图解

4.2 两个对象的内存图

代码

//手机类
public class Phone {//属性, 成员变量String brand; //品牌int price;      //价格String color;   //颜色//行为, 成员方法//打电话public void call(String name) {System.out.println("给" + name + "打电话!...");}//发短信public void sendMessage(String name) {System.out.println("给" + name + "发短信!...");}
}//手机类的测试类
public class PhoneTest {public static void main(String[] args) {//1. 创建手机类的对象.Phone p = new Phone();//2. 设置成员变量值.p.brand = "华为";p.price = 6666;p.color = "黑色";//3. 打印成员变量.System.out.println(p.brand + "--" + p.price + "--" + p.color);//4. 调用成员方法.p.call("传智播客");p.sendMessage("传智播客");Phone p2 = new Phone();p2.brand = "小米";p2.price = 3333;p2.color = "白色";System.out.println(p2.brand + "--" + p2.price + "--" + p2.color);p2.call("黑马程序员");p2.sendMessage("黑马程序员");}
}

内存图解

5. 成员变量和局部变量的区别

5.1 简述

• 成员变量: 指的是定义在类中, 方法外的变量.
• 局部变量: 指的是定义在方法中, 或者方法声明上的变量.

它们的区别如下:

  1. 定义位置不同.
      – 成员变量: 定义在类中, 方法外.
      – 局部变量: 定义在方法中, 或者方法声明上.
  2. 在内存中的存储位置不同.
      – 成员变量: 存储在堆内存.
      – 局部变量: 存储在栈内存.
  3. 生命周期不同.
      – 成员变量: 随着对象的创建而存在, 随着对象的消失而消失.
      – 局部变量: 随着方法的调用而存在, 随着方法的调用完毕而消失.
  4. 初始化值不同.
      – 成员变量: 有默认值.
      – 局部变量: 没有默认值, 必须先定义, 再赋值, 然后才能使用.

5.2 代码演示

public class VariableDemo{int x;public void show() {int y = 10;System.out.println(x);System.out.println(y);}
}

6. 封装

上述的代码中, 我们可以任意的设置属性的值, 包括我们可以设置一些非法值, 例如: 把年龄设置成负数, 这样做程序就容易出问题, 针对于这种情况, 我们可以通过private关键字来优化它.

6.1 private关键字

6.1.1 简述

private是一个关键字, 也是访问权限修饰符的一种, 它可以用来修饰类的成员(成员变量和成员方法).

6.1.2 特点

被private修饰的内容只能在本类中直接使用.

6.1.3 应用场景

  1. 在实际开发中, 成员变量基本上都是用private关键字来修饰的.
  2. 如果明确知道类中的某些内容不想被外界直接访问, 都可以通过private来修饰.

6.1.4 示例

需求

  1. 定义学生类Student, 包含姓名, 年龄属性.
  2. 在StudentTest测试类中, 创建Student类的对象, 并调用Student类中的成员.
  3. 对年龄或者姓名属性加private修饰, 然后观察结果.

参考代码

//学生类
public class Student{//属性String name;       //姓名private int age;    //年龄//getXxx()和setXxx()方法public void setAge(int a) {if(a >= 0 && age <= 150) {//年龄合法, 就赋值.age = a;}}public int getAge() {return age;}//行为public void show() {//被private修饰的内容, 可以在本类中直接访问.System.out.println(name + "..." + age);}
}//学生类的测试类
public class StudentTest{public static void main(String[] args) {//1. 创建学生类的对象Student s = new Student();//2. 给成员变量赋值.s.name = "张三";//s.age = -23;      //被private修饰的内容, 外界无法直接访问.s.setAge(-23);//3. 调用成员方法.s.show();}
}

6.2 标准代码

刚才的代码, 为了讲解private关键字, 只给年龄属性加了private, 而在实际开发中, 除非必要, 否则成员变量都要用private来修饰, 然后提供对应的getXxx()和setXxx()方法, 方便用户访问对应的成员变量, 接下来, 我们来写一个实际开发中的标准代码.

需求

  1. 定义一个标准的学生类Student, 属性: 姓名和年龄, 行为: 学习, 吃饭.
  2. 在测试类中创建学生类的对象, 然后访问类中的成员.

参考代码

public class Student {//属性, 全部用private修饰.//姓名private String name;//年龄private int age;public String getName() {return name;}public void setName(String n) {name = n;}public int getAge() {return age;}public void setAge(int a) {age = a;}//行为, 也就是成员方法.public void study() {System.out.println("键盘敲烂, 月薪过万!");}public void eat() {System.out.println("学习饿了就要吃饭!.");}
}//测试类
public class StudentTest {public static void main(String[] args) {//1. 创建学生对象.Student s = new Student();//2. 设置成员变量值.s.setName("张三");s.setAge(23);//3. 打印成员变量值.System.out.println(s.getName() + "..." + s.getAge());//4. 调用成员方法.s.study();s.eat();}
}

6.3 封装的概述和好处

6.3.1 概述

封装是面向对象编程思想的三大特征之一, 所谓的封装指的就是隐藏对象的属性和实现细节, 仅对外提供一个公共的访问方式.

记忆:
== 面向对象的三大特征: 封装, 继承, 多态==.

问题一: 怎么隐藏?
通过private关键字实现.
问题二: 公共的访问方式是什么?
getXxx() 和 setXxx()方法.

6.3.2 原则

  1. 把不需要对外提供的内容都隐藏起来.
  2. 把属性隐藏, 并提供公共方法对其访问.

解释: 就是成员变量都用private修饰, 并提供对应的getXxx()和setXxx()方法, 除此以外, 都用public修饰.

6.3.3 好处

  1. 提高代码的安全性.
    这点是由private关键字来保证的.
  2. 提高代码的复用性.
    这点是由方法来保证的, 方法也是封装的一种体现形式.

6.4 this关键字

6.4.1 概述

this代表本类当前对象的引用, 大白话翻译: 谁调用, this就代表谁.

6.4.2 作用

用来解决局部变量和成员变量重名问题的.

6.4.3 示例

需求

  1. 定义一个标准的学生类Student, 属性: 姓名和年龄, 行为: 学习, 吃饭.
  2. 在测试类中创建学生类的对象, 然后访问类中的成员.

参考代码

public class Student {//属性, 全部用private修饰.//姓名private String name;//年龄private int age;public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;//s.age = 23;}//行为, 也就是成员方法.public void study() {System.out.println("键盘敲烂, 月薪过万!");}public void eat() {System.out.println("学习饿了就要吃饭!.");}
}//测试类
public class StudentTest {public static void main(String[] args) {//1. 创建学生对象.Student s = new Student();//2. 设置成员变量值.s.setName("张三");s.setAge(23);//3. 打印成员变量值.System.out.println(s.getName() + "..." + s.getAge());//4. 调用成员方法.s.study();s.eat();}
}

6.4.4 总结

Java中, 使用变量遵循就近原则, 局部位置有就使用, 没有就去本类的成员位置找, 有就使用, 没有就报错.
解释: 先这么记忆, 不严谨, 因为本类没有, 还会去父类中查找, 这点在继承部分再解释.

6.5 构造方法

6.5.1 概述

构造方法是用来创建对象的, 捎带着可以给对象的各个成员变量赋值.
大白话:
构造方法就是用来快速对对象的各个属性赋值的.

6.5.2 格式

  1. 构造方法名必须和类名完全一致(包括大小写).
  2. 构造方法没有返回值类型, 连void都不能写.
  3. 构造方法没有具体的返回值, 但是可以写return(实际开发, 一般不写).
public 类名(参数类型 参数名1, 参数类型 参数名2) {  //这里可以写多个参数.//给对象的各个属性赋值即可.
}

6.5.3 示例: 构造方法入门

需求

  1. 定义学生类Student, 在类的空参构造中打印一句话"这是构造方法".
  2. 在StudentTest测试类中, 创建学生类的对象, 并观察程序的运行结果.
    小技巧: 创建对象的格式如下:
    类名 对象名 = new 构造方法(参数列表);

参考代码

//学生类.
public class Student{//类的空参构造.public Student() {System.out.println("这是构造方法");}
}//学生类的测试类
public class StudentTest{public static void main(String[] args) {Student s = new Student();}
}

6.5.4 构造方法的注意事项

  1. 如果我们没有给出构造方法, 系统将给出一个默认的无参构造供我们使用.
  2. 如果我们给出了构造方法, 系统将不再提供默认的构造方法给我们使用.
  3. 这个时候, 如果我们还想使用无参构造, 就必须自己提供.
  4. 建议定义类时, 我们给出无参构造, 方便用户调用(实际开发都这么做的).

思考题
问: 给成员变量赋值有几种方式?
答: 1. 通过setXxx()方法实现(该方式不会创建新对象).
2. 通过构造方法实现(该方式会创建新对象).

6.6 标准的类的定义和使用

6.6.1 格式

以后在实际开发中, 也都是这样写的, 即: 标准的类的定义格式如下:

public class 类名{//属性(成员变量), 全部用private修饰.//构造方法, 一般提供两个(无参, 全参)//getXxx()和setXxx()方法//行为(成员方法), 根据需求来定义.
}

6.6.2 示例

需求

  1. 定义一个标准的学生类Student, 属性: 姓名和年龄, 行为: 学习, 吃饭.
  2. 在测试类中创建学生类的对象, 然后访问类中的成员.

参考代码

//学生类
public class Student {//属性(成员变量), 全部用private修饰.private String name;    //姓名private int age;        //年龄//构造方法, 一般提供两个(无参, 全参)public Student() {}public Student(String name, int age) {this.name = name;this.age = age;}//getXxx()和setXxx()方法public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}//行为(成员方法), 根据需求来定义.public void study() {System.out.println("键盘敲烂, 月薪过万!");}public void eat() {System.out.println("学习饿了要吃饭");}
}//学生类的测试类
public class StudentTest {public static void main(String[] args) {//1. 创建学生对象.Student s = new Student();//2. 设置成员变量值.s.setName("张三");s.setAge(23);//3. 打印成员变量值.System.out.println(s.getName() + "..." + s.getAge());//4. 调用成员方法.s.study();s.eat();}
}

7. 继承

7.1 概述

多个类中存在相同属性和行为时, 将这些内容抽取到单独的一个类中, 那么这多个类就无需再定义这些属性和行为了, 只要继承那个类即可. 这个关系, 就叫继承.
注意:
有了继承以后, 我们在定义一个类的时候, 可以在一个已经存在的类的基础上, 还可以定义自己的新成员.

7.2 格式

在Java中, 可以通过extends关键字来实现类与类的继承, 具体格式如下:

public class 类A extends 类B { //子承父业}

解释:
• 类A: 叫子类, 或者派生类.
• 类B: 叫父类, 基类, 或者超类.
我们一般会念做: 子类和父类.

7.3 继承的好处和弊端

7.3.1 示例

需求

  1. 按照标准格式定义一个人类(Person类), 属性为姓名和年龄.
  2. 定义老师类(Teacher), 继承自人类, 并在老师类中定义teach()方法.
  3. 定义学生类(Student), 继承自人类, 并在学生类中定义study()方法.
  4. 在PersonTest测试类的main方法中, 分别创建老师类和学生类的对象, 并调用各自类中的成员.

参考代码

人类代码:

public class Person {//属性private String name;private int age;//构造方法, 如果我们不写, 系统会默认加一个: 空参构造.public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}//行为public void eat() {System.out.println("人要吃饭");}public void sleep() {System.out.println("人要睡觉");}}

老师类代码:

public class Teacher extends Person {//老师类独有的功能: 讲课public void teach() {System.out.println("老师要讲课!");}
}

学生类代码:

public class Student extends Person {//学生类独有的功能: 学习public void study() {System.out.println("好好学习, 天天向上!");}
}

测试类代码

public class PersonTest {public static void main(String[] args) {//1. 测试老师类Teacher t = new Teacher();//属性//从Person类继承.t.setName("刘亦菲");t.setAge(33);System.out.println(t.getName() + "..." + t.getAge());//方法t.eat();        //从Person类继承.t.sleep();      //从Person类继承.t.teach();      //本类的独有功能.//2. 测试学生类, 留给你自己写.}
}

运行结果为:

刘亦菲...33
人要吃饭
人要睡觉
老师要讲课!

7.3.2 好处

  1. 提高了代码的复用性.
  2. 提高了代码的可维护性.
  3. 让类与类之间产生关系, 是多态的前提.

7.3.3 弊端

让类与类之间产生了关系, 也就让类的耦合性增强了.
解释:
开发原则: 高内聚, 低耦合.
• 内聚: 指的是类自己独立完成某些事情的能力.
• 耦合: 指的是类与类之间的关系.

7.4 Java中继承的特点

7.4.1 示例

  1. 定义GrandFather类, 该类有一个grandFatherSay()方法, 该方法打印一句话爷爷都是从孙子过来的.
  2. 定义Father类, 该类有一个fatherSay()方法, 该方法打印一句话爸爸都是从儿子过来的.
  3. 定义Son类, 分别先继承自GrandFather类和Father类, 此时发现, 上述的两个方法只能同时调用一个.
  4. 如果想让Son类的对象, 同时能调用上述的两个方法, 则可以这样做:
    Son类继承自Father类, Father类继承自GrandFather类.

7.4.2 参考代码

//爷爷类,
//一个类如果没有显式的写父类, 默认就继承自Object类.
//Object类, 是所有类的父类.
public class GrandFather {public void grandFather() {System.out.println("grandFather....");}
}
//父亲类
public class Father extends GrandFather{public void father() {System.out.println("father....");}
}
//儿子类
public class Son extends Father {}
//测试类
public class SonTest {public static void main(String[] args) {//创建子类对象.Son s = new Son();//问: Son的对象, 可以调用哪些方法?s.father();         //从Father类继承过来的.s.grandFather();    //从Father类继承过来的, 而Father类又从GrandFather类继承过来了.}
}

7.4.3 总结

  1. Java中类与类之间只能单继承, 不能多继承.
public class 类A extends 类B,类C {  //这种写法会报错.
}
  1. Java中类与类之间, 可以多层继承.
public class A { }public class B extends A{  }public class C extends B{  }       //这种写法可以.

7.5 继承中成员变量的特点

7.5.1 示例

  1. 定义Father类, 在该类的成员位置定义变量: int age = 30;
  2. 定义Son类, 让它继承Father类, 并在该类的成员位置定义变量: int age = 20;
  3. 在测试类FatherTest的main方法中, 定义变量: int age = 10;
  4. 通过输出语句, 直接打印age变量的值, 并查看程序的运行结果.

7.5.2 参考代码

public class Father {int age = 30;
}public class Son extends Father {int age = 20;
}public class FatherTest {public static void main(String[] args) {int age = 10;System.out.println(age);     //这里打印结果会是多少呢? }
}

7.5.3 总结

Java中使用变量遵循就近原则, 局部位置有就使用, 没有就去本类的成员位置找. 有就使用, 没有就去父类的成员位置找, 有就使用, 没有就报错.
注意: 不考虑父类的父类这种情况, 因为会一直往上找, 直到把所有的父类都找完, 还找不到, 就报错了.

7.6 super关键字

7.6.1 概述

super的用法和this很像:
• this: 代表本类对象的引用.
• super: 代表当前对象的父类的内存空间标识.

解释: 可以理解为父类对象引用.

7.6.2 用法

功能 本类 父类
访问成员变量 this.成员变量名 super.成员变量名
访问构造方法 this(…) super(…)
访问成员方法 this.成员方法名(参数值…) super.成员方法名(参数值…)

7.7 方法重写

7.7.1 概述

子类中出现和父类一模一样的方法时, 称为方法重写. 方法重写要求返回值的数据类型也必须一样.

7.7.2 应用场景

当子类需要使用父类的功能, 而功能主体又有自己独有需求的时候, 就可以考虑重写父类中的方法了, 这样, 即沿袭了父类的功能, 又定义了子类特有的内容.

7.7.3 示例

需求

  1. 定义Phone类, 并在类中定义call(String name)方法.
  2. 定义NewPhone类, 继承Phone类, 然后重写call(String name)方法.
  3. 在PhoneTest测试类中, 分别创建两个类的对象, 然后调用call()方法, 观察程序执行结果.

参考代码

手机类

public class Phone {//打电话的功能.public void call(String name) {System.out.println("给" + name + "打电话!...");}
}

新手机类

//定义一个手机类, 表示: 新式手机.
public class NewPhone extends Phone{//重写父类Phone#call()方法, 在打电话的时候, 播放彩铃.@Overridepublic void call(String name) {//因为基本的打电话的功能, 父类已经实现了, 我们可以直接拿来用.//System.out.println("给" + name + "打电话!...");//调用父类的call()方法, 实现打电话功能.super.call(name);//在父类call()方法的功能主体上, 加入自己独有的需求: 播放彩铃System.out.println("播放彩铃...");}
}

测试类

public class PhoneTest {public static void main(String[] args) {//1. 测试 老式手机.Phone p = new Phone();p.call("刘亦菲");System.out.println("----------------");//2. 测试 新式手机NewPhone np = new NewPhone();np.call("赵丽颖");}
}

运行结果为:

给刘亦菲打电话!...
----------------
给赵丽颖打电话!...
播放彩铃...

7.7.4 注意事项

  1. 子类重写父类方法时, 方法声明上要用@Override注解来修饰.
  2. 父类中私有的方法不能被重写.
  3. 子类重写父类方法时, 访问权限不能更低.

8. 多态

8.1 概述

多态指的是同一个事物(或者对象)在不同时刻表现出来的不同状态.
例如: 一杯水.
• 常温下是液体.
• 高温下是气体.
• 低温下是固体.
但是水还是那杯水, 只不过在不同的环境下, 表现出来的状态不同.

8.2 前提条件

  1. 要有继承关系.
  2. 要有方法重写.
  3. 要有父类引用指向子类对象.

8.3 示例: 多态入门

需求

  1. 定义动物类Animal, 并在类中定义一个成员方法: eat()
  2. 定义猫类Cat, 继承Animal类, 并重写eat()方法.
  3. 在AnimalTest测试类的main方法中, 通过多态的方式创建猫类对象.
  4. 通过猫类对象, 调用eat()方法.

参考代码

动物类:

//父类, 动物类
public class Animal {public void eat() {System.out.println("动物要吃");}
}

猫咪类:

//子类, 猫类
public class Cat extends Animal {@Overridepublic void eat() {System.out.println("猫吃鱼!");}public void catchMouse() {System.out.println("猫会抓老鼠!....");}
}

测试类:

public class AnimalTest {public static void main(String[] args) {//1 多态形式的创建猫类对象Animal an = new Cat();//2. 演示多态的弊端.an.eat();               //编译看左 运行看右.//3. 升级功能: 尝试通过多态版的 猫类对象, 调用猫类中独有的 catchMouse()功能.//an.catchMouse();      //这样做不行, 因为an是Animal动物类的引用, 我们不能说  动物会抓老鼠//4. 通过向下转型, 把 多态版的 猫类对象 ->  Cat类型的猫类对象.Cat c = (Cat)an;          //引用类型的: 向下转型,     即: 大 -> 小.c.catchMouse();//int a = (int)10.3;        基本类型的: 强制类型转换, 即: 大 -> 小.}
}

运行结果为:

猫吃鱼!
猫会抓老鼠!....

8.4 多态中的成员访问特点

• 成员变量: 编译看左边, 运行看左边.
• 成员方法: 编译看左边, 运行看右边.

需求

  1. 定义一个人类Person. 属性为姓名和年龄, 行为是: eat()方法.
  2. 定义Student类, 继承自Person类, 定义age属性及重写eat()方法.
  3. 在PersonTest测试类的main方法中, 创建Student类的对象, 并打印其成员.

参考代码
人类:

public class Person {//属性String name = "刘亦菲";int age = 50;//行为public void eat() {System.out.println("人要吃饭!");}
}

学生类:

//子类, 学生类
public class Student extends Person{int age = 30;@Overridepublic void eat() {System.out.println("学生吃牛肉!");}
}

测试类:

public class PersonTest {public static void main(String[] args) {//1. 通过多态, 创建学生类对象.Person p = new Student();//2. 调用成员变量.System.out.println(p.age);      //50//3. 调用成员方法.p.eat();                        //1学生吃牛肉}
}

运行结果为:

50
学生吃牛肉!

8.5 好处和弊端.

8.5.1 好处

提高了程序的扩展性.

8.5.2 弊端

父类引用不能访问子类的特有功能.
问: 那如何解决这个问题呢?
答: 通过向下转型来解决这个问题.

8.5.3 示例

需求

  1. 定义动物类Animal, 该类有一个eat()方法.
  2. 定义猫类Cat, 继承自Animal类, 该类有一个自己独有的方法: catchMouse().
  3. 在AnimalTest测试类中, 通过多态的方式创建Cat类的对象, 并尝试调用catchMouse()方法.

参考代码

动物类:

//父类, 动物类
public class Animal {public void eat() {System.out.println("动物要吃");}
}

猫咪类:

//子类, 猫类
public class Cat extends Animal {@Overridepublic void eat() {System.out.println("猫吃鱼!");}public void catchMouse() {System.out.println("猫会抓老鼠!....");}
}

测试类:

public class AnimalTest {public static void main(String[] args) {//1 多态形式的创建猫类对象Animal an = new Cat();//2. 演示多态的弊端.an.eat();               //编译看左 运行看右.//3. 升级功能: 尝试通过多态版的 猫类对象, 调用猫类中独有的 catchMouse()功能.//an.catchMouse();      //这样做不行, 因为an是Animal动物类的引用, 我们不能说  动物会抓老鼠//4. 通过向下转型, 把 多态版的 猫类对象 ->  Cat类型的猫类对象.Cat c = (Cat)an;          //引用类型的: 向下转型,     即: 大 -> 小.c.catchMouse();//int a = (int)10.3;        基本类型的: 强制类型转换, 即: 大 -> 小.}
}

8.5.4 向上转型和向下转型

向上转型

//格式
父类型 对象名 = new 子类型();//例如
Animal an = new Cat();

向下转型

//格式
子类型 对象名 = (子类型)父类引用;//例如
Cat c = (Cat)an;

小Bug

//下述代码会报: ClassCastException(类型转换异常)
Animal an = new Cat();
Cat c = (Cat)an;       //这样写不报错.
Dog d = (Dog)an;       //这样写会报错.

8.6 示例: 猫狗案例

需求

  1. 已知猫狗都有姓名和年龄, 都要吃饭.
  2. 猫类独有自己的catchMouse()方法, 狗类独有自己的lookHome()方法.
  3. 在AnimalTest测试类的main方法中, 通过多态分别创建猫类, 狗类的对象.
  4. 分别通过猫类对象和狗类对象, 访问对象的成员.

参考代码
动物类:

//父类, 动物类.
public class Animal {private  String name;public String getName() {return name;}public void setName(String name) {this.name = name;}
}

猫咪类:

//子类, 猫.
public class Cat extends Animal {}

狗狗类:

//子类, 狗.
public class Dog extends Animal {}

测试类:

public class AnimalTest {public static void main(String[] args) {//1. 多态的形式创建, 猫类对象.Animal an = new Cat();          //向上转型.//Animal an2 = new Dog();      //向上转型.//2. 向下转型.Cat c = (Cat)an;      //这样写不报错.//细节: 编译期间只检查语法问题, 所以下边这样代码在编译期间不会报错.
//        Dog d = (Dog) an;       //这样写报错, ClassCastException, 类型转换异常.}
}

9. 两个关键字

9.1 final关键字

9.1.1 概述

final是一个关键字, 表示最终的意思, 可以修饰类, 成员变量, 成员方法.
• 修饰的类: 不能被继承, 但是可以继承其他的类.
• 修饰的变量: 是一个常量, 只能被赋值一次.
• 修饰的方法: 不能被子类重写.

9.1.2 示例

需求

  1. 定义Father类, 并定义它的子类Son.
  2. 先用final修饰Father类, 看Son类是否还能继承Father类.
  3. 在Son类中定义成员变量age, 并用final修饰, 然后尝试给其重新赋值, 并观察结果.
  4. 在Father类中定义show()方法, 然后用final修饰, 看Son类是否能重写该方法.

参考代码

父亲类:

public class Father {//int age = 20;    //变量final int AGE = 20;    //自定义常量String name;        //变量public void show() {System.out.println("这个是绝密文件, 不能动!");}
}

儿子类:

//子类
public class Son extends Father {@Overridepublic void show() {System.out.println("这个是垃圾文件, 赶紧删除!");}
}

测试类:

public class FatherTest {public static void main(String[] args) {Father f = new Father();//f.age = 25;   常量只能赋值一次, 不能重复赋值.System.out.println(f.AGE);System.out.println("------------------");Son s = new Son();s.show();}
}

运行结果为:

20
------------------
这个是垃圾文件, 赶紧删除!

9.2 static关键字

9.2.1 概述

static是一个关键字, 表示静态的意思, 可以修饰成员变量, 成员方法.

9.2.2 特点

  1. 随着类的加载而加载.
  2. 优先于对象存在.
  3. 被static修饰的内容, 能被该类下所有的对象共享.
    解释: 这也是我们判断是否使用静态关键字的条件.
  4. 可以通过类名.的形式调用.

9.2.3 示例

需求

  1. 定义学生类, 属性为姓名, 年龄, 毕业院校(graduateFrom).
  2. 在学生类中定义show()方法, 用来打印上述的各个属性信息.
  3. 在测试类的main方法中, 创建学生对象, 并调用学生类的各个成员.

参考代码

//学生类
public class Student {//属性String name;int age;static String graduateFrom;//行为public void show() {System.out.println(name + ".." + age + ".." + graduateFrom);}
}//测试类
public class StudentTest {public static void main(String[] args) {//1. 设置学生的毕业院校.Student.graduateFrom = "传智学院";//2. 创建学生对象s1.Student s1 = new Student();s1.name = "刘亦菲";s1.age = 33;//3. 创建学生对象s2.Student s2 = new Student();s2.name = "赵丽颖";s2.age = 31;//4. 打印属性值.s1.show();s2.show();}
}

9.2.4 静态方法的访问特点及注意事项

• 访问特点
静态方法只能访问静态的成员变量和静态的成员方法.
简单记忆: 静态只能访问静态.
• 注意事项

  1. 在静态方法中, 是没有this, super关键字的.
  2. 因为静态的内容是随着类的加载而加载, 而this和super是随着对象的创建而存在.
    即: 先进内存的, 不能访问后进内存的.

需求

  1. 定义学生类, 属性为姓名和年龄(静态修饰), 非静态方法show1(),show2(), 静态方法show3(), show4().
  2. 尝试在show1()方法中, 调用: 姓名, 年龄, show2(), show4().
    结论: 非静态方法可以访问所有成员(非静态变量和方法, 静态变量和方法)
  3. 尝试在show3()方法中, 调用: 姓名, 年龄, show2(), show4().
    结论: 静态方法只能访问静态成员.

参考代码

public class Student {String name = "刘亦菲";        //非静态成员变量static int age = 33;           //静态的成员变量public void show1() {System.out.println(name);System.out.println(age);//this.show2();         标准写法show2();//Student.show3();      标准写法show3();                //因为是访问本类的静态成员方法, 所以可以省略类名不写.show4();System.out.println("show1方法  非静态方法");}public void show2() {System.out.println("show2方法  非静态方法");}public static void show3() {//System.out.println(name);       //非静态成员变量System.out.println(age);         //静态成员变量//this.show2();                   //非静态方法Student.show4();                //静态方法System.out.println("show3方法  静态方法");}public static void show4() {System.out.println("show4方法  静态方法");}
}

测试类:

public class StudentTest {public static void main(String[] args) {Student s = new Student();//s.show1();  //结论: 非静态方法可以访问所有成员(非静态变量和方法, 静态变量和方法)//s.show3();    这样写不报错, 只是不推荐.Student.show3();    //静态方法只能访问静态成员}
}

运行结果为:

33
show4方法  静态方法
show3方法  静态方法

10. 抽象类

10.1 概述

回想前面我们的猫狗案例, 提取出了一个动物类, 这个时候我们可以通过Animal an = new Animal();来创建动物对象, 其实这是不对的, 因为, 我说动物, 你知道我说的是什么动物吗? 只有看到了具体的动物, 你才知道, 这是什么动物. 所以说, 动物本身并不是一个具体的事物, 而是一个抽象的事物. 只有真正的猫, 狗才是具体的动物. 同理, 我们也可以推想, 不同的动物吃的东西应该是不一样的, 所以, 我们不应该在动物类中给出具体的体现, 而是应该给出一个声明即可. 在Java中, 一个没有方法体的方法应该定义为抽象方法, 而类中如果有抽象方法, 该类必须定义为抽象类

10.2 入门案例

需求

  1. 创建抽象类Animal.
  2. 在该类中定义抽象方法eat()

参考代码

//抽象的动物类.
public abstract class Animal {//抽象方法, 吃.public abstract void eat();
}

10.3 抽象类的特点

  1. 抽象类和抽象方法必须用abstract关键字修饰.
//抽象类
public abstract class 类名{ }//抽象方法
public abstract void eat();
  1. 抽象类中不一定有抽象方法, 有抽象方法的类一定是抽象类.
  2. 抽象类不能实例化.
    – 那抽象类如何实例化呢?
    – 可以通过多态的方式, 创建其子类对象, 来完成抽象类的实例化. 这也叫: 抽象类多态.
  3. 抽象类的子类:
  • 如果是普通类, 则必须重写父抽象类中所有的抽象方法.
  • 如果是抽象类, 则可以不用重写父抽象类中的抽象方法.

需求

  1. 定义抽象类Animal , 类中有一个抽象方法eat(), 还有一个非抽象方法sleep().
  2. 尝试在测试类中, 创建Animal类的对象, 并观察结果.
  3. 创建普通类Cat, 继承Animal类, 观察是否需要重写Animal#eat()方法.

参考代码
动物类:

//父类, 动物类
public abstract class Animal {//1.类中有一个抽象方法eat(), 还有一个非抽象方法sleep().public abstract void eat();public void sleep() {System.out.println("动物要睡!");}
}

猫咪类:

public class Cat extends Animal{@Overridepublic void eat() {System.out.println("猫吃鱼!");}
}

测试类:

public class AnimalTest {public static void main(String[] args) {//1. 演示: 抽象类不能实例化.//Animal an = new Animal();   这样写会报错.//2. 抽象类可以通过创建其子类对象的形式, 来完成抽象类的初始化.//抽象类多态Animal an = new Cat();}
}

10.4 抽象类的成员特点

抽象类中可以有变量, 常量, 构造方法, 抽象方法和非抽象方法.
思考: 既然抽象类不能实例化, 那要构造方法有什么用?
答: 用于子类对象访问父类数据前, 对父类数据进行初始化.

需求

  1. 定义抽象类Person, 在类中定义变量age, 常量country, 空参, 全参构造.
  2. 在Person类中定义非抽象方法show(), 抽象方法eat().
  3. 在测试类的main方法中, 创建Person类的对象, 并调用类中的成员.

参考代码

人类:

public abstract class Person {//变量int age;                            //年龄//常量static final String COUNTRY = "中国";     //国籍//构造方法public Person() {}public Person(int age) {this.age = age;}//getXxx(), setXxx()//成员方法,public void show() {System.out.println("show方法  非抽象方法");}//抽象方法, 强制要求子类必须完成某些事情public abstract void eat();
}

学生类:

//学生类
public class Student extends Person {public Student() {super();}public Student(int age) {super(age);}@Overridepublic void eat() {System.out.println("学生吃牛肉!...");}
}

测试类:

public class PersonTest {public static void main(String[] args) {//1. 创建Person类型的对象.//只能通过 抽象类多态的形式 实现.Person p = new Student();//2. 调用其成员.System.out.println(p.age);System.out.println(p.COUNTRY);System.out.println(Person.COUNTRY);p.show();p.eat();}
}

运行结果为:

0
中国
中国
show方法  非抽象方法
学生吃牛肉!...

10.5 案例: 老师类

10.5.1 需求

  1. 传智播客公司有基础班老师(BasicTeacher)和就业班老师(WorkTeacher), 他们都有姓名和年龄, 都要讲课.
  2. 不同的是, 基础班老师讲JavaSE, 就业班老师讲解JavaEE.
  3. 请用所学, 模拟该知识点.

10.5.2 分析

  1. 定义父类Teacher, 属性: 姓名和年龄, 行为: 讲课(因为不同老师讲课内容不同, 所以该方法是抽象的).
  2. 定义BasicTeacher(基础班老师), 继承Teacher, 重写所有的抽象方法.
  3. 定义WorkTeacher(就业班老师), 继承Teacher, 重写所有的抽象方法.
  4. 定义TeacherTest测试类, 分别测试基础班老师和就业班老师的成员.

10.5.3 参考代码

老师类:

//父类, 表示老师类.
public abstract class Teacher {//属性.private String name;private int age;//构造方法public Teacher() {}public Teacher(String name, int age) {this.name = name;this.age = age;}//getXxx(), setXxx()public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}//行为//抽象方法, 讲课.public abstract void teach();
}

基础班类:

//子类, 基础班老师
public class BasicTeacher extends Teacher{//构造方法public BasicTeacher() {}public BasicTeacher(String name, int age) {super(name, age);}//重写Teacher#teach()@Overridepublic void teach() {System.out.println("基础班老师讲: JavaSE");}
}

就业班类:

//子类, 就业班老师
public class WorkTeacher extends Teacher{//构造方法public WorkTeacher() {}public WorkTeacher(String name, int age) {super(name, age);}//重写Teacher#teach()@Overridepublic void teach() {System.out.println("就业班老师讲: JavaEE, Linux, Hadoop...");}
}

测试类:

//案例: 演示抽象类版的 老师类案例.
public class TeacherTest {public static void main(String[] args) {//1. 测试基础班老师, 空参.//抽象类多态版Teacher t1 = new BasicTeacher();//BasicTeacher t1 = new BasicTeacher();t1.setName("刘亦菲");t1.setAge(33);System.out.println(t1.getName() + "..." + t1.getAge());t1.teach();System.out.println("---------------------");//2. 测试基础班老师, 全参.Teacher t2 = new BasicTeacher();t2.setName("赵丽颖");t2.setAge(31);System.out.println(t2.getName() + "..." + t2.getAge());t2.teach();//3. 测试就业班老师, 空参, 自己做.//4. 测试就业班老师, 全参.}
}

运行结果为:

刘亦菲...33
基础班老师讲: JavaSE
---------------------
赵丽颖...31
基础班老师讲: JavaSE

11. 接口

11.1 概述

继续回到我们的猫狗案例,我们想想狗一般就是看门,猫一般就是作为宠物了。但是,现在有很多的驯养员或者是驯兽师,可以训练出:猫钻火圈,狗跳高,狗做计算等。而这些额外的动作,并不是所有猫或者狗一开始就具备的,这应该属于经过特殊的培训训练出来的。所以,这些额外的动作定义到动物类中就不合适,也不适合直接定义到猫或者狗中,因为只有部分猫狗具备这些功能。
所以,为了体现事物功能的扩展性,Java中就提供了接口来定义这些额外功能,并不给出具体实现,将来哪些猫狗需要被训练,只需要这部分猫狗把这些额外功能实现即可。

11.2 特点

  1. 接口用interface关键字修饰.
  2. 类和接口之间是实现关系, 用implements关键字表示.
  3. 接口不能实例化.
    – 那接口如何实例化呢?
    – 可以通过多态的方式, 创建其子类对象, 来完成接口的实例化. 这也叫: 接口多态.
  4. 接口的子类:
  • 如果是普通类, 则必须重写父接口中所有的抽象方法.
  • 如果是抽象类, 则可以不用重写父接口中的抽象方法.

需求

  1. 定义Jumpping接口, 接口中有一个抽象方法jump().
  2. 定义Cat类, 实现Jumpping接口, 重写jump()方法.
  3. 在测试类的main方法中, 创建Jumpping接口对象, 并调用其jump()方法

接口:

//定义Jumpping接口, 表示: 跳高的功能
public interface Jumpping {//定义jump方法, 表示跳高.public abstract void jump();
}

猫咪类:

public class Cat implements Jumpping {public void catchMouse() {System.out.println("猫会抓老鼠!");}@Overridepublic void jump() {System.out.println("猫会跳高");}
}

测试类:

public class CatTest {public static void main(String[] args) {//1. 创建猫类对象.Cat c = new Cat();//2. 调用猫类中的功能.c.catchMouse();c.jump();       //这个方法, 是Cat从Jumpping接口中继承过来的.System.out.println("------------------");//3. 测试接口多态Jumpping jp = new Cat();jp.jump();//向下转型Cat c2 = (Cat)jp;c2.catchMouse();}
}

运行结果为:

猫会抓老鼠!
猫会跳高
------------------
猫会跳高
猫会抓老鼠!

11.3 成员特点

接口中有且只能有常量或者抽象方法, 原因是因为:
• 成员变量有默认修饰符: public static final
• 成员方法有默认修饰符: public abstract
注意: 因为接口主要是扩展功能的, 而没有具体存在, 所有接口中是没有构造方法的.
记忆: JDK1.8的时候, 接口中加入了两个新的成员: 静态方法, 默认方法(必须用default修饰).

需求
定义接口Inter, 测试接口中的成员特点.
参考代码

接口类:

public interface Inter {//变量的默认修饰符: public static finalpublic static final  int age = 20;//方法的默认修饰符: public abstractpublic abstract void show();//尝试编写接口中的构造方法(这样写会报错, 因为接口中没有构造方法)//public Inter(){}//以下是JDK1.8的新特性: 接口中加入了静态方法和默认方法.public static void method() {System.out.println("我是JDK1.8的新特性: 接口中可以写静态方法");}public default void method2() {System.out.println("我是JDK1.8的新特性: 接口中可以写默认方法");}
}

测试类:

public class InterTest {public static void main(String[] args) {//1. 测试接口中的成员变量 ->  其实是一个常量//Inter.age = 50;System.out.println(Inter.age);}
}

运行结果为:

20

11.4 类与接口之间的关系

• 类与类之间: 继承关系, 只能单继承, 不能多继承, 但是可以多层继承.
• 类与接口之间: 实现关系, 可以单实现, 也可以多实现. 还可以在继承一个类的同时实现多个接口.
• 接口与接口之间: 继承关系, 可以单继承, 也可以多继承.

12. 运动员和教练案例

12.1 需求

  1. 已知有乒乓球运动员(PingPangPlayer)和篮球运动员(BasketballPlayer), 乒乓球教练(PingPangCoach)和篮球教练(BasketballCoach).
  2. 他们都有姓名和年龄, 都要吃饭, 但是吃的东西不同.
  3. 乒乓球教练教如何发球, 篮球教练教如何运球和投篮.
  4. 乒乓球运动员学习如何发球, 篮球运动员学习如何运球和投篮.
  5. 为了出国交流, 跟乒乓球相关的人员都需要学习英语.
  6. 请用所学, 模拟该知识.

12.2 代码:

人类:

//父类, 人类
public abstract class Person {//属性, 姓名, 年龄.private String name;private int age;public Person() {}public Person(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}//行为: 抽象方法eat()public abstract void eat();
}

教练类:

//Person类的子类, 表示教练类
public abstract class Coach extends Person{//构造方法public Coach() {}public Coach(String name, int age) {super(name, age);}//自身的方法: teach()public abstract void teach();
}

球员类:

//Person类的子类, 表示运动员类
public abstract class Player extends Person{//构造方法public Player() {}public Player(String name, int age) {super(name, age);}//自身的方法: study()public abstract void study();
}

说英语接口:

//定义接口, 表示: 说英语的功能
public interface SpeakEnglish {void speak();
}

篮球教练类:

//定义类, 表示篮球教练
public class BasketballCoach extends Coach{//构造方法public BasketballCoach() {}public BasketballCoach(String name, int age) {super(name, age);}//重写父类的抽象方法.@Overridepublic void teach() {System.out.println("篮球教练教如何运球和投篮");}@Overridepublic void eat() {System.out.println("篮球教练吃牛肉, 喝牛奶");}
}

篮球球员类:

//篮球运动员
public class BasketballPlayer extends Player{//构造方法public BasketballPlayer() {}public BasketballPlayer(String name, int age) {super(name, age);}//重写父类的抽象方法@Overridepublic void study() {System.out.println("篮球运动员学习如何运球和投篮");}@Overridepublic void eat() {System.out.println("篮球运动员吃羊肉, 喝羊奶");}
}

乒乓球教练类:

//定义乒乓球教练类
public class PingPangCoach extends Coach implements SpeakEnglish {//构造方法public PingPangCoach() {}public PingPangCoach(String name, int age) {super(name, age);}//重写父类(接口)的所有抽象方法@Overridepublic void teach() {System.out.println("乒乓球教练教如何发球");}@Overridepublic void eat() {System.out.println("乒乓球教练吃大白菜, 喝小米粥");}@Overridepublic void speak() {System.out.println("乒乓球教练需要学习英语");}
}

乒乓球球员类:

//定义类, 表示乒乓球运动员
public class PingPangPlayer extends Player implements SpeakEnglish {//构造方法public PingPangPlayer() {}public PingPangPlayer(String name, int age) {super(name, age);}//重写父类(接口)的所有的抽象方法@Overridepublic void study() {System.out.println("乒乓球运动员学习如何发球");}@Overridepublic void eat() {System.out.println("乒乓球运动员吃小白菜, 喝大米粥");}@Overridepublic void speak() {System.out.println("乒乓球运动员需要学习英语!");}
}

测试类:

//案例: 运动员和教练类案例,   该类是一个测试类
public class PersonTest {public static void main(String[] args) {//1. 测试乒乓球运动员.//接口多态//SpeakEnglish se = new PingPangPlayer("马龙", 31);//抽象类多态//Person p = new PingPangPlayer("马龙", 31);//Player p2 = new PingPangPlayer("马龙", 31);//标准写法PingPangPlayer p1 = new PingPangPlayer("马龙", 31);//打印属性值.System.out.println(p1.getName() + "..." + p1.getAge());//调用方法p1.eat();p1.study();p1.speak();System.out.println("----------------------------");//2. 测试乒乓球教练.PingPangCoach p2 = new PingPangCoach("刘国梁", 45);//打印属性值.System.out.println(p2.getName() + "..." + p2.getAge());//调用方法p2.eat();p2.teach();p2.speak();//3. 测试篮球运动员.//4. 测试篮球教练.}
}

运行结果为:

马龙...31
乒乓球运动员吃小白菜, 喝大米粥
乒乓球运动员学习如何发球
乒乓球运动员需要学习英语!
----------------------------
刘国梁...45
乒乓球教练吃大白菜, 喝小米粥
乒乓球教练教如何发球
乒乓球教练需要学习英语

13. 包

13.1 简述层

包(package)就是文件夹, 用来对类进行分类管理的. 例如:
• 学生的增加, 删除, 修改, 查询.
• 老师的增加, 删除, 修改, 查询.
• 其他类的增删改查…
• 基本的划分: 按照模块和功能划分.
• 高级的划分: 就业班做项目的时候你就能看到了.

13.2 格式

package 包名1.包名2.包名3; //多级包之间用.隔开

注意:

  1. package语句必须是程序的第一条可执行的代码.
  2. package语句在一个.java文件中只能有一个.

13.3 常见分类

• 按照功能分
 – com.itheima.add
  • AddStudent.java
  • AddTeacher.java
 – com.itheima.delete
  • DeleteStudent.java
  • DeleteTeacher.java
• 按照模块分
 – com.itheima.student
  • AddStudent
  • DeleteStudent
 – com.itheima.teacher
  • AddTeacher
  • DeleteTeacher

13.4 导包

13.4.1 概述

不同包下的类之间的访问,我们发现,每次使用不同包下的类的时候,都需要加包的全路径。比较麻烦。这个时候,java就提供了导包的功能。

13.4.2 格式

import 包名;
  1. import java.util.*; 意思是导入java.util包下所有类, 这样做效率较低, 不推荐使用.
  2. import java.util.Scanner; 意思是导入java.util.Scanner类, 推荐使用. 用谁就导入谁.

14. 权限修饰符

14.1 概述

权限修饰符是用来修饰类, 成员变量, 构造方法, 成员方法的, 不同的权限修饰符对应的功能不同. 具体如下:

public protected 默认 private
同一个类中
同一个包中的子类或者其他类
不同包中的子类
不同包中的其他类(无关类)

14.2 示例

需求

  1. 在com.itheima包下定义Father类, 该类中有四个方法, 分别是show1(), show2(), show3(), show4().
  2. 上述的四个方法分别用权限修饰符private, 默认, protected, public修饰.
  3. 在Father类中, 创建main方法, 然后创建Father类的对象, 并调用上述的4个方法, 并观察结果.
  4. 在com.itheima包下创建Test类及main方法, 然后创建Father类的对象, 并调用上述的4个方法, 并观察结果.
  5. 在com.itheima包下创建Father类的子类Son, 添加main方法.
  6. 在main方法中, 创建Son类的对象, 并调用上述的4个方法, 并观察结果.
  7. 在cn.itcast包下创建Father类的子类Son, 然后在该类中添加main方法.
  8. 在main方法中, 创建Son类的对象, 并调用上述的4个方法, 并观察结果.
  9. 在cn.itcast包下创建Test类及main方法, 然后创建Father类的对象, 并调用上述的4个方法, 并观察结果.

参考代码

father类:

public class Father {private void show1() {System.out.println("Father show1方法, private 修饰");}void show2() {System.out.println("Father show2方法, 默认权限修饰符 修饰");}protected void show3() {System.out.println("Father show3方法, protected 修饰");}public void show4() {System.out.println("Father show4方法, public 修饰");}public static void main(String[] args) {//1. 创建Father对象.Father f = new Father();//2. 尝试调用Father类中的方法.f.show1();f.show2();f.show3();f.show4();}
}

son类:

//和Father的关系: 同包下的子类
public class Son extends Father {public static void main(String[] args) {//1. 创建Father对象.Father f = new Father();//2. 尝试调用Father类中的方法.//f.show1();f.show2();f.show3();f.show4();System.out.println("------------------------------");Son s = new Son();//s.show1();s.show2();s.show3();s.show4();}
}

测试类:

public class Test {public static void main(String[] args) {//1. 创建Father对象.Father f = new Father();//2. 尝试调用Father类中的方法.//f.show1();f.show2();f.show3();f.show4();}
}

运行结果为:

Father show2方法, 默认权限修饰符 修饰
Father show3方法, protected 修饰
Father show4方法, public 修饰

14.3 总结

  1. 访问权限修饰符的权限从大到小分别是: public > protected > 默认 > private
  2. 在实际开发中, 如果没有特殊需求, 则成员变量都用private修饰, 其它都用public修饰.
  3. 大白话总结四个访问权限修饰符的作用:
      1. private: 强调的是给自己使用.
      2. 默认: 强调的是给同包下的类使用.
      3. protected: 强调的是给子类使用.
      4. public: 强调的是给大家使用.

15. 作业

  1. 定义手机类Phone, 属性和行为如下, 并在测试类PhoneTest中, 创建手机类的对象, 然后访问类中的成员.
    属性:
    品牌: brand
    价格: price
    颜色: color
    行为:
    打电话: call(String name) //该方法接收一个"姓名"参数, 输出格式为: 给张三打电话…
    发短信: sendMessage(String name) //该方法接收一个"姓名"参数, 输出格式为: 给张三发短信…

代码:
手机类:

public class Phone {// 属性.成员变量// 手机品牌String brand;// 价格int price;// 颜色String color;public Phone() {}public Phone(String brand, int price, String color) {this.brand = brand;this.price = price;this.color = color;}public String getBrand() {return brand;}public void setBrand(String brand) {this.brand = brand;}public int getPrice() {return price;}public void setPrice(int price) {this.price = price;}public String getColor() {return color;}public void setColor(String color) {this.color = color;}//行为,成员方法//打电话public void call(String name) {System.out.println("给" + name + "打电话!");}// 发短信public void sendMessage(String name) {System.out.println("给" + name + "发短信!!");}
}

测试类:

public class PhoneTest {public static void main(String[] args) {// 创建手机类的对象Phone p = new Phone();// 设置变量值p.brand = "华为";p.price = 5999;p.color = "曜石黑";// 打印成员变量System.out.println(p.brand);System.out.println(p.price);System.out.println(p.color);// 调用方法p.call("落空空");p.sendMessage("落空空");}
}

运行结果为:

华为
5999
曜石黑
给落空空打电话!
给落空空发短信!!
  1. 定义老师类Teacher, 属性和行为如下, 并在测试类TeacherTest中, 创建老师类的对象, 然后访问类中的成员.
    属性:
    姓名: name
    年龄: age
    讲课内容: content
    行为:
    吃饭: eat()
    讲课: teach()

老师类:

public class Teacher {private String name;private int age;private String content;public Teacher() {}public Teacher(String name, int age, String content) {this.name = name;this.age = age;this.content = content;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String getContent() {return content;}public void setContent(String content) {this.content = content;}// 行为方法// 吃饭public void eat(){System.out.println("年龄为" + age + "的" + name + "正在吃饭");}// 讲课public void teach(){System.out.println("年龄为" + age + "的" + name + "正在讲" + content);}}

测试类:

public class TeacherTest {public static void main(String[] args) {Teacher teacher = new Teacher("刘老师",32,"java");// 打印行为teacher.eat();teacher.teach();}
}

运行结果为:

年龄为32的刘老师正在吃饭
年龄为32的刘老师正在讲java
  1. 定义项目经理类Manager, 属性和行为如下, 并在测试类ManagerTest中, 创建项目经理类的对象, 然后访问类中的成员.
    属性:
    姓名: name
    工号: id
    工资: salary
    奖金: bonus
    行为:
    工作: work()

经理类:

public class Manager {private String name;private  int id;private  int salary;private  int bonus;public Manager() {}public Manager(String name, int id, int salary, int bonus) {this.name = name;this.id = id;this.salary = salary;this.bonus = bonus;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getId() {return id;}public void setId(int id) {this.id = id;}public int getSalary() {return salary;}public void setSalary(int salary) {this.salary = salary;}public int getBonus() {return bonus;}public void setBonus(int bonus) {this.bonus = bonus;}// 行为public void work(){System.out.println("工号为" + id + ",基本工资为" + salary + ",奖金为" + bonus + "的项目经理" + name + "正在努力工作!!!");}
}

测试类:

public class ManagerTest {public static void main(String[] args) {Manager m1 = new Manager();m1.setId(123);m1.setSalary(16666);m1.setBonus(6666);m1.setName("张三");m1.work();Manager m2 = new Manager("李四",124,12345,1234);m2.work();}
}

运行结果为:

工号为123,基本工资为16666,奖金为6666的项目经理张三正在努力工作!!!
工号为124,基本工资为12345,奖金为1234的项目经理李四正在努力工作!!!

Java基础教程-05-面向对象相关推荐

  1. Java基础教程:面向对象编程[2]

    Java基础教程:面向对象编程[2] 内容大纲 访问修饰符 四种访问修饰符 Java中,可以使用访问控制符来保护对类.变量.方法和构造方法的访问.Java 支持 4 种不同的访问权限. default ...

  2. Java基础教程(4)--面向对象概念

      如果你之前从来没有使用过面向对象编程语言,那么在学习Java之前需要先理解几个有关面向对象编程的基本概念.这篇教程将会向你介绍对象.类.集成.接口和包的概念,以及这些概念是如何与现实世界相关联,并 ...

  3. java基础教程05讲:什么是java分隔符

    java语言种的分隔符 分号:.花括号{}.方括号[].圆括号().空格.圆点..都具有分隔的作用,被统称为分隔符. 分号java语言里对语句的分隔不是使用回车来完成的,java语言使用分号作为语句的 ...

  4. Java基础教程-刘刚-专题视频课程

    Java基础教程-2704人已学习 课程介绍         Java基础教程是一套入门Java开发语言的课程,它是由浅入深的介绍Java基础内容,包括Java介绍.基本类型及运算符.控制执行流程.字 ...

  5. java基础教程(一)

    Java 开发环境配置 在进行Java开发之前,需要先安装Java开发工具包(JDK)和集成开发环境(IDE).以下是Java开发环境的配置和搭建步骤: 下载JDK:访问Oracle官方网站,选择适合 ...

  6. Java基础教程:反射基础

    Java基础教程:反射基础 引入反射 反射是什么 能够动态分析类能力的程序称为反射. 反射是一种很强大且复杂的机制. Class类 在程序运行期间,Java运行时系统始终为所有对象维护一个被称为运行时 ...

  7. Java基础教程:多线程基础(3)——阻塞队列

    Java基础教程:多线程基础(3)--阻塞队列 快速开始 引入问题 生产者消费者问题是线程模型中的经典问题:生产者和消费者在同一时间段内共用同一存储空间,生产者向空间里生产数据,而消费者取走数据. 模 ...

  8. python中delete怎么用_python删除np.deletePython基础教程05 - 缩进和选择

    缩进 Python最具特色的是用缩进来标明成块的代码.我下面以if选择结构来举例.if后面跟随条件,如果条件成立,则执行归属于if的一个代码块. 先看C语言的表达方式(注意,这是C,不是Python! ...

  9. Java基础教程(12)--深入理解类

    一.方法的返回值   当我们在程序中调用方法时,虚拟机将会跳转到对应的方法中去执行.当以下几种情况发生时,虚拟机将会回到调用方法的语句并继续向下执行: 执行完方法中所有的语句: 遇到return语句: ...

最新文章

  1. 如何找出应用程序未使用绑定变量
  2. App Store 状态列表
  3. mysql 8.0 自定义函数_PHP+Mysql防止SQL注入的方法(life)
  4. android 直播 app下载地址,蓝泡泡直播
  5. Spring动态注入泛型集合Bean
  6. vim下更省心地用中文
  7. vivo X30新细节曝光:搭载潜望式超远摄支持双模5G
  8. 【带着canvas去流浪(5)】绘制K线图
  9. 又拍云沈志华:如何打造一款安全的App
  10. Python ini文件读取(configparser模块)(转载)
  11. 网络工程师考试第一节计算机硬件基础
  12. 【无机纳米材料科研制图——OriginLab 0208】Origin拟合SERS拉曼光谱
  13. 电脑蓝屏,问题:你的电脑未正确启动,按“重启”以重启你的电脑,有时这样可以解决问题,你还可以按“高级选项”,尝试使用其他选项修复你的电脑
  14. GNSS原理及技术(一)——GNSS现状与发展
  15. 手机怎么解决同ip多账号_游戏工作室如何实现手游多开多窗口多IP
  16. 解决MATLAB的simulink仿真Scop窗口曲线显示不全只显示部分曲线的问题
  17. linux 二次封装 释放,Linux必学的60个命令(二)
  18. Linux 上最好的 9 个免费视频编辑软件(2018) | Linux 中国
  19. CoBOT检测出AI开源框架TensorFlow中的缺陷
  20. GO + React + Axios Response to preflight request doesn't pass access control check: It does not hav

热门文章

  1. 数据分析(二) - Excel按一个单元格内的分隔符进行分行
  2. AI中分类算法与聚类算法
  3. 2020,前端主流框架和主题,以及下一个十年的技术趋势
  4. Python3爬虫实战一之爬取网易云音乐热评
  5. 初始化器 java_来说说Java中的实例初始化器
  6. WFG测试函数的matlab版本
  7. 怎么才能混过人脸验证?这些你居然还不知道
  8. 概率统计笔记:用python实现贝叶斯回归
  9. 555组成的断线式报警器制作电路图讲解_光电报警电子电路图讲解
  10. 硬件面试(2)-PCB类问题