13 Java枚举和注解

Java枚举

在某些情况下,一个类的对象是有限而且固定的。例如季节类,只能有 4 个对象。

当类的对象是有限时,就应该使用枚举,而不使用普通类。(枚举对象是单例模式)

枚举的属性

实现接口的枚举类

例子

public class Test5 {
    public static void main(String[] args) {
        Season spring = Season.SPRING;
        spring.showInfo();
        spring.test();

        Season summer = Season.SUMMER;
        summer.showInfo();
        summer.test();

        Season spring2 = Season.SPRING;
        //每次执行Season.SPRING获得是相同的对象,枚举类中的每个枚举对象都是单例模式
        System.out.println(spring.equals(spring2));//true
    }
}

enum Season implements ITest{
    //枚举的实例对象都是默认修饰:private static final
    //下面的四个实例对象虽然没有修饰,但是已经是修饰了,只是没显式修饰。
    SPRING("春天","春暖花开"),//此处相当于在调用有参的私有构造private season(String name,String desc)
    SUMMER("夏天","炎炎夏日"),
    AUTUMN("秋天","秋高气爽"),
    WINTER("冬天","寒风凛冽");

    private final String name;
    private final String desc;

    private Season(String name,String desc) {
        this.name = name;
        this.desc = desc;
    }
    public void showInfo() {
        System.out.println(this.name+ ": "+this.desc);
    }

    @Override
    public void test() {
        System.out.println("实现接口的方法,这是("+this.name+")的调用。");
    }
}

interface ITest{
    public void test();
}

枚举类的常用方法

比较重要的是compareTo()方法,这个之前TreeSet和TreeMap都有例子,这里就不演示了。

Annotation注解

注解概述

注解作用:每当你创建描述符性质的类或者接口时,一旦其中包含重复性的工 作,就可以考虑使用注解来简化与自动化该过程。 Java提供了四种元注解,专门负责新注解的创建工作。

基本的注解

例子

import java.util.ArrayList;
import java.util.List;

public class Test6 {
    public static void main(String[] args) {
        TestB n = new TestB();
        n.test1();//可以看见方法名有删除线,但是还是可以使用

        //通常集合没有指定泛型,会有警告
        //可以使用@SuppressWarnings()注解 : 抑制编译器警告
        @SuppressWarnings({ "rawtypes", "unused" })
        List list = new ArrayList();
    }
}

class TestA{
    public void test() {}
}

class TestB extends TestA{
    //常见 @Override注解,作用:重写方法
    @Override
    public void test() {
        // TODO Auto-generated method stub
        super.test();
    }

    //过时的方法注解:@Deprecated,声明该方法已经过时了
    @Deprecated
    public void test1() {
        //过时的方法
        System.out.println("过时的方法");
    }
}

自定义注解

例子

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

public class Test7 {

    //注解这些属性有什么用呢,通常都是要取出注解的属性使用,要通过反射取注解的属性,反射暂时没学,略过
    @TestAnn(id=1,desc = "test")
    int i;
//    @TestAnn(id=1,desc = "test")这里会报错,因为该注解已经限定只能在属性使用。
    public static void main(String[] args) {

    }
}

/**
 *
 * @author leak
 *    自定义注解格式 : @interface 注解名
 *    @Target: 注解声明该自定义注解的“作用对象”,比如这个注解是作用于属性/类/方法/接口/枚举
 *    @Retention():声明该注解的生命周期,就是该注解什么时候有效
 *    @Documented:Javadoc工具会将此注解标记元素的注解信息包含在javadoc中。默认,注解信息不会包含在Javadoc中。
 */

@Target(ElementType.FIELD)//这里是作用于属性,也就是说这个自定义注解只能在属性上使用
@Retention(RetentionPolicy.RUNTIME)//这里是运行时都有效
@Documented
@interface TestAnn{
    public int id() default 0;
    public String desc() default "";
}

下面是注解的详细信息,上面的只是简单的介绍。

元注解

元注解的作用就是负责注解其他注解。Java5.0定义了4个标准的metaannotation类型,它们被用来提供对其它 annotation类型作说明。 Java5.0定义的元注解:

[email protected]

[email protected]

[email protected]

[email protected]

