第一章 面向对象高级部分

发布于:2025-03-18 ⋅ 阅读:(16) ⋅ 点赞:(0)

1. static

1.1 面向对象高级部分内容介绍

在这里插入图片描述

1.2 static:修饰成员变量

static:静态,可以修饰成员变量和成员方法。

在这里插入图片描述

在这里插入图片描述

类变量在计算机中的执行原理:类变量在计算机中的执行原理.mp4 链接: https://pan.baidu.com/s/1GbxQNu8xGV2iZtBjmU35dw?pwd=hxtn 提取码: hxtn

类变量在计算机中的执行原理

1.3 static:类变量的应用场景

在开发中,如果某个数据只需要一份,且希望能够被共享(访问、修改),则该数据可以定义成类变量来记住。

需求:要求用户类记住创建了多少个用户对象。

用户类:

package com.itheima.staticDemo;

/**
 * @ClassName User
 * @Description 用户类
 * @Author 孙克旭
 * @Date 2025/3/15 13:58
 */
public class User {
    //类变量一般用public修饰
    public static int number;

    //每创建一个用户对象,都会执行一次构造器
    public User() {
        number++;
    }

}

测试类:

package com.itheima.staticDemo;

/**
 * @ClassName UserTest
 * @Description 用户测试类
 * @Author 孙克旭
 * @Date 2025/3/15 14:01
 */
public class UserTest {
    public static void main(String[] args) {
        User u1 = new User();
        User u2 = new User();
        User u3 = new User();
        User u4 = new User();
        User u5 = new User();
        System.out.println(User.number); //5
    }
}

1.4 static:修饰成员方法

在这里插入图片描述

在这里插入图片描述

类方法在计算机中的执行原理:类方法在计算机中的执行原理.mp4 链接: https://pan.baidu.com/s/15rq4Qg041Cgh4e6HdikcNw?pwd=r3re 提取码: r3re

类方法在计算机中的执行原理

1.4.1 搞懂main方法

在这里插入图片描述

1.5 static:类方法的应用场景-工具类

类方法最常见的应用场景是做工具类。

  • 工具类中的方法都是一些类方法,每个方法都是用来完成一个功能的,工具类是给开发人员共同使用的特殊类。
  • 使用工具类的好处:提高了代码复用;调用方便,提高了开发效率。
  • 工具类没有创建对象的需求,建议将工具类的构造器进行私有。

1.5.1 为啥工具类中使用类方法?而不是实例方法?

  • 实例方法需要创建对象来调用,此时对象只是为了调用方法,对象占内存,这样会浪费内存。
  • 类方法,直接用类名调用即可,调用方便,也能节省内存。

1.6 static:注意事项

package com.itheima.staticDemo;

/**
 * @ClassName Student
 * @Description 学生类
 * @Author 孙克旭
 * @Date 2025/3/15 13:14
 */
public class Student {
    //类变量
    static String name;
    //实例变量(对象的变量)
    int age;

    //1.类方法中可以访问类成员(类变量、类方法),不能访问实例成员
    //3.this关键字只能在实例方法中,不能被类方法调用
    public static void print() {
        name = "孙克旭";
//        System.out.println(age); 访问失败
        print1();
//        print2(); 访问失败
//        System.out.println(this); 报错
    }

    //类方法
    public static void print1() {
        System.out.println("Hello World1");
    }

    //2.实例方法中既可以访问类成员,可以访问实例成员
    public void print2() {
        System.out.println("Hello World2");
        name = "孙克旭";
        age = 10;
        print1();
        print3();
        System.out.println(this);
    }

    //实例方法
    public void print3() {
        System.out.println("Hello World3");
    }
}

1.7 单元测试

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

1.8 单元练习1

1.8.1 什么是static关键字?

static是java中的关系字,可以修饰成员变量,被称为静态变量,也叫类变量,也可以修饰成员方法,被称为静态方法,又叫类方法

1.8.2 static关键字有什么特点?

1.可以通过类名调用,也可以通过对象名调用,推荐使用类名调用
2.被类的所有对象共享
3.随着类的存在而存在,优先于对象存在

1.8.3 请分析如下程序编译是否会报错并说明原因?

public class Student {
public static void method() {
System.out.println("static的method方法");
show();
}
private void show() {
System.out.println("非静态的show方法");
}
}

会报错,静态方法method直接调用非静态方法show

1.8.4 编码题1

学生具有姓名、年龄、生日等属性(这些学生均为15岁),有学习的能力
要求:
①定义一个学生类,描述班级学生的班级、姓名、年龄、生日这些属性(私有)
②定义一个可以通过类名来调用学生学习的方法
③编写测试类通过类名调用学习方法(输出格式如下)
好好学习,天天向上
④创建两个学生对象张三和李四,在控制台输出学员的信息(输出格式如下)
张三,15岁,生日:9月12日
李四,15岁,生日:9月15日


学生类:

package com.itheima.staticDemo.work;

/**
 * @ClassName Student
 * @Description 学生类
 * @Author 孙克旭
 * @Date 2025/3/15 15:24
 */
public class Student {
    private String name;
    private final int age = 15;
    private String birthday;
    private String Class;

    /**
     * 类方法
     */
    public static void study() {
        System.out.println("好好学习,天天向上!");
    }

    @Override
    public String toString() {
        return name + "," + age + ", birthday:" + birthday;
    }

    public Student() {
    }

    public Student(String name, String birthday) {
        this.name = name;
        this.birthday = birthday;
    }

    public Student(String name, String birthday, String aClass) {
        this.name = name;
        this.birthday = birthday;
        Class = aClass;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public String getBirthday() {
        return birthday;
    }

    public void setBirthday(String birthday) {
        this.birthday = birthday;
    }


    public void setClass(String aClass) {
        Class = aClass;
    }

}

测试类:

package com.itheima.staticDemo.work;

/**
 * @ClassName Demo1
 * @Description 编码题
 * @Author 孙克旭
 * @Date 2025/3/15 15:23
 */
public class Demo1 {
    public static void main(String[] args) {
        Student.study();
        Student student = new Student("张三", "9月12日");
        Student student2 = new Student("李四", "9月15日");
        System.out.println(student);
        System.out.println(student2);
    }
}

1.8.5 编码题2

定义一个尊享无忧的学生类(Student),
①学生类的成员属性分别是姓名(name),年龄(age),语文成绩(yuwen),数学成绩(shuxue),班级(banji)(所有的学生都是尊享无忧班级)
②定义学习的方法(study)
③创一个测试类,并完成如下内容:
创建两个学生对象张三和李四,通过成员方法(study)将学生信息打印到控制台上。(格式如下)
张三,18岁,语文成绩:98,数学成绩:90,班级:尊享无忧
好好学习,天天向上
张三,19岁,语文成绩:98,数学成绩:90,班级:尊享无忧
好好学习,天天向上


学生类:

package com.itheima.staticDemo.work;

/**
 * @ClassName Student
 * @Description 学生类
 * @Author 孙克旭
 * @Date 2025/3/15 15:24
 */
public class Student {
    private String name;
    private int age;
    private double yuwen;
    private double shuxue;

    public void study() {
        System.out.println(name + "," + age + "岁,语文成绩:" + yuwen + ",数学成绩:" + shuxue + ",班级:尊享无忧");
        System.out.println("好好学习,天天向上!");
    }

    public Student(String name, int age, double yuwen, double shuxue) {
        this.name = name;
        this.age = age;
        this.yuwen = yuwen;
        this.shuxue = shuxue;
    }
}

测试类:

package com.itheima.staticDemo.work;

/**
 * @ClassName Demo2
 * @Description 编码题
 * @Author 孙克旭
 * @Date 2025/3/15 15:23
 */
public class Demo1 {
    public static void main(String[] args) {
        Student student = new Student("张三", 18, 98, 90);
        Student student2 = new Student("李四", 19, 90, 89);
        student.study();
        student2.study();
    }
}

1.8.6 编码题3

超市从新西兰引进一批牛肉,请定义一个类,有成员属性分别是部位,价格,产地(都是新西兰),创建一个测试类并完成如下内容:
① 创建对象通过成员方法将肉类信息打印到控制台上。(格式如下)
产自新西兰的上脑115元/斤
产自新西兰的吊龙
105元/斤
② 在main方法中生成一个1-1000钱随机数(整数、单位:元),问最多能购买多少斤上脑并输出在控制台上,最多能购买多少斤吊龙并输出在控制台上。(不足1斤,则舍掉)
最终结果例如:
150元能买1斤上脑
150元能买1斤吊龙


牛肉类:

package com.itheima.staticDemo.work;

/**
 * @ClassName Beef
 * @Description 牛肉类
 * @Author 孙克旭
 * @Date 2025/3/15 16:18
 */
public class Beef {
    private String part; //部位
    private double price; //价格
    public static String origin = "新西兰"; //产地

    public void buy(int money) {
        System.out.println(money + "元能买" + (int) (money / price) + "斤" + part);
    }

    public Beef(String part, double price) {
        this.part = part;
        this.price = price;
    }

    public String getPart() {
        return part;
    }

    public void setPart(String part) {
        this.part = part;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    public static String getOrigin() {
        return origin;
    }

    public static void setOrigin(String origin) {
        Beef.origin = origin;
    }

    @Override
    public String toString() {
        return "产自" + origin + "的" + part + "==" + price + "元/斤";
    }
}

测试类:

package com.itheima.staticDemo.work;

import java.util.Random;

/**
 * @ClassName BeefTest
 * @Description 牛肉测试类
 * @Author 孙克旭
 * @Date 2025/3/15 16:21
 */
public class BeefTest {
    public static void main(String[] args) {
        Random random = new Random();
        Beef b1 = new Beef("上脑", 115);
        Beef b2 = new Beef("吊龙", 105);
        System.out.println(b1);
        System.out.println(b2);
        int money = random.nextInt(1000) + 1;
        b1.buy(money);
        b2.buy(money);
    }
}

2. 设计模式&继承

2.1 类的成分:代码块

2.1.1 静态代码块

  • 格式:static { }
  • 特点:类加载时自动执行,由于类只会加载一次,所以静态代码快也只会执行一次。
  • 作用:完成类的初始化,例如:对类变量的初始化赋值。

在这里插入图片描述

2.1.2 实例代码块

  • 格式:{ }
  • 特点:每次创建对象时,执行实例代码块,并在构造器前执行
  • 作用:和构造器一样,都是用来完成对象的初始化的,例如:对实例变量进行初始化赋值

在这里插入图片描述

2.2 设计模式:概述、饿汉式单例

在这里插入图片描述

2.2.1 单例设计模式

确保一个类只有一个对象(对类做结扎手术)

饿汉式单例:

  • 把类的构造器私有
  • 定义一个类变量记住类的一个对象
  • 定义一个类方法,返回对象

在这里插入图片描述

2.2.2 单例有啥应用场景?有啥好处?

  • 任务管理器、获取运行时对象(Runtime)
  • 在这些业务场景下,使用单例模式,可以避免浪费内存

2.3 设计模式:懒汉式单例

在这里插入图片描述

在这里插入图片描述

2.4 继承:概述

Java中提供了一个关键字extends,用这个关键字,可以让一个类和另一个类建立起父子关系。

在这里插入图片描述

  • 继承的特点:子类能继承父类的非私有成员(成员变量、成员方法)
  • 继承后对象的创建:子类的对象是由子类、父类共同完成的

继承的执行原理:继承的执行原理.mp4 链接: https://pan.baidu.com/s/1nX0noKghwJUdawW_1IAX7w?pwd=4g6k 提取码: 4g6k

继承的执行原理

2.5 继承:使用继承的好处

  • 减少重复代码的编写

父类:

package com.itheima.extendsDemo;

/**
 * @ClassName People
 * @Description 父类
 * @Author 孙克旭
 * @Date 2025/3/15 21:16
 */
public class People {

    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}

子类:

package com.itheima.extendsDemo;

/**
 * @ClassName Teacher
 * @Description 子类
 * @Author 孙克旭
 * @Date 2025/3/15 21:18
 */
public class Teacher extends People {
    private String skill;

    public String getSkill() {
        return skill;
    }

    public void setSkill(String skill) {
        this.skill = skill;
    }

