八、枚举注解与反射

一、枚举

一、概述

1、JDK1.5引入了新的类型——枚举。
2、在JDK1.5 之前,我们定义常量都是: public static fianl… 很难管理。
3、枚举,可以把相关的常量分组到一个枚举类型里,而且枚举提供了比常量更多的方法。
4、类的对象只有有限个
5、当需要定义一组常量时,强烈建议使用枚举类

二、定义

方式一、jdk5.0之前,自定义枚举类

//自定义枚举类
public class Season {
	 //1、声明Season对象的属性 private final修饰
 	 private final String seasonName;
   	 private final String seasonDesc;
   	 //2、私有化类的构造器 并给对象属性赋值
     private Season(String seasonName,String seasonDesc){
       		this.seasonName=seasonName;
      		this.seasonDesc=seasonDesc;
   	 }
     //3、提供当前枚举类的多个对象  public static final 
  	 public static final Season SPRING=new Season("春天","春暖花开");
     public static final Season SUMMER=new Season("夏天","夏日炎炎");
     public static final Season AUTUMN=new Season("夏天","秋高气爽");
     public static final Season WINTER=new Season("夏天","冰天雪地");
}

方式二、jdk5.0 使用enum关键字定义m枚举类

public enum Color {  
	RED, GREEN, BLANK, YELLOW  
}
public enum Level {
	LOW(30), MEDIUM(15), HIGH(7), URGENT(1);
	private int levelValue;
	private Level(int levelValue) {
	this.levelValue = levelValue;
	}
	public int getLevelValue() {
	return levelValue;
	}
}

三、常见方法

在这里插入图片描述

public enum Level1 {
	 LOW,MIDDLE,HIGH;
}
public enum Level2 {
   LOW(10),MIDDLE(20),HIGH(30);
   private int levelValue;
   private Level2(int levelValue){
       this.levelValue=levelValue;
   }
   public int getLevelValue(){
       return levelValue;
   }
   @Override
   public String toString() {
       return "Level2{" +
               "levelValue=" + levelValue +
               '}';
   }
   public static void main(String[] args) {
       System.out.println(Level2.LOW.getLevelValue());
       System.out.println(Level1.LOW.compareTo(Level1.HIGH));
       System.out.println(Level2.LOW.name());
       System.out.println(Level2.LOW.toString());
       System.out.println(Level2.LOW.ordinal());
       Level2 x=Enum.valueOf(Level2.class,"HIGH");
       System.out.println(x.name());
   }
}

四、枚举接口

public enum Level1 implements LShow {
    LOW{
        @Override
        public void show(){
            System.out.println("低级别");
        }
    },MIDDLE{
        @Override
        public void show(){
            System.out.println("中级别");
        }
    },HIGH{
        @Override
        public void show(){
            System.out.println("高级别");
        }
    };
    public static void main(String[] args) {
        Level1.LOW.show();
        Level1.MIDDLE.show();
    }
}
interface LShow{
    void show();
}

五、注意事项

一旦定义了枚举,最好不要妄图修改里面的值,除非修改是必要的。
枚举类默认继承的是java.lang.Enum类而不是Object类
枚举类不能有子类,因为其枚举类默认被final修饰
只能有private构造方法
switch中使用枚举时,直接使用常量名,不用携带类名
不能定义name属性,因为自带name属性
不要为枚举类中的属性提供set方法,不符合枚举最初设计初衷。

六、枚举常见用法

1、switch

public enum WeekDay {
    SUN, MON, TUE, WED, THT, FRI, SAT
}
 
public class SelectDay{
    WeekDay weekday = WeekDay.SUN;
    public void select(){
        switch(weekday){
            case SUN:
                weekday = WeekDay.SUN;
                bread;
            ...
        }
    }
}

2、向枚举添加新方法

public enum Color {  
    RED("红色", 1), GREEN("绿色", 2), BLANK("白色", 3), YELLO("黄色", 4);  
    // 成员变量  
    private String name;  
    private int index;  
    // 构造方法  
    private Color(String name, int index) {  
        this.name = name;  
        this.index = index;  
    }  
    // 普通方法  
    public static String getName(int index) {  
        for (Color c : Color.values()) {  
            if (c.getIndex() == index) {  
                return c.name;  
            }  
        }  
        return null;  
    }  
    // get set 方法  
    public String getName() {  
        return name;  
    }  
    public void setName(String name) {  
        this.name = name;  
    }  
    public int getIndex() {  
        return index;  
    }  
    public void setIndex(int index) {  
        this.index = index;  
    }  
}  

3、覆盖枚举方法

