面向对象6

面向对象6

抽象类与抽象方法

随着继承层次中一个个新子类的定义,类变得越来越具体,而父类则更一般,更通用。类的设计应该保证父类和子类能够共享特征。有时将一个父类设计得非常抽象,以至于它没有具体的实例,这样的类叫做抽象类。

abstract关键字的使用

  1. abstract:抽象的

  2. abstract可以用来修饰的结构:类、方法

  3. abstract修饰类:抽象类

    • 此类不能实例化
    • 抽象类中一定有构造器,便于子类实例化时调用(涉及:子类对象实例化的全过程)
    • 开发中,都会提供抽象类的子类,让子类对象实例化,完成相关的操作
  4. abstract修饰方法:抽象方法

    • 抽象方法只有方法的声明,没有方法体
    • 包含抽象方法的类,一定是一个抽象类。反之,抽象类中可以没有抽象方法的。
    • 若子类重写了父类中的所有的抽象方法后,此子类方可实例化
    • 若子类没有重写父类中的所有的抽象方法,则此子类也是一个抽象类,需要使用abstract修饰

abstract使用上的注意点:

  1. abstract不能用来修饰:属性、构造器等结构
  2. abstract不能用来修饰私有方法、静态方法、final的方法、final的类
package com.xin.OOPTest.demo07;

 public abstract class Employee {
    private String name;
    private int id;
    private double salary;

    public Employee() {
    }

    public Employee(String name, int id, int salary) {
        this.name = name;
        this.id = id;
        this.salary = salary;
    }
    abstract void work();
    abstract void walk(Employee employee);
}
=============
    package com.xin.OOPTest.demo07;
//对于Manager类来说,他既是员工,还具有奖金(bonus)的属性。
public class Manager extends Employee{
    private double bonus;

    public Manager(double bonus) {
        this.bonus = bonus;
    }

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

    @Override
    void work() {
        System.out.println("管理员工,提高效率");
    }

    @Override
    void walk(Employee employee) {
        System.out.println("他的工资是"+this.bonus);
    }

}
===============
    package com.xin.OOPTest.demo07;

public class CommonEmployee extends Employee{
    @Override
    void work() {
        System.out.println("员工在一线车间生产产品");
    }

    @Override
    void walk(Employee employee) {
        System.out.println("他的id是0000");
        work();
    }

}
===============
    package com.xin.OOPTest.demo07;

//请使用继承的思想,设计CommonEmployee类和Manager类,要求类中提供必要的方法进行属性访问。
public class EmployeeTest {
    public static void main(String[] args) {
        Manager manager = new Manager("库克", 1001, 5000, 50000);
        manager.work();
        CommonEmployee commonEmployee = new CommonEmployee();
        commonEmployee.work();
    }
}

抽象类的匿名子类

package com.xin.OOPTest.demo07;

public class Day72500 {
    public static void main(String[] args) {
        method(new Man());//匿名对象
        Wark wark = new Wark();
        method1(wark);//非匿名的类,非匿名的对象
        method1(new Wark());//非匿名的类,匿名的对象
        System.out.println("===========");
        //创建了一个匿名子类的对象person
        Person person = new Person() {
            @Override
            public void eat() {
                System.out.println("吃东西");
            }
        };
        method1(person);
    }
    public static void method1(Person person){
        person.eat();
    }
    public static void method(Man man){

    }
}

abstract class Person {
    int age;
    String name;

    public Person() {
    }

    public Person(int age, String name) {
        this.age = age;
        this.name = name;
    }
    public abstract void eat();
}

class Man extends Person {
//    int age;
//    String name;


    public Man() {

    }

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

    @Override
    public void eat() {

    }
}
class Wark extends Person{

    @Override
    public void eat() {

    }
}

多态的应用:模板方法设计模式(TemplateMethod)

抽象类体现的就是一种模板模式的设计,抽象类作为多个子类的通用模板,子类在抽象类的基础上进行扩展、改造,但子类总体上会保留抽象类的行为方式。

解决的问题:

当功能内部一部分实现是确定的,一部分实现是不确定的。这时可以把不确定的部分暴露出去,让子类去实现。