    public void print() {
        System.out.println(getName() + "具备的技能:" + skill);
    }
}

测试类:

package com.itheima.extendsDemo;

/**
 * @ClassName Test
 * @Description 测试类
 * @Author 孙克旭
 * @Date 2025/3/15 21:24
 */
public class Test {
    public static void main(String[] args) {
        Teacher teacher = new Teacher();
        teacher.setName("孙克旭");
        teacher.setSkill("Java、Linux");
        teacher.print();
    }
}

2.6 继承:权限修饰符

在这里插入图片描述

  • “任意包下的子类”:表示子类而不是子类对象

2.7 单元练习2

2.7.1 使用单例模式的好处有哪些?

实例控制,单例模式会阻止其他对象实例化其自己的单例对象的副本,从而确保所有对象都访问唯一实例。
灵活性,因为类控制了实例化过程,所以类可以灵活更改实例化过程

2.7.2 下面程序编译是否会报错并说明原因?

public class fu {
    private int a=45;
}
class zi extends fu {
    public void show() {
        System.out.println(a);
    }
}

会报错,子类不能直接调用父类私有变量a

2.7.3 使用继承的好处有哪些?

提高了代码的复用性(多个类相同的成员可以放到同一个类里)
提高了代码的维护性(如果放大的代码需要修改,修改一处就行)

2.7.4 编码题1

模拟教学管理系统师生信息。
①定义Person类包含属性:姓名、年龄;和成员方法:getXxx方法,setXxx方法,显示基本信息showMsg方法
②定义Teacher类,继承Person包含属性:学科;和成员方法:getXxx方法,setXxx方法,讲课方法
③定义Student类,继承Person包含属性:分数和成员方法:getXxx方法,setXxx方法,考试方法
④最后定义测试类,输出案例如图:

在这里插入图片描述


People类:

package com.itheima.extendsDemo.work;

/**
 * @ClassName Person
 * @Description Person类
 * @Author 孙克旭
 * @Date 2025/3/16 8:00
 */
public class Person {
    private String name; //姓名
    private int age; // 年龄

    public void showMsg() {
        System.out.println("姓名:" + name + ",年龄:" + 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;
    }
}

学生类:

package com.itheima.extendsDemo.work;

import com.itheima.extendsDemo.People;

/**
 * @ClassName Student
 * @Description 学生类
 * @Author 孙克旭
 * @Date 2025/3/16 8:04
 */
public class Student extends People {
    private double score;

    public void examination() {
        System.out.println(getName() + "考试得了"+score);
    }

    public double getScore() {
        return score;
    }

    public void setScore(double score) {
        this.score = score;
    }
}

教师类:

package com.itheima.extendsDemo.work;

import com.itheima.extendsDemo.People;

/**
 * @ClassName Teacher
 * @Description Teacher类
 * @Author 孙克旭
 * @Date 2025/3/16 8:03
 */
public class Teacher extends People {

    private String subject; //subject

    public void speak() {
        System.out.println(getName() + "讲课" + subject);
    }

    public String getSubject() {
        return subject;
    }

    public void setSubject(String subject) {
        this.subject = subject;
    }
}

测试类:

package com.itheima.extendsDemo.work;

/**
 * @ClassName Test1
 * @Description 测试类
 * @Author 孙克旭
 * @Date 2025/3/16 8:06
 */
public class Test1 {
    public static void main(String[] args) {
        Teacher teacher = new Teacher();
        teacher.setName("王老师");
        teacher.setSubject("Java");
        teacher.speak();
        Student student = new Student();
        student.setName("孙克旭");
        student.setScore(100);
        student.examination();
    }
}

2.7.5 编码题2

按照提示模拟汽车网站信息
①定义汽车Auto类

属性:品牌,车长,价格
②定义SUV继承Auto类,包含
(1)属性:小型车车长标准值:4295,中型车车长标准值:5070。
(2)定义判断车型方法
判断小型车:小于小型车车长标准值
判断大型车:大于中型车车长标准值
判断中型车:大于小型车车长标准值并且小于等于中型车车长标准值
③测试类中,创建若干SUV对象,保存到集合,遍历集合,输出中型SUV
输出示例如图:

在这里插入图片描述


Auto类:

package com.itheima.extendsDemo.work;

/**
 * @ClassName Auto
 * @Description Auto类
 * @Author 孙克旭
 * @Date 2025/3/16 8:15
 */
public class Auto {
    private String brand; //品牌
    private double length;//车长
    private double price;// 价格

    public Auto() {
    }

    public Auto(String brand, double length, double price) {
        this.brand = brand;
        this.length = length;
        this.price = price;
    }

    @Override
    public String toString() {
        return "Auto{" +
                "brand='" + brand + '\'' +
                ", length=" + length +
                ", price=" + price +
                '}';
    }

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public double getLength() {
        return length;
    }

    public void setLength(double length) {
        this.length = length;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }
}

SUV类:

package com.itheima.extendsDemo.work;

/**
 * @ClassName SUV
 * @Description SUV
 * @Author 孙克旭
 * @Date 2025/3/16 8:28
 */
public class SUV extends Auto {
    private int smallCarLength = 4295;
    private int mediumCarLength = 5070;

    public SUV(String brand, double length, double price) {
        super(brand, length, price);
    }

    public String judge() {
        double length = getLength();
        if (length < smallCarLength) {
            return "小型车";
        } else if (length > mediumCarLength) {
            return "大型车";
        } else if (length > smallCarLength && length <= mediumCarLength) {
            return "中型车";
        } else {
            return null;
        }
    }
}

测试类:

package com.itheima.extendsDemo.work;

import java.util.ArrayList;

/**
 * @ClassName Test2
 * @Description 测试类
 * @Author 孙克旭
 * @Date 2025/3/16 8:34
 */
public class Test2 {
    public static void main(String[] args) {
        ArrayList<SUV> suvs = new ArrayList<>();
        suvs.add(new SUV("A", 5000, 52453));
        suvs.add(new SUV("B", 4500, 5453));
        suvs.add(new SUV("C", 4500, 452453));
        suvs.add(new SUV("D", 6000, 4553));
        suvs.add(new SUV("E", 4550, 452453));
        for (int i = 0; i < suvs.size(); i++) {
            SUV suv = suvs.get(i);
            if ("中型车".equals(suv.judge())) {
                System.out.println(suv);
            }
        }
    }
}

2.7.6 编码题3

请使用面向对象的思想,设计自定义类,描述出租车和家用轿车的信息,要求如下。
①分析出租车和家用轿车的公共成员,提取出父类—汽车类(这里父类不写方法,可在学完方法重写后再优化)
分析:
出租车类属性包括:车型,车牌,所属出租公司;方法包括:启动,停止(输出相应对顾客的提醒问候语)
家用轿车类属性包括:车型,车牌,车主姓名;方法包括:启动,停止
②利用继承机制,实现出租车类和家用轿车类
③编写测试类,分别测试出租车类和家用轿车类对象的相关方法
④定义名为car的包存放汽车类,出租车类,家用轿车类和测试类

在这里插入图片描述


Car类:

package com.itheima.extendsDemo.work;

/**
 * @ClassName Car
 * @Description Car类
 * @Author 孙克旭
 * @Date 2025/3/16 8:45
 */
public class Car {
    private String type; //车型
    private String brand; //车牌

    public void start() {
        System.out.println("汽车启动!");
    }

    public void stop() {
        System.out.println("汽车停止!");
    }

    public Car() {
    }

    public Car(String type, String brand) {
        this.type = type;
        this.brand = brand;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

}

Taxi类:

package com.itheima.extendsDemo.work;

/**
 * @ClassName Taxi
 * @Description 出租车类
 * @Author 孙克旭
 * @Date 2025/3/16 8:52
 */
public class Taxi extends Car {
    private String belongingCompany; //所属公司

    @Override
    public void start() {
        System.out.println("欢迎乘坐" + belongingCompany + "的车牌号为" + getBrand() + "的" + getType() + "型出租车,请系好安全带");
    }

    @Override
    public void stop() {
        System.out.println("感谢乘坐" + belongingCompany + "的车牌号为" + getBrand() + "的" + getType() +
                "型出租车,下车时请带好随身物品");
    }

    public Taxi() {
    }

    public Taxi(String type, String brand, String belongingCompany) {
        super(type, brand);
        this.belongingCompany = belongingCompany;
    }

    public String getBelongingCompany() {
        return belongingCompany;
    }

    public void setBelongingCompany(String belongingCompany) {
        this.belongingCompany = belongingCompany;
    }

}

家用汽车类:

package com.itheima.extendsDemo.work;

/**
 * @ClassName FamilyCar
 * @Description 家用轿车
 * @Author 孙克旭
 * @Date 2025/3/16 8:57
 */
public class FamilyCar extends Car {
    private String CarOwnerName; //车主姓名

    @Override
    public void start() {
        System.out.println("您现在驾驶的是" + CarOwnerName + "的车牌号为" + getBrand() + "的" + getType() + ",请系好安全带");
    }

    @Override
    public void stop() {
        System.out.println(CarOwnerName + "的车牌号为" + getBrand() + "的" + getType() + "行驶完毕");
    }

    public FamilyCar() {
    }

    public FamilyCar(String type, String brand, String carOwnerName) {
        super(type, brand);
        CarOwnerName = carOwnerName;
    }

    public String getCarOwnerName() {
        return CarOwnerName;
    }

    public void setCarOwnerName(String carOwnerName) {
        CarOwnerName = carOwnerName;
    }
}

测试类:

package com.itheima.extendsDemo.work;

/**
 * @ClassName Test3
 * @Description 测试类
 * @Author 孙克旭
 * @Date 2025/3/16 9:00
 */
public class Test3 {
    public static void main(String[] args) {
        Taxi taxi = new Taxi("SUV", "京A.J888888", "传智播客");
        taxi.start(); //欢迎乘坐传智播客的车牌号为京A.J888888的SUV型出租车,请系好安全带
        taxi.stop(); //感谢乘坐传智播客的车牌号为京A.J888888的SUV型出租车,下车时请带好随身物品
        FamilyCar familyCar = new FamilyCar("Tesla", "京A.J888888", "孙克旭");
        familyCar.start(); //您现在驾驶的是孙克旭的车牌号为京A.J888888的Tesla,请系好安全带
        familyCar.stop(); //孙克旭的车牌号为京A.J888888的Tesla行驶完毕
    }
}

3. 继承

3.1 继承:特点详解

在这里插入图片描述

  • Object类是所有类的祖宗类,所有类都是Object类的子类

3.2 继承:方法重写

子类重写一个方法名称、参数列表一样的方法,去覆盖父类的这个方法,这就是方法重写。

重写后,方法的访问,Java会遵循就近原则。

方法重写的其它注意事项

  1. 重写小技巧:使用Override注解,他可以指定java编译器,检查我们方法重写的格式是否正确,代码可读性也会更好。
  2. 子类重写父类方法时,访问权限必须大于或者等于父类该方法的权限(public>protected>缺省)。
  3. 重写的方法返回值类型,必须与被重写方法的返回值类型一样,或者范围更小。
  4. 私有方法、静态方法不能被重写,如果重写会报错的

方法重载的应用:

  • 子类重写toString方法,输出对象的属性

3.3 继承:子类访问的特点

  • 在子类方法中访问其他成员(成员变量、成员方法),是依照就近原则的。

在这里插入图片描述

  • 如果子父类中,出现了重名的成员,会优先使用子类的,如果此时一定要在子类中使用父类怎么办?
  • 可以通过super关键字,指定父类的成员:super.父类成员变量/父类成员方法

3.4 继承:子类构造器的特点

子类的全部构造器,都回先调用父类的构造器,再调用自己的。

在这里插入图片描述

  • 默认情况下,子类全部构造器的第一行代码都是super()(写不写都有),它会调用父类的无参数构造器。
  • 如果父类没有无参数构造器,则我们必须在子类构造器的第一行手写super(…),指定去调用父类的有参数构造器。

3.5 继承:子类构造器的常见应用

  • 将多个属性通过父类和子类构造器进行赋值。
package com.itheima.extendsDemo;

/**
 * @ClassName Demo1
 * @Description 子类构造器
 * @Author 孙克旭
 * @Date 2025/3/16 11:15
 */
public class Demo1 {
    public static void main(String[] args) {
        Student student = new Student("孙克旭", 20, "学习");
      /*  父类构造器 
          子类构造器*/
    }

}

class Person {
    private String name;
    private int age;

    public Person() {
    }