public enum Color { 
    RED("红色", 1), GREEN("绿色", 2), BLANK("白色", 3), YELLO("黄色", 4); 
    // 成员变量
    private String name; private int index; 
    // 构造方法 
    private Color(String name, int index) { 
        this.name = name; this.index = index; 
    } 
    //覆盖方法 
    @Override 
    public String toString() { 
    return this.index+"_"+this.name; 
    } 
}

4、实现接口

public interface Behaviour { 
    void print(); 
    String getInfo(); 
} 
public enum Color implements Behaviour{ 
    RED("红色", 1), GREEN("绿色", 2), BLANK("白色", 3), YELLO("黄色", 4); 
    // 成员变量 
    private String name; 
    private int index; 
    // 构造方法 
    private Color(String name, int index) { 
        this.name = name; this.index = index; 
    } 
    //接口方法 
    @Override 
    public String getInfo() { 
        return this.name; 
    } 
    //接口方法 
    @Override 
    public void print() { 
        System.out.println(this.index+":"+this.name); 
    } 
}

6、接口组织枚举

public interface Food { 
    enum Coffee implements Food{ 
        BLACK_COFFEE,DECAF_COFFEE,LATTE,CAPPUCCINO 
    } 
    enum Dessert implements Food{ 
        FRUIT, CAKE, GELATO 
    } 
}

7、枚举集合

public class Test {
    public static void main(String[] args) {
        EnumSet<WeekDay> week = EnumSet.noneOf(WeekDay.class);
        week.add(WeekDay.MON);
        System.out.println("EnumSet中的元素:" + week);
        week.remove(WeekDay.MON);
        System.out.println("EnumSet中的元素:" + week);
        week.addAll(EnumSet.complementOf(week));
        System.out.println("EnumSet中的元素:" + week);
        week.removeAll(EnumSet.range(WeekDay.FRI, WeekDay.SAT));
        System.out.println("EnumSet中的元素:" + week);
    }

二、注解

一、简介

Java 注解(Annotation)又称 Java 标注,是 JDK5.0 引入的一种注释机制。
Java 语言中的类、方法、变量、参数和包等都可以被标注。和注释不同,Java >标注可以通过反射获取标注内容。在编译器生成类文件时,标注可以被嵌入到>>字节码中。Java 虚拟机可以保留标注内容,在运行时可以获取到标注内容 。 >当然它也支持自定义 Java 标注。

二、重点

重点:
1、怎么使用内置注解
2、怎么自定义注解
3、反射中怎么获取注解内容

三、内置注解

1、@Override : 重写 *
标注在方法上,无属性。定义在java.lang.Override

2、@Deprecated:废弃 *
过时注解,标注在属性方法参数构造器局部变量上,无属性定义在java.lang.Deprecated
Java 9 中注解增加了两个新属性:
since: 该属性指定已注解的API元素已被弃用的版本。
forRemoval: 改属性表示注解的 API 元素在将来的版本中被删除,应该迁移 API。

3、@SuppressWarnings
抑制编译器警告注解,标注在属性方法参数构造器局部变量上,属性为String[] value()。
@SuppressWarnings(“unchecked”) 抑制单类型的警告
@SuppressWarnings({“unchecked”,“rawtypes”}) 抑制多类型的警告
@SuppressWarnings(“all”) 抑制所有类型的警告

在这里插入图片描述

4、@SafeVarargs
抑制堆污染警告注解,标注在构造器和方法上无属性
该注解的作用是告诉编译器取消unchecked警告。
unchecked警告是什么?
Heap Pollution堆污染,首先我们看下什么是堆污染:
某个 可变泛型参数 指向的对象 并不是该泛型参数,而是无泛型参数。