换句话说,在软件开发中实现一个算法时,整体步骤很固定、通用,这些步骤已经在父类中写好了。但是某些部分易变,易变部分可以抽象出来,供不同子类实现。这就是一种模板模式。

package com.xin.OOPTest.demo07;

public class Day72501 {
    public static void main(String[] args) {
        SubTemplate subTemplate = new SubTemplate();
        subTemplate.spendTime();
    }
}

abstract class Template {
    //计算某段代码执行所需要花费的时间
    public void spendTime() {
        long start = System.currentTimeMillis();
        code();//不确定的部分
        long end = System.currentTimeMillis();
        System.out.println("花费的时间" + (end - start));
    }

    public abstract void code();
}

class SubTemplate extends Template {
    @Override
    public void code() {//质数
        lable:
        for (int i = 2; i < 1000; i++) {
            for (int j = 2; j <= Math.sqrt(i); j++) {
                if (i % j == 0) {
                    continue lable;
                }
            }
            System.out.println(i);
        }
    }
}

image-20230725132423829

package com.xin.OOPTest.demo08;
/*
(1)定义一个Employee类,该类包含:
private成员变量name,number,birthday,其中birthday 为MyDate类的对象;abstract方法earnings();
toString()方法输出对象的name,number和birthday。

 */
public abstract class Employee {
    private String name;
    private int number;
    private MyDate birthday;
    public abstract double earnings();

    public Employee(String name, int number, MyDate birthday) {
        this.name = name;
        this.number = number;
        this.birthday = birthday;
    }

    public String getName() {
        return name;
    }

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

    public int getNumber() {
        return number;
    }

    public void setNumber(int number) {
        this.number = number;
    }

    public MyDate getBirthday() {
        return birthday;
    }

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

    @Override
    public String toString() {
        return "{" +
                "name='" + name + '\'' +
                ", number=" + number +
                ", birthday=" + birthday.toDateString() +
                '}';
    }
}
=======
    package com.xin.OOPTest.demo08;
/*
*定义SalariedEmployee类继承Employee类,
* 实现按月计算工资的员工处理。该类包括: private成员变量monthlySalary,
* 实现父类的抽象方法earnings(),该方法返回monthlysalary值;
toString()方法输出员工类型信息.及员工的name,number, birthday.

 */
public class SalariedEmployee extends Employee{
    private int monthlySalary;//月工资


    public SalariedEmployee(String name, int number, MyDate birthday, int monthlySalary) {
        super(name, number, birthday);
        this.monthlySalary = monthlySalary;
    }

    public int getMonthlySalary() {
        return monthlySalary;
    }

    public void setMonthlySalary(int monthlySalary) {
        this.monthlySalary = monthlySalary;
    }

    @Override
    public double earnings() {
        return monthlySalary;
    }

    public SalariedEmployee(String name, int number, MyDate birthday) {
        super(name, number, birthday);
    }
    public String toString(){
        return "SalariedEmployee"+super.toString();
    }
}
============
    package com.xin.OOPTest.demo08;
/*
参照SalariedEmployee类定义HourlyEmployee类,实现按小时计算工资的员工处理
该类包括:
private成员变量wage和hour;
实现父类的抽象方法earnings(),该方法返回wage*hour值;
toString()方法输出员工类型信息及员工的name,number , birthday。

 */
public class HourlyEmployee extends Employee{
    private int wage;//每小时的工资
    private int hour;//月工作的小时数
    public HourlyEmployee(String name, int number, MyDate birthday) {
        super(name, number, birthday);
    }

    public HourlyEmployee(String name, int number, MyDate birthday, int wage, int hour) {
        super(name, number, birthday);
        this.wage = wage;
        this.hour = hour;
    }

    public int getWage() {
        return wage;
    }

    public void setWage(int wage) {
        this.wage = wage;
    }

    public int getHour() {
        return hour;
    }

    public void setHour(int hour) {
        this.hour = hour;
    }

    @Override
    public double earnings() {
        return hour*wage;
    }

    public String toString() {
        return "HourlyEmployee" +super.toString();
    }
}
============
    package com.xin.OOPTest.demo08;
/*
* MyDate类包含:
private成员变量year , month,day ;
toDateString()方法返回日期对应的字符串:XXXX年XX月XX日

 */
public class MyDate {
    private int year;
    private int month;
    private int day;