    public Person(String name, int age) {
        System.out.println("父类构造器");
        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;
    }
}


class Student extends Person {
    private String skill;

    public Student() {
    }

    public Student(String name, int age, String skill) {
        super(name, age);
        System.out.println("子类构造器");
        this.skill = skill;
    }

    public String getSkill() {
        return skill;
    }

    public void setSkill(String skill) {
        this.skill = skill;
    }
}

子类构造器的执行原理:子类构造器的执行原理.mp4 链接: https://pan.baidu.com/s/1wSdxbqbVW1Xl4hRwX6ac3w?pwd=t1wq 提取码: t1wq

子类构造器的执行原理

3.6 其他:this()调用兄弟构造器

在类中,可以通过this()调用本类的其他构造器

在这里插入图片描述

3.7 单元测试

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

3.8 课后练习

3.8.1 题目一

分析事物的共性,并抽取出正确的继承体系
现有基础班老师(BaseTeacher)和就业班老师(WorkTeacher)两个类,两者都含有姓名和年龄两个属性,还有一个讲课的行为teach,但不同的是,基础班老师的teach方法输出【基础班老师讲JavaSE】,就业班老师的teach方法输出【就业班老师讲JavaEE】,请用代码实现。
运行结果:
张三老师…23
基础班老师讲JavaSE
李四老师…24
就业班老师讲JavaEE

##【训练目标】:
能够独立分析事物抽取出正确的继承体系

##【思路分析】:

  1. 两个类都有属性的姓名年龄,行为的teach方法均为共性内容,是否可以抽取?
  2. BaseTeacher和WorkTeacher作为子类,对于teach方法都有自己的实现方式,这时候需要做什么?
  3. 测试类创建两个类的对象,获取属性打印,并调用teach方法

Teacher类:

package com.itheima.extendsDemo.work1;

/**
 * @ClassName Teacher
 * @Description 教师类
 * @Author 孙克旭
 * @Date 2025/3/16 12:57
 */
public class Teacher {

    private String name; //姓名
    private int age; //年龄

    /**
     * 讲课
     */
    public void teach() {
        System.out.println("讲课");
    }

    public Teacher() {
    }

    public Teacher(String name, int age) {
        this.name = name;
        this.age = age;
        System.out.println(getName() + "……" + getAge());
    }

    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;
    }
}

BaseTeacher类:

package com.itheima.extendsDemo.work1;

/**
 * @ClassName BaseTeacher
 * @Description 基础班老师
 * @Author 孙克旭
 * @Date 2025/3/16 12:55
 */
public class BaseTeacher extends Teacher {
    public BaseTeacher(String name, int age) {
        super(name, age);
    }

    @Override
    public void teach() {
        System.out.println("【基础班老师讲JavaSE】");
    }
}

WorkTeacher类:

package com.itheima.extendsDemo.work1;

/**
 * @ClassName WorkTeacher
 * @Description 就业班老师
 * @Author 孙克旭
 * @Date 2025/3/16 13:03
 */
public class WorkTeacher extends Teacher {
    public WorkTeacher(String name, int age) {
        super(name, age);
    }

    @Override
    public void teach() {
        System.out.println("【就业班老师讲JavaEE】");
    }
}

测试类:

package com.itheima.extendsDemo.work1;

/**
 * @ClassName Test
 * @Description 测试类
 * @Author 孙克旭
 * @Date 2025/3/16 13:08
 */
public class Test {
    public static void main(String[] args) {
        BaseTeacher t1 = new BaseTeacher("孙克旭", 25);
        t1.teach();
        WorkTeacher t2 = new WorkTeacher("王老师", 40);
        t2.teach();
    }
}

3.8.2 题目二

结合继承的思想,分析下列需求并实现

  1. 定义项目经理类Manager 【属性:姓名 工号 工资 奖金】【行为:工作work】
  2. 定义程序员类Coder【属性:姓名 工号 工资】【行为:工作work】
  3. 要求:通过有参构造创建两个类的对象,并调用各自的work方法
    运行结果:
    姓名为:张三,工号为:9527,工资为:10000.0,的程序员正在编写代码
    姓名为:李四,工号为:9528,工资为:15000.0,奖金为:2000.0,的项目经理正在管理程序员写代码

##【训练目标】:
能够抽取出正确的继承体系,并解决子类特有属性的初始化问题

##【思路分析】:

  1. 姓名 工号 工资属性,work行为均为共性内容,是否可以向上抽取?
  2. 项目经理类中的奖金属于特有的内容,不应该抽取到父类中,那该定义在哪里?
  3. 集合题目和运行结果,重写work方法的时候,里面应该打印属性,子类该通过什么方式获取属性打印?

##【参考步骤】:

  1. 将同性行为向上抽取出一个父类,Employee(员工类)
  2. 编写子类构造方法的时候,通过super访问父类构造方法初始化,单独在项目经理Manager类中定义奖金属性,其中姓名 工号 工资属性通过父类初始化,奖金属性自己初始化。
  3. 重写父类work方法,通过super.getXxx获取属性并拼接打印
  4. 创建子类对象,并调用work方法

员工类:

package com.itheima.extendsDemo.work1;

/**
 * @ClassName Employee
 * @Description 员工类
 * @Author 孙克旭
 * @Date 2025/3/16 13:29
 */
public class Employee {
    private String name; //姓名
    private int id; //工号
    private double money; //工资

    /**
     * 工作
     */
    public void work() {
        System.out.print("姓名为" + name + ",工号为" + id + ",工资为" + money);
    }

    public Employee() {
    }

    public Employee(String name, int id, double money) {
        this.name = name;
        this.id = id;
        this.money = money;
    }

    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 double getMoney() {
        return money;
    }

    public void setMoney(double money) {
        this.money = money;
    }
}

经理类:

package com.itheima.extendsDemo.work1;

/**
 * @ClassName Manager
 * @Description 经理类
 * @Author 孙克旭
 * @Date 2025/3/16 13:31
 */
public class Manager extends Employee {

    private double bonus; //奖金

    @Override
    public void work() {
        super.work();
        System.out.println("的项目经理正在管理程序员写代码");
    }

    public Manager() {
    }

    public Manager(String name, int id, double money, double bonus) {
        super(name, id, money);
        this.bonus = bonus;
    }

    public double getBonus() {
        return bonus;
    }

    public void setBonus(double bonus) {
        this.bonus = bonus;
    }
}

程序员类:

package com.itheima.extendsDemo.work1;

/**
 * @ClassName Coder
 * @Description 程序员类
 * @Author 孙克旭
 * @Date 2025/3/16 13:34
 */
public class Coder extends Employee {

    public Coder(String name, int id, double money) {
        super(name, id, money);
    }

    @Override
    public void work() {
        super.work();
        System.out.println("的程序员正在编写代码");
    }

}

测试类:

package com.itheima.extendsDemo.work1;


/**
 * @ClassName Test2
 * @Description 测试类
 * @Author 孙克旭
 * @Date 2025/3/16 13:37
 */
public class Test2 {
    public static void main(String[] args) {
        Manager manager = new Manager("张三", 9527, 50000, 2000);
        manager.work(); //    姓名为张三,工号为9527,工资为50000.0的项目经理正在管理程序员写代码
        Coder coder = new Coder("孙克旭", 8628, 20000);
        coder.work(); //       姓名为孙克旭,工号为8628,工资为20000.0的程序员正在编写代码
    }
}

3.9 单元练习3

3.9.1 如何调用父类中的成员?

父类成员域由private修饰,那么在子类中不能直接访问父类成员域,但是可以通过父类中的公共方法访问以及修改父类成员域

3.9.2 继承中构造方法的访问有什么特点?

首先是构造方法的方法名要与类名一致。
构造方法无返回类型,void类型也不可以。
如果没有定义构造器,则会默认一个无参构造器。
与普通方法一样,构造器也支持重载。一个对象中是可以支持同时定义多个构造器,通过不同的参数列表来实现重载。
构造方法是不能被继承的,但是可以使用super来调用,且super必须声明在在子类构造方法中的首行。子类构造方法会默认调用父类无参构造器,如果父类没有无参构造器,则必须在子类构造器的第一行通过 super关键字指定调用父类的哪个构造器

3.9.3 编码题1

模拟简历信息
①定义一个Person类,有姓名(name)、年龄(age)、住址(address)属性,定义一个方法info描述个人信息
②编写学生类继承Person,重写info方法,描述自己的学生身份和个人信息
③编写老师类继承Person, 重写info方法,描述自己的老师身份和个人信息
④定义一个测试类,创建学生和老师对象,并分别调用info方法,把信息输出到控制台

在这里插入图片描述


Person类:

package com.itheima.extendsDemo.work2;

/**
 * @ClassName Person
 * @Description Person类
 * @Author 孙克旭
 * @Date 2025/3/16 13:56
 */
public class Person {
    private String name;
    private int age;
    private String address;

    public void info() {
        System.out.println(name + ",年龄:" + age + ",地址:" + address);
    }

    public Person() {
    }

    public Person(String name, int age, String address) {
        this.name = name;
        this.age = age;
        this.address = address;
    }

    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 getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }
}

学生类:

package com.itheima.extendsDemo.work2;

/**
 * @ClassName Student
 * @Description 学生类
 * @Author 孙克旭
 * @Date 2025/3/16 14:00
 */
public class Student extends Person {

    public Student(String name, int age, String address) {
        super(name, age, address);
    }

    @Override
    public void info() {
        System.out.print("我是学生:");
        super.info();
    }
}

教师类:

package com.itheima.extendsDemo.work2;

/**
 * @ClassName Teacher
 * @Description 教师类
 * @Author 孙克旭
 * @Date 2025/3/16 14:02
 */
public class Teacher extends Person {

    public Teacher(String name, int age, String address) {
        super(name, age, address);
    }

    @Override
    public void info() {
        System.out.print("我是老师:");
        super.info();
    }
}

测试类:

package com.itheima.extendsDemo.work2;

/**
 * @ClassName Test
 * @Description 测试类
 * @Author 孙克旭
 * @Date 2025/3/16 14:02
 */
public class Test {
    public static void main(String[] args) {
        Student student = new Student("孙克旭", 24, "济南");
        student.info(); //我是学生:孙克旭,年龄:24,地址:济南
        Teacher teacher = new Teacher("王老师", 35, "北京");
        teacher.info(); //我是老师:王老师,年龄:35,地址:北京
    }
}

3.9.4 编码题2

定义一个动物类,有品种、年龄(age)等属性,用吃食物等行为
①在动物类的子类,鲸鱼和狗(需重写吃食物的方法)
②定义一个测试类,创建鲸鱼和狗对象,并分别调用eat方法,把信息输出到控制台

在这里插入图片描述


动物类:

package com.itheima.extendsDemo.work2;

/**
 * @ClassName Animal
 * @Description 动物类
 * @Author 孙克旭
 * @Date 2025/3/16 14:09
 */
public class Animal {
    private String brand; //品种
    private int age; //年龄

    public void eat() {
        System.out.println(age + "岁大的" + brand + "正在吃东西");
    }

    public Animal() {
    }

    public Animal(String brand, int age) {
        this.brand = brand;
        this.age = age;
    }

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

鲸鱼类:

package com.itheima.extendsDemo.work2;
/**
 * @ClassName Whale
 * @Description 鲸鱼类
 * @Author 孙克旭
 * @Date 2025/3/16 14:11
 */
public class Whale extends Animal{

    public Whale(String brand, int age) {
        super(brand, age);
    }

}

狗类:

package com.itheima.extendsDemo.work2;

/**
 * @ClassName Dog
 * @Description 狗类
 * @Author 孙克旭
 * @Date 2025/3/16 14:13
 */
public class Dog extends Animal {

    public Dog(String brand, int age) {
        super(brand, age);
    }
}

测试类:

package com.itheima.extendsDemo.work2;

/**
 * @ClassName Test2
 * @Description 测试类
 * @Author 孙克旭
 * @Date 2025/3/16 14:14
 */
public class Test2 {
    public static void main(String[] args) {
        Whale whale = new Whale("虎鲸", 3);
        whale.eat(); //3岁大的虎鲸正在吃东西
        Dog dog = new Dog("柴犬", 5);
        dog.eat(); //5岁大的柴犬正在吃东西
    }
}

4. 多态、关键字、抽象类

4.1 多态:概述

多肽是在继承/实现情况下的一种现象,表现:对象多态、行为多态

在这里插入图片描述

在这里插入图片描述

多态前提:

  1. 有继承/实现关系
  2. 存在父类引用子类对象
  3. 存在方法重写

多态的一个注意事项

  • 多态是对象/行为的多态,Java中的属性(成员变量)不谈多态

4.2 多态:使用多态的好处

  • 在多态形式下,右边对象是解耦合的,更便于扩展和维护。
  • 定义方法时,使用父类类型的形参,可以接收一切子类对象,扩展性更强、更便利。

在这里插入图片描述

4.2.1 类型转换

在这里插入图片描述

在这里插入图片描述

4.3 前置知识:final关键字

  • final关键字是最终的意思,可以修饰(类、方法、变量)
  • 修饰类:该类被称为最终类,特点是不能被继承了。
  • 修饰方法:该方法被称为最终方法,特点是不能被重写了。
  • 修饰变量:该变量只能被赋值一次。

final修饰变量的注意:

  • final修饰基本类型的变量,变量存储的数据不能被改变。
  • final修饰引用类型的变量,变量存储的地址不能被改变,但地址所指向对象的内容是可以被改变的。

4.4 前置知识:常量

使用了static final修饰的成员变量就被称为常量;
作用:通常用于记录系统的配置信息。

在这里插入图片描述

使用常量的优势:

  • 代码可读性更好,可维护性也更好。
  • 程序编译后,常量会被“宏替换”:出现常量的地方全部会被替换成其记住的字面量
    这样可以保证使用常量和直接用字面量的性能是一样的。

4.5 抽象类:认识抽象类

在Java中有一个关键字叫:abstract,它就是抽象的意思,可以用它修饰类、成员方法。
abstract修饰类,这个类就是抽象类;修饰方法,这个方法就是抽象方法。

抽象类的注意事项、特点:

  • 抽象类中不一定有抽象方法,有抽象方法的类一定是抽象类。
  • 类该有的成员(成员变量、方法、构造器)抽象类都可以有。
  • 抽象类最主要的特点:抽象类不能创建对象,仅作为一种特殊的父类,让子类继承并实现。
  • 一个类继承抽象类,必须重写完抽象类的全部抽象方法,否则这个类也必须定义成抽象类。

4.6 抽象类:使用抽象类的好处

  • 两种主要的应用场景,一种是:用抽象类,我们可以把子类中相同的代码,包括方法签名都抽
    上来,这样能更好的支持多态,以提高代码的灵活性。
  • 一种是:反过来用,我们不知道系统未来具体的业务实现时,我们可以先定义抽象类,将来让
    子类去继承实现,以方便系统的扩展。

在这里插入图片描述

在这里插入图片描述

4.7 抽象类:模板方法设计模式

1、定义一个抽象类
2、在里面定义2个方法
一个是模板方法:把相同代码放里面去。

一个是抽象方法:具体实现交给子类完成。

在这里插入图片描述

建议使用final关键字修饰模板方法,为什么?

  • 模板方法是给对象直接使用的,不能被子类重写。一旦子类重写了模板方法,模板方法就失效了。

4.8 单元测试

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

4.9 单元练习4

4.9.1 下面代码编译时报错吗?如果报错怎么修改?

public abstract class Bike {
    int colornum;
    int brand;
    int speed;
    public abstract void speedup();
}
public class SpeedBike extends Bike { //位置一
    public void speedup();  //位置二
}

会报错,在位置一处将SpeedBike类设为抽象类,同时将位置2处的speedup也设为抽象方法
或将位置二中speedup()方法中加入方法的实现

4.9.2 多态的前提条件是什么?

1)有继承关系。
(2)有方法的重写。
(3)有父类引用指向子类对象。

4.9.3 多态的好处有哪些?

提高了代码的维护性(继承保证);提高了代码的扩展性

4.9.4 编码题1

①定义一个汽水类Drink(抽象类),汽水类中有一个味道的方法taste
②定义一个可口可乐类,Coco继承自汽水类,重写父类的taste方法,输出“我是可口可乐,我是甜汽水”;
③定义一个盐汽水类SaltDrink继承自汽水类,重写父类的taste方法,输出“我是盐汽水,我是咸的”;
④定义一个测试类,提供一个售卖汽水的方法sell,接收用户输入的值,如果是“甜的”,就卖给客户甜的汽水,否则卖给客户咸的汽水


汽水类:

package com.itheima.polymorphic;

/**
 * @ClassName Drink
 * @Description 汽水类
 * @Author 孙克旭
 * @Date 2025/3/16 17:53
 */
public abstract class Drink {
    /**
     * 味道
     */
    public abstract void taste();
}

可口可乐类:

package com.itheima.polymorphic;

/**
 * @ClassName Coco
 * @Description 可口可乐类
 * @Author 孙克旭
 * @Date 2025/3/16 17:54
 */
public class Coco extends Drink {
    @Override
    public void taste() {
        System.out.println("我是可口可乐,我是甜汽水");
    }
}

咸汽水类:

package com.itheima.polymorphic;

/**
 * @ClassName SaltDrink
 * @Description 盐汽水类
 * @Author 孙克旭
 * @Date 2025/3/16 17:55
 */
public class SaltDrink extends Drink {
    @Override
    public void taste() {
        System.out.println("我是盐汽水,我是咸的");
    }
}

测试类:

package com.itheima.polymorphic;

import java.util.Scanner;

/**
 * @ClassName Test1
 * @Description 测试类
 * @Author 孙克旭
 * @Date 2025/3/16 17:56
 */
public class Test1 {
    public static void main(String[] args) {
        sell();
    }

    public static void sell() {
        Scanner scanner = new Scanner(System.in);
        System.out.println("您喜欢什么味道的饮料?");
        String taste = scanner.next();
        switch (taste) {
            case "甜的":
                Coco coco = new Coco();
                coco.taste();
                break;
            case "咸的":
                SaltDrink saltDrink = new SaltDrink();
                saltDrink.taste();
                break;
            default:
                break;
        }
    }
}

4.9.5 编码题2

① 定义一个图形类Picture(抽象类),需包含属性:边长(sideLength)、边数(sideCount), 需包含抽象方法:求周长getPerimeter方法、求面积getArea方法、显示图形信息show方法
② 定义图形类Picture的两个子类:圆形类Circle 和 矩形类Rect
圆形类Cirle需包含属性:圆心x(centerX)、圆心y (centerY)、半径(radius),重写求周长、求面积方法、显示信息方法,矩形类Rect需包含属性:长(length)、宽(width),重写求周长、求面积方法、显示信息方法
③ 定义测试类:测试方法中用多态的形式创建圆形类Cirle对象 和 矩形类Rect对象,分别调用show方法显示信息


图形类:

package com.itheima.polymorphic;

/**
 * @ClassName Picture
 * @Description 图形类
 * @Author 孙克旭
 * @Date 2025/3/16 19:04
 */
public abstract class Picture {
    private int sideLength; //边长
    private int sideCount; //边数

    /**
     * 求周长
     *
     * @return
     */
    public abstract double getPerimeter();

    /**
     * 求面积
     *
     * @return
     */
    public abstract double getArea();

    /**
     * 显示图形信息
     */
    public abstract void show();

    public Picture() {
    }

    public Picture(int sideLength, int sideCount) {
        this.sideLength = sideLength;
        this.sideCount = sideCount;
    }

    public int getSideLength() {
        return sideLength;
    }

    public void setSideLength(int sideLength) {
        this.sideLength = sideLength;
    }

    public int getSideCount() {
        return sideCount;
    }

    public void setSideCount(int sideCount) {
        this.sideCount = sideCount;
    }
}

圆形类:

package com.itheima.polymorphic;

/**
 * @ClassName Circle
 * @Description 圆形类
 * @Author 孙克旭
 * @Date 2025/3/16 19:10
 */
public class Circle extends Picture {
    private final double PI = 3.14;
    private int centerX; //圆心x
    private int centerY; //圆心y
    private int radius; //半径

    public Circle() {
    }

    public Circle(int radius) {
        this.radius = radius;
    }

    public Circle(int centerX, int centerY, int radius) {
        this.centerX = centerX;
        this.centerY = centerY;
        this.radius = radius;
    }

    public int getCenterX() {
        return centerX;
    }

    public void setCenterX(int centerX) {
        this.centerX = centerX;
    }

    public int getCenterY() {
        return centerY;
    }

    public void setCenterY(int centerY) {
        this.centerY = centerY;
    }

    public int getRadius() {
        return radius;
    }

    public void setRadius(int radius) {
        this.radius = radius;
    }

    @Override
    public double getPerimeter() {
        return 2 * PI * radius;
    }

    @Override
    public double getArea() {
        return PI * radius * radius;
    }

    @Override
    public void show() {
        System.out.println("圆的半径:" + radius + ",周长:" + getPerimeter() + ",面积:" + getArea());
    }
}

矩形类:

package com.itheima.polymorphic;

/**
 * @ClassName Rect
 * @Description 矩形类
 * @Author 孙克旭
 * @Date 2025/3/16 19:19
 */
public class Rect extends Picture {
    private int length; //长
    private int width; //宽

    public Rect() {
    }

    public Rect(int length, int width) {
        this.length = length;
        this.width = width;
    }

    public int getLength() {
        return length;
    }

    public void setLength(int length) {
        this.length = length;
    }

    public int getWidth() {
        return width;
    }

    public void setWidth(int width) {
        this.width = width;
    }

    @Override
    public double getPerimeter() {
        return 2 * (length + width);
    }

    @Override
    public double getArea() {
        return length * width;
    }

    @Override
    public void show() {
        System.out.println("矩形的长:" + length + ",宽:" + width + ",周长:"
                + getPerimeter() + ",面积:" + getArea());
    }
}

测试类:

package com.itheima.polymorphic;

/**
 * @ClassName Test2
 * @Description 测试类
 * @Author 孙克旭
 * @Date 2025/3/16 19:23
 */
public class Test2 {
    public static void main(String[] args) {
        Picture circle = new Circle(2);
        circle.show(); //圆的半径:2,周长:12.56,面积:12.56
        Picture rect = new Rect(5, 8);
        rect.show(); //矩形的长:5,宽:8,周长:26.0,面积:40.0
    }
}

4.9.6 编码题3

有一个游戏设计有以下需求:
① 父类:角色Role 是所有职业的父类(抽象类),需包含属性:角色的名字(name),
需包含抽象方法:伤害统计方法:public int attack() :返回值为角色的攻击对敌人的伤害值
② 定义Role的两个子类:法师Magician 和 战士Soldier
法师Magician需包含属性:魔法等级(magicLevel),
方法:重写父类attack(); 返回法师的攻击对敌人造成的伤害值。法师攻击伤害值为:魔法等级*魔法基本伤害值(固定为5)
战士Soldier需包含属性:攻击伤害值(attackPower),
方法:重写父类attack(); 返回战士的攻击对敌人造成的伤害值。战士的攻击伤害值为:其攻击伤害属性值
③ 定义Team类(表示组队):方法:addMember(); 增加一个队员(注意:组队成员最多为6人) 提示:利用一个数组属性,保存所有成员
方法:attackSum (); 表示组队所有成员进行攻击时,对敌人造成的总伤害值
④ 定义测试类:创建一个Magician对象和一个Soldier对象,以及一个小队Team ,将Magician和Soldier对象加入小队,然后调用小队的伤害计算方法


角色类:

package com.itheima.polymorphic;

/**
 * @ClassName Role
 * @Description 角色类
 * @Author 孙克旭
 * @Date 2025/3/16 19:33
 */
public abstract class Role {
    private String name;

    /**
     * 攻击的伤害值
     *
     * @return
     */
    public abstract int attack();

    public Role() {
    }

