一、单例类
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
是抽象类,包含抽象方法 shout
。Dog
和 Cat
类继承自 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
和共有方法 commonMethod
。ConcreteTemplate
类继承自 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();
}
}
解释:A
和 B
是接口,分别定义了抽象方法。C
类实现了 A
和 B
接口,必须实现接口中的所有抽象方法。在 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
类在打印信息时包含男女人数,并计算去掉最高分和最低分后的平均分。通过面向接口编程,实现了业务的解耦合。