Java:单例类、枚举类、抽象类与接口总结

一、单例类

1. 单例模式概述

单例模式是一种设计模式,确保每个类只能创建一个对象。实现步骤如下:

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

2. 饿汉式单例

package com.duoduo.danli;

// 设计成单例设计模式,饿汉式
public class A {
    // 2.定义一个静态变量
    private static final A a = new A();

    // 1.私有化构造器
    private A() {
        // System.out.println("A的构造器");
    }

    public static A getInstance() {
        return a;
    }
}
package com.duoduo.danli;

public class demo1 {
    public static void main(String[] args) {
        // A a = new A();
        A a = A.getInstance();
        A b = A.getInstance();
        System.out.println(a == b);
    }
}

解释:饿汉式单例在类加载时就创建了对象,通过静态常量 a 保存该对象,getInstance 方法用于返回该对象。在 demo1 类的 main 方法中,通过 getInstance 方法获取两个对象,比较它们的引用,结果为 true,说明获取的是同一个对象。

3. 懒汉式单例

package com.duoduo.danli;

// 懒汉单例
public class B {
    private static B instance;

    private B() {
        System.out.println("B的构造方法");
    }

    // 等到真正创建对象的时候才会new对象,返回值类型为B
    public static B getInstance() {
        if (instance == null) {
            instance = new B();
        }
        return instance;
    }
}

解释:懒汉式单例在第一次调用 getInstance 方法时才创建对象。通过判断 instance 是否为 null 来决定是否创建新对象。

二、枚举类

1. 枚举类的应用场景

枚举类用于做信息的分类和标志,相比使用常量做信息标志,枚举类的参数值受约束,更易于扩展。

2. 示例代码

package com.duoduo.enumdemo;

class Constant {
    public static final int UP = 1;
    public static final int DOWN = 2;
    public static final int LEFT = 3;
    public static final int RIGHT = 4;
}

enum Direction {
    UP, DOWN, LEFT, RIGHT
}

public class test1 {
    public static void main(String[] args) {
        // 目标:掌握枚举类的应用场景,做信息的分类和标志
        // 需求,模拟上下左右移动图片

        // 第一种是用常量做信息标志和分类,缺点:参数值不受约束,不易扩展
        move(Constant.UP);

        // 第二种是使用枚举做信息标志和分类,枚举类是特殊的类,不能创建对象,枚举类中的常量就是对象
        move2(Direction.UP);
    }

    public static void move2(Direction direction) {
        switch (direction) {
            case UP:
                System.out.println("向上移动");
                break;
            case DOWN:
                System.out.println("向下移动");
                break;
            case LEFT:
                System.out.println("向左移动");
                break;
            case RIGHT:
                System.out.println("向右移动");
                break;
            default:
                System.out.println("无效的移动方向");
        }
    }

    public static void move(int direction) {
        switch (direction) {
            case Constant.UP:
                System.out.println("向上移动");
                break;
            case Constant.DOWN:
                System.out.println("向下移动");
                break;
            case Constant.LEFT:
                System.out.println("向左移动");
                break;
            case Constant.RIGHT:
                System.out.println("向右移动");
                break;
            default:
                System.out.println("无效的移动方向");
        }
    }
}

解释Constant 类使用常量来表示方向,而 Direction 枚举类使用枚举常量表示方向。move 方法使用常量作为参数,move2 方法使用枚举作为参数。使用枚举可以使代码更具可读性和可维护性。

三、抽象类

1. 抽象类和抽象方法的应用场景

抽象类不能创建对象,仅作为一种特殊的父类,让子类继承并实现。抽象类中不一定要有抽象方法,但有抽象方法的类必须是抽象类。类有的成员,如成员变量、方法、构造器等,抽象类都可以有。

2. 示例代码

package com.duoduo.abstract1;

// 抽象类
abstract class Animal {
    public abstract void shout();
}

class Dog extends Animal {
    @Override
    public void shout() {
        System.out.println("汪汪汪");
    }
}

class Cat extends Animal {
    @Override
    public void shout() {
        System.out.println("喵喵喵");
    }
}