这些类型和它们所支持的类在java.lang.annotation包中可以找到。

下面我们看一下每个元注解的作用和相应分参数的使用说明。

@Target

@Target说明了Annotation所修饰的对象范围:Annotation可被用 于 packages、types(类、接口、枚举、Annotation类型)、类型成员 (方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、 catch参数)。在Annotation类型的声明中使用了target可更加明晰其修饰 的目标。

作用:用于描述注解的使用范围(即:被描述的注解可以用在什么地方)

取值(ElementType)有:

1.CONSTRUCTOR: 用于描述构造器

2.FIELD: 用于描述域

3.LOCAL_VARIABLE: 用于描述局部变量

4.METHOD: 用于描述方法

5.PACKAGE: 用于描述包

6.PARAMETER: 用于描述参数

7.TYPE: 用于描述类、接口(包括注解类型) 或enum声明
使用示例:

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/*** * * 实体注解接口 */
@Target(value = { ElementType.TYPE })
@Retention(value = RetentionPolicy.RUNTIME)
public @interface Entity {
    /**
     * 实体默认firstLevelCache属性为false
     *
     * @return boolean
     */
    boolean firstLevelCache() default false;

    /**
     * 实体默认secondLevelCache属性为false
     * @return boolean
     */
    boolean secondLevelCache() default true;

    /**
     * 表名默认为空
     * @return String
     */
    String tableName() default "";

    /**
    *  默认以""分割注解
    */
    String split() default "";
}

@Retention

@Retention定义了该Annotation被保留的时间长短:某些Annotation 仅出现在源代码中,而被编译器丢弃;而另一些却被编译在class文件中;编译 在class文件中的Annotation可能会被虚拟机忽略,而另一些在class被装载 时将被读取(请注意并不影响class的执行,因为Annotation与class在使用
上是被分离的)。使用这个meta­Annotation可以对 Annotation的“生命 周期”限制。

作用:表示需要在什么级别保存该注释信息,用于描述注解的生命周期 (即:被描述的注解在什么范围内有效)

取值(RetentionPoicy)有:

1.SOURCE:在源文件中有效(即源文件保留)

2.CLASS:在class文件中有效(即class保留)

3.RUNTIME:在运行时有效(即运行时保留)

使用示例:

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/*** * 字段注解接口 */
@Target(value = { ElementType.FIELD }) // 注解可以被添加在属性上
@Retention(value = RetentionPolicy.RUNTIME) // 注解保存在JVM运行时 刻,能够在运行时刻通过反射API来获取到注解的信息
public @interface Column {
    String name();
    // 注解的name属性   Column注解的的RetentionPolicy的属性值是RUTIME,这样注解处理器可以
    // 通过反射,获取到该注解的属性值,从而去做一些运行时的逻辑处理
}

@Documented

@Documented用于描述其它类型的annotation应该被作为被标注的程序 成员的公共API,因此可以被例如javadoc此类的工具文档化。Documented是 一个标记注解,没有成员。

@Inherited

@Inherited 元注解是一个标记注解,@Inherited阐述了某个被标注的 类型是被继承的。

如果一个使用了@Inherited修饰的annotation类型被用于 一个class,则这个annotation将被用于该class的子类。
注意:

@Inherited annotation类型是被标注过的class的子类所继承。

类并不从它所实现的接口继承annotation,方法并不从它所重载的方法继 承annotation。

当@Inherited annotation类型标注的annotation的Retention是 RetentionPolicy.RUNTIME,则反射API增强了这种继承性。

如果我们使用 java.lang.reflect去查询一个@Inherited annotation类型的 annotation时,反射代码检查将展开工作:检查class和其父类,直到发现指 定的annotation类型被发现,或者到达类继承结构的顶层。

自定义注解概述

使用@interface自定义注解时,自动继承了 java.lang.annotation.Annotation接口,由编译程序自动完成其他细 节。在定义注解时,不能继承其他的注解或接口。@interface用来声明一个注 解,其中的每一个方法实际上是声明了一个配置参数。方法的名称就是参数的名 称,返回值类型就是参数的类型(返回值类型只能是基本类型、Class、 String、enum)。可以通过default来声明参数的默认值。

定义注解格式:

public @interface 注解名 {定义体}     注解参数的可支持数据类型:

1.所有基本数据类型 (int,float,boolean,byte,double,char,long,short)

2.String类型

3.Class类型

4.enum类型

5.Annotation类型

6.以上所有类型的数组

Annotation类型里面的参数该怎么设定:

第一:只能用public或默认(default)这两个访问权修饰.例如,String  value()?这里把方法设为defaul默认类型;    
第二:参数成员只能用基本类型 byte,short,char,int,long,float,double,boolean八种基本数据类型 和 String,Enum,Class,annotations等数据类型,以及这一些类型的数 组.例如,String value()?这里的参数成员就为String?

第三:如果只有一个参数成员,最好把参数名称设为"value",后加小括号. 例:下面的例子FruitName注解就只有一个参数成员。

简单的自定义注解和使用注解实例:

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

//示例1
/*** *主键注解接口 */
@Target(value = { ElementType.FIELD })
@Retention(value = RetentionPolicy.RUNTIME)
public @interface Id {
}

//示例2
/** 属性不需要被持久化注解 **/
@Target(value = { ElementType.FIELD })
@Retention(value = RetentionPolicy.RUNTIME)
@Documented
@interface Transient {
}

注解元素的默认值:

注解元素必须有确定的值,要么在定义注解的默认值中指定,要么在使用注 解时指定,非基本类型的注解元素的值不可为null。因此, 使用空字符串或0 作为默认值是一种常用的做法。这个约束使得处理器很难表现一个元素的存在或 缺失的状态,因为每个注解的声明中,所有元素都存在,并且都具有相应的值, 为了绕开这个约束,我们只能定义一些特殊的值,例如空字符串或者负数,一次 表示某个元素不存在,在定义注解时,这已经成为一个习惯用法。

定义了注解,并在需要的时候给相关类,类属性加上注解信息,如果没有响应的 注解信息处理流程,注解可以说是没有实用价值。如何让注解真真的发挥作用,
主要就在于注解处理方法,下一步我们将学习注解信息的获取和处理!

如果没有用来读取注解的方法和工作,那么注解也就不会比注释更有用处了。使 用注解的过程中,很重要的一部分就是创建于使用注解处理器。Java SE5扩展 了反射机制的API,以帮助程序员快速的构造自定义注解处理器。

注解处理器类库(java.lang.reflect.AnnotatedElement):

Java使用Annotation接口来代表程序元素前面的注解,该接口是所有 Annotation类型的父接口。除此之外,Java在java.lang.reflect 包下 新增了AnnotatedElement接口,该接口代表程序中可以接受注解的程序元 素,该接口主要有如下几个实现类:

Class:类定义

Constructor:构造器定义

Field:累的成员变量定义

Method:类的方法定义

Package:类的包定义

java.lang.reflect 包下主要包含一些实现反射功能的工具类,实际 上,java.lang.reflect 包所有提供的反射API扩充了读取运行时 Annotation信息的能力。当一个Annotation类型被定义为运行时的 Annotation后,该注解才能是运行时可见,当class文件被装载时被保存在 class文件中的Annotation才会被虚拟机读取。

AnnotatedElement 接口是所有程序元素(Class、Method和 Constructor)的父接口,所以程序通过反射获取了某个类的 AnnotatedElement对象之后,程序就可以调用该对象的如下四个个方法来访 问Annotation信息:

方法1:<T extends Annotation> T getAnnotation(Class<T>  annotationClass): 返回改程序元素上存在的、指定类型的注解,如果该类 型注解不存在,则返回null。

方法2:Annotation[] getAnnotations():返回该程序元素上存在的 所有注解。

方法3:boolean is AnnotationPresent(Class<?extends  Annotation> annotationClass):判断该程序元素上是否包含指定类型的注解,存在则返回true,否则返回false.

方法4:Annotation[] getDeclaredAnnotations():返回直接存在 于此元素上的所有注释。与此接口中的其他方法不同,该方法将忽略继承的注 释。(如果没有注释直接存在于此元素上,则返回长度为零的一个数组。)该方 法的调用者可以随意修改返回的数组;这不会对其他调用者返回的数组产生任何 影响。

一个简单的注解处理器:

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Field;