	//此时test方法的入参是List<String>
	public static void test(List<String> list) {
	}
	public static void main(String[] args) {
	        List list = Lists.newArrayList();
	        list.add(1);
	        //test方法的入参(可变泛型参数)指向的并不是List<String>,而是List(无泛型参数)
	        test(list);
	}

5、@FunctionalInterface
函数式接口注解,标注在接口上,无属性
该注解只能标志在"有且仅有一个抽象方法"的接口上。
有且仅有一个抽象方法不包括JDK8接口中的静态方法和默认方法,不包括覆盖>了Object中方法。
该注解不是必须的,如果一个符合函数式接口要求的接口加不加该注解都可>以,但是如果不满足要求加该注解则会编译报错。

6、@Repeatable:标识某注解可以在同一个声明上使用多次
Java 8 开始支持,标识某注解可以在同一个声明上使用多次。

四、元注解

1、@Target:表示该注解用于什么地方

ElemenetType.CONSTRUCTOR-----------------------------构造器声明 
ElemenetType.FIELD ----------------------------------域声明(包括 enum 实例) 
ElemenetType.LOCAL_VARIABLE------------------------- 局部变量声明 
ElemenetType.METHOD ---------------------------------方法声明 
ElemenetType.PACKAGE --------------------------------包声明 
ElemenetType.PARAMETER ------------------------------参数声明 
ElemenetType.TYPE----------------------------------- 类,接口(包括注解类型)或enum声明 
ElemenetType.TYPE_PARAMETER----------------------------------- 类型参数
 ElemenetType.TYPE_USE-------------------------类型的使用
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
    ElementType[] value();
}
public enum ElementType {
    TYPE, /** 类,接口(包括注解类型)或enum声明  */
    FIELD,/** 域声明(包括 enum 实例) */
    METHOD,/** 方法声明 */
    PARAMETER, /** 参数声明 */
    CONSTRUCTOR,/** 构造器声明 */
    LOCAL_VARIABLE, /** 局部变量声明  */
    ANNOTATION_TYPE,/** Annotation type declaration */
    PACKAGE, /**  包声明  */
    TYPE_PARAMETER, /** 类型参数声明  @since 1.8 */
    TYPE_USE  /*类型的使用  @since 1.8*/
}

2、@Retention:表示该注解可以保存的范围
SOURCE,CLASS,RUNTIME

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {

    RetentionPolicy value();
}
public enum RetentionPolicy {
    /**
     * 源代码:即此注解只能保存在源代码中
     * 当编译时,会被丢弃
     */
    SOURCE,

   /**
     * class文件:即此注解可以在class文件中保留
     * 但会被jvm丢弃
     */
    CLASS,

   /**
     * 运行期:即此注解可以在运行时保留
     * 可以通过反、反射获得
     */
    RUNTIME
}

3、@Documented
即拥有这个注解的元素可以被javadoc此类的工具文档化。它代表着此注解会被javadoc工具提取成文档。在doc文档中的内容会因为此注解的信息内容不同而不同。相当与@return,@param 等

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Documented {
}

4、@Inherited:

  1. 子类会继承父类使用的注解中被@Inherited修饰的注解
  2. 接口继承关系中,子接口不会继承父接口中的任何注解,不管父接口中使用的注解有没有被@Inherited修饰
  3. 类实现接口时不会继承任何接口中定义的注解
//注解是否包含在文档中
@Documented
//用途类型 可以用在类和方法上
@Target({ElementType.TYPE,ElementType.METHOD})
//保存策略
@Retention(RetentionPolicy.RUNTIME)
//可以继承
@Inherited
@interface  MyAnnotation{
    String[] value();
}

五、自定义注解

参考链接

1、注解的基本元素

1、修饰符
访问修饰符必须为public,不写默认为pubic;
2、 关键字
关键字为@interface;
3、注解名称
注解名称为自定义注解的名称,使用时还会用到;
4、注解类型元素
注解类型元素是注解中内容,可以理解成自定义接口的实现部分;

public @interface Info {
    String value() default "tracy";
    boolean isDelete();
}

2、使用元注解修饰注解

@Target

在这里插入图片描述

@Retention

在这里插入图片描述

@Document
@Inherited

@Target({ElementType.FIELD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Info {
      String value() default "tracy";
      boolean isDelete();
}

3、使用自定义注解

自定义Person类

@Data
@Builder
// 为Person类配置了刚刚定义的注解@Info
@Info(isDelete = true)
public class Person {

    /**
     * 姓名
     */
    private String name;

    /**
     * 年龄
     */
    private int age;

    /**
     * 是否有效
     */
    private boolean isDelete;
}

利用反射解析注解


public class AnnotationTest {
    public static void main(String[] args) {
        try {
            //获取Person的Class对象
            Person person = Person.builder().build();
            Class clazz = person.getClass();
            //判断person对象上是否有Info注解
            if (clazz.isAnnotationPresent(Info.class)) {
                System.out.println("Person类上配置了Info注解!");
                //获取该对象上Info类型的注解
                Info infoAnno = (Info) clazz.getAnnotation(Info.class);
                System.out.println("person.name :" + infoAnno.value() + ",person.isDelete:" + infoAnno.isDelete());
            } else {
                System.out.println("Person类上没有配置Info注解!");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}


对于一个类或者接口来说,Class类(java.lang包下)中提供了一些方法用于反射注解,当然对于字段、方法来说反射注解的方式很类似。

//返回指定的注解
getAnnotation
//判断当前元素是否被指定注解修饰
isAnnotationPresent
//返回所有的注解
getAnnotations

三、反射


版权声明:本文为qq_42643165原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。