Day01
类的继承与抽象
1、继承
1.继承的定义
- 在Java中,类的继承是指在一个现有类的基础上去构建一个新的类,构建出来的新类就被称为子类,现有的类就被称为父类,子类会自动拥有父类除private以及构造方法之外的属性和方法。
- 当要定义一个类的时候,发现已有类与要定义的相似,并且要定义的类是属于已有类的一种时,可以将要定义的类定义为已有类的子类。
- 总的来说,就是向上抽取共性,把相同的内容定义在父类中
- 父类:基类/超类
- 子类:派生类
- 什么情况会使用继承
- 必须满足我们的is a的关系
- 什么是什么的一种
- 继承的好处是什么
- 子类可以使用父类的除private和构造方法之外的内容
- 提高了代码的复用性
- 让类与类之间发生了关系(父子类关系)
- 是多态的前提
2.继承的关键字
-
extends
-
格式:
子类 extends 父类
父类
package com.itheima.p1_extends;
public class Employee {
String name;
int age;
int salary;
public void show(){
System.out.println("姓名:"+name+", 年龄:"+age+", 薪资:"+salary);
}
}
子类:
package com.itheima.p1_extends;
public class Teacher extends Employee{
public void teaching(){
System.out.println("讲师:"+name+"在讲课");
}
}
子类
package com.itheima.p1_extends;
public class Teacher extends Employee{
public void teaching(){
System.out.println("讲师:"+name+"在讲课");
}
}
测试类:
package com.itheima.p1_extends;
public class Demo01Extends {
public static void main(String[] args) {
/*
* 格式:
public class 父类 {
//成员变量
//成员方法
//构造方法
}
public class 子类 extends 父类 {
//成员变量
//成员方法
//构造方法
}
public class A extends B {
//...
}
注意:
1.B是父类,又叫做基类/超类,A是子类
2.子类可以使用父类中除了private修饰的和构造方法以外的内容
* */
Teacher teacher = new Teacher();
teacher.name = "立夏";
teacher.age = 24;
teacher.salary = 20000;
teacher.show();
teacher.teaching();
System.out.println("------------");
Manager manager = new Manager();
manager.name = "立冬";
manager.age = 27;
manager.salary = 300000;
manager.show();
manager.managerClass();
}
}
3.继承中成员变量的访问特点
-
成员变量不重名
- 变量名是什么就直接找对应的
- 现在子类找没有就去父类找
- 父类不能找子类,子类可以找父类
-
成员变量重名
- (1)在方法内部,直接写 变量名
- 从方法内部开始向上找
- 方法内部有:直接使用
- 方法内部没有:向上找本类的成员位置
- 本类的成员位置没有:向上找父类的成员位置
- (2)在方法内部,直接写 this.变量名
- 从本类的成员位置开始向上找
- 本类的成员位置有:直接使用
- 本类的成员位置没有:向上找父类的成员位置
- (3)在方法内部,直接写 super.变量名
- 从父类的成员位置开始找
- ‘父类的成员位置有:直接使用
- 父类的成员位置没有:向上找父类的父类的成员位置
- (4)总结:就近原则(只是就近的开始位置不同)
- (1)在方法内部,直接写 变量名
父类:
package com.itheima.p2_exdends_var;
public class Fu02 {
int num = 10000;
}
子类:
package com.itheima.p2_exdends_var;
public class Zi02 extends Fu02{
int num = 1000;
public void show(){
int num = 10;
System.out.println(num);//10
System.out.println(this.num);//1000
System.out.println(super.num);//10000
}
}
测试类:
package com.itheima.p2_exdends_var;
public class Demo02 {
public static void main(String[] args) {
Zi02 zi02 = new Zi02();
zi02.show();
}
}
4.继承中重名成员变量的图解分析
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JtZSCUXB-1669299784504)(C:\Users\王超越\AppData\Roaming\Typora\typora-user-images\image-20221124112416274.png)]
- Demo03Extends,Fu03,Zi03(因为继承Fu03所以Fu03先进入)的编译文件进入方法区,
- main()方法启动进入栈内存,创建Zi03对象,
- Zi03对象在堆内存开辟一块区域,地址值为0x666
- 因为Zi03类继承了Fu03类,所以创建Zi03对象时,会在区域中优先给父类成员开辟一块区域,这块空间使用super关键字标记
- 此时堆内存中的对象Zi03有两个num,但是因为父类被super标记所以可以区分
- 然后引用变量zi调用方法method(),该方法进入栈内存,
- 方法执行,
- 输出num,从方法内部就近向上找,
- 输出this.num,从本来的成员位置就近向上找,
- 输出super.num,从父类的成员位置就近向上找,
5.继承中成员方法的访问特点
-
成员方法不重名
- 如果子类父类中出现不重名的成员方法,调用是没有影响的
- 对象调用方法时,先在子类中查找有没有对应的方法,如果子类中没有就执行父类中相应的方法,如果有就会执行子类中的方法
-
成员方法重名
- 子类出现和父类一模一样的方法时(返回值类型,方法名和参数列表都相同),会出现覆盖效果。声明不变,重新实现
- 必要条件:方法名和形参列表必须相同
- 可选条件:返回值类型可以不一致(子类的返回值类型 <= 父类的返回值类型,即存在继承关系)
-
方法重写的使用场景
- 子类可以根据需要,定义特定于自己的行为。既沿袭了父类的功能名称,又根据子类的需要重新实现父类的方法,从而进行扩展增强;
-
方法重写的注意事项:
-
私有方法不可以被重写(父类的私有成员类不能继承)
-
子类方法覆盖父类方法,访问权限必须等于大于父类
public > protected > 默认(什么都不写)> private
-
子类方法覆盖父类方法,返回值类型、函数名和参数列表都要一样,且不能抛出更多的异常。
- 必要条件:
函数名和参数列表都要一样
子类不能抛出比父类更多的异常 - 可选条件:
返回值类型可以不一样
子类覆盖重写后的方法返回值类型 <= 父类方法返回值类型
- 必要条件:
-
-
@Override 注解
作用:用于检测当前方法是否是对父类方法的覆盖重写
是:不报错,不是:报错
方法重写要求名称和参数列表必须相同
//父类
package com.itheima.p3_extends_method;
public class Fu03 {
public void car(){
System.out.println("开着奥拓");
}
public void work(){
System.out.println("努力工作");
}
public void show(){
System.out.println("Fu03");
}
}
//子类
package com.itheima.p3_extends_method;
public class Zi03 extends Fu03{
public void car(){
System.out.println("开着玛莎拉蒂");
}
/*
@Override 注解
作用:用于检测当前方法是否是对父类方法的覆盖重写
是:不报错,不是:报错
方法重写要求名称和参数列表必须相同
* */
@Override
public void work() {
System.out.println("游手好闲");
}
public void show(int num) {
System.out.println("Zi03"+num);
}
@Override
public void show() {
System.out.println("Zi03");
}
}
//测试类
package com.itheima.p3_extends_method;
public class Demo03 {
public static void main(String[] args) {
Zi03 zi = new Zi03();
zi.car();
zi.work();
zi.show();
zi.show(100);
}
}
-
方法重写的应用_手机类的分析【重点】
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LeUBLUjS-1669299784505)(C:\Users\王超越\AppData\Roaming\Typora\typora-user-images\image-20221124155927559.png)]
//父类 package com.itheima.p4_extends_methodTest; public class OldPhone { public void call(String name){ System.out.println("给"+name+"打电话"); } public void sendMessage(String name,String mess){ System.out.println("给"+name+"发信息,内容为:"+mess); } public void showInfo(){ System.out.println("110来电。。。"); } } //子类 package com.itheima.p4_extends_methodTest; public class NewPhone extends OldPhone{ @Override public void showInfo() { super.showInfo(); System.out.println("在北京"); System.out.println("头像:🐱"); } } //测试类 package com.itheima.p4_extends_methodTest; public class Test { public static void main(String[] args) { NewPhone newPhone = new NewPhone(); newPhone.call("张三"); newPhone.sendMessage("张三","在哪里?"); newPhone.showInfo(); } }
6.继承中构造方法的访问特点
- 1、构造方法的名字与类名相同,所以子类无法继承父类的构造方法
- 2、子类继承父类,是为了使用父类的内容,所以子类创建对象调用构造方法的时候,必须先调用父类的构造方法,完成父类成员的初始化动作,子类才可以使用父类的成员,super()表示调用父类的无参构造
- 3、子类的构造方法中如果没有手动给写出super调用父类的构造,JVM默认提供一个super()调用父类的无参构造
- 4、super调用父类构造只能写在子类构造方法内部的第一行,并且只能写一句
- 5、构造方法可以重载,即有参构造,所以通过**super(…)**调用父类的有参构造,当然也是放在第一行
- 6、建议:子无参调用父无参,子有参调用父有参
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SPn9Vqze-1669299784505)(C:\Users\王超越\AppData\Roaming\Typora\typora-user-images\image-20221124161006370.png)]
//父类
package com.itheima.p5_extends_constructor;
public class Fu05 {
int num;
public Fu05() {
System.out.println("父无参");
}
public Fu05(int num) {
System.out.println("父有参");
this.num = num;
return;
}
}
//子类
package com.itheima.p5_extends_constructor;
public class Zi05 extends Fu05{
public Zi05() {
super();//调用父类的无参构造,默认有,可以不写,不写就是默认调用无参
System.out.println("子无参");
}
public Zi05(int num) {
//子类所有构造中只要不写super调用父类构造
//默认隐藏super()调用父类空参,无论是在子类的有参还是无参
super(num);
System.out.println("子有参");
}
}
//测试类
package com.itheima.p5_extends_constructor;
public class Demo05 {
public static void main(String[] args) {
Zi05 zi05 = new Zi05(10);
}
}
练习:
//父类Employee
package com.itheima.p6_extends_constructortest;
public class Employee {
private String name;
private int age;
private int salary;
public Employee() {
}
public Employee(String name, int age, int salary) {
this.name = name;
this.age = age;
this.salary = salary;
}
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 int getSalary() {
return salary;
}
public void setSalary(int salary) {
this.salary = salary;
}
}
//子类Teacher
package com.itheima.p6_extends_constructortest;
public class Teacher extends Employee{
public Teacher() {
//默认有super();去调用父类的无参构造
}
public Teacher(String name, int age, int salary) {
super(name, age, salary);
}
public void teaching(){
System.out.println("讲师:"+getName()+"在讲课");
}
}
//子类Manager
package com.itheima.p6_extends_constructortest;
public class Manager extends Employee{
public Manager() {
}
public Manager(String name, int age, int salary) {
super(name, age, salary);
}
public void managerClass(){
System.out.println("班主任:"+getName()+"在管理班级");
}
}
//测试类
package com.itheima.p6_extends_constructortest;
public class Demo06 {
public static void main(String[] args) {
//使用无参构造
Teacher t = new Teacher();
t.setName("立夏");
t.setAge(24);
t.setSalary(20000);
t.teaching();
System.out.println("===========");
//使用有参构造
Manager m = new Manager("立冬",26,30000);
m.managerClass();
}
}
this和super的总结:
1.成员变量
(1)this.变量名:找本类的成员变量,没有继续找父类
(2)super.变量名:找父类的成员变量,没有继续找父类的父类
2.成员方法
(1)this.成员方法名(实际参数列表):找本类的其他方法,但是不要出现自己调用自己的情况
(2)super.成员方法名(实际参数列表):找父类的成员方法
3.构造方法
(1)this.(实际参数列表):调用本类自己的其他构造方法,但是不要出现自己调用自己的情况
(2)super.成员方法名(实际参数列表):调用父类自己的构造方法
7.继承的特点
- 继承只能是单继承,不能多继承(子类只能有一个父类)
- 继承可以多层继承
- 一个父类可以有多个子类
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aA3RxsYU-1669299784506)(C:\Users\王超越\AppData\Roaming\Typora\typora-user-images\image-20221124192948299.png)]
2、抽象类
1.抽象类概述
-
什么是抽象类
- 在类的设计中把说不清楚的,不够具体的,但是子类要用的功能,在父类中声明为抽象方法,此时的类必须是抽象类。父类具体无法实现的方法称为抽象方法。即父类不管,子类自己决定
- 关键字:abstruct
-
抽象类的定义格式
public abstruct class 类名{ //成员变量/成员方法/构造方法 //抽象方法 public abstruct 返回值类型 方法名称(形参列表...)//没有{} }
-
注意
- 抽象方法所在的类一定是抽象类
- 抽象类中不一定非得有抽象方法
- 子类继承抽象父类后,必须要重写全部的抽象方法,否则子类也必须为抽象类
- 抽象不用看作是一门技术,抽象更偏向与代码的设计理念,而且抽象类肯定是作为父类来使用的
- 抽象类不能直接new对象,只能创建其非抽象子类的对象
- 抽象类中可以有构造方法,是供子类创建对象使用的,用来初始化父类成员的
- 抽象类中,可以有成员变量
- 抽象类中,不一定包含抽象方法,但是有抽象方法的类一定是抽象类
- 抽象类的子类必须重写抽象父类中的所有抽象方法,否则编译无法通过.除非该子类也是抽象类
//抽象类Animal
package com.itheima.p7_extends_abstract; public abstract class Animal { private String name; private int weight; public Animal() { } public Animal(String name, int weight) { this.name = name; this.weight = weight; } public abstract void eat(); public abstract void sleep(); public void showInfo(){ System.out.println("名字是:"+name+",体重是:"+weight); } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getWeight() { return weight; } public void setWeight(int weight) { this.weight = weight; } } //子类Dog package com.itheima.p7_extends_abstract; public class Dog extends Animal{ public Dog() { } public Dog(String name, int weight) { super(name, weight); } @Override public void eat() { System.out.println("🐕:"+getName()+"吃骨头"); } @Override public void sleep() { System.out.println("🐕:"+getName()+"睡觉"); } public void lookHome(){ System.out.println("🐕:"+getName()+"看家"); } } //子类Cat package com.itheima.p7_extends_abstract; public class Cat extends Animal{ public Cat() { } public Cat(String name, int weight) { super(name, weight); } @Override public void eat() { System.out.println("🐱:"+getName()+"吃鱼"); } @Override public void sleep() { System.out.println("🐱:"+getName()+"睡觉"); } public void catchMouse(){ System.out.println("🐱:"+getName()+"抓老鼠"); } } //测试类 package com.itheima.p7_extends_abstract; public class Demo { public static void main(String[] args) { //通过无参 Dog dog = new Dog(); dog.setName("大黄"); dog.setWeight(50); dog.showInfo(); dog.eat(); dog.lookHome(); dog.sleep(); System.out.println("============="); //通过有参 Cat cat = new Cat("咪咪", 15); cat.showInfo(); cat.eat(); cat.catchMouse(); cat.sleep(); } }
id catchMouse(){
System.out.println(“🐱:”+getName()+“抓老鼠”);
}
}
//测试类
package com.itheima.p7_extends_abstract;
public class Demo {
public static void main(String[] args) {
//通过无参
Dog dog = new Dog();
dog.setName(“大黄”);
dog.setWeight(50);
dog.showInfo();
dog.eat();
dog.lookHome();
dog.sleep();
System.out.println("=============");
//通过有参
Cat cat = new Cat("咪咪", 15);
cat.showInfo();
cat.eat();
cat.catchMouse();
cat.sleep();
}
}