import org.chen.day11.FruitColor.Color;

/***********注解声明***************/
/** 水果名称注解 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@interface FruitName {
    String value() default "";
}

/** 水果颜色注解 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@interface FruitColor {
    /** * 颜色枚举 * * */
    enum Color {
        BULE, RED, GREEN
    };

    /** * 颜色属性 * @return */
    Color fruitColor() default Color.GREEN;
}

/** 水果供应者注解 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@interface FruitProvider {
    /** * 供应商编号 * @return */
    public int id() default -1;

    /** * 供应商名称 * @return */
    public String name() default "";

    /** * 供应商地址 * @return */
    public String address() default "";
}

/*********** 注解使用 ***************/
class Apple {
    // 下面进行注解赋值
    @FruitName("Apple")
    private String appleName;
    @FruitColor(fruitColor = Color.RED)
    private String appleColor;
    @FruitProvider(id = 1, name = "陕西红富士集团", address = "陕西省西安市延安路89号红 富士大厦")
    private String appleProvider;

    // 下面的set/get方法对比注解,是不是注解更方便,如果赋值要属性一个个用set方法设置
    // get/set这里只是对比,没有使用到,可注释掉
    public void setAppleColor(String appleColor) {
        this.appleColor = appleColor;
    }

    public String getAppleColor() {
        return appleColor;
    }

    public void setAppleName(String appleName) {
        this.appleName = appleName;
    }

    public String getAppleName() {
        return appleName;
    }

    public void setAppleProvider(String appleProvider) {
        this.appleProvider = appleProvider;
    }

    public String getAppleProvider() {
        return appleProvider;
    }
}

/*********** 注解处理器 ***************/
public class FruitRun {
    public static void getFruitInfo(Class<?> clazz) {
        String strFruitName = " 水果名称:";
        String strFruitColor = " 水果颜色:";
        String strFruitProvicer = "供应商信息:";
        //getDeclaredFields():获得某个类的所有声明的字段,即包括public、private和proteced,但是不包括父类的声明字段。
        Field[] fields = clazz.getDeclaredFields();
        // 遍历所有注解包含的信息
        for (Field field : fields) {
            //注解算特殊的类
            if (field.isAnnotationPresent(FruitName.class)) {
                FruitName fruitName = (FruitName) field.getAnnotation(FruitName.class);
                strFruitName = strFruitName + fruitName.value();
                System.out.println(strFruitName);// 输出水果名称
            } else if (field.isAnnotationPresent(FruitColor.class)) {
                FruitColor fruitColor = (FruitColor) field.getAnnotation(FruitColor.class);
                strFruitColor = strFruitColor + fruitColor.fruitColor().toString();
                System.out.println(strFruitColor);// 输出水果颜色
            } else if (field.isAnnotationPresent(FruitProvider.class)) {
                FruitProvider fruitProvider = (FruitProvider) field.getAnnotation(FruitProvider.class);
                strFruitProvicer = " 供应商编号:" + fruitProvider.id() + " 供应 商名称:" + fruitProvider.name() + " 供应商地址:"
                        + fruitProvider.address();
                System.out.println(strFruitProvicer);// 输出水果详细信息
            }
        }
    }

    /*********** 输出结果 ***************/
    /** * @param args */
    public static void main(String[] args) {
        //在Apple.class对属性赋值的,getFruitInfo()取出注解里面的值
        FruitRun.getFruitInfo(Apple.class);
    }
}

原文地址:https://www.cnblogs.com/unlasting/p/12688669.html

时间: 2024-08-27 12:23:08

13 Java枚举和注解的相关文章

Effective Java - 枚举与注解

Enumeration 于Java 1.5增加的enum type... enum type是由一组固定的常量组成的类型,比如四个季节.扑克花色. 在出现enum type之前,通常用一组int常量表示枚举类型. 比如这样: public static final int APPLE_FUJI = 0; public static final int APPLE_PIPPIN = 1; public static final int APPLE_GRANNY_SMITH = 2; public

编写高质量代码:改善Java程序的151个建议(第6章:枚举和注解___建议88~92)