public class Abstractdemo1 {
    // 目标Learn:抽象类和抽象方法的应用场景
    // 注意事项:抽象类中不一定要有抽象方法,有抽象方法的类必须是抽象类;
    // 类有的成员,成员变量,方法,构造器等,抽象类都可以有;

    // 抽象类的核心特点:抽象类不能创建对象,仅作为一种特殊的父类,让子类继承并实现

    // 一个类继承抽象类,必须实现抽象类中的所有抽象方法,否则,子类也必须声明为抽象类
    public static void main(String[] args) {
        // 认识抽象类的好处
        // 1.面向多态,父类知道每个子类都要做某种行为,但是每个子类的具体行为又不太一样,因此可以将父类定义为抽象方法,交给子类去重写抽象方法实现
        Animal B = new Cat();
        Animal A = new Dog();
        A.shout();
        B.shout();
    }
}

解释Animal 是抽象类,包含抽象方法 shoutDogCat 类继承自 Animal 类,并重写了 shout 方法。在 Abstractdemo1 类的 main 方法中,通过多态的方式调用 shout 方法,展示了抽象类在多态中的应用。

3. 抽象类的模板设计方法

package com.duoduo.abstract2;

// 抽象类
abstract class Template {
    // 抽象方法
    public abstract void specificMethod();

    // 共有方法,建议使用final修饰
    public final void commonMethod() {
        System.out.println("开始执行通用操作");
        specificMethod();
        System.out.println("结束执行通用操作");
    }
}

class ConcreteTemplate extends Template {
    @Override
    public void specificMethod() {
        System.out.println("执行具体的操作");
    }
}

public class Test {
    // 抽象类的使用场景:模板设计方法
    // 解决:父类定义了共有方法,子类需要实现共有方法,但是共有方法中包含子类特有的功能,
    // 实现:定义抽象类,在里面定义两个方法,一个抽象方法,一个共有方法,子类实现抽象方法,实现共有方法,建议使用final修饰

    public static void main(String[] args) {
        Template template = new ConcreteTemplate();
        template.commonMethod();
    }
}

解释Template 是抽象类,包含抽象方法 specificMethod 和共有方法 commonMethodConcreteTemplate 类继承自 Template 类,实现了 specificMethod 方法。在 Test 类的 main 方法中,创建 ConcreteTemplate 对象并调用 commonMethod 方法,展示了模板设计方法的应用。

四、接口

1. 接口的定义和特点

接口使用 interface 关键字定义,在 JDK 8 之前,接口中的成员变量只能是常量,方法只能是抽象方法。接口不能创建对象,是用来被类实现的,一个类可以实现多个接口。

2. 示例代码

package com.duoduo.interface1;

// 接口 A
public interface A {
    // 常量
    public static final String NAME = "dong wu";
    // 抽象方法
    public abstract void eat();
    public abstract void sleep();
}

// 接口 B
public interface B {
    public abstract void smile();
    public abstract void run();
}

// 实现类 C
public class C implements A, B {
    public void eat() {
        System.out.println("C eat");
    }

    public void sleep() {
        System.out.println("C sleep");
    }

    public void smile() {
        System.out.println("C smile");
    }

    public void run() {
        System.out.println("C run");
    }
}

public class Test {
    public static void main(String[] args) {
        System.out.println(A.NAME);
        // 接口不能创建对象
        // 接口是用来被类实现的,实现接口的类被称之为实现类,一个类可以实现多个接口
        C c = new C();
        c.eat();
        c.sleep();
        c.smile();
        c.run();
    }
}

解释AB 是接口,分别定义了抽象方法。C 类实现了 AB 接口,必须实现接口中的所有抽象方法。在 Test 类的 main 方法中,创建 C 对象并调用其方法。

3. 接口的好处

接口弥补了类的继承只能单继承的缺点,支持多继承。程序可以面向接口编程,实现业务的解耦合。

package com.duoduo.inerface2;

interface Diver {
}

class B {
}

class A extends B implements Diver {
}

public class Test {
    public static void main(String[] args) {
        // 接口的好处
        // 弥补了类的继承只能单继承的缺点,接口可以多继承
        // B b = new A(); 此处代码有误,A不是B的子类,无法编译通过
        Diver diver = new A();

        // 让程序可以面向接口编程,这样程序员可以灵活切换各种业务的实现 解耦合
    }
}