    public Role(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

法师类:

package com.itheima.polymorphic;

/**
 * @ClassName Magician
 * @Description 法师
 * @Author 孙克旭
 * @Date 2025/3/16 19:37
 */
public class Magician extends Role {
    private int magicLevel; //魔法等级

    @Override
    public int attack() {
//        魔法等级*魔法基本伤害值(固定为5)
        return magicLevel * 5;
    }

    public Magician() {
    }

    public Magician(String name, int magicLevel) {
        super(name);
        this.magicLevel = magicLevel;
    }

    public int getMagicLevel() {
        return magicLevel;
    }

    public void setMagicLevel(int magicLevel) {
        this.magicLevel = magicLevel;
    }
}

战士类:

package com.itheima.polymorphic;

/**
 * @ClassName Soldier
 * @Description 战士类
 * @Author 孙克旭
 * @Date 2025/3/16 19:39
 */
public class Soldier extends Role {
    private int attackPower; //攻击伤害值

    @Override
    public int attack() {
        return attackPower;
    }

    public Soldier() {
    }

    public Soldier(String name, int attackPower) {
        super(name);
        this.attackPower = attackPower;
    }

    public int getAttackPower() {
        return attackPower;
    }

    public void setAttackPower(int attackPower) {
        this.attackPower = attackPower;
    }
}

队伍类:

package com.itheima.polymorphic;

import java.util.ArrayList;

/**
 * @ClassName Team
 * @Description 组多类
 * @Author 孙克旭
 * @Date 2025/3/16 19:42
 */
public class Team {
    private ArrayList<Role> roles = new ArrayList<>();

    /**
     * 增加一个队员
     *
     * @param role
     */
    public void addMember(Role role) {
        if (roles.size() < 6) { //队伍人数未满
            roles.add(role);
            System.out.println("组队成功!");
        } else {
            System.out.println("队伍满员,加入失败!");
        }
    }

    /**
     * 计算队伍伤害总值
     *
     * @return
     */
    public int attackSum() {
        int sum = 0;
        for (int i = 0; i < roles.size(); i++) {
            Role role = roles.get(i);
            sum += role.attack();
        }
        return sum;
    }
}

测试类:

package com.itheima.polymorphic;

/**
 * @ClassName Test3
 * @Description 测试类
 * @Author 孙克旭
 * @Date 2025/3/16 19:50
 */
public class Test3 {
    public static void main(String[] args) {
        Team team = new Team();
        team.addMember(new Magician("上官婉儿", 25));
        team.addMember(new Soldier("关羽", 1500));
        System.out.println(team.attackSum());
    }
}

5. 接口

5.1 接口:认识接口

Java提供了一个关键字interface,用这个关键字可以定义出一个特殊的结构:接口。

在这里插入图片描述

  • 注意:接口不能创建对象;接口是用来被类实现(implements)的,实现接口的类称为实现类。

  • 一个类可以实现多个接口(接口可以理解成干爹),实现类实现多个接口,必须重写完全部接口的全部抽象
    方法,否则实现类需要定义成抽象类。

    在这里插入图片描述

5.2 接口:使用接口的好处

  • 弥补了类单继承的不足,一个类同时可以实现多个接口。
  • 让程序可以面向接口编程,这样程序员就可以灵活方便的切换各种业务实现。

E9%83%A8%E5%88%86%2F1742132395625.png&pos_id=img-9wfiUA0v-1742217255808)

5.3 接口:综合案例

在这里插入图片描述

学生类:

package com.itheima.interfaceDemo;

/**
 * @ClassName Student
 * @Description 学生类
 * @Author 孙克旭
 * @Date 2025/3/17 7:48
 */
public class Student {
    private String name;
    private char sex;
    private double score;

    public Student() {
    }

    public Student(String name, char sex, double score) {
        this.name = name;
        this.sex = sex;
        this.score = score;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public char getSex() {
        return sex;
    }

    public void setSex(char sex) {
        this.sex = sex;
    }

    public double getScore() {
        return score;
    }

    public void setScore(double score) {
        this.score = score;
    }
}

班级管理类:

package com.itheima.interfaceDemo;

import java.util.ArrayList;

/**
 * @ClassName ClassManager
 * @Description 班级管理类
 * @Author 孙克旭
 * @Date 2025/3/17 7:52
 */
public class ClassManager {
    private ArrayList<Student> students = new ArrayList<>();
    private StudentOperator studentOperator;

    public ClassManager(StudentOperator studentOperator) {
        this.studentOperator = studentOperator;
        students.add(new Student("孙克旭", '男', 100));
        students.add(new Student("老男孩", '男', 1000));
        students.add(new Student("马林思维", '男', 999));
        students.add(new Student("刘风凌", '男', 800));
        students.add(new Student("图灵机", '男', 950));
    }


    /**
     * 打印学生的全部信息
     */
    public void printInfo() {
        studentOperator.printInfo(students);
    }

    /**
     * 打印学生的平均成绩
     */
    public void printAvgScore() {
        studentOperator.printAvgScore(students);
    }
}

学生操作接口:

package com.itheima.interfaceDemo;

import java.util.ArrayList;

/**
 * @ClassName StudentOperator
 * @Description 学生操作接口
 * @Author 孙克旭
 * @Date 2025/3/17 8:01
 */
public interface StudentOperator {

    void printInfo(ArrayList<Student> students);

    void printAvgScore(ArrayList<Student> students);
}

学生操作实现类1:

package com.itheima.interfaceDemo;

import java.util.ArrayList;

/**
 * @ClassName StudentOperatorImpl1
 * @Description 学生操作接口实现类1
 * @Author 孙克旭
 * @Date 2025/3/17 8:04
 */
public class StudentOperatorImpl1 implements StudentOperator {
    @Override
    public void printInfo(ArrayList<Student> students) {
        for (int i = 0; i < students.size(); i++) {
            Student student = students.get(i);
            System.out.println("姓名:" + student.getName() + ",性别:" + student.getSex() + ",成绩:" + student.getScore());
        }
    }

    @Override
    public void printAvgScore(ArrayList<Student> students) {
        double allScore = 0;
        for (int i = 0; i < students.size(); i++) {
            Student student = students.get(i);
            allScore += student.getScore();
        }
        System.out.println("平均分:" + (allScore / students.size()));
    }
}

学生操作实现类2:

package com.itheima.interfaceDemo;

import java.util.ArrayList;

/**
 * @ClassName StudentOperatorImpl2
 * @Description 学生操作实现类2
 * @Author 孙克旭
 * @Date 2025/3/17 8:15
 */
public class StudentOperatorImpl2 implements StudentOperator {
    @Override
    public void printInfo(ArrayList<Student> students) {
        int manCount = 0, womanCount = 0;
        for (int i = 0; i < students.size(); i++) {
            Student student = students.get(i);
            char sex = student.getSex();
            System.out.println("姓名:" + student.getName() + ",性别:" + sex + ",成绩:" + student.getScore());
            if (sex == '男') {
                manCount++;
            } else {
                womanCount++;
            }
        }
        System.out.println("男生人数:" + manCount + ",女生人数:" + womanCount);
        System.out.println("班级总人数:" + students.size());
    }

    @Override
    public void printAvgScore(ArrayList<Student> students) {
        double allScore = 0, max = students.get(0).getScore(), min = students.get(0).getScore();
        for (int i = 0; i < students.size(); i++) {
            Student student = students.get(i);
            double score = student.getScore();
            allScore += score;
            if (score > max) {
                max = score;
            } else if (score < min) {
                min = score;
            }
        }
        System.out.println("最高分:" + max + ",最低分:" + min + ",平均分:" + (allScore - max - min) / (students.size() - 2));
    }
}

测试类:

package com.itheima.interfaceDemo;

/**
 * @ClassName Test
 * @Description 测试类
 * @Author 孙克旭
 * @Date 2025/3/17 8:30
 */
public class Test {
    public static void main(String[] args) {
        ClassManager classManager = new ClassManager(new StudentOperatorImpl1());
        classManager.printInfo();
        classManager.printAvgScore();
        System.out.println("--------------------------------");
        ClassManager classManager1 = new ClassManager(new StudentOperatorImpl2());
        classManager1.printInfo();
        classManager1.printAvgScore();
    }
}

5.4 接口:JDK8开始、新增的方法

在这里插入图片描述

5.5 接口:接口的多继承、使用接口的注意事项

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

5.6 单元测试

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

5.7 课后练习

5.7.1 题目1

请对下列代码进行补充,打印出接口中的变量num, 随后调用method方法,要求程序与最终运行结果吻合,(注意:打印num变量,不允许创建对象调用)

public class Demo1 {
	/*
	 * 请编写程序, 打印出接口中的变量num, 随后调用method方法
	 * 要求程序与最终运行结果吻合
	 */
	public static void main(String[] args) {
	
	}
}

        interface Inter {
            int num = 10;
            void method();
        }

【训练目标】:
能够熟知接口中的成员特点,并创建接口的实现类使用
【思路分析】:

  1. 接口中的num变量不允许创建对象,思考接口中的变量都默认被什么修饰?
  2. method方法是非静态的,非静态的方法只能创建对象调用,接口本身能创建对象吗?不能怎么办?
    【参考步骤】:
  3. 通过类名.调用接口中的num变量并打印
  4. 编写Inter接口的实现类,随后创建实现类对象,调用method方法

package com.itheima.interfaceDemo;

public class Demo1 {
    public static void main(String[] args) {
        System.out.println(Inter.num);
        InterImpl inter = new InterImpl();
        inter.method();
    }
}

interface Inter {
    int num = 10;

    void method();
}

class InterImpl implements Inter {
    @Override
    public void method() {
        System.out.println("method方法");
    }
}

5.7.2 题目2

1.定义USB接口:(开启功能)(关闭功能)

2.定义笔记本类:(开机功能)(关机功能)

3.定义鼠标类:要符合USB接口

4.定义测试类:创建电脑对象,依次调用开机方法,使用USB设备, 关机方法

运行结果:
开机
连接鼠标的USB
断开鼠标的USB
关机

【训练目标】:
能够独立定义接口
【思路分析】:
笔记本类中使用USB设备的功能
【参考方案】:
【参考步骤】:
1.按照题目要求,定义USB接口、鼠标类、笔记本类,笔记本类中定义的使用usb设备方法,形参接受接口类型
2.定义测试类,创建笔记本类对象,根据案例运行结果调用内部方法。


public class Demo5 {
public static void main(String[] args) {
        // 创建笔记本对象
        Computer c = new Computer();
        // 笔记本开机
        c.start();
        // 使用鼠标
        c.useUSB(new Mouse());
        // 笔记本关机
        c.end();
        }
        }

// 定义USB接口
interface USB {
    void open();
    void close();
}
// 定义笔记本类
class Computer {
    public void start(){
        System.out.println("开机");
    }

    public void end(){
        System.out.println("关机");
    }

    public void useUSB(USB u){
        u.open();
        u.close();
    }
}
// 定义鼠标类
class Mouse implements USB{

    @Override
    public void open() {
        System.out.println("连接鼠标的USB");
    }

    @Override
    public void close() {
        System.out.println("断开鼠标的USB");
    }

}

5.7.3 题目3

请在main方法中通过多态创建对象,随后使用对象,使得程序符合最终运行结果

public class Demo1 {
    /*
        请在main方法中通过多态创建对象,随后使用对象,使得程序符合最终运行结果
     */
    public static void main(String[] args) {
    
    }
}

class Fu {
    int num = 10;

    public void method(){
        System.out.println("父类的method方法");
    }
}

class Zi extends Fu{
    int num = 20;

    public void method(){
        System.out.println("子类的method方法");
    }
  
    public void show(){
        System.out.println("子类的show方法");
    }
}

运行结果:
10
子类的method方法
子类的show方法

【训练目标】:
能够使用多态的方式创建对象,并清楚多态的成员访问特点。
【思路分析】:
多态形式创建的对象,有什么弊端?遇到了这个弊端该如何解决?
【参考步骤】:

  1. 多态创建对象,然后直接使用父类引用,得到【10】【子类的method方法】
  2. 向下转型后,使用子类的引用去调用show方法

package com.itheima.interfaceDemo;

public class Demo2 {

    public static void main(String[] args) {
        Fu zi = new Zi();
        System.out.println(zi.num); //10
        zi.method(); //子类的method方法
        Zi z = (Zi) zi;
        z.show(); //子类的show方法
    }
}

class Fu {
    int num = 10;

    public void method() {
        System.out.println("父类的method方法");
    }
}

class Zi extends Fu {
    int num = 20;

    @Override
    public void method() {
        System.out.println("子类的method方法");
    }

    public void show() {
        System.out.println("子类的show方法");
    }
}


5.7.4 题目4

定义人(Person)类,人类中有吃饭方法(eat)和工作方法(work)。
定义超人(SuperMan)类,超人类中有救人方法(save)并且超人也属于人类。
要求:使用多态的方式创建超人对象,调用吃饭和工作的方法。再将此对象转为超人对象,调用救人的方法。

##【训练目标】:
能够使用多态的方式创建对象,能完成向下转型。
##【思路分析】:
人类和超人类有什么样的关系?

##【参考步骤】:

  1. 创建人类,人类中定义吃饭方法和工作方法。
  2. 创建超人类,继承人类,并定义自己特有的救人方法。
  3. 在测试类中,使用父类引用指向子类对象的方式创建对象。
  4. 分别调用父类的吃饭方法和工作方法。
  5. 将对象向下转型成超人对象。
  6. 使用子类对象调用救人方法。

Person类:

package com.itheima.interfaceDemo.work;

/**
 * @ClassName Person
 * @Description Person类
 * @Author 孙克旭
 * @Date 2025/3/17 9:51
 */
public class Person {
    /**
     * 吃饭
     */
    public void eat() {
        System.out.println("人是铁饭是钢,一顿不吃饿的慌!");
    }

    /**
     * 工作
     */
    public void work() {
        System.out.println("劳动最光荣!");
    }

}

超人类:

package com.itheima.interfaceDemo.work;

/**
 * @ClassName SuperMan
 * @Description 超人类
 * @Author 孙克旭
 * @Date 2025/3/17 9:53
 */
public class SuperMan extends Person {
    /**
     * 救人
     */
    public void save() {
        System.out.println("惩恶扬善,造福一方!");
    }
}

测试类:

package com.itheima.interfaceDemo.work;

/**
 * @ClassName Test2
 * @Description 测试类
 * @Author 孙克旭
 * @Date 2025/3/17 9:54
 */
public class Test2 {
    public static void main(String[] args) {
        Person man = new SuperMan();
        man.eat();
        man.work();
        SuperMan superMan = (SuperMan) man;
        superMan.save();
    }
}

5.8 单元练习5

5.8.1 抽象类是否可实现(implements)接口?需要重写抽象方法吗?

可以,并且因为抽象类允许有抽象方法,所以不是一定要重写抽象方法

5.8.2 接口和抽象类的联系和区别?

联系主要体现在:
抽象类:
(1)一个类中有抽象方法,这个类就变成了抽象类。
(2)抽象类中class的前面必须有abstract修饰符。
(3)抽象类中可以有普通方法,也可以有抽象方法,而抽象方法的个数可以是0个,也可以是多个。
(4)子类继承父类,必须重写全部的抽象方法,除非这个类也变成了抽象类。
接口:
(1)表面上看,接口是一种特殊的抽象类,但是类是类,接口是接口,是并列的关系。
(2)接口中所有方法都必须是抽象的。
(3)接口中方法定义默认为public abstract类型,成员变量默认为public static final 类型。(如果省略,系统会默认补全)。

区别主要体现在:
(1)抽象类可以有构造方法,接口中不能有构造方法。
(2)抽象类中可以有成员变量,接口中没有成员变量。(被final修饰变成了常量)
(3)抽象类中可以有普通方法,接口中所有方法都必须是抽象的。
(4)抽象类中抽象方法的访问类型可以是publicprotected,但接口中抽象方法的访问类型只能是public,并且默认为public abstract(省略则自动默认补全)。
(5)抽象类中可以有静态方法,接口中不能有静态方法。

5.8.3 接口的优点有哪些?

减少代码的书写(上边分析的代码重载)
提高了代码的可维护性和扩展性。
在团队合作中,代码的规范性

5.8.4 编码题1

按如下要求编写Java程序::
① 定义接口A,里面包含值为3.14的常量PI和 抽象方法double area();计算面积
② 定义接口B,里面包含 抽象方法void setColor(String c);设置颜色
③ 定义接口C,该接口继承了接口A和B,里面包含 抽象方法 double volume();计算体积
④ 定义圆柱体类Cylinder实现接口C,该类中包含三个成员变量:底圆半径radius、圆柱体的高height、颜色color,并进行方法重写(area方法计算圆柱体的侧面积,setColor方法设置颜色,volume方法计算圆柱体的体积)
⑤定义测试类及测试方法,创建Cylinder对象,打印该圆柱体对象的侧面积、体积及颜色
提示:圆柱体的侧面积计算公式为:S侧=2πrh 圆柱体的体积计算公式为:V=πr²h


接口A:

package com.itheima.interfaceDemo.work2;

/**
 * @ClassName A
 * @Description 接口A
 * @Author 孙克旭
 * @Date 2025/3/17 10:09
 */
public interface A {
    double PI = 3.14;

    /**
     * 计算面积
     *
     * @return
     */
    double area();
}

接口B:

package com.itheima.interfaceDemo.work2;

/**
 * @ClassName B
 * @Description 接口B
 * @Author 孙克旭
 * @Date 2025/3/17 10:10
 */
public interface B {
    /**
     * 设置颜色
     *
     * @param c
     */
    void setColor(String c);
}

接口C:

package com.itheima.interfaceDemo.work2;

/**
 * @ClassName C
 * @Description 接口C
 * @Author 孙克旭
 * @Date 2025/3/17 10:11
 */
public interface C extends A, B {
    /**
     * 计算体积
     *
     * @return
     */
    double volume();
}

圆柱体类:

package com.itheima.interfaceDemo.work2;

/**
 * @ClassName Cylinder
 * @Description 圆柱体类
 * @Author 孙克旭
 * @Date 2025/3/17 10:12
 */
public class Cylinder implements C {
    private int radius; //底圆半径
    private int height; //高
    private String color; //颜色

    /**
     * 圆柱体的侧面积
     *
     * @return
     */
    @Override
    public double area() {
        return 2 * PI * radius * height;
    }

    @Override
    public void setColor(String c) {
        this.color = c;
    }

    /**
     * 圆柱体的体积
     *
     * @return
     */
    @Override
    public double volume() {
        return PI * radius * radius * height;
    }

    public Cylinder() {
    }

    public Cylinder(int radius, int height, String color) {
        this.radius = radius;
        this.height = height;
        this.color = color;
    }

    public int getRadius() {
        return radius;
    }

    public void setRadius(int radius) {
        this.radius = radius;
    }

    public int getHeight() {
        return height;
    }

    public void setHeight(int height) {
        this.height = height;
    }

    public String getColor() {
        return color;
    }
}

测试类:

package com.itheima.interfaceDemo.work2;

/**
 * @ClassName Test
 * @Description 测试类
 * @Author 孙克旭
 * @Date 2025/3/17 10:19
 */
public class Test {
    public static void main(String[] args) {
        Cylinder cylinder = new Cylinder(3, 6, "红色");
        System.out.println(cylinder.area());
        System.out.println(cylinder.volume());
    }
}

5.8.5 编码题2

利用接口做参数,写个计算器,能完成加减乘除运算。
①定义一个接口Compute含有一个方法int computer(int n, int m)。
②设计四个类分别实现此接口,完成加减乘除运算。
③设计一个类UseCompute,类中含有方法:public void useCom(Compute com, int one, int two),此方法能够用传递过来的对象调用computer方法完成运算,并输出运算的结果。
④设计一个主类Test,调用UseCompute中的方法useCom来完成加减乘除运算

在这里插入图片描述


计算器接口:

package com.itheima.interfaceDemo.work2;

/**
 * @ClassName Compute
 * @Description 计算器接口
 * @Author 孙克旭
 * @Date 2025/3/17 10:48
 */
public interface Compute {
    /**
     * 计算
     *
     * @param n
     * @param m
     * @return
     */
    double computer(int n, int m);
}

加法类:

package com.itheima.interfaceDemo.work2;

/**
 * @ClassName Addition
 * @Description 加法类
 * @Author 孙克旭
 * @Date 2025/3/17 11:01
 */
public class Addition implements Compute {
    @Override
    public double computer(int n, int m) {
        return n + m;
    }
}

减法类:

package com.itheima.interfaceDemo.work2;

/**
 * @ClassName Subtraction
 * @Description 减法类
 * @Author 孙克旭
 * @Date 2025/3/17 11:02
 */
public class Subtraction implements Compute {
    @Override
    public double computer(int n, int m) {
        return n - m;
    }
}

乘法类:

package com.itheima.interfaceDemo.work2;

/**
 * @ClassName Multiplication
 * @Description 乘法类
 * @Author 孙克旭
 * @Date 2025/3/17 11:03
 */
public class Multiplication implements Compute {
    @Override
    public double computer(int n, int m) {
        return n * m;
    }
}

除法类:

package com.itheima.interfaceDemo.work2;

/**
 * @ClassName Division
 * @Description 除法类
 * @Author 孙克旭
 * @Date 2025/3/17 11:04
 */
public class Division implements Compute {
    @Override
    public double computer(int n, int m) {
        return 1.0 * n / m;
    }
}

计算器使用类:

package com.itheima.interfaceDemo.work2;

/**
 * @ClassName UseCompute
 * @Description 计算器使用类
 * @Author 孙克旭
 * @Date 2025/3/17 11:06
 */
public class UseCompute {
    public void useCom(Compute com, int one, int two) {
        double result = com.computer(one, two);
        String flag;
        if (com instanceof Addition) {
            flag = "+";
        } else if (com instanceof Subtraction) {
            flag = "-";
        } else if (com instanceof Multiplication) {
            flag = "*";
        } else {
            flag = "/";
        }
        System.out.println(one + " " + flag + " " + two + " is " + result);
    }
}

测试类:

package com.itheima.interfaceDemo.work2;

/**
 * @ClassName Test2
 * @Description 计算器测试类
 * @Author 孙克旭
 * @Date 2025/3/17 11:12
 */
public class Test2 {
    public static void main(String[] args) {
        UseCompute useCompute = new UseCompute();
        useCompute.useCom(new Addition(), 10, 5); // 10 + 5 is 15.0
        useCompute.useCom(new Subtraction(), 10, 5); //10 - 5 is 5.0
        useCompute.useCom(new Multiplication(), 10, 5); // 10 * 5 is 50.0
        useCompute.useCom(new Division(), 10, 5); // 10 / 5 is 2.0
    }
}

5.8.6 编码题3

现有一个5星级酒店,按照要求完成代码:
①定义抽象类员工(Employee),具有姓名name,工号id等属性
②接口Service,实现这一接口表示具有vip服务
③再定义厨师Cooker类,服务员Waiter类,经理Manager类,三个员工都有姓名name,工号id的属性,只有厨师和服务员有vip服务,厨师vip服务加菜,服务员嘘寒问暖,
④定义程序实现功能并测试


员工类:

package com.itheima.interfaceDemo.work3;

/**
 * @ClassName Employee
 * @Description 员工类
 * @Author 孙克旭
 * @Date 2025/3/17 11:52
 */
public abstract class Employee {
    private String name;
    private int id;

    public Employee() {
    }

    public Employee(String name, int id) {
        this.name = name;
        this.id = id;
    }

    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;
    }
}

服务接口:

package com.itheima.interfaceDemo.work3;

/**
 * @ClassName Service
 * @Description 服务接口
 * @Author 孙克旭
 * @Date 2025/3/17 11:53
 */
public interface Service {
    void vip();
}

厨师类:

package com.itheima.interfaceDemo.work3;

/**
 * @ClassName Cooker
 * @Description 厨师类
 * @Author 孙克旭
 * @Date 2025/3/17 11:54
 */
public class Cooker extends Employee implements Service {

    public Cooker(String name, int id) {
        super(name, id);
    }


    @Override
    public void vip() {
        System.out.println("加菜");
    }
}

服务员类:

package com.itheima.interfaceDemo.work3;

/**
 * @ClassName Waiter
 * @Description 服务员类
 * @Author 孙克旭
 * @Date 2025/3/17 11:55
 */
public class Waiter extends Employee implements Service {

    public Waiter(String name, int id) {
        super(name, id);
    }

    @Override
    public void vip() {
        System.out.println("嘘寒问暖");
    }
}

经理类:

package com.itheima.interfaceDemo.work3;

/**
 * @ClassName Manager
 * @Description 经理类
 * @Author 孙克旭
 * @Date 2025/3/17 11:56
 */
public class Manager extends Employee {