建议88:用枚举实现工厂方法模式更简洁 工厂方法模式(Factory Method Pattern)是" 创建对象的接口,让子类决定实例化哪一个类,并使一个类的实例化延迟到其它子类".工厂方法模式在我们的开发中经常会用到.下面以汽车制造为例,看看一般的工厂方法模式是如何实现的,代码如下: 1 //抽象产品 2 interface Car{ 3 4 } 5 //具体产品类 6 class FordCar implements Car{ 7 8 } 9 //具体产品类 10 class B

Java基础13:反射与注解详解

Java基础13:反射与注解详解 什么是反射? 反射(Reflection)是Java 程序开发语言的特征之一,它允许运行中的 Java 程序获取自身的信息,并且可以操作类或对象的内部属性. Oracle官方对反射的解释是 Reflection enables Java code to discover information about the fields, methods and constructors of loaded classes, and to use reflected fi

Effective java经验之谈,枚举,注解,方法,通用设计,异常

这几章看的比较快,内容就如同标题一样比较容易理解,所以只有部分内容会在[]中解释,其他的就直接理解标题,并不影响阅读质量. 不过如果时间充足的话,还是仔细读一读原书的内容,相信还是有所收获的.主要最近自己想进入算法与机器学习部分,尽快结束这本书. 另一方面,讨论一些自己感兴趣的内容,我会将搞过的东西总结下.后面可能写一部分关于java字节码阅读以及编写的东西.只所以这么来, 是因为字节码编程还是非常用途实际的,这一"java编译语言"使得String与StringBuilder的性能对

Java复习——枚举与注解

枚举 枚举就是让某些变量的取值只能是若干固定值中的一个,否则编译器就会报错,枚举可以让编译器在编译阶段就控制程序的值,这一点是普通变量无法实现的.枚举是作为一种特殊的类存在的,使用的是enum关键字修饰 枚举常量 枚举常量默认都是使用static final修饰的,所以语法建议使用大写,一个枚举类在第一次被实例化的时候,这些常量就会被创建,这些常量都是枚举类子类的对象 public enum WeekDay{ //每一个枚举的元素(枚举常量)就是一个枚举类子类的对象,是使用static fina

[Effective Java]第六章 枚举和注解

第六章      枚举和注解 30.      用enum代替int常量 枚举类型是指由一组固定的常量组成合法值的类型,例如一年中的季节或一副牌中的花色.在没引入枚举时,一般是声明一组int常量,每个类型成员一个常量: public static final int APPLE_FUJI = 0; public static final int APPLE_PIPPIN = 1; public static final int APPLE_GRANNY_SMITH = 2; public sta

改善java程序的151个建议--枚举和注解

83.项目开发中,推荐使用枚举定义常量,来代替接口常量或类常量 Eg:enum{Spring,Summer,Autumn,Winter;} 枚举定义常量相对于经常使用的常量类和静态常量相比的优势: 1)枚举常量更简单:枚举常量不需要定义枚举值,int spring=1:枚举表示的 是一个枚举项,字面含义不同,其他常量必须是一个类型: 2)枚举常量属于稳态型 3)枚举具有内置的方法,例如values:获得所有值的集合,可用于遍历,ordinal: 获得排序值,compareTo比较方法等: 4)枚

【java】java中的注解(Annotation)是如何工作的?

Java中的注解是如何工作的? 自Java5.0版本引入注解之后,它就成为了Java平台中非常重要的一部分.开发过程中,我们也时常在应用代码中会看到诸如@Override,@Deprecated这样的注解.这篇文章中,我将向大家讲述到底什么是注解,为什么要引入注解,注解是如何工作的,如何编写自定义的注解(通过例子),什么情况下可以使用注解以及最新注解和ADF(应用开发框架).这会花点儿时间,所以为自己准备一杯咖啡,让我们来进入注解的世界吧. 什么是注解? 用一个词就可以描述注解,那就是元数据,即

java 枚举(enum)学习

之前没有用过枚举,不懂.今天找了些资料学习了,现在总结如下:(希望高手看到后批评指教) 枚举的作用: 1.限定某一类型的取值范围. 2.不再写public static final...(如果取值范围太广,就太麻烦了),但最终enum还是要转化成class类型,还是会加public static final... 一段代码说明为什么java要有enum类型: package good.good.study; public class EnumStudy2 { public static void