Java基础教程-05-面向对象
Java基础教程-05-面向对象
1. 面向过程和面向对象解释
1.1 面向过程
1.1.1 简述
我们回想一下, 前面我们完成一个需求的步骤是怎样的?
- 首先是搞清楚我们要做什么.
- 然后在分析怎么做.
- 最后我们在通过代码一步一步去实现.
上述的每一个步骤, 我们都是参与者, 并且需要面对具体的每一个步骤和过程, 这就是面向过程最直接的体现.
1.1.2 举例
• 生活中的例子: 洗衣服. 想完成洗衣服这个需求, 我们得完成下述的每一个步骤:
- 找个盆.
- 接点水.
- 到洗衣液.
- 把衣服放进去浸泡10分钟.
- 把衣服揉搓干净.
- 漂洗.
- 拧干水分.
- 晾晒.
注意:
- 上述的这些步骤, 但凡有一个我们不会做, 就没有办法完成洗衣服这个需求.
- 即: 每一步都需要我们亲自做, 这就是: 面向过程思想.
• 代码举例: 把数组元素按照[11, 22, 33, 44, 55]的格式进行输出.
- 定义方法printArray(), 参数列表为: int[] arr, 返回值的类型为String.
- 定义字符串变量s, 用来记录数组元素拼接后的结果.
- 字符串变量s的初始化值设置为[.
- 对数组对象进行判断, 看其是否是合法对象.
即: 数组对象不为: null - 通过for循环遍历数组, 获取到每一个元素.
- 判断当前获取到的元素是否是最后一个元素, 并和字符串变量s进行拼接.
• 如果是最后一个元素, 则在后边在拼接上]
• 如果不是最后一个元素, 则在后边在拼接上, - 当for循环执行结束后, 字符串变量s记录的就是拼接后的结果, 将其直接返回即可.
注意: 上述的每一步代码都需要我们编写, 这样做比较繁琐.
1.1.3 总结
面向过程思想其实就是一种编程思想. 所谓的面向过程开发, 指的就是面向着具体的每一个步骤和过程, 把每一个步骤和过程完成, 然后由这些功能方法相互调用, 完成需求.
记忆: 面向过程的代表语言是: C语言.
1.2 面向对象
1.2.1 简述
当需求单一, 或者简单时, 我们一步一步去操作是没问题的, 并且效率也挺高. 可随着需求的更改, 功能的增多, 发现需要面对每一个步骤就很麻烦了, 于是我们就想着, 能不能把这些步骤和功能在进行封装, 封装时根据不同的功能, 进行不同的封装, 功能类似的用一个类封装在一起, 这样结构就清晰了很多. 用的时候, 找到对应的类就可以了. 这就是面向对象的思想.
1.2.2 举例
• 生活中的例子: 洗衣服.
- 想完成洗衣服这个需求, 我们可以通过洗衣机 来实现.
- 对于我们来讲, 洗衣机就是我们的对象.
- 总结: 万物皆对象.
• 代码举例: 把数组元素按照[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.4 总结
面向对象思想是一种编程思想, 它是基于面向过程的, 强调的是以对象为基础完成各种操作.
总结来讲, 万物皆对象.
2. 类和对象
2.1 概述
问题一: 你为什么学习编程语言?
我们学习编程语言, 其实就是为了把现实世界的事物通过代码模拟出来, 实现信息化.
例如:
• 超市的计费系统.
• 银行的核心系统.
• 千亿级数据仓库.
分析PB级数据,为企业提供高效、稳健的实时数据洞察。
采用类似阿里巴巴大数据数仓设计的分层架构思想,使用主流的实时仓库技术Flink、Druid、Kafka。
• 企业级360°全方位用户画像.
360°全方位还原用户画像,实现对个体和群体信息的标签化,实现精准推荐和营销.
• 电商推荐系统.
项目利用Neo4j构建用户和商品的关系图示,基于词向量相似度推荐商品、CTR/CVR点击率预估模型、逻辑斯特回归算法进行CTR点击率预估。
问题二: 我们是如何表示现实世界的事物呢?
- 属性.
– 属性指的就是事物的描述信息(名词).
– 属性在Java中被称之为成员变量. - 行为.
– 行为指的就是事物能够做什么.
– 行为在Java中被称之为成员方法.
例如: 学生
• 属性: 姓名, 年龄, 性别…
• 行为: 学习, 吃饭, 睡觉…
问题三: Java语言是如何表示现实世界的事物呢?
- 在Java语言中, 是通过类来体现事物的. Java语言最基本的单位是类, 它是一个抽象的概念, 看不见, 摸不着.
- 对象: 对象就是该类事物的具体体现, 实现.
举例:
类 学生 大象
对象 张三, 23 北京动物园叫图图的大象
2.2 类的定义格式
2.2.1 简述
定义类其实就是定义类的成员(成员变量和成员方法)
• 成员变量:
- 和以前定义变量是一样的, 只不过位置发生了改变, 写到类中, 方法外
- 而且成员变量还可以不用赋值, 因为它有默认值.
• 成员方法:
- 和以前定义方法是一样的, 只不过把static关键字去掉.
- 这点先记忆即可, 后面我们再讲解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 格式
- 创建该类的对象.
类名 对象名 = new 类名();
- 通过对象名.的形式, 调用类中的指定成员即可.
//成员变量
对象名.成员变量//成员方法
对象名.成员方法(参数列表中各数据类型对应的值…)
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 需求
- 定义手机类Phone.
属性: 品牌(brand), 价格(price), 颜色(color)
行为: 打电话(call), 发短信(sendMessage) - 创建测试类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 简述
• 成员变量: 指的是定义在类中, 方法外的变量.
• 局部变量: 指的是定义在方法中, 或者方法声明上的变量.
它们的区别如下:
- 定义位置不同.
– 成员变量: 定义在类中, 方法外.
– 局部变量: 定义在方法中, 或者方法声明上. - 在内存中的存储位置不同.
– 成员变量: 存储在堆内存.
– 局部变量: 存储在栈内存. - 生命周期不同.
– 成员变量: 随着对象的创建而存在, 随着对象的消失而消失.
– 局部变量: 随着方法的调用而存在, 随着方法的调用完毕而消失. - 初始化值不同.
– 成员变量: 有默认值.
– 局部变量: 没有默认值, 必须先定义, 再赋值, 然后才能使用.
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 应用场景
- 在实际开发中, 成员变量基本上都是用private关键字来修饰的.
- 如果明确知道类中的某些内容不想被外界直接访问, 都可以通过private来修饰.
6.1.4 示例
需求
- 定义学生类Student, 包含姓名, 年龄属性.
- 在StudentTest测试类中, 创建Student类的对象, 并调用Student类中的成员.
- 对年龄或者姓名属性加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()方法, 方便用户访问对应的成员变量, 接下来, 我们来写一个实际开发中的标准代码.
需求
- 定义一个标准的学生类Student, 属性: 姓名和年龄, 行为: 学习, 吃饭.
- 在测试类中创建学生类的对象, 然后访问类中的成员.
参考代码
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 原则
- 把不需要对外提供的内容都隐藏起来.
- 把属性隐藏, 并提供公共方法对其访问.
解释: 就是成员变量都用private修饰, 并提供对应的getXxx()和setXxx()方法, 除此以外, 都用public修饰.
6.3.3 好处
- 提高代码的安全性.
这点是由private关键字来保证的. - 提高代码的复用性.
这点是由方法来保证的, 方法也是封装的一种体现形式.
6.4 this关键字
6.4.1 概述
this代表本类当前对象的引用, 大白话翻译: 谁调用, this就代表谁.
6.4.2 作用
用来解决局部变量和成员变量重名问题的.
6.4.3 示例
需求
- 定义一个标准的学生类Student, 属性: 姓名和年龄, 行为: 学习, 吃饭.
- 在测试类中创建学生类的对象, 然后访问类中的成员.
参考代码
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 格式
- 构造方法名必须和类名完全一致(包括大小写).
- 构造方法没有返回值类型, 连void都不能写.
- 构造方法没有具体的返回值, 但是可以写return(实际开发, 一般不写).
public 类名(参数类型 参数名1, 参数类型 参数名2) { //这里可以写多个参数.//给对象的各个属性赋值即可.
}
6.5.3 示例: 构造方法入门
需求
- 定义学生类Student, 在类的空参构造中打印一句话"这是构造方法".
- 在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. 通过setXxx()方法实现(该方式不会创建新对象).
2. 通过构造方法实现(该方式会创建新对象).
6.6 标准的类的定义和使用
6.6.1 格式
以后在实际开发中, 也都是这样写的, 即: 标准的类的定义格式如下:
public class 类名{//属性(成员变量), 全部用private修饰.//构造方法, 一般提供两个(无参, 全参)//getXxx()和setXxx()方法//行为(成员方法), 根据需求来定义.
}
6.6.2 示例
需求
- 定义一个标准的学生类Student, 属性: 姓名和年龄, 行为: 学习, 吃饭.
- 在测试类中创建学生类的对象, 然后访问类中的成员.
参考代码
//学生类
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 示例
需求
- 按照标准格式定义一个人类(Person类), 属性为姓名和年龄.
- 定义老师类(Teacher), 继承自人类, 并在老师类中定义teach()方法.
- 定义学生类(Student), 继承自人类, 并在学生类中定义study()方法.
- 在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 好处
- 提高了代码的复用性.
- 提高了代码的可维护性.
- 让类与类之间产生关系, 是多态的前提.
7.3.3 弊端
让类与类之间产生了关系, 也就让类的耦合性增强了.
解释:
开发原则: 高内聚, 低耦合.
• 内聚: 指的是类自己独立完成某些事情的能力.
• 耦合: 指的是类与类之间的关系.
7.4 Java中继承的特点
7.4.1 示例
- 定义GrandFather类, 该类有一个grandFatherSay()方法, 该方法打印一句话爷爷都是从孙子过来的.
- 定义Father类, 该类有一个fatherSay()方法, 该方法打印一句话爸爸都是从儿子过来的.
- 定义Son类, 分别先继承自GrandFather类和Father类, 此时发现, 上述的两个方法只能同时调用一个.
- 如果想让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 总结
- Java中类与类之间只能单继承, 不能多继承.
public class 类A extends 类B,类C { //这种写法会报错.
}
- Java中类与类之间, 可以多层继承.
public class A { }public class B extends A{ }public class C extends B{ } //这种写法可以.
7.5 继承中成员变量的特点
7.5.1 示例
- 定义Father类, 在该类的成员位置定义变量: int age = 30;
- 定义Son类, 让它继承Father类, 并在该类的成员位置定义变量: int age = 20;
- 在测试类FatherTest的main方法中, 定义变量: int age = 10;
- 通过输出语句, 直接打印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 示例
需求
- 定义Phone类, 并在类中定义call(String name)方法.
- 定义NewPhone类, 继承Phone类, 然后重写call(String name)方法.
- 在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 注意事项
- 子类重写父类方法时, 方法声明上要用@Override注解来修饰.
- 父类中私有的方法不能被重写.
- 子类重写父类方法时, 访问权限不能更低.
8. 多态
8.1 概述
多态指的是同一个事物(或者对象)在不同时刻表现出来的不同状态.
例如: 一杯水.
• 常温下是液体.
• 高温下是气体.
• 低温下是固体.
但是水还是那杯水, 只不过在不同的环境下, 表现出来的状态不同.
8.2 前提条件
- 要有继承关系.
- 要有方法重写.
- 要有父类引用指向子类对象.
8.3 示例: 多态入门
需求
- 定义动物类Animal, 并在类中定义一个成员方法: eat()
- 定义猫类Cat, 继承Animal类, 并重写eat()方法.
- 在AnimalTest测试类的main方法中, 通过多态的方式创建猫类对象.
- 通过猫类对象, 调用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 多态中的成员访问特点
• 成员变量: 编译看左边, 运行看左边.
• 成员方法: 编译看左边, 运行看右边.
需求
- 定义一个人类Person. 属性为姓名和年龄, 行为是: eat()方法.
- 定义Student类, 继承自Person类, 定义age属性及重写eat()方法.
- 在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 示例
需求
- 定义动物类Animal, 该类有一个eat()方法.
- 定义猫类Cat, 继承自Animal类, 该类有一个自己独有的方法: catchMouse().
- 在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 示例: 猫狗案例
需求
- 已知猫狗都有姓名和年龄, 都要吃饭.
- 猫类独有自己的catchMouse()方法, 狗类独有自己的lookHome()方法.
- 在AnimalTest测试类的main方法中, 通过多态分别创建猫类, 狗类的对象.
- 分别通过猫类对象和狗类对象, 访问对象的成员.
参考代码
动物类:
//父类, 动物类.
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 示例
需求
- 定义Father类, 并定义它的子类Son.
- 先用final修饰Father类, 看Son类是否还能继承Father类.
- 在Son类中定义成员变量age, 并用final修饰, 然后尝试给其重新赋值, 并观察结果.
- 在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 特点
- 随着类的加载而加载.
- 优先于对象存在.
- 被static修饰的内容, 能被该类下所有的对象共享.
解释: 这也是我们判断是否使用静态关键字的条件. - 可以通过类名.的形式调用.
9.2.3 示例
需求
- 定义学生类, 属性为姓名, 年龄, 毕业院校(graduateFrom).
- 在学生类中定义show()方法, 用来打印上述的各个属性信息.
- 在测试类的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 静态方法的访问特点及注意事项
• 访问特点
静态方法只能访问静态的成员变量和静态的成员方法.
简单记忆: 静态只能访问静态.
• 注意事项
- 在静态方法中, 是没有this, super关键字的.
- 因为静态的内容是随着类的加载而加载, 而this和super是随着对象的创建而存在.
即: 先进内存的, 不能访问后进内存的.
需求
- 定义学生类, 属性为姓名和年龄(静态修饰), 非静态方法show1(),show2(), 静态方法show3(), show4().
- 尝试在show1()方法中, 调用: 姓名, 年龄, show2(), show4().
结论: 非静态方法可以访问所有成员(非静态变量和方法, 静态变量和方法) - 尝试在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 入门案例
需求
- 创建抽象类Animal.
- 在该类中定义抽象方法eat()
参考代码
//抽象的动物类.
public abstract class Animal {//抽象方法, 吃.public abstract void eat();
}
10.3 抽象类的特点
- 抽象类和抽象方法必须用abstract关键字修饰.
//抽象类
public abstract class 类名{ }//抽象方法
public abstract void eat();
- 抽象类中不一定有抽象方法, 有抽象方法的类一定是抽象类.
- 抽象类不能实例化.
– 那抽象类如何实例化呢?
– 可以通过多态的方式, 创建其子类对象, 来完成抽象类的实例化. 这也叫: 抽象类多态. - 抽象类的子类:
- 如果是普通类, 则必须重写父抽象类中所有的抽象方法.
- 如果是抽象类, 则可以不用重写父抽象类中的抽象方法.
需求
- 定义抽象类Animal , 类中有一个抽象方法eat(), 还有一个非抽象方法sleep().
- 尝试在测试类中, 创建Animal类的对象, 并观察结果.
- 创建普通类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 抽象类的成员特点
抽象类中可以有变量, 常量, 构造方法, 抽象方法和非抽象方法.
思考: 既然抽象类不能实例化, 那要构造方法有什么用?
答: 用于子类对象访问父类数据前, 对父类数据进行初始化.
需求
- 定义抽象类Person, 在类中定义变量age, 常量country, 空参, 全参构造.
- 在Person类中定义非抽象方法show(), 抽象方法eat().
- 在测试类的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 需求
- 传智播客公司有基础班老师(BasicTeacher)和就业班老师(WorkTeacher), 他们都有姓名和年龄, 都要讲课.
- 不同的是, 基础班老师讲JavaSE, 就业班老师讲解JavaEE.
- 请用所学, 模拟该知识点.
10.5.2 分析
- 定义父类Teacher, 属性: 姓名和年龄, 行为: 讲课(因为不同老师讲课内容不同, 所以该方法是抽象的).
- 定义BasicTeacher(基础班老师), 继承Teacher, 重写所有的抽象方法.
- 定义WorkTeacher(就业班老师), 继承Teacher, 重写所有的抽象方法.
- 定义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 特点
- 接口用interface关键字修饰.
- 类和接口之间是实现关系, 用implements关键字表示.
- 接口不能实例化.
– 那接口如何实例化呢?
– 可以通过多态的方式, 创建其子类对象, 来完成接口的实例化. 这也叫: 接口多态. - 接口的子类:
- 如果是普通类, 则必须重写父接口中所有的抽象方法.
- 如果是抽象类, 则可以不用重写父接口中的抽象方法.
需求
- 定义Jumpping接口, 接口中有一个抽象方法jump().
- 定义Cat类, 实现Jumpping接口, 重写jump()方法.
- 在测试类的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 需求
- 已知有乒乓球运动员(PingPangPlayer)和篮球运动员(BasketballPlayer), 乒乓球教练(PingPangCoach)和篮球教练(BasketballCoach).
- 他们都有姓名和年龄, 都要吃饭, 但是吃的东西不同.
- 乒乓球教练教如何发球, 篮球教练教如何运球和投篮.
- 乒乓球运动员学习如何发球, 篮球运动员学习如何运球和投篮.
- 为了出国交流, 跟乒乓球相关的人员都需要学习英语.
- 请用所学, 模拟该知识.
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; //多级包之间用.隔开
注意:
- package语句必须是程序的第一条可执行的代码.
- 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 包名;
- import java.util.*; 意思是导入java.util包下所有类, 这样做效率较低, 不推荐使用.
- import java.util.Scanner; 意思是导入java.util.Scanner类, 推荐使用. 用谁就导入谁.
14. 权限修饰符
14.1 概述
权限修饰符是用来修饰类, 成员变量, 构造方法, 成员方法的, 不同的权限修饰符对应的功能不同. 具体如下:
public | protected | 默认 | private | |
---|---|---|---|---|
同一个类中 | √ | √ | √ | √ |
同一个包中的子类或者其他类 | √ | √ | √ | |
不同包中的子类 | √ | √ | ||
不同包中的其他类(无关类) | √ |
14.2 示例
需求
- 在com.itheima包下定义Father类, 该类中有四个方法, 分别是show1(), show2(), show3(), show4().
- 上述的四个方法分别用权限修饰符private, 默认, protected, public修饰.
- 在Father类中, 创建main方法, 然后创建Father类的对象, 并调用上述的4个方法, 并观察结果.
- 在com.itheima包下创建Test类及main方法, 然后创建Father类的对象, 并调用上述的4个方法, 并观察结果.
- 在com.itheima包下创建Father类的子类Son, 添加main方法.
- 在main方法中, 创建Son类的对象, 并调用上述的4个方法, 并观察结果.
- 在cn.itcast包下创建Father类的子类Son, 然后在该类中添加main方法.
- 在main方法中, 创建Son类的对象, 并调用上述的4个方法, 并观察结果.
- 在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 总结
- 访问权限修饰符的权限从大到小分别是: public > protected > 默认 > private
- 在实际开发中, 如果没有特殊需求, 则成员变量都用private修饰, 其它都用public修饰.
- 大白话总结四个访问权限修饰符的作用:
1. private: 强调的是给自己使用.
2. 默认: 强调的是给同包下的类使用.
3. protected: 强调的是给子类使用.
4. public: 强调的是给大家使用.
15. 作业
- 定义手机类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
曜石黑
给落空空打电话!
给落空空发短信!!
- 定义老师类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
- 定义项目经理类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-面向对象相关推荐
- Java基础教程:面向对象编程[2]
Java基础教程:面向对象编程[2] 内容大纲 访问修饰符 四种访问修饰符 Java中,可以使用访问控制符来保护对类.变量.方法和构造方法的访问.Java 支持 4 种不同的访问权限. default ...
- Java基础教程(4)--面向对象概念
如果你之前从来没有使用过面向对象编程语言,那么在学习Java之前需要先理解几个有关面向对象编程的基本概念.这篇教程将会向你介绍对象.类.集成.接口和包的概念,以及这些概念是如何与现实世界相关联,并 ...
- java基础教程05讲:什么是java分隔符
java语言种的分隔符 分号:.花括号{}.方括号[].圆括号().空格.圆点..都具有分隔的作用,被统称为分隔符. 分号java语言里对语句的分隔不是使用回车来完成的,java语言使用分号作为语句的 ...
- Java基础教程-刘刚-专题视频课程
Java基础教程-2704人已学习 课程介绍 Java基础教程是一套入门Java开发语言的课程,它是由浅入深的介绍Java基础内容,包括Java介绍.基本类型及运算符.控制执行流程.字 ...
- java基础教程(一)
Java 开发环境配置 在进行Java开发之前,需要先安装Java开发工具包(JDK)和集成开发环境(IDE).以下是Java开发环境的配置和搭建步骤: 下载JDK:访问Oracle官方网站,选择适合 ...
- Java基础教程:反射基础
Java基础教程:反射基础 引入反射 反射是什么 能够动态分析类能力的程序称为反射. 反射是一种很强大且复杂的机制. Class类 在程序运行期间,Java运行时系统始终为所有对象维护一个被称为运行时 ...
- Java基础教程:多线程基础(3)——阻塞队列
Java基础教程:多线程基础(3)--阻塞队列 快速开始 引入问题 生产者消费者问题是线程模型中的经典问题:生产者和消费者在同一时间段内共用同一存储空间,生产者向空间里生产数据,而消费者取走数据. 模 ...
- python中delete怎么用_python删除np.deletePython基础教程05 - 缩进和选择
缩进 Python最具特色的是用缩进来标明成块的代码.我下面以if选择结构来举例.if后面跟随条件,如果条件成立,则执行归属于if的一个代码块. 先看C语言的表达方式(注意,这是C,不是Python! ...
- Java基础教程(12)--深入理解类
一.方法的返回值 当我们在程序中调用方法时,虚拟机将会跳转到对应的方法中去执行.当以下几种情况发生时,虚拟机将会回到调用方法的语句并继续向下执行: 执行完方法中所有的语句: 遇到return语句: ...
最新文章
- 如何找出应用程序未使用绑定变量
- App Store 状态列表
- mysql 8.0 自定义函数_PHP+Mysql防止SQL注入的方法(life)
- android 直播 app下载地址,蓝泡泡直播
- Spring动态注入泛型集合Bean
- vim下更省心地用中文
- vivo X30新细节曝光:搭载潜望式超远摄支持双模5G
- 【带着canvas去流浪(5)】绘制K线图
- 又拍云沈志华:如何打造一款安全的App
- Python ini文件读取(configparser模块)(转载)
- 网络工程师考试第一节计算机硬件基础
- 【无机纳米材料科研制图——OriginLab 0208】Origin拟合SERS拉曼光谱
- 电脑蓝屏,问题:你的电脑未正确启动,按“重启”以重启你的电脑,有时这样可以解决问题,你还可以按“高级选项”,尝试使用其他选项修复你的电脑
- GNSS原理及技术(一)——GNSS现状与发展
- 手机怎么解决同ip多账号_游戏工作室如何实现手游多开多窗口多IP
- 解决MATLAB的simulink仿真Scop窗口曲线显示不全只显示部分曲线的问题
- linux 二次封装 释放,Linux必学的60个命令(二)
- Linux 上最好的 9 个免费视频编辑软件(2018) | Linux 中国
- CoBOT检测出AI开源框架TensorFlow中的缺陷
- GO + React + Axios Response to preflight request doesn't pass access control check: It does not hav