Java复习——枚举与注解

枚举

枚举就是让某些变量的取值只能是若干固定值中的一个,否则编译器就会报错,枚举可以让编译器在编译阶段就控制程序的值,这一点是普通变量无法实现的。枚举是作为一种特殊的类存在的,使用的是enum关键字修饰

枚举常量

枚举常量默认都是使用static final修饰的,所以语法建议使用大写,一个枚举类在第一次被实例化的时候,这些常量就会被创建,这些常量都是枚举类子类的对象

public enum WeekDay{
        //每一个枚举的元素(枚举常量)就是一个枚举类子类的对象,是使用static final修饰的
        //第一次实例化枚举类会初始化这些对象
        SUN ,MON;

    }

在没有枚举类型之前,要实现类似的功能,需要这样设计:

//使用普通类来模拟Enum
public abstract class MyEnum {

    //构造私有
    private MyEnum(){}

    //元素是子类的实例(使用匿名内部类)
    public static final MyEnum SUN=new MyEnum(){};

    public static final MyEnum MON=new MyEnum(){};
}

构造函数私有化

构造函数私有化是枚举类的一各特点,我们可以尝试在枚举类中添加public修饰的构造函数,结果会报错。而默认的枚举常量在创建的时候调用的是无参的构造函数,可以在定义这些常量的时候给一个值,就会调用有参的构造了:

    //枚举是作为一种特殊的类存在的
    public enum WeekDay{
        //每一个枚举的元素(枚举常量)就是一个枚举类子类的对象,是使用static final修饰的
        //所以每次调用枚举类都会初始化这些对象
        SUN ,MON(100);
        //枚举的构造是私有的
        //枚举常量默认调用的是无参构造
        private WeekDay(){
            System.out.println("无参构造");
        }

        //可以通过给枚举常量添加参数列表的方式来调用有参构造
        private WeekDay(int i){
            System.out.println("有参构造");
        }

    }

这里的SUN和MON分别调用无参和有一个参数的构造器

枚举类中定义属性和方法

枚举类中成分(方法,属性)需要放在枚举常量的后面,注意枚举常量要以;结尾。除了构造函数必须设置为私有的之外,其他的方法没有要求,甚至可以为abstract抽象类型,不过,枚举常量就要实现这些抽象的方法了

//枚举是作为一种特殊的类存在的
    public enum WeekDay{
        //每一个枚举的元素(枚举常量)就是一个枚举类子类的对象,是使用static final修饰的
        //所以每次调用枚举类都会初始化这些对象
        SUN {
            @Override
            public void getTime() {
                //在这里可以看到枚举常量是作为枚举类子类的对象存在的,
                //需要实现枚举类的抽象方法
            }
        },MON(100) {
            @Override
            public void getTime() {
                System.out.println(time);
            }
        };

        //枚举类中成分(方法,属性)需要放在枚举常量的后面,注意枚举常量要以;结尾
        //枚举的构造是私有的
        //枚举常量默认调用的是无参构造
        private WeekDay(){
            System.out.println("无参构造");
        }

        //可以通过给枚举常量添加参数列表的方式来调用有参构造
        private WeekDay(int i){
            System.out.println("有参构造");
            this.time=i;
        }

        public int time;

        public abstract void getTime();

    }

调用枚举类和枚举常量的方法

枚举类本身提供了一些方法,例如valueOf和values方法

valueOf():返回枚举类中是否有指定名称的枚举常量,返回值为true/false

values():返回包含枚举类中常量的数组

枚举常量的方法例如:

name():返回枚举常量的名字,好像没什么用

ordinal():返回该枚举常量在枚举类中的位置,默认是0开始

public class EnumTest {

    public static void main(String[] args) {

        WeekDay weekDay=WeekDay.MON;
        //enum对象实现了toString方法
        System.out.println(weekDay);
        //name方法返回枚举元素的名字
        System.out.println(weekDay.name());
        //ordinal返回枚举元素的位置,从0开始
        System.out.println(weekDay.ordinal());
        //enum类的valueOf方法将字符串转化为枚举类中的元素,这个字符串应该存在与enum中的元素一致
        System.out.println(WeekDay.valueOf("SUN"));
        //values()方法返回枚举类中所有元素的数组
        System.out.println(WeekDay.values().length);

        weekDay.getTime();

    }

    //枚举是作为一种特殊的类存在的
    public enum WeekDay{
        //每一个枚举的元素(枚举常量)就是一个枚举类子类的对象,是使用static final修饰的
        //所以每次调用枚举类都会初始化这些对象
        SUN {
            @Override
            public void getTime() {
                //在这里可以看到枚举常量是作为枚举类子类的对象存在的,
                //需要实现枚举类的抽象方法
            }
        },MON(100) {
            @Override
            public void getTime() {
                System.out.println(time);
            }
        };

