枚举是 Java 中一种特殊的类(类型),它可以定义固定数量的枚举实例(此类的对象),例如: 性别、交通信号灯、季节等等 -> enum
枚举类的对象不是new出来的, 而是一一罗列出来的. -> 数量有限
类的对象只有有限个,确定的
假设我们要定义一个人类,人类中包含姓名和性别。通常会将性别定义成字符串类型,效果如下:
public class Person {
private String name;
private String sex;
public Person() {
}
public Person(String name, String sex) {
this.name = name;
if(sex.equals("男") || sex.equals("女")){
this.sex = sex;
}
}
// 省略get/set/toString方法
}
public class Demo01 {
public static void main(String[] args) {
Person p1 = new Person("张三", "男");
Person p2 = new Person("张三", "abc"); // 因为性别是字符串,所以我们可以传入任意字符串,但事实上性别只能是‘男’或者‘女’
}
}
不使用枚举存在的问题:可以给性别传入任意的字符串,导致性别是非法的数据,不安全。
问题解决:
//定义一个枚举类型
public enum Gender{
//Sex类中只有2个对象
MALE,//男
FEMALE;//女
}
public class Person {
private String name;
private Gender gender;
public Person() {
}
public Person(String name, Gender gender) {
this.name = name;
this.gender = gender;
}
// 省略get/set/toString方法
}
public class Demo01 {
public static void main(String[] args) {
Person p1 = new Person("张三", Gender.MALE);
Person p2 = new Person("张三", Gender.FAMALE);
}
}
枚举的实现方式
JDK1.5之前需要自定义普通类
JDK1.5及以后新增的enum关键字用于定义枚举类 -> 枚举从JDK5版本有的
需求: 定义一个方法,方法的参数传递“一年四季中的某一个季节”,根据不同的季节,打印对不同季节的描述
properties
定义枚举类的做法
枚举类的定义:
public enum 类名{
//枚举项的名称全部大写 : 规范
//枚举项都是此类的对象
枚举项1,
枚举项2,
...
枚举项n;
}
枚举对象的使用:
枚举类类名.枚举项;
public enum SeasonEnum {
//这四个枚举项是SeasonEnum枚举类的对象,只有四个!!
SPRING,
SUMMER,
AUTUMN,
WINTER;
}
//通过枚举类 可以这样写
public static void printSeasonByEnum(SeasonEnum seasonEnum){
switch (seasonEnum){
case SPRING:
System.out.println("春暖花开");
break;
case SUMMER:
System.out.println("夏日炎炎");
break;
case AUTUMN:
System.out.println("硕果累累");
break;
case WINTER:
System.out.println("雪花飘飘");
break;
}
}
public static void main(String[] args) {//使用枚举类,作为方法的参数
printSeasonByEnum(SeasonEnum.AUTUMN);
}
enum Sex {
MALE, FEMALE; // 男,女
}
Perosn中的性别有String类型改为Sex枚举类型
public class Person {
private String name;
private Sex sex;
public Person() {
}
public Person(String name, Sex sex) {
this.name = name;
this.sex = sex;
}
// 省略get/set/toString方法
}
public class Demo02 {
public static void main(String[] args) {
Person p1 = new Person("张三", Sex.MALE);
Person p2 = new Person("张三", Sex.FEMALE);
Person p3 = new Person("张三", "abc");//这样写就不可以,只能是固定的枚举类型的对象
}
}
枚举的本质是一个类,所以枚举中还可以有成员变量,成员方法等。
例如:定义一个交通信号灯,分别有红灯,绿灯,黄灯,并对每一个信号灯加以说明: 比如 红灯停,绿灯行,黄灯亮了等一等 ,
public enum Light {
//1.枚举类必须先定义对象 (类似调用类的无参构造器对象 )
RED("红灯停"),GREEN("绿灯行"),YELLOW("黄灯亮了等一等");
//2.在枚举中定义属性 和 方法
String colorDesc;
public String getColorDesc() {
return colorDesc;
}
public void setColorDesc(String colorDesc) {
this.colorDesc = colorDesc;
}
//3.通过构造器给不同的枚举对象传参
private Light(String colorDesc){
this.colorDesc = colorDesc;
}
}
public static void main(String[] args) {
System.out.println(Light.GREEN);
//枚举对象的方法
System.out.println(Light.GREEN.getColorDesc());
//遍历所有的枚举对象 (values() 方法来自父类 Enum类)
Light[] values = Light.values();
for(Light light : values){
System.out.println(light.name() + "---" + light.getColorDesc() );
}
Light light = Light.valueOf("GREEN");
System.out.println("根据字符串返回一个枚举对象:"+light);
}
常用方法 | 解释 | 返回类型 |
---|---|---|
枚举类.values() | 返回枚举类的所有对象,是一个对象数组 | 对象数组 |
枚举类.valueOf(String) | 根据字符串返回对应的枚举类型 | 枚举类型 |
枚举对象.ordinal() | 返回该对象在枚举类中的序号 | int |
枚举对象.name() | 返回该对象的枚举名称 | Stirng |
注解英文是annotation,是一种代码级别的说明(注释: 文字对代码的解释说明;注解:代码对代码的解释说明),注解和类 接口平级关系。相当于一种标记,在程序中加入注解就等于为程序打上某种标记,以后,javac编译器、开发工具和其他程序可以通过反射来了解你的类及各种元素上有无标记,看你的程序有什么标记,就去干相应的事,标记可以加在包、类,属性、方法,方法的参数以及局部变量上定义.
@Override
:描述方法的重写.@SuppressWarnings
:压制警告.@Deprecated
:标记过时语法: @interface 注解名{}
示例
/**
* 定义了注解
*
*/
public @interface Annotation01 {
}
定义新的Annotation类型使用关键字@interface关键字;
自定义注解自动继承了java.lang.annotation.Annotation接口;
注解属性可以让注解具备携带存储数据的功能
基本类型
String
枚举类型
注解类型
Class类型
以上类型的一维数组类型
属性的定义格式: 运行的数据类型 属性名();
注意:
一旦注解有属性了,使用注解的时候,属性必须有值
/**
*注解的属性; 格式和接口的方法很类似
* 1.基本类型
2.String
3.枚举类型
4.注解类型
5.Class类型
6.以上类型的一维数组类型
*/
public @interface Annotation02 {
int a();//基本类型
String b();//String
Color c();//枚举类型
Annotation01 d();//注解类型
Class e();//Class类型
String[] f();//一维数组类型
}
格式
@注解名(属性名=值,属性名2=值2) eg:@MyAnnotation3(i = 0,s="23")
若属性类型的一维数组的时候,当数组的值只有一个的时候可以省略{}
@MyAnnotation4(ss = { "a" })
@MyAnnotation4(ss = "a")
注解属性可以有默认值
属性类型 属性名() default 默认值;
//属性有默认值后,在使用注解的时候就可以选择性的给属性赋值
若属性名为value的时候,且只有这一个属性需要赋值的时候可以省略value【重点】
注解: 用代码约束代码
元注解: 用元注解来约束注解的
元注解是使用在自定义的注解上,为自定义的注解提供支持的
@Target
: 用于指定被修饰的注解Annotation能用在修饰哪些程序元素,默认注解可以在任何程序元素. 值为:ElementType
的枚举值
`METHOD`:方法
`TYPE`:类 接口
`FIELD`:字段
`CONSTRUCTOR`:构造方法声明
@Retention
:定义该注解保留到那个代码阶段, 值为:RetentionPolicy
类型,默认只在源码阶段保留
`SOURCE`:只在源码上保留(默认)
`CLASS`:在源码和字节码上保留
`RUNTIME`:在所有的阶段都保留
java (源码阶段) ----编译—> .class(字节码阶段) ----加载内存–> 运行(RUNTIME)
@Target(value = {ElementType.METHOD,ElementType.TYPE })
@Retention(value = RetentionPolicy.RUNTIME)
public @interface MyAnnotation03 {
int a();
String b();
}
注解解析目的
Method、Field、Constructer、Class都实现了AnnotationElement的接口
java.lang.reflect.AnnotatedElement
****** T getAnnotation(ClassannotationType)**:得到指定类型的注解引用。没有返回null。
****boolean isAnnotationPresent(Class annotationType):判断指定的注解类型是否存在于某个元素上
Annotation[] getAnnotations():得到所有的注解,包含从父类继承下来的。
Annotation[] getDeclaredAnnotations():得到自己身上的注解。
public @interface Annotation01(){
}
@Annotation01
class Demo01(){
@Annotation01
public void fun01(){
}
public void fun02(){
}
}
//1.获得Demo01字节码对象
Class clazz = Demo01.class;
//2. 获得Demo01上面的注解对象
Annotation01 annotation01 = clazz.getAnnotation(Annotation01.class);
//3.反射获得fun01()方法对象
Method method = clazz.getMethod("fun01");
//4.判断fun01()方法上面是否有@Annotation01注解
boolean flag = method.isAnnotationPresent(Annotation01.class);