枚举类
枚举类的定义比较复杂
依据下方代码做出解释
- 枚举常量必须位于枚举类最顶端,他表示我们需要使用的常量
- 定义私有属性,这些属性将成为枚举常量中的参数
- 定义构造函数,构造函数的格式对应枚举常量的格式,一一赋值给私有属性
- 定义私有属性的 getter,这样外界才可以获取枚举常量中的参数值
package chapter3;
public class EnumClass {
public static void main(String[] args) {
Persons[] persons = Persons.values();
for (Persons person : persons) {
StringBuilder sb = new StringBuilder();
sb.append(person.getAge());
sb.append(person.getName());
sb.append(person.name());
System.out.println(sb.toString());
}
}
}
enum Persons {
JACK("jack", 12), // 枚举常量 JACK,名称为 "jack",年龄为 12
TOM("tom", 13), // 枚举常量 TOM,名称为 "tom",年龄为 13
WHITE("white", 41), // 枚举常量 WHITE,名称为 "white",年龄为 41
ALIEN("undefined"); // 枚举常量 ALIEN,名称为 "undefined",使用默认年龄 999
private final String name; // 枚举常量的名称
private final int age; // 枚举常量的年龄
// 枚举常量的构造方法,接受名称和年龄
Persons(String name, int age) {
this.name = name;
this.age = age;
}
// 枚举常量的构造方法,只接受名称,年龄使用默认值 999
Persons(String name) {
this.name = name;
this.age = 999;
}
// 获取枚举常量的名称
public String getName() {
return name;
}
// 获取枚举常量的年龄
public int getAge() {
return age;
}
}
或者,直接使用最简单的办法,所有枚举常量本身就是一个字符串常量
他们不需要任何参数,只需要再被用到时取出 name()
即可
public class EnumClass {
public static void main(String[] args) {
GENDER boy = GENDER.BOY;
GENDER girl = GENDER.GIRL;
System.out.println(boy.name());
}
}
enum GENDER {
BOY, GIRL;
}
因为枚举类 enum 默认隐式继承了 Enum,所以你没法再用 extends 了,但是还是可以实现接口的!
枚举类挂载多个接口然后实现他们,就可以直接被外界调用
package chapter3;
public class EnumInterfaceClass {
public static void main(String[] args) {
// 直接通过枚举常量调用对应接口方法
BB.ASD.say();
}
}
// 接口
interface B {
void say();
}
enum BB implements B {
ASD("asd"), QWE("qwe");
private final String msg;
BB(String msg) {
this.msg = msg;
}
// 实现对应的方法
@Override
public void say() {
System.out.println(msg);
}
}
注解
三个常见的注解:
@Override
重写注解@Deprecated
表示方法已被废弃@SuppressWarnings
抑制编译器警告
@Override
只能修饰方法
只能指定为重写父类的方法,如果父类没有该方法,就会报错
@Target
是修饰注解的注解,也被称为元注解
@Deprecated
可以标注所有类型成员
表示该类型已经过时,用于新旧版本切换过度
@SuppressWarnings
抑制编译器警告
抑制的范围根据你放置该注解的位置有关
你可以通过指定抑制哪一个方面的注解,对应抑制名称可以上网查
@SuppressWarnings({
"unchecked"})
public void asd(){
}
四种元注解
@Retention
:用于指定被注解的注解的保留策略。注解的保留策略决定了注解在编译时、类加载时或运行时可见。
他接受一个参数,可选取值为:
- RetentionPolicy.SOURCE:注解仅保留在源代码中,在编译后不会包含在编译好的文件中。
- RetentionPolicy.CLASS:注解保留在编译后的字节码文件中,但不会被加载到虚拟机中,在运行时不可见。
- RetentionPolicy.RUNTIME:注解保留在编译后的字节码文件中,并被加载到虚拟机中,在运行时可通过反射机制获取。
@Target
:用于指定被注解的注解可以应用于哪些元素上。注解可以应用于类、方法、字段等不同的元素上,@Target 用于限制注解的使用范围。
@Target 接受一个参数 ElementType[],表示注解可以应用于的元素类型。
@Documented
:用于指定被注解的注解是否包含在 Java 文档中。如果一个注解被标注了该注解 d,则在生成 Java 文档时,该注解会包含在文档中。
@Inherited
:用于指定被注解的注解是否可以被继承。当一个类被继承时,是否继承父类上的注解。
异常
异常可以划分为两类:
- Error:JVM 无法解决的严重问题,如系统内部错误或者资源耗尽等情况
- Exception:一般性错误,如空指针异常;他又可以分为两大类:
- 运行时异常:不要求强制处理的异常,一般都是编程时的逻辑错误
- 编译时异常:编译器要求必须处理的异常
运行时异常
常见的运行时异常:
- NullPointerException(空指针异常):当代码尝试使用一个空对象的方法或访问空对象的属性时抛出。
- ArrayIndexOutOfBoundsException(数组越界异常):当尝试访问数组中不存在的索引时抛出。
- ClassCastException(类转换异常):当尝试将一个对象强制转换为不兼容的类型时抛出。
- NumberFormatException(数字格式异常):当字符串无法转换为数字类型时抛出,例如使用 Integer.parseInt 时传入的字符串不是合法的数字格式。
- ArithmeticException(算术异常):当进行算术运算时出现错误,例如除以零或模运算时除数为零。
- IllegalArgumentException(非法参数异常):当传递给方法的参数不合法或无效时抛出,例如传递了空对象或不允许的参数值。
- IllegalStateException(非法状态异常):当对象处于不允许的状态时抛出,例如在不正确的时间调用方法或操作。
- IndexOutOfBoundsException(索引越界异常):当访问集合(如列表或字符串)中不存在的索引时抛出。
- ConcurrentModificationException(并发修改异常):当在迭代集合的同时,使用不允许的方式(如修改集合)进行修改时抛出。
- UnsupportedOperationException(不支持的操作异常):当调用不支持的方法或操作时抛出,通常是因为对象不支持特定的操作。
捕获异常
最简单的 try catch 代码块来捕获异常
子类异常写在前面,父类异常写在后面
finally 表示无论如何都会执行的代码
package chapter4;
public class Exp1 {
public static void main(String[] args) {
try {
String str = "123";
int num = Integer.parseInt(str);
System.out.println(num);
} catch (NumberFormatException e) {
e.printStackTrace();
} finally {
System.out.println("我一直会被执行");
}
}
}
抛出异常
我们可以直接摆烂,不去主动处理异常,而是由子类去处理
此时可以使用 throw 抛出异常,抛出的异常可以是当前异常的父类;
如果你为了省事,可以直接 throw Exception
package chapter4;
public class Exp2 {
public static void main(String[] args) {
try {
int num = new Exp2().getNum("asd");
System.out.println(num);
} catch (NumberFormatException e) {
e.printStackTrace();
}
}
public int getNum(String str) throws NumberFormatException {
return Integer.parseInt(str);
}
}
编译时异常一定要处理或者抛出;运行时异常一般直接抛出;
如果你已经处理异常,就没必要抛出异常了
自定义异常
package chapter4;
import java.util.Scanner;
public class Exp3 {
public static void main(String[] args) {
int age = 100;
if (age < 100) throw new CustomException("你的数字不对");
}
}
class CustomException extends RuntimeException {
public CustomException(String message) {
super(message);
}
}