        //枚举类中成分(方法,属性)需要放在枚举常量的后面,注意枚举常量要以;结尾
        //枚举的构造是私有的
        //枚举常量默认调用的是无参构造
        private WeekDay(){
            System.out.println("无参构造");
        }

        //可以通过给枚举常量添加参数列表的方式来调用有参构造
        private WeekDay(int i){
            System.out.println("有参构造");
            this.time=i;
        }

        public int time;

        public abstract void getTime();

    }

}

这里我将枚举类作为内部类,其实没有什么特殊的用意,就是少写一个类文件,这里再复习一下内部类的知识:内部类可以是任意的访问修饰权限

注解

注解就相当于一种标记,有这种标记就做相应的事情,没有就不做。枚举可以加在包,类,属性,方法,方法的参数以及局部变量上。在Java中真的就是万事万物皆对象,注解和上面的枚举都是作为一种特殊的类存在的。与注解相关的操作都在 java.lang.annotation 这个包下,我们在框架中使用注解开发也很常见,下面我们就来了解一下注解

lang包中自带的三个注解

@Override

这个注解应该说是较为常见的,我们通常在重写父类方法的时候添加这个注解用于效验是否是在重写,而不是因为参数列表的不同而变成重载,或者是变成一个同名的新方法,是起一个效验的作用,但并不说重写方法一定要加这个注解

@SuppressWarnings("deprecation")

这个注解可以消除编译器的警告,我们在写程序的时候可能会使用过时的方法,这时编译的时候会有警告,就可以使用这个注解消除警告了,括号中没有指定哪个属性默认的是就是使用value

@Deprecated

想知道如何将一个方法变成过时的吗?使用@Deprecated这个注解在方法上即可,这样调用我们的这个方法的时候就会有过时的警告

自定义注解

自定义注解就是使用@interface来修饰一个类,这个类就作为注解类存在:

/**
 * 注解也是一种特殊的类存在
 *
 */

public @interface MyAnnotation {}

我们接下来可是将这个注解加在一个类上,并通过反射来获得注解的一些信息

@MyAnnotation(value="abc",array={"3"},array2=6)
public class AnnotationTest {

    /**
     * 消除编译器警告的注解
     * @param args
     */

    public static void main(String[] args) {

       //通过反射可以检查注解Class类的isAnnotationPresent方法检查某个类是否存在注解
       if(AnnotationTest.class.isAnnotationPresent(MyAnnotation.class)){
           //得到注解
           MyAnnotation myAnnotation = AnnotationTest.class.getAnnotation(MyAnnotation.class);
           //想要使用注解,就需要设置注解存活时间
           System.out.println(myAnnotation);
       }

    }

}

这时你会发现什么都没输出,不要怀疑这段反射代码是不是写错了,真正的原因在我们在自定义注解类的时候没有设置它的存活期限,默认只存在与source源码阶段,当变成class文件,或者是之后的运行时就已将失效了,所以不起作用

下面就为 MyAnnotation 这个自定义注解设置存活期限,使用的是 @Retention 

其value值可以是

RetentionPolicy.Source:编译阶段就会丢弃的注释

RetentionPolicy.CLASS:编译器将把注释记录在类文件中,但在运行时 VM 不需要保留注释。

RetentionPolicy.RUNTIME:编译器将把注释记录在类文件中,在运行时 VM 将保留注释,因此可以反射性地读取。

我们还可以为自定义的注解指定可以添加的位置,默认是包,类,属性,方法,变量等都可添加,指定位置使用的是@Target ,其value值可以是一个数组

ElementType.TYPE:可以添加到类、接口(包括注释类型)或枚举声明上

ElementType.FIELD:可以添加到字段声明(包括枚举常量)

ElementType.METHOD:添加到方法上

ElementType.PACKAGE:添加到包上

等等

这两个注解我们称之为元注解

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

/**
 * 注解也是一种特殊的类存在
 * @author LZ
 *
 */
//设置注解类存活时间
@Retention(RetentionPolicy.RUNTIME)
//还可以限制注解的存在的位置(默认可以在任何地方比如类上,方法上,属性上,参数上等等)
//这里设置的MyAnnotation注解可以在类,方法上.{...}这是一个数组
@Target({ElementType.TYPE,ElementType.METHOD})
public @interface MyAnnotation {}

给注解添加属性

我们在使用 @SuppressWarnings("deprecation") 这个注解的时候可以使用括号来添加值,如何让我们的自定义注解也可以添加属性呢?

就可以在我们自定义的这个注解类中使用 : 类型 属性名() [default] 默认值 的语法来添加属性