    public Manager(String name, int id) {
        super(name, id);
    }
}

测试类:

package com.itheima.interfaceDemo.work3;

/**
 * @ClassName Test
 * @Description 测试类
 * @Author 孙克旭
 * @Date 2025/3/17 11:58
 */
public class Test {
    public static void main(String[] args) {
        Employee e1 = new Cooker("张三", 100);
        Cooker e = (Cooker) e1;
        e.vip();
    }
}

6. 内部类、枚举

6.1 内部类:概述、成员内部类

内部累是类中的五大成分之一(成员变量、方法、构造器、内部类、代码块),如果一个类定义在另一个类的内部,这个类就是内部类。

场景:当一个类的内部,包含了一个完整的事物,且这个事物没有必要单独设计时,就可以把这个事物设计成内部类。

6.1.1 成员内部类

在这里插入图片描述

在这里插入图片描述

6.1.2 静态内部类

在这里插入图片描述

在这里插入图片描述

6.1.3 局部内部类

在这里插入图片描述

6.1.4 匿名内部类

匿名内部类就是一种特殊的局部内部类;所谓匿名:指的是程序员不需要为这个类声明名字。

在这里插入图片描述

在这里插入图片描述

  • 特点:匿名内部类本质就是一个子类,并会立即创建出一个子类对象。
  • 作用:用于更方便的创建一个子类对象。

6.2 内部类:匿名内部类的使用场景

在这里插入图片描述

6.3 枚举:认识枚举

枚举是一种特殊的类。

在这里插入图片描述

在这里插入图片描述

6.4 枚举:枚举的作用

在这里插入图片描述

在这里插入图片描述

6.5 单元测试

在这里插入图片描述

在这里插入图片描述

6.6 单元练习6

6.6.1 请问有几种形式的内部类?

4种;分别是成员内部类、静态成员内部类、局部内部类、匿名内部类

6.6.2 请问内部类会被编译成class文件吗?

在编译一个类的时候,假如该类中有内部类,则会直接生成 类$内部类.class 文件

6.6.3 枚举的优点有哪些?

1 增强代码可读性
2 传递参数错误
3 去除equals两者判断 由于常量值地址唯一,使用枚举可以直接通过“==”进行两个值之间的对比,性能会有所提高。
4 编译优势(与常量类相比)
常量类编译时,常量被直接编译进二进制代码中,常量值在升级中变化后,需要重新编译引用常量的类,因为二进制代码中存放的是旧值。枚举类编译时,没有把常量值编译到代码中,即使常量值发生改变,也不会影响引用常量的类。
5 修改优势(与常量类相比)
枚举类编译后默认final class,不允许继承可防止被子类修改。常量类可被继承修改、增加字段等,易导致父类不兼容。
6 枚举型可直接与数据库交互。
7 Switch语句优势
使用intString类型switch时,当出现参数不确定的情况,偶尔会出现越界的现象,这样我们就需要做容错操作(if条件筛选等),使用枚举,编译期间限定类型,不允许发生越界

6.6.4 编码题1

利用接口做参数,写个计算器,能完成加减乘除运算:
① 定义一个接口Compute含有一个 方法int computer(int n, int m);
②设计一个类UseCompute,类中含有 方法:public void useCom(Compute com, int one, int two),
此方法能够用传递过来的对象调用computer方法完成运算,并输出运算的结果
③ 设计一个主类Test,调用UseCompute中的方法useCom来完成加减乘除运算(使用匿名内部类)


计算器接口:

package com.itheima.innerClass.work;

/**
 * @ClassName Compute
 * @Description 计算器接口
 * @Author 孙克旭
 * @Date 2025/3/17 15:54
 */
public interface Compute {
    int computer(int n, int m);
}

计算器使用类:

package com.itheima.innerClass.work;

/**
 * @ClassName UseCompute
 * @Description 计算器使用类
 * @Author 孙克旭
 * @Date 2025/3/17 15:56
 */
public class UseCompute {
    public void useCom(Compute com, int one, int two) {
        int computer = com.computer(one, two);
        System.out.println(computer);
    }
}

测试类:

package com.itheima.innerClass.work;



/**
 * @ClassName Test
 * @Description 测试类
 * @Author 孙克旭
 * @Date 2025/3/17 16:00
 */
public class Test {
    public static void main(String[] args) {
        UseCompute useCompute = new UseCompute();
        useCompute.useCom(new Compute() {
            @Override
            public int computer(int n, int m) {
                return n+m;
            }
        },10,20);

        useCompute.useCom(new Compute() {
            @Override
            public int computer(int n, int m) {
                return n-m;
            }
        },10,20);

        useCompute.useCom(new Compute() {
            @Override
            public int computer(int n, int m) {
                return n*m;
            }
        },10,20);

        useCompute.useCom(new Compute() {
            @Override
            public int computer(int n, int m) {
                return n/m;
            }
        },40,20);
    }
}

6.6.5 编码题2

某手机需完成闹钟功能(通过匿名内部类方式),需要如下:
①定义一个铃声接口Bell,里面有个ring方法。
②定义一个手机类Cellphone,具有闹钟功能alarmClock,参数是Bell类型
③定义一个测试类,来测试手机类的闹钟功能,通过匿名内部类 ( 对象 ) 作为参数,打印:懒猪起床了
④再在测试类中通过匿名内部类 ( 对象 ) 作为参数,打印:小伙伴上课了


Bell接口:

package com.itheima.innerClass.work;

/**
 * @ClassName Bell
 * @Description 手机铃声
 * @Author 孙克旭
 * @Date 2025/3/17 16:08
 */
public interface Bell {
    void ring();
}

手机类:

package com.itheima.innerClass.work;

/**
 * @ClassName Cellphone
 * @Description 手机类
 * @Author 孙克旭
 * @Date 2025/3/17 16:09
 */
public class Cellphone {

    /**
     * 闹钟
     *
     * @param bell
     */
    public void alarmClock(Bell bell) {
        bell.ring();
    }
}

测试类:

package com.itheima.innerClass.work;

/**
 * @ClassName Test2
 * @Description 测试类
 * @Author 孙克旭
 * @Date 2025/3/17 16:12
 */
public class Test2 {
    public static void main(String[] args) {
        Cellphone cellphone = new Cellphone();
        cellphone.alarmClock(new Bell() {
            @Override
            public void ring() {
                System.out.println("懒猪起床了");
            }
        });

        cellphone.alarmClock(new Bell() {
            @Override
            public void ring() {
                System.out.println("小伙伴上课了");
            }
        });
    }
}

6.6.6 编码题3

小明家是果农,因为针对不同品相的苹果收购价格不同,现需要实现苹果按照品相分级,需要工人挑苹果,按照不同品相完成定价;为完成品相分级这一功能,请按照需求完成代码:
①定义苹果类需包含属性:大小,颜色;提供基本的构造方法和get方法,set方法
②定义接口CompareAble包含定义默认方法compare,挑选较大苹果。
③定义接口实现类Compare。
④定义工人类要有成员方法:挑选苹果Apple pickApple(CompareAble,Apple a1,Apple a2)。
⑤测试类:创建Worker对象、创建两个Apple对象,一个Apple(5,“青色”),一个Apple(3,“红色”);需实现默认挑选大的苹果,打印苹果信息;指定颜色挑选,通过匿名内部类实现。


苹果类:

package com.itheima.innerClass.work;

/**
 * @ClassName Apple
 * @Description 苹果类
 * @Author 孙克旭
 * @Date 2025/3/17 16:23
 */
public class Apple {
    private int size; //大小
    private String color; //颜色

    @Override
    public String toString() {
        return "Apple{" +
                "size=" + size +
                ", color='" + color + '\'' +
                '}';
    }

    public Apple() {
    }

    public Apple(int size, String color) {
        this.size = size;
        this.color = color;
    }

    public int getSize() {
        return size;
    }

    public void setSize(int size) {
        this.size = size;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }
}

比较接口:

package com.itheima.innerClass.work;

/**
 * @ClassName Compareable
 * @Description 比较苹果接口
 * @Author 孙克旭
 * @Date 2025/3/17 16:27
 */
public interface Compareable {
    /**
     * 比较两个苹果大小
     *
     * @param a1
     * @param a2
     */
    Apple compare(Apple a1, Apple a2);
}

比较接口实现类:

package com.itheima.innerClass.work;

/**
 * @ClassName Compare
 * @Description 比较苹果实现类
 * @Author 孙克旭
 * @Date 2025/3/17 16:30
 */
public class Compare implements Compareable {
    @Override
    public Apple compare(Apple a1, Apple a2) {
        return (a1.getSize() > a2.getSize()) ? a1 : a2;
    }
}

测试类:

package com.itheima.innerClass.work;

/**
 * @ClassName Test3
 * @Description 测试类
 * @Author 孙克旭
 * @Date 2025/3/17 16:37
 */
public class Test3 {
    public static void main(String[] args) {
        Worker worker = new Worker();
        Apple a1 = new Apple(5, "青色");
        Apple a2 = new Apple(3, "红色");
        Apple apple = worker.pickApple(new Compare(), a1, a2);
        System.out.println(apple);
        Apple apple1 = worker.pickApple(new Compareable() {
            @Override
            public Apple compare(Apple a1, Apple a2) {
                if (a1.getColor().equals("红色")) {
                    return a1;
                } else {
                    return a2;
                }
            }
        }, a1, a2);
        System.out.println(apple1);
    }
}

7. 泛型

7.1 泛型:认识泛型

定义类、接口、方法时,同时声明了一个或者多个类型变量(如:<E>),称为泛型类、泛型接口,泛型方法、它们统称为泛型。

  • 作用:泛型提供了在编译阶段约束所能操作的数据类型,并自动进行检查的能力!这样可以避免强制类型转换,及其可能出现的异常。
  • 泛型的本质:把具体的数据类型作为参数传给类型变量。

7.2 泛型:泛型类

在这里插入图片描述

在这里插入图片描述

7.3 泛型:泛型接口

在这里插入图片描述

在这里插入图片描述

7.4 泛型:泛型方法

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

7.5 泛型:泛型的注意事项

在这里插入图片描述

在这里插入图片描述

7.6 单元练习7

7.6.1 什么是Java泛型,它有什么作用?

泛型的主要作用是为了在编译时限制类或方法可以操作的数据类型,从而避免在运行时出现类型转换错误。
通过使用泛型,我们可以编写更加通用、可重用的代码,同时减少运行时错误。

7.6.2 请简述Java中的泛型通配符及其作用。

1.无限定通配符:<?>,表示任何类型。
2.上界通配符:<? extends T>,表示类型T或其子类型。
3.下界通配符:<? super T>,表示类型T或其父类型。
通过使用通配符,我们可以编写更加灵活的泛型代码,处理各种不同类型的情况。

7.6.3 使用泛型的注意事项都有哪些

泛型是工作在编译阶段的,一旦程序编译成class文件,class文件中就不存在泛型了,这就是泛型擦除。
泛型不支持基本数据类型,只能支持对象类型(引用数据类型)。

7.6.4 编码题1

请定义一个泛型类 MyMap<K,V>,包含两个成员变量 first 和 second,first的类型是K,second的类型是V,
① 定义有参构造方法和first、second的get/set方法。
② 新建一个测试类,在main方法中创建MyMap对象传入值,打印first和second
③ 在MyMap类中定义一个无返回值的泛型方法print,接收一个泛型参数,并将接收到的泛型参数打印到控制台上


MyMap类:

package com.itheima.genericDemo;

public class MyMap<K, V> {
    private K first;
    private V second;

    public void print(K k) {
        System.out.println(k);
    }

    public MyMap(K first, V second) {
        this.first = first;
        this.second = second;
    }

    public K getFirst() {
        return first;
    }

    public void setFirst(K first) {
        this.first = first;
    }

    public V getSecond() {
        return second;
    }

    public void setSecond(V second) {
        this.second = second;
    }
}

测试类:

package com.itheima.genericDemo;

public class Test {
    public static void main(String[] args) {
        MyMap<String, String> map = new MyMap<>("A", "B");
        System.out.println(map.getFirst());
        System.out.println(map.getSecond());
        map.print("孙克旭");
    }
}

7.6.5 编码题2

编写一个泛型接口 DataStructure
① 定义一个抽象方法 void push(E element),表示向数据结构中添加元素。
② 再定义一个抽象方法 E pop(),表示从数据结构中取出一个元素并返回。
③ 编写一个泛型类 Stack,实现 DataStructure 接口,并完成 push 和 pop 方法的实现。
④ 新建一个测试类,在main方法中测试调用xxx类的 push (存一个数据)和 pop(取出一个数据)


DataStructure类:

package com.itheima.genericDemo;

public interface DataStructure<E> {
    void push(E element);

