day01【复习回顾、继承、抽象类模板设计模式】
今日内容
- 面向对象复习------>必须掌握
- 继承
- 继承的格式------>必须掌握
- 继承后成员访问特点------>必须掌握
- this和super关键字---->必须掌握
- 抽象类----->必须掌握
- 抽象类的定义以及使用
- 抽象方法的定义以及调用
- 模板设计模式----->必须掌握
第1章 复习回顾
1.1 类和对象
定义一个类
-
格式:
修饰符 class 类名{
//类中的五大成分。
1.成员变量(属性)
2.成员方法 (行为)
3.构造器 (初始化类的对象数据的)
4.内部类
5.代码块
} -
代码:
public class Student {
// 成员变量: private 数据类型 变量名;
/**
* 姓名
/
private String name;
/*
* 年龄
*/
private int age;// 构造方法: alt + insert -->Constructor public Student() { } public Student(String name, int age) { this.name = name; this.age = age; } // set\get方法: alt + insert --> getter and setter 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 show() { System.out.println("我的姓名是:" + name + ",年龄是:" + age); } }
创建并使用对象
-
格式:
创建对象的格式: 类名 对象名 = new 类名(实参); // 通过new调用构造方法创建对象
访问成员变量: 对象名.成员变量名 // 调用set\get方法访问成员变量
访问成员方法:
无返回值的方法: 对象名.成员方法名(实参);
有返回值的方法:
直接调用: 对象名.成员方法名(实参); // 不常见
赋值调用: 数据类型 变量名 = 对象名.成员方法名(实参); // 开发中常见
输出调用: System.out.println(对象名.成员方法名(实参));// 讲课中常见 -
代码:
public class Test {
public static void main(String[] args) {
// 需求:创建学生对象,访问成员变量和成员方法
// 通过调用空参构造方法创建对象
Student stu1 = new Student();// 通过调用满参构造方法创建对象 Student stu2 = new Student("李四",18); // 访问成员变量--set\get方法 stu1.setName("张三"); stu1.setAge(18); System.out.println(stu1.getName()+","+stu1.getAge());// 张三,18 // 访问成员方法 stu1.show(); stu2.show(); } }
1.2 对象的内存图
画图依据
- 只要是new对象就会在堆区开辟一块独立的空间
- 只要调用方法,方法就会被加载进栈
- 只要方法执行完毕,方法就会被弹栈
- 方法执行的流程: 调用方法-->加载方法到栈区-->声明形参-->把实参传递给形参--->执行方法体-->结束方法,弹栈
内存图
1.3 匿名对象
概述
- 概述:匿名对象就是指没有名字的对象。
使用
public class Test {
public static void main(String[] args) {
/*
概述:匿名对象就是指没有名字的对象。
使用: 匿名对象只能使用一次
*/
// 以前:
Student stu1 = new Student("张三",18);// 0x111 有名字的对象
method(stu1);// 我的姓名是:张三,年龄是:18
method(stu1);// 我的姓名是:张三,年龄是:18
// 匿名对象:
new Student("李四",19);// 匿名对象
method(new Student("李四",19));// 我的姓名是:李四,年龄是:19
method(new Student("李四",19));// 我的姓名是:李四,年龄是:19
}
public static void method(Student stu){
stu.show();
}
}
第2章 继承
2.1 继承概述
为什么要有继承
- 生活中为什么要有继承
- 程序中为什么还要有继承
继承的概述
- 继承在java中指的是“一个类”可以“继承自”“另一个类”。 "被继承的类"叫做: 父类/超类/基类,"继承其他类的类"叫做:子类。继承后,“子类”中就“拥有”了“父类”中所有的成员(成员变量、成员方法)。 “子类就不需要再定义了”。
继承的好处
- 提高代码的复用性;
- 使类与类之间产生了关系,作为多态的前提条件
2.2 继承的格式
继承的格式
修饰符 class 子类名 extends 父类名{
}
继承的演示
-
父类
// 父类
public class Person {
private String name;
private int age;
private String gender;public Person(String name, int age, String gender) { this.name = name; this.age = age; this.gender = gender; } public Person() { } 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 getGender() { return gender; } public void setGender(String gender) { this.gender = gender; } public void eat() { System.out.println("吃东西..."); } public void sleep() { System.out.println("睡觉..."); } public void show() { System.out.println("姓名:" + name + ",年龄:" + age + ",性别:" + gender); } }
-
子类
// 子类
public class Student extends Person {
}// 子类 public class Teacher extends Person { }
-
测试类
public class Test {
public static void main(String[] args) {
/*
继承的格式:
修饰符 class 子类名 extends 父类名{} */ // 创建学生对象 Student stu = new Student(); // 访问成员变量 stu.setName("张三"); stu.setAge(18); stu.setGender("男"); // 访问成员方法 stu.eat(); stu.sleep(); stu.show(); } }
2.3 扩展一个文件定义多个类
class Person{
}
class Student extends Person{
}
class Teacher extends Person{
}
public class Test {
public static void main(String[] args) {
/*
一个文件可以定义多个类
该文件中只能有一个public修饰的类
public修饰的类的类名必须和文件名一致
注意: 开发中,一般是一个类对应一个文件,只是目前阶段为了更好的理解知识点,所以才一个文件定义多个类
*/
}
}
2.4 继承后成员访问规则
继承后构造方法的访问规则
-
子类无法继承父类的构造方法
class Fu{
public Fu(){} public Fu(String name,int age){ } } class Zi extends Fu{ } public class Test { public static void main(String[] args) { // 继承后构造方法的访问规则: 子类无法继承父类的构造方法 // Zi zi = new Zi("张三",18);// 编译报错 } }
继承后私有成员的访问规则
- 子类可以继承父类的私有成员,但无法直接访问,可以间接访问
-
私有成员变量: 通过set\get方法间接访问
-
私有成员方法: 通过其他公共的方法间接访问
class Fu {
// 私有成员变量
private String name;// 私有成员方法 private void show() { System.out.println("姓名:" + name); } // 公共的方法 public void method(){ show();// 调用私有的show()方法 }
}
class Zi extends Fu {
}
public class Test {
public static void main(String[] args) {
/*
私有成员访问规则: 子类可以继承父类的私有成员,但无法直接访问,可以间接访问
快捷键: alt+鼠标左键往下拽: 同时操作多行
*/
// 创建子类对象
Zi zi = new Zi();
// System.out.println(zi.name);// 编译报错
// zi.show();// 编译报错// 间接访问show方法: 通过调用method方法,来执行show方法 zi.method(); }
}
-
继承后非私有成员的访问规则
-
子类可以继承父类的非私有成员,并且可以直接访问
-
访问规则: 优先在子类中查找,如果在子类中找到了就直接使用子类的,如果没有找到就去父类中查找
class Fu{
public int num = 10;public void show(){ System.out.println("Fu num:"+num); } } class Zi extends Fu{ public int num = 20; public void show(){ System.out.println("Zi num:"+num); } } public class Test { public static void main(String[] args) { /* - 子类可以继承父类的非私有成员,并且可以直接访问 - 访问规则: 优先在子类中查找,如果在子类中找到了就直接使用子类的,如果没有找到就去父类中查找 */ // 创建子类对象 Zi zi = new Zi(); // 访问非私有成员 System.out.println(zi.num);// 20 zi.show();// Zi num: 20 } }
2.5 方法重写
方法重写的概念
-
概念:子类中出现与父类一模一样的方法时(返回值类型,方法名和参数列表都相同),该方法就是重写的方法。
-
代码:
class Fu{
public void method(){
System.out.println(“Fu method…”);
}
}class Zi extends Fu{ // 重写的method方法 public void method(){ System.out.println("Zi method..."); } } public class Test { public static void main(String[] args) { /* 方法重载概述: 在同一个类中,出现多个同名的方法,但参数列表不同,与其他无关 方法重写概述: 子类中出现与父类一模一样的方法时(返回值类型,方法名和参数列表都相同),该方法就是重写的方法。 */ } }
重写的注意事项
-
代码:
class Fu{
public void method(){
System.out.println(“Fu method…”);
}
}class Zi extends Fu{ @Override public void method(){ System.out.println("Zi method..."); } public void show(){ } } public class Test { public static void main(String[] args) { /* - 方法重写是发生在父子类之间的关系。 - 子类方法重写父类方法,返回值类型、方法名和参数列表都要一模一样。 - 使用场景:父类的方法,子类有不同的实现,那么子类就需要重写父类的该方法 - 子类方法重写父类方法,必须要保证权限大于等于父类权限。 访问权限从大到小: public > protected > (默认) > private - 使用@Override注解,检验是否重写成功,重写注解校验! - 建议重写方法都加上这个注解,一方面可以提高代码的可读性,一方面可以防止重写出错! */ } }
2.6 this和super关键字
this关键字的三种用法
-
介绍:this可以访问本类的成员属性、成员方法、构造方法;
-
this访问本类成员变量: this.成员变量
class Fu {
int num = 10;public void show() { int num = 20; System.out.println("局部变量num:" + num);// 20 System.out.println("成员变量num:" + this.num);// 10 } } public class Test { public static void main(String[] args) { /* this访问本类的成员变量: this.成员变量名 使用场景: 区别同名的局部变量和成员变量 */ Fu f = new Fu(); f.show(); } }
-
this访问本类成员方法: this.成员方法名(实参);
class Fu{
public void show1(){
System.out.println(“show1…”);
}public void show2(){ System.out.println("show2..."); } public void show3(){ System.out.println("show3..."); // 调用show1方法,show2方法 this.show1(); this.show2(); } } public class Test { public static void main(String[] args) { // this访问本类的成员变量: this.成员方法名(实参); Fu f = new Fu(); f.show3(); } }
-
this访问本类构造方法: this(实参)可以在本类的一个构造方法中,调用另一个构造方法
class Fu{
String name;
int age;public Fu(String name) { this();// 访问本类的空参构造 this.name = name; System.out.println("有参构造..."); } public Fu() { System.out.println("空参构造...."); } public Fu(String name,int age){ this(name); this.age = age; } } public class Test { public static void main(String[] args) { /* this访问本类构造方法: this(实参); 注意: 1.只能在本类的构造方法中使用this调用本类的其他构造方法 2.this调用本类的构造方法必须放在构造方法的第一行 3.两个本类的构造方法不能使用this相互调用 */ // 调用Fu类的有参构造创建对象 Fu f1 = new Fu("张三"); System.out.println("=============="); // 调用Fu类的满参构造创建对象 Fu f2 = new Fu("李四",18); System.out.println(f2.name+","+f2.age);// 李四,18 } }
super关键字的三种用法
-
介绍:super可以访问父类的成员属性、成员方法、构造方法;
-
super访问父类的成员变量: super.父类成员变量名
class Fu {
int num = 10;
}class Zi extends Fu { int num = 100; public void show() { int num = 1000; System.out.println("局部变量num:" + num);// 1000 System.out.println("本类成员变量num:" + this.num);// 100 System.out.println("父类成员变量num:" + super.num);// 10 } } public class Test { public static void main(String[] args) { // super访问父类的成员变量: super.成员变量名 // 使用场景: 区别父子类中同名的成员变量 Zi zi = new Zi(); zi.show(); } }
-
super访问父类的成员方法: super.成员方法名(实参);
class Fu{
public void show(){
System.out.println(“Fu show…”);
}public void show1(){ System.out.println("Java..."); System.out.println("Java..."); System.out.println("Java..."); } } class Zi extends Fu{ @Override public void show(){ System.out.println("Zi show..."); } public void method(){ // 调用子类的show方法 this.show(); // 调用父类的show方法 super.show(); } @Override public void show1() { super.show1();// 调用父类的show1方法 System.out.println("itheima..."); System.out.println("itheima..."); System.out.println("itheima..."); } } public class Test { public static void main(String[] args) { // super访问父类的成员方法: super.成员方法名(实参); // 使用场景: 区别父子类中同名的方法 Zi zi = new Zi(); zi.method(); zi.show1(); } }
-
super访问父类的构造方法: super(实参)
class Fu {
private String name;
private int age;public Fu() { System.out.println("Fu 空参构造..."); } public Fu(String name, int age) { this.name = name; this.age = age; System.out.println("Fu 满参构造..."); } public void show() { System.out.println(name + "," + age); } } class Zi extends Fu { public Zi(){ super();// 调用父类的空参构造 } public Zi(String name,int age){ super(name,age);// 调用父类的满参构造 } } public class Test { public static void main(String[] args) { /* super访问父类的构造方法: super(实参); 注意: 1.super访问父类的构造方法一定要放在子类构造方法的第一行 2.子类构造方法默认会调用父类的空参构造方法 3.在子类构造方法中调用父类的构造方法,其实就是为了初始化从父类继承过来的属性 */ // 调用Zi类的空参构造方法创建对象 Zi zi1 = new Zi(); System.out.println("============"); // 创建Zi类对象的时候,为Zi类对象的属性赋初始值 Zi zi2 = new Zi("张三",18); zi2.show();// 张三,18 } }
2.7 super的注意事项
super的注意事项一
-
super访问成员变量和成员方法: 优先去父类中找,如果有就直接使用,如果没有就去爷爷类中找,如果有,就用,依次类推…
class Ye /extends Object/{
int num = 10;
}class Fu extends Ye{ int num = 20; } class Zi extends Fu{ int num = 30; public void show(){ System.out.println(super.num);// 20 } } public class Test { public static void main(String[] args) { /* super访问成员变量和成员方法: 优先去父类中找,如果有就直接使用, 如果没有就去爷爷类中找,如果有,就用,依次类推... Java中顶层父类是Object类,所有的类都直接或者间接继承Object类 Ye类直接继承Object类 Fu类,Zi类间接继承Object类 */ Zi zi = new Zi(); zi.show(); } }
super的注意事项二
-
子类的构造方法默认会调用父类的空参构造方法,如果父类中没有空参构造方法,只定义了有参构造方法,会编译报错
class Fu{
String name;
int age;public Fu(String name, int age) { this.name = name; this.age = age; } } // 子类编译报错: 子类会自动生成空参构造方法,而该空参构造方法中会默认调用父类的空参构造方法,而父类没有生成空参构造方法 /*class Zi extends Fu{ }*/ public class Test { public static void main(String[] args) { /* 子类的构造方法默认会调用父类的空参构造方法,如果父类中没有空参构造方法,只定义了有参构造方法,会编译报错 */ } }
2.8 继承体系对象的内存图
书写继承案例
class Fu{
int num = 10;
public void method(){
System.out.println("Fu method");
}
}
class Zi extends Fu{
int num = 20;
@Override
public void method() {
System.out.println("Zi method");
}
public void show(){
int num = 30;
System.out.println("局部变量num:"+num);// 30
System.out.println("本类成员变量num:"+this.num);// 20
System.out.println("父类成员变量num:"+super.num);// 10
// 访问本类成员方法method
this.method();// Zi method
// 访问父类成员方法method
super.method();// Fu method
}
}
public class Test {
public static void main(String[] args) {
Zi zi = new Zi();
zi.show();
}
}
根据案例绘制内存图
2.9 继承的特点
-
Java只支持单继承,不支持多继承。
// 一个类只能有一个父类,不可以有多个父类。
class A {}
class B {}
class C1 extends A {// ok}
class C2 extends A, B {// error}
-
一个类只能有一个父类,但可以有多个子类。
// A可以有多个子类
class A {}
class C1 extends A {}
class C2 extends A {}
-
可以多层继承。
class A /extends Object/{// 爷爷 默认继承Object类 直接
}
class B extends A {// 父亲 间接}
class C extends B {// 儿子}
补充: Java中顶层父类是Object类。所有的类默认继承Object,作为父类。
class A {} 默认继承Object类 直接继承Object
class B extends A{} B的父类就是A,但是A的父类是Object类 间接继承Object类
第3章 抽象类
3.1 抽象类的概述和定义
抽象类的概述
- 概述: 使用abstract关键字修饰的类就是抽象类
抽象类的定义
-
格式:
修饰符 abstract class 类名{}
抽象类中的成员
- 成员变量,成员方法,构造方法,抽象方法
案例
// 抽象类
public abstract class Person {
// 成员变量
private String name;
private int age;
// 构造方法
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public Person() {
}
// 成员方法
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 show() {
System.out.println(name + "," + age);
}
// 抽象方法
}
3.2 抽象方法的概述和定义
抽象方法的概述
- 概述:没有方法体,使用abstract修饰的方法就是抽象方法
- 特点:
- 有抽象方法的类一定是抽象类,抽象类中不一定有抽象方法
- 强制要求子类重写
抽象方法的定义
-
格式: 修饰符 abstract 返回值类型 方法名(形参列表);
-
代码:
public abstract class Person {
// 抽象方法
public abstract void eat();
public abstract void sleep();
}// 子类是普通类,但必须重写抽象父类中所有的抽象方法 class Student extends Person{ @Override public void eat() { } @Override public void sleep() { } } // 子类是抽象类 abstract class Teacher extends Person{ }
3.3 抽象类的注意事项
-
抽象类不能被创建对象,只能用来做“父类”,被子类继承的,体现的是模板思想 。
public abstract class Animal{
public void sleep(){// 所有子类通用的方法
System.out.println(“两眼一闭,就睡觉了…”);
}
public abstract void eat();// 所有子类都需要重写的方法
}public class Dog extends Animal{ @Override public void eat(){ System.out.println("狗吃骨头..."); } } public class Cat extends Animal{ @Override public void eat(){ System.out.println("猫吃鱼..."); } }
-
抽象类不能被创建对象,但可以有“构造方法”——为从父类继承过来的属性初始化。
public abstract class Animal{
private String name;
private int age;// 抽象类中的构造方法其实就是给子类调用的 public Animal(){} public Animal(String name,int age){ this.name = name; this.age = age; } } public class Dog extends Animal{ public Dog(){ super(); // 调用父类的空参构造 } public Dog(String name, int age){ super(name,age);// 调用父类的满参构造 } } public class Test{ public static void main(String[] args){ // 编译报错 // Animal anl = new Animal(); } }
-
抽象类中可以没有抽象方法,但抽象方法必须定义在抽象类中
public abstract class Person {
// 抽象方法
public abstract void eat();
public abstract void sleep();
}public abstract class Animal { // 没有抽象方法 }
-
子类继承抽象类后,必须重写抽象类中所有的抽象方法,否则子类必须也是一个抽象类
public abstract class Person {
// 抽象方法
public abstract void eat();
public abstract void sleep();
}// 子类是普通类,但必须重写抽象父类中所有的抽象方法 class Student extends Person{ @Override public void eat() { } @Override public void sleep() { } } // 子类是抽象类 abstract class Teacher extends Person{ }
3.4 模板设计模式
- 设计模式: 设计模式就是解决一些问题时的固定思路,也就是代码设计思路经验的总结。
- 模板思想:
- 模板是通用的东西,抽象类体现的是模板思想。
- 抽象类中可以是具体实现的方法(通用模板),也可以有抽象方法(填充模板)。
- 模板中不能决定的行为定义成抽象方法,让需要使用模板的类(子类)负责重写抽象方法实现。
- 模板中能决定的行为就定义成有方法体的方法,让需要使用模板的类(子类)直接继承调用即可。
- 案例:
-
需求:按照下述要求,使用代码实现
定义新、老司机类,新、老司机类都有开车功能,开车的步骤一样,但驾驶时的姿势不同
新司机:开门,点火,双手紧握方向盘,刹车,熄火
老司机:开门,点火,右手握方向盘左手抽烟,刹车,熄火 -
代码:
// 抽象父类: 体现的就是模板设计思想
public abstract class Driver {// 开车的方法: 通用方法 public void driveCar(){ System.out.println("开门..."); System.out.println("点火..."); // 开车的姿势 ziShi(); System.out.println("刹车..."); System.out.println("熄火..."); } // 姿势的方法: 填充方法 public abstract void ziShi(); } public class NewDriver extends Driver { @Override public void ziShi() { System.out.println("双手紧握方向盘..."); } } public class OldDriver extends Driver { @Override public void ziShi() { System.out.println("右手握方向盘左手抽烟..."); } } public class Test { public static void main(String[] args) { /* 需求:按照下述要求,使用代码实现 定义新、老司机类,新、老司机类都有开车功能,开车的步骤一样,但驾驶时的姿势不同 新司机:开门,点火,双手紧握方向盘,刹车,熄火 老司机:开门,点火,右手握方向盘左手抽烟,刹车,熄火 */ // 创建新司机对象 NewDriver d1 = new NewDriver(); // 创建老司机对象 OldDriver d2 = new OldDriver(); // 开车 d1.driveCar(); System.out.println("========"); d2.driveCar(); } }
-
总结
必须练习:
1.定义类,创建对象,使用对象----->必须掌握
2.继承的格式,继承后成员访问规则--->必须掌握
3.this和super关键字的三种用法--->必须掌握
4.方法重写--->必须掌握
5.抽象类的定义以及使用--->必须掌握
6.抽象方法的定义以及使用--->必须掌握
7.模板设计思想
- 能够写出类的继承格式
修饰符 class 子类名 extends 父类名{}
- 能够说出继承的特点
1.子类继承父类后,就可以拥有父类所有的成员变量和成员方法
2.子类继承父类后,可以直接访问从父类继承过来的非私有成员
3.只能单继承,不能多继承,但可以多层继承
4.不要为了继承而继承,必须满足is a的关系才去继承
- 能够说出子类调用父类的成员特点
子类继承父类后,可以直接访问从父类继承过来的非私有成员
子类继承父类后,不可以直接访问从父类继承过来的私有成员,需要间接访问
- 够说出方法重写的概念
概念: 子类中出现和父类一模一样的方法(返回值类型,方法名,参数列表),该方法就是重写的方法
特点:
1.子类重写的方法的权限不能低于父类方法的权限
public > protected > 默认 > private
2.重写的方法可以使用@Override注解进行标识,可以起到提高代码可读性以及校验重写是否正确的作用
- 能够说出this可以解决的问题
this可以访问本类的成员变量: this.成员变量名
this可以访问本类的成员方法: this.成员方法名(实参);
this可以访问本类的构造方法: this(实参);
- 能够说出super可以解决的问题
super可以访问父类的成员变量: super.成员变量名
super可以访问父类的成员方法: super.成员方法名(实参);
super可以访问父类的构造方法: super(实参);
- 描述抽象方法的概念
概念: 没有方法体,并且使用abstract修饰的方法
- 写出抽象类的格式
概述:使用abstract修饰的类就是抽象类
格式:修饰符 abstract class 类名{}
特点:
1.抽象类的子类可以是普通类,也可以是抽象类
2.抽象类的子类是普通类,必须重写抽象类中所有的抽象方法,否则抽象类的子类必须也是抽象类
3.有抽象方法的类一定是抽象类,但抽象类中不一定有抽象方法
4.抽象类不能创建对象,但可以有构造方法,主要是用来做父类被其他类继承的
- 写出抽象方法的格式
格式: 修饰符 abstract 返回值类型 方法名(实参);
- 能够说出父类抽象方法的存在意义
强制要求子类重写