    public int getYear() {
        return year;
    }

    public MyDate(int year, int month, int day) {
        this.year = year;
        this.month = month;
        this.day = day;
    }

    public void setYear(int year) {
        this.year = year;
    }

    public int getMonth() {
        return month;
    }

    public void setMonth(int month) {
        this.month = month;
    }

    public int getDay() {
        return day;
    }

    public void setDay(int day) {
        this.day = day;
    }

    public String toDateString(){
        return year+"年"+month+"月"+day+"日";
    }
}
================
    package com.xin.OOPTest.demo08;

import java.util.Calendar;
import java.util.Scanner;

/*
定义Payrollsystem类,创建Employee变量数组并初始化,该数组存放各类雇员对象的引用。
利用循环结构遍历数组元素,输出各个对象的类型, name , number, birthday.
当键盘输入本月月份值时,如果本月是某个Employee对象的生日,还要输出增加工资信息。

 */
public class PayrollSystem {
    public static void main(String[] args) {
//        Scanner scanner = new Scanner(System.in);
//        System.out.println("请输入当前的月份:");
//        int month=scanner.nextInt();
        //方式2:日历
        Calendar calendar=Calendar.getInstance();
        int month=calendar.get(Calendar.MONTH);//获取当前的月份,1月份为0
        System.out.println(month+1);

        Employee[] employees=new Employee[10];
        employees[0]=new SalariedEmployee("马斯",1002,new MyDate(1992,2,28),10000);
        employees[1]=new SalariedEmployee("看谷歌",1003,new MyDate(1969,1,1),9999);
        employees[2]=new HourlyEmployee("巨野",2001,new MyDate(1991,7,6),60,240);
        for (int i = 0; i < 3; i++) {
            System.out.println(employees[i]);
            double salary=employees[i].earnings();
            System.out.println("月工资为:"+salary);
            if (month+1==employees[i].getBirthday().getMonth()){
                System.out.println("生日快乐,奖励100元");
            }
        }
    }
}


6.6接口:概述

  • 一方面,有时必须从几个类中派生出一个子类,继承它们所有的属性和方法。但是,Java不支持多重继承。有了接口,就可以得到多重继承的效果
  • 另一方面,有时必须从几个类中抽取出一些共同的行为特征,而它们之间又没有is-a的关系,仅仅是具有相同的行为特征而已。例如:鼠标、键盘、打
    印机、扫描仪、摄像头、充电器、MP3机、手机、数码相机、移动硬盘等都支持USB连接。
  • 接口就是规范,定义的是一组规则,体现了现实世界中“如果你是/要...则必须能..”的思想。继承是一个"是不是"的关系,而接口实现则是"能不能的关系。
  • 接口的本质是契约,标准,规范,就像我们的法律一样。制定好后大家都要遵守。

image-20230725143123231

接口的使用

  1. 接口使用interface来定义

  2. Java中,接口和类是并列的两个结构

  3. 如何定义接口:定义接口中的成员

    • JDK7及以前:只能定义全局常量和抽象方法全局常量:public static final的,可以不写
    • 抽象方法: public abstract的
    • JDK8:除了定义全局常量和抽象方法之外,还可以定义静态方法、默认方法(略)
  4. 接口中不能定义构造器的!意味着接口不可以实例化

  5. Java开发中,接口通过让类去实现(implements)的方式来使用.

    • 如果实现类覆盖了接口中的所有抽象方法,则此实现类就可以实例化
    • 如果实现类没有覆盖接口中所有的抽象方法,则此实现类仍为一个抽象类
  6. Java类可以实现多个接口--->弥补了Java单继承性的局限性

    • 格式:class AA extends BB implements CC,DD,EE
    • 先继承,后接口
  7. 接口与接口之间可以继承,而且可以多继承

  8. 接口的具体使用,体现多态性

  9. 接口,实际上可以看做是—种规范

接口的使用

  1. 接口使用上也满足多态性
  2. 接口,实际上就是定义了一种规范
  3. 开发中,体会面向接口编程!
package com.xin.OOPTest.demo09;