解释A 类继承自 B 类并实现了 Diver 接口,展示了接口在弥补单继承缺点方面的作用。

4. 接口在实际项目中的应用

package com.duoduo.interface3;

class Student {
    private String name;
    private char gender;
    private int score;

    public Student(String name, char gender, int score) {
        this.name = name;
        this.gender = gender;
        this.score = score;
    }

    public String getName() {
        return name;
    }

    public char getGender() {
        return gender;
    }

    public int getScore() {
        return score;
    }
}

interface ClassDatainter {
    void show();
    void printaverageScore();
}

class ClassDatainterimpl1 implements ClassDatainter {
    private Student[] students;

    public ClassDatainterimpl1(Student[] students) {
        this.students = students;
    }

    @Override
    public void show() {
        for (Student student : students) {
            System.out.println("姓名:" + student.getName() + ",性别:" + student.getGender() + ",成绩:" + student.getScore());
        }
    }

    @Override
    public void printaverageScore() {
        int sum = 0;
        for (Student student : students) {
            sum += student.getScore();
        }
        double average = (double) sum / students.length;
        System.out.println("平均分:" + average);
    }
}

class ClassDatainterimpl2 implements ClassDatainter {
    private Student[] students;

    public ClassDatainterimpl2(Student[] students) {
        this.students = students;
    }

    @Override
    public void show() {
        int maleCount = 0;
        int femaleCount = 0;
        for (Student student : students) {
            System.out.println("姓名:" + student.getName() + ",性别:" + student.getGender() + ",成绩:" + student.getScore());
            if (student.getGender() == '男') {
                maleCount++;
            } else {
                femaleCount++;
            }
        }
        System.out.println("男生人数:" + maleCount + ",女生人数:" + femaleCount);
    }

    @Override
    public void printaverageScore() {
        int max = Integer.MIN_VALUE;
        int min = Integer.MAX_VALUE;
        int sum = 0;
        for (Student student : students) {
            int score = student.getScore();
            if (score > max) {
                max = score;
            }
            if (score < min) {
                min = score;
            }
            sum += score;
        }
        double average = (double) (sum - max - min) / (students.length - 2);
        System.out.println("去掉最高分和最低分后的平均分:" + average);
    }
}

public class Test {
    public static void main(String[] args) {
        // 设计一个班级学生信息管理模块:学生的数据有,姓名,性别,成绩
        // 准备学生数据
        Student[] allstudents = new Student[10];
        allstudents[0] = new Student("张三", '男', 100);
        allstudents[1] = new Student("李四", '女', 90);
        allstudents[2] = new Student("王五", '男', 80);
        allstudents[3] = new Student("赵六", '女', 70);
        allstudents[4] = new Student("钱七", '男', 60);
        allstudents[5] = new Student("孙八", '女', 50);
        allstudents[6] = new Student("周九", '男', 40);
        allstudents[7] = new Student("吴十", '女', 30);
        allstudents[8] = new Student("郑十一", '男', 20);
        allstudents[9] = new Student("王十二", '女', 10);

        // 实现两套实现方案,支持灵活切换(解耦合)
        // 定义规范接口
        // 实现第一个实现类,完成打印学生信息,实现打印平均分
        // 实现第二个实现类,完成打印学生信息(包含男女人数),实现打印平均分(去掉最高分和最低分)
        ClassDatainter A = new ClassDatainterimpl1(allstudents);
        A.show();
        A.printaverageScore();
        ClassDatainter B = new ClassDatainterimpl2(allstudents);
        B.show();
        B.printaverageScore();
    }
}

解释:该示例设计了一个班级学生信息管理模块,通过定义 ClassDatainter 接口,实现了两种不同的学生信息展示和平均分计算方案。ClassDatainterimpl1 类完成基本的学生信息打印和平均分计算,ClassDatainterimpl2 类在打印信息时包含男女人数,并计算去掉最高分和最低分后的平均分。通过面向接口编程,实现了业务的解耦合。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值