    E pop();
}

Stack类:

package com.itheima.genericDemo;

public class Stack<E> implements DataStructure<E> {
    private E element;

    @Override
    public void push(E element) {
        this.element = element;
    }

    @Override
    public E pop() {
        return element;
    }
}

测试类:

package com.itheima.genericDemo;

public class Test2 {
    public static void main(String[] args) {
        Stack<String> stack = new Stack<>();
        stack.push("孙克旭");
        System.out.println(stack.pop());
    }
}

7.6.6 编码题3

设计一个简单的音乐播放器程序。
①使用泛型类 Playlist 来管理播放列表中的音乐。
②每首音乐都有一个名称和一个时长,可以用 Music 类来表示。
③定义两个方法 addMusic 和 play,并分别在 Playlist 类中实现。
④在 Playlist 类中,我们定义了一个泛型类型参数 T extends Music,表示 T 必须是 Music 的子类或本身。我们使用 List 来存储播放列表中的音乐,并实现了两个方法 addMusic 和 play,分别用于向播放列表中添加音乐和按添加顺序播放音乐。
⑤在测试类中,新建一个 Playlist 对象,并向播放列表中添加三首音乐。然后播放音乐


音乐类:

package com.itheima.genericDemo;

/**
 * @ClassName Music
 * @Description 音乐类
 * @Author 孙克旭
 * @Date 2025/3/17 20:53
 */
public class Music {
    private String name;
    private int time;

    public Music() {
    }

    public Music(String name, int time) {
        this.name = name;
        this.time = time;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getTime() {
        return time;
    }

    public void setTime(int time) {
        this.time = time;
    }
}

PlayList类:

package com.itheima.genericDemo;

import java.util.ArrayList;

public class Playlist<E extends Music> {
    private ArrayList<E> arrayList = new ArrayList<>();

    public void addMusic(E e) {
        arrayList.add(e);
    }

    public void play() {
        for (int i = 0; i < arrayList.size(); i++) {
            E e = arrayList.get(i);
            System.out.println("播放音乐:" + e.getName() + ",播放时间:" + e.getTime());
        }
    }

}

测试类:

package com.itheima.genericDemo;

public class Test3 {
    public static void main(String[] args) {
        Playlist<Music> musicPlaylist = new Playlist<>();
        musicPlaylist.addMusic(new Music("只因你太美", 2));
        musicPlaylist.addMusic(new Music("挪威的坤坤", 3));
        musicPlaylist.addMusic(new Music("坤的救赎", 4));
        musicPlaylist.play();
    }
}

7.7 章节测评

7.7.1 接口和抽象类的联系和区别?

联系主要体现在:
抽象类:
(1)一个类中有抽象方法,这个类就变成了抽象类。
(2)抽象类中class的前面必须有abstract修饰符。
(3)抽象类中可以有普通方法,也可以有抽象方法,而抽象方法的个数可以是0个,也可以是多个。
(4)子类继承父类,必须重写全部的抽象方法,除非这个类也变成了抽象类。
接口:
(1)表面上看,接口是一种特殊的抽象类,但是类是类,接口是接口,是并列的关系。
(2)接口中所有方法都必须是抽象的。
(3)接口中方法定义默认为public abstract类型,成员变量默认为public static final 类型。(如果省略,系统会默认补全)。

区别主要体现在:
(1)抽象类可以有构造方法,接口中不能有构造方法。
(2)抽象类中可以有成员变量,接口中没有成员变量。(被final修饰变成了常量)
(3)抽象类中可以有普通方法,接口中所有方法都必须是抽象的。
(4)抽象类中抽象方法的访问类型可以是publicprotected,但接口中抽象方法的访问类型只能是public,并且默认为public abstract(省略则自动默认补全)。
(5)抽象类中可以有静态方法,接口中不能有静态方法。

7.7.2 多态的前提条件是什么?

1)有继承关系。
(2)有方法的重写。
(3)有父类引用指向之类对象。

7.7.3 什么是方法重写?

子类中出现与父类一模一样的方法时(返回值类型,方法名和参数列表都相同),会出现覆盖效果,也称为重写或者复写。声明不变,重新实现。

7.7.4 编码题1

① 定义一个图形类Picture(抽象类),需包含属性:边长(sideLength)、边数(sideCount), 需包含抽象方法:求周长getPerimeter方法、求面积getArea方法、显示图形信息show方法
② 定义图形类Picture的两个子类:圆形类Circle 和 矩形类Rect
圆形类Cirle需包含属性:圆心x(centerX)、圆心y (centerY)、半径(radius),重写求周长、求面积方法、显示信息方法,矩形类Rect需包含属性:长(length)、宽(width),重写求周长、求面积方法、显示信息方法
③ 定义测试类:测试方法中用多态的形式创建圆形类Cirle对象 和 矩形类Rect对象,分别调用show方法显示信息


package com.itheima;

/**
 * 图形类
 */
public abstract class Picture {

      private int sideLength;  //边长
      private int sideCount;   //边数

      public Picture() {
      }

      public Picture(int sideLength, int sideCount) {
            this.sideLength = sideLength;
            this.sideCount = sideCount;
      }

      public int getSideLength() {
            return sideLength;
      }

      public void setSideLength(int sideLength) {
            this.sideLength = sideLength;
      }

      public int getSideCount() {
            return sideCount;
      }

      public void setSideCount(int sideCount) {
            this.sideCount = sideCount;
      }

      /**
       * 求周长
       * @return
       */
      public abstract double getPerimeter();

      /**
       * 求面积
       * @return
       */
      public abstract double getArea();

      /**
       * 显示图形信息
       */
      public abstract void show();

}
package com.itheima;

/**
 * 圆形类
 */
public class Circle extends Picture{

      private double centerX; //圆心x
      private double centerY;//圆心y
      private double radius; //半径


      public Circle(double centerX, double centerY, double radius) {
            this.centerX = centerX;
            this.centerY = centerY;
            this.radius = radius;
      }

      public Circle(int sideLength, int sideCount, double centerX, double centerY, double radius) {
            super(sideLength, sideCount);
            this.centerX = centerX;
            this.centerY = centerY;
            this.radius = radius;
      }

      public double getCenterX() {
            return centerX;
      }

      public void setCenterX(double centerX) {
            this.centerX = centerX;
      }

      public double getCenterY() {
            return centerY;
      }

      public void setCenterY(double centerY) {
            this.centerY = centerY;
      }

      public double getRadius() {
            return radius;
      }

      public void setRadius(double radius) {
            this.radius = radius;
      }

      /**
       *  重写求周长方法,圆形周长为2πr
       */
      @Override
      public double getPerimeter() {
            return 2 * Math.PI * radius;
      }

      /**
       *重写求面积方法,圆形面积为πr²
       */
      @Override
      public double getArea() {
            return Math.PI * radius * radius;
      }

      /**
       * 显示圆形图形信息
       */
      @Override
      public void show() {
            System.out.println("圆形的周长:" + getPerimeter());
            System.out.println("圆形的面积:" + getArea());
      }
}
package com.itheima;

/**
 * 矩形类
 */
public class Rect extends Picture{

      private double length;
      private double width;

      public Rect(double length, double width) {
            this.length = length;
            this.width = width;
      }

      public Rect(int sideLength, int sideCount, double length, double width) {
            super(sideLength, sideCount);
            this.length = length;
            this.width = width;
      }

      public double getLength() {
            return length;
      }

      public void setLength(double length) {
            this.length = length;
      }

      public double getWidth() {
            return width;
      }

      public void setWidth(double width) {
            this.width = width;
      }

      /**
       * 重写求周长方法,矩形周长: 为2倍的长加2倍的宽
       * @return
       */
      @Override
      public double getPerimeter() {
            return 2 * length + 2 * width;
      }

      /**
       * 重写求面积方法,矩形面积为长乘以宽
       * @return
       */
      @Override
      public double getArea() {
            return length * width;
      }

      /**
       * 显示矩形图形信息
       */
      @Override
      public void show() {
            System.out.println("矩形的周长:" + getPerimeter());
            System.out.println("矩形的面积:" + getArea());
      }
}
package com.itheima;


/**
 * 测试类
 */
public class AppTest {

      public static void main(String[] args) {

            //1.多态的形式创建Circle对象
            Picture circle = new Circle(5, 6, 7);
            //2.多态的形式创建Rect对象
            Picture rect = new Rect(8, 9);
            //3.分别调用show方法()
            circle.show();
            rect.show();


      }
}

7.7.5 编码题2

现有一个5星级酒店,按照要求完成代码:
①定义抽象类员工(Employee),具有姓名name,工号id等属性
②接口Service,实现这一接口表示具有vip服务
③再定义厨师Cooker类,服务员Waiter类,经理Manager类,三个员工都有姓名name,工号id的属性,只有厨师和服务员有vip服务,厨师vip服务加菜,服务员嘘寒问暖,
④定义程序实现功能并测试


package com.itheima;

/**
 * 测试类
 */
public class AppTest {

      public static void main(String[] args) {

            // 1.分别创建厨师对象、服务员对象、经理对象
            Chef chef = new Chef("厨师", 1);
            Waiter waiter = new Waiter("服务员", 2);
            Manager manager = new Manager("经理", 3);
            // 2.输出厨师对象的普通服务内容、VIP服务内容
            chef.providerService();
            chef.vipService();
            // 3.输出服务员对象的普通服务内容、VIP服务内容
            waiter.providerService();
            waiter.vipService();
            // 4.输出经理的服务内容
            manager.providerService();


      }
}
package com.itheima;

public class Chef extends Employee implements Service{


      public Chef(String name, int id) {
            super(name, id);
      }

      /**
       * 普通服务
       */
      @Override
      public void providerService() {
            System.out.println( getName() + "提供的普通服务:做菜");
      }

      /**
       * VIP
       */
      @Override
      public void vipService() {
            System.out.println( getName() + "提供的vip服务:加菜");
      }
}
package com.itheima;

public abstract class Employee {

      protected String name;
      protected int id;

      public Employee(String name, int id) {
            this.name = name;
            this.id = id;
      }

      public String getName() {
            return name;
      }

      public int getId() {
            return id;
      }

      public abstract void providerService();
}
package com.itheima;

public class Manager extends Employee{

      public Manager(String name, int id) {
            super(name, id);
      }

      @Override
      public void providerService() {
            System.out.println( getName() + "提供的服务:管理");
      }
}
package com.itheima;

public interface Service {

      void vipService();

}
package com.itheima;

public class Waiter extends Employee implements Service{

      public Waiter(String name, int id) {
            super(name, id);
      }

      @Override
      public void providerService() {
            System.out.println( getName() + "提供的普通服务:端菜");
      }

      @Override
      public void vipService() {
            System.out.println( getName() + "提供的vip服务:嘘寒问暖");
      }
}

7.7.6 编码题3

定义一个动物类,有品种、年龄(age)等属性,用吃食物等行为
①在动物类的子类,鲸鱼和狗(需重写吃食物的方法)
②定义一个测试类,创建鲸鱼和狗对象,并分别调用eat方法,把信息输出到控制台

在这里插入图片描述


public class Exe3 {

    public static void main(String[] args) {
        Jingyu jingyu = new Jingyu("虎鲸", 3);
        jingyu.eat();
        Dog dog = new Dog("柴犬", 2);
        dog.eat();
    }
}
public class Dog extends DongWu {
    public Dog() {
    }

    public Dog(String pinZhong, int age) {
        super(pinZhong, age);
    }
    public void eat(){
        System.out.println(this.getAge()+"岁大的"+this.getPinZhong()+"正在吃东西");
    }
}
public class Jingyu extends DongWu {

    public Jingyu() {
    }

    public Jingyu(String pinZhong, int age) {
        super(pinZhong, age);
    }
  
    public void eat(){
        System.out.println(this.getAge()+"岁大的"+this.getPinZhong()+"正在吃东西");
    }
}
public class DongWu {
    private String pinZhong;

    private int age;

    public DongWu() {
    }

    public DongWu(String pinZhong, int age) {
        this.pinZhong = pinZhong;
        this.age = age;
    }

    public String getPinZhong() {
        return pinZhong;
    }

    public void setPinZhong(String pinZhong) {
        this.pinZhong = pinZhong;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public void eat(){
        System.out.println(this.age+"岁大的"+this.pinZhong+"正在吃东西");
    }
}