public interface Flyable {
    //全局常量
    public static final int MAX_SPEED=7900;
     int MIN_SPEED=1;//   public static final可省
    //抽象方法
    public abstract void fly();
    void walk();// public abstract可省
}
interface Attack{
    void attack();
}
===========
    package com.xin.OOPTest.demo09;

public class Plane implements Flyable{
    @Override
    public void fly() {
        System.out.println("飞飞飞飞");
    }

    @Override
    public void walk() {
        System.out.println("走走走");
    }
}
class Bullet extends Git implements Flyable,Attack{

    @Override
    public void fly() {

    }

    @Override
    public void walk() {

    }

    @Override
    public void attack() {

    }
}
class Git{

}
======
    package com.xin.OOPTest.demo09;

public class Day72501 {
    public static void main(String[] args) {
        System.out.println(Flyable.MAX_SPEED);
        System.out.println(Flyable.MIN_SPEED);
        Plane plane = new Plane();
        plane.fly();
        plane.walk();
    }
}

//1.创建了接口的非匿名实现类的非匿名对象
Flash flash = new Flash();
com.transferData(flash);
//2.创建了接口的非匿名实现类的匿名对象
com.transferData( new Printer());
//3.创建了接口的匿名实现类的非匿名对象
USB phone = new USB(){重写方法};
com.transferData(phone);
//4.创建了接口的匿名实现类的匿名对象
com.transferData( new USB(){
   重写方法 
});

image-20230725152949529

image-20230725153711214

接口方法

  1. 接口中定义的静态方法,只能通过接口来调用。

  2. 通过实现类的对象,可以调用接口中的默认方法

    如果实现类重写了接口中的默认方法,调用时,仍然调用的是重写以后的方法

  3. 如果子类(或实现类)继承的父类和实现的接口中声明了同名同参数的方法,那么子类在没有重写此方法的情况下,默认调用的是父类中的同名同参数的方法。类优先原则

  4. 如果实现类实现了多个接口,而这多个接口中定义了同名同参数的默认方法,那么在实现类没有重写此方法的情况下,报错。-->接口冲突。解决方法,重写

  5. //知识点5:如何在子类(或实现类)的方法中调用父类、接口中被重写的方法
    public void myMethod()i
    method3();//调用自己定义的重写的方法
    super.method3();//调用的是父类中声明的
    //调用接口中的默认方法
    CompareA.super.method3();
    CompareB.super.method3();
    
    

6.7类的成员之五:内部类

  • 当一个事物的内部,还有一个部分而要一个完整的结构进行描述,而这个内部的完整的结构又只为外部事物提供服务,那么整个内部的完整结构最好使用内部类。

  • 在Java中,允许一个类的定义位于另一个类的内部,前者称为内部类,后者称为外部类。

  • Inner class一般用在定义它的类或语句块之内,在外部引用它时必须给出完整的名称。

    Inner class的名字不能与包含它的外部类类名相同;

  • 分类:

    • 成员内部类(static成员内部类和非static成员内部类)
    • 局部内部类(不谈修饰符)、匿名内部类

类的内部成员之五:内部类

  1. Java中允许将一个类A声明在另一个类B中,则类A就是内部类,类B称为外部类
  2. 内部类的分类:成员内部类(静态与非静态)vs局部内部类(方法内、代码块内、构造器内)
  3. 成员内部类:

一方面,作为外部类的成员:

  • 调用外部类的结构
  • 可以被static修饰
  • 可以被4种不同的权限修饰

另一方面,作为一个类:

  • 类内可以定义属性、方法、构造器等
  • 可以被final修饰,表示此类不能被继承。言外之意,不使用final,就可以被继承
  • 可以被abstract修饰

4.关注如下的3个问题

4.1 如何实例化成员内部类的对象

//创建Dog实例(静态的成员内部类)∶
Person.Dog dog = new Person. Dog();
dog.show();
//创建Bird实例(非静态的成员内部类)∶
Person p = new Person();
Person . Bird bird = p.new Bird();
bird.sing();

4.2 如何在成员内部类中区分调用外部类的结构

public void display (String name)
system.out.println(name);//方法的形参
system.out.println(this.name);//内部类的属性
System.out.println(Person.this.name);//外部类的属性

4.3 开发中局部内部类的使用

posted @   新至所向  阅读(9)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
点击右上角即可分享
微信分享提示