和普通类不同的一点在于属性后面竟然是一个括号,搞的像一个方法一样,但实际上我们通过反射得到注解的属性的时候,就是将这些属性类似于方法在调用。注解的属性类型可以是基本类型,字符串,数组类型,枚举,注解,Class类型:

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

/**
 * 注解也是一种特殊的类存在
 *
 */
//设置注解类存活时间
@Retention(RetentionPolicy.RUNTIME)
//还可以限制注解的存在的位置(默认可以在任何地方比如类上,方法上,属性上,参数上等等)
//这里设置的MyAnnotation注解可以在类,方法上.{...}这是一个数组
@Target({ElementType.TYPE,ElementType.METHOD})
public @interface MyAnnotation {

    //为注解添加属性
    String value();

    //添加默认值
    int num() default 0;

    //数组类型
    String[] array();

    int[] array2() default{3,2,1};

    //枚举
    WeekDay day() default WeekDay.SUN;

    //注解类型
    MyAnnotation2 myAnnotation2() default @MyAnnotation2(value="666");

    //Class类型
    Class clazz() default Integer.class;

}

可以在添加了我们这个自定义注解的类上来设置注解属性值,在方法中使用反射来获得这些值:

@MyAnnotation(value="abc",array={"3"},array2=6)
public class AnnotationTest {

    public static void main(String[] args) {
       System.runFinalizersOnExit(true);

       //通过反射可以检查注解Class类的isAnnotationPresent方法检查某个类是否存在注解
       if(AnnotationTest.class.isAnnotationPresent(MyAnnotation.class)){
           //得到注解
           MyAnnotation myAnnotation = AnnotationTest.class.getAnnotation(MyAnnotation.class);
           //想要使用注解,就需要设置注解存活时间
           System.out.println(myAnnotation);
           System.out.println(myAnnotation.value());
           System.out.println(myAnnotation.num());
           System.err.println(myAnnotation.array().length);
           System.out.println(myAnnotation.array2().length);
           System.out.println(myAnnotation.day());
           System.out.println(myAnnotation.myAnnotation2());
           System.out.println(myAnnotation.clazz());
       }

    }
}
时间: 2024-12-22 22:06:17

Java复习——枚举与注解的相关文章

Java基础——枚举与注解

枚举类: 1.自定义枚举类 1.提供类的属性,声明为private final 2.声明为final的属性,在构造器中初始化,私有化构造器, 保证不能在类的外部创建其对象 3.通过公共的方法调用属性 4.创建枚举类的对象:将类的对象声明为public static final 2.关键字 enum定义枚举类 1.enum中的常用方法 (1)values();//以数组的形式返回整个枚举类型的所有的对象 Season[] seasons = Season.values();//返回的是一个数组 (

java之枚举和注解

JDK1.5新增的enum关键字用于定义枚举类. 枚举类和普通类的区别: 使用enum定义的枚举类默认继承了java.lang.Enum类: 枚举类的构造器只能使用private修饰符: 枚举类的所有实例必须在枚举类中显示列出(分隔:结尾).列出的实例系统会自动添加public static final修饰: 所有的枚举类都提供了一个values方法,该方法可以很方便地遍历所有的枚举值: JDK1.5中可以在switch表达式中使用枚举类的对象作为表达式,case子句可以直接使用枚举值的名字,无

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

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

编写高质量代码:改善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

[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语言基础--枚举,注解,正则和反射

注解 @Retention(RetentionPolicy.RUNTIME)//注解保留策略 public @interface MyAnno { String str(); int val(); } @MyAnno(str = "测试注解",val = 100) public void test() { } 所有注解都只包含方法声明,不能提供方法体.应用注解时,需要为注解成员提供值 注解的保留策略,java指定三种保留策略,它们被封装到java.lang.annotation.Ret

关于Java中枚举Enum的深入剖析

在编程语言中我们,都会接触到枚举类型,通常我们进行有穷的列举来实现一些限定.Java也不例外.Java中的枚举类型为Enum,本文将对枚举进行一些比较深入的剖析. 什么是Enum Enum是自Java 5 引入的特性,用来方便Java开发者实现枚举应用.一个简单的Enum使用如下. // ColorEnum.javapublic enum ColorEmun { RED, GREEN, YELLOW} public void setColorEnum(ColorEmun colorEnum) {

Java 核心技术点之注解

转自:http://www.open-open.com/lib/view/open1473649808122.html 什么是注解 我们都知道在Java代码中使用注释是为了向以后阅读这份代码的人解释说明一些事情,注解是注释的升级版,它可以向编译器.虚拟机等解释说明一 些事情.比如我们非常熟悉的@Override就是一种元注解,它的作用是告诉编译器它所注解的方法是重写父类的方法,这样编译器就会去检查父类是否存在 这个方法,以及这个方法的签名与父类是否相同. 也就是说,注解是用来描述Java代码的,