java 之枚举问题(超详细!!!!)
Java 枚举基础知识讲解 (实例配套解析!!)
我将为你详细讲解 Java 枚举(Enum)的基本知识,包括定义、特性、使用场景以及常见操作。
1. 什么是 Java 枚举?
Java 中的枚举(enum
)是一种特殊的数据类型,用于定义一组命名的常量。枚举是在 Java 5 中引入的,通过关键字 enum
定义。它本质上是一个类,继承自 java.lang.Enum
,但开发者无需显式继承。
示例:
enum Day {
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
}
在这个例子中,Day
是一个枚举类型,包含 7 个常量,表示一周的每一天。
2. 枚举的特性
- 类型安全:枚举限制了变量只能取定义中的值,避免无效值。
- 单例性:每个枚举常量都是一个唯一的实例,由 JVM 在类加载时创建。
- 继承自 Enum 类:枚举自动继承
java.lang.Enum
,因此具有一些内置方法(如name()
和ordinal()
)。 - 不可继承:枚举不能被其他类继承,也不能继承其他类(因为已经隐式继承了
Enum
)。 - 可实现接口:枚举可以实现接口,但不能被继承。
3. 基本用法
(1) 定义和使用
public class Main {
enum Color {
RED, GREEN, BLUE
}
public static void main(String[] args) {
Color myColor = Color.RED;
System.out.println(myColor); // 输出: RED
}
}
(2) 在 switch 语句中使用
枚举非常适合与 switch
语句结合使用:
enum Day {
MONDAY, TUESDAY, WEDNESDAY
}
public class Main {
public static void main(String[] args) {
Day today = Day.MONDAY;
switch (today) {
case MONDAY:
System.out.println("今天是星期一");
break;
case TUESDAY:
System.out.println("今天是星期二");
break;
case WEDNESDAY:
System.out.println("今天是星期三");
break;
}
}
}
4. 枚举的高级特性
(1) 带构造方法和字段
枚举可以有构造方法、字段和方法,但构造方法必须是私有的(默认就是 private)。
enum Planet {
EARTH(5.972e24, 6.371e6), // 质量 (kg), 半径 (m)
MARS(6.417e23, 3.389e6);
private final double mass; // 质量
private final double radius; // 半径
// 私有构造方法
Planet(double mass, double radius) {
this.mass = mass;
this.radius = radius;
}
public double getMass() {
return mass;
}
public double getRadius() {
return radius;
}
}
public class Main {
public static void main(String[] args) {
Planet earth = Planet.EARTH;
System.out.println("地球质量: " + earth.getMass()); // 输出: 地球质量: 5.972E24
System.out.println("地球半径: " + earth.getRadius()); // 输出: 地球半径: 6371000.0
}
}
(2) 实现接口
枚举可以实现接口,为每个常量定义不同的行为。
interface Description {
String getDesc();
}
enum Season implements Description {
SPRING {
public String getDesc() {
return "春天,温暖而美好";
}
},
SUMMER {
public String getDesc() {
return "夏天,炎热且充满活力";
}
};
// 抽象方法必须由每个常量实现
public abstract String getDesc();
}
public class Main {
public static void main(String[] args) {
System.out.println(Season.SPRING.getDesc()); // 输出: 春天,温暖而美好
}
}
5. 内置方法
由于枚举继承自 java.lang.Enum
,它提供了一些有用的方法:
name()
:返回枚举常量的名称。Day day = Day.MONDAY; System.out.println(day.name()); // 输出: MONDAY
ordinal()
:返回枚举常量的声明顺序(从 0 开始)。System.out.println(day.ordinal()); // 输出: 0
values()
:返回包含所有枚举常量的数组(由编译器自动生成)。Day[] days = Day.values(); for (Day d : days) { System.out.println(d); // 输出: MONDAY, TUESDAY, WEDNESDAY, ... }
valueOf(String name)
:根据名称返回对应的枚举常量(名称大小写敏感)。Day d = Day.valueOf("TUESDAY"); System.out.println(d); // 输出: TUESDAY
6. 常见使用场景
- 状态表示:如订单状态(
PENDING
,SHIPPED
,DELIVERED
)。 - 配置选项:如日志级别(
INFO
,DEBUG
,ERROR
)。 - 替代常量:比使用
public static final
更安全、更灵活。
7. 注意事项
- 不能使用 new 创建实例:枚举常量在定义时由 JVM 创建,不能通过
new
实例化。 - 线程安全:枚举常量是单例的,天生线程安全,非常适合用作单例模式。
- 序列化:枚举默认支持序列化,且保证反序列化后仍是同一个实例。
8. 示例:完整代码
以下是一个综合示例:
enum TrafficLight {
RED(30), // 红灯 30 秒
GREEN(45), // 绿灯 45 秒
YELLOW(5); // 黄灯 5 秒
private final int duration;
TrafficLight(int duration) {
this.duration = duration;
}
public int getDuration() {
return duration;
}
}
public class Main {
public static void main(String[] args) {
for (TrafficLight light : TrafficLight.values()) {
System.out.printf("%s: %d 秒%n", light, light.getDuration());
}
// 输出:
// RED: 30 秒
// GREEN: 45 秒
// YELLOW: 5 秒
}
}
综合案例解析
一、 小新的神秘棋盘
问题描述
在一次偶然的机会,小新发现了一个神秘的棋盘。这个棋盘和普通的 8x8 格子棋盘不同,它的棋子可以进行非常神奇的移动。每个棋子都只能移动到与其当前所在位置颜色不同的格子上。
小新非常好奇,他想要知道如果他把棋子放在 (A,B)(A,B) 位置,那么把棋子移动到 (P,Q)(P,Q) 位置最少需要多少步。他希望你能帮他解答这个问题。
注意:棋盘是一个 8x8 的方形棋盘,其中 (i,j)(i,j) 表示第 ii 行和第 jj 列的交叉点。如果 i+ji+j 是偶数,(i,j)(i,j) 就是白色,如果 i+ji+j 是奇数,(i,j)(i,j) 就是黑色。
输入格式
输入的第一行包含一个单独的整数 TT,表示有多少个测试用例。
每个测试用例都包含一个单独的输入行,其中包含四个用空格分隔的整数 AA,BB,PP,QQ。
数据范围保证:1≤T≤50001≤T≤5000,1≤A,B,P,Q≤81≤A,B,P,Q≤8。
输出格式
对于每个测试用例,输出一个单独的行,其中包含一个整数 - 从 (A,B)(A,B) 到 (P,Q)(P,Q) 所需的最小移动次数。
样例输入
3
1 1 8 8
5 7 5 8
3 3 3 3
样例输出
2
1
0
说明
测试用例 1:(1,1)(1,1) 和 (8,8)(8,8) 的颜色是一样的,所以小新不能在一步之内移动棋子。小新首先可以把棋子从 (1,1)(1,1) 移动到 (8,1)(8,1),然后从 (8,1)(8,1) 移动到 (8,8)(8,8),总共需要 22 步。
测试用例 2:(5,7)(5,7) 和 (5,8)(5,8) 的颜色是不同的,所以小新可以在一步之内把棋子从 (5,7)(5,7) 移动到 (5,8)(5,8),总共需要 11 步。
测试用例 3:因为棋子已经处在目标位置 (3,3)(3,3),所以小新不需要移动棋子,总共需要 00 步。
-
解题思路
1.通过for循环,建造结构
2.分类讨论情况,分为以下三种情况
- 两点之和都为奇数 || 两点之和都为偶数–》 结果为2
- 两点位置相同 --〉 结果为0
- 其余情况都是 --》 结果为1
至此解决问题。
import java.util.Scanner;
// 1:无需package
// 2: 类名必须Main, 不可修改
public class Main{
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int num = scan.nextInt();
for(int i=0;i<num;i++) {
int a =scan.nextInt();
int b =scan.nextInt();
int p =scan.nextInt();
int q =scan.nextInt();
if(a == p&& b==q) {
System.out.println(0);
}else if(((a+b)%2==0&&(p+q)%2==0)||((a+b)%2!=0&&(p+q)%2!=0)) {
System.out.println(2);
}else {
System.out.println(1);
}
}
scan.close();
}
}
二、货物摆放
题目描述
小蓝有一个超大的仓库,可以摆放很多货物。
现在,小蓝有 n 箱货物要摆放在仓库,每箱货物都是规则的正方体。小蓝规定了长、宽、高三个互相垂直的方向,每箱货物的边都必须严格平行于长、宽、高。
小蓝希望所有的货物最终摆成一个大的长方体。即在长、宽、高的方向上分别堆 LL、WW、HH 的货物,满足 n=L×W×Hn=L×W×H。
给定 nn,请问有多少种堆放货物的方案满足要求。
例如,当 n=4n=4 时,有以下 66 种方案:1×1×4、1×2×2、1×4×1、2×1×2、2×2×1、4×1×11×1×4、1×2×2、1×4×1、2×1×2、2×2×1、4×1×1。
请问,当 n=2021041820210418 (注意有 16位数字)时,总共有多少种方案?
提示:建议使用计算机编程解决问题。
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
-
解题思路
1.通过尝试发现,直接三层for固然简单,但是计算机会超时,因此我们应该降低算法复杂度,通过发现,这与这个数的因子有关。
2.通过因子迭代寻找答案便会简化很多。
-
本题难点
1.如何求出n的因数。
2.如何存储n的因数(由于无法得出因子个数,故不能用数组直接存储,我们使用列表。
3.定义long的输入格式为nextLong();。
4.掌握求因子的快捷方法。
import java.util.Scanner;
import static java.lang.Math.sqrt;
import java.util.ArrayList;
// 1:无需package
// 2: 类名必须Main, 不可修改
public class 蓝桥杯真题_货物摆放 {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
ArrayList<Long> list = new ArrayList();
long n =2021041820210418l;
long res = 0;
long sum = 0;
for (long i = 1; i <= Math.sqrt(n); i++) {
if (n % i == 0) {
sum++;
list.add(i);
}
long m = n/i;//根号后
if(m!=i&&(m*i)==n) {
sum++;
list.add(m);
}
}
// System.out.println(sum);
for(Object i:list) {
for(Object j:list) {
for(Object k:list) {
if((long)i *(long)j*(long)k==n) {
res++;
}
}
}
}
System.out.println(res);
scan.close();
}
}
三、特别数的和
题目描述
小明对数位中含有 2、0、1、9 的数字很感兴趣(不包括前导 0),在 1 到 40 中这样的数包括 1、2、9、10 至 32、39 和 40,共 28 个,他们的和是 574。
请问,在 1 到 nn 中,所有这样的数的和是多少?
输入描述
输入格式:
输入一行包含两个整数 n(1≤n≤10000)n(1≤n≤10000)。
输出描述
输出一行,包含一个整数,表示满足条件的数的和。
输入输出样例
示例
输入
40
输出
574
import java.util.Scanner;
// 1:无需package
// 2: 类名必须Main, 不可修改
public class Main {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int n = scan.nextInt();
long sum = 0;
for(int i=1;i<=n;i++) {
if(check(i)) {
sum =sum + i;
}
}
System.out.print(sum);
scan.close();
}
private static boolean check(int i) {
while (i!=0) {
int n = i%10;
if(n==0||n==1||n==2||n==9) {
return true;
}
i = i/10;
}
return false;
}
}
-
思路总结与难点
1.通过子函数实现判断过程。
2.理解判断一个数的每位数的迭代过程。
3.学会main函数嵌套函数的规范格式。