枚举

枚举就是让某些变量的取值只能是若干固定值中的一个,否则编译器就会报错,枚举可以让编译器在编译阶段就控制程序的值,这一点是普通变量无法实现的。枚举是作为一种特殊的类存在的,使用的是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{
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{
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); 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());
} }
}

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

  1. [改善Java代码]枚举和注解结合使用威力更大

    注解的写法和接口很类似,都采用了关键字interface,而且都不能有实现代码,常量定义默认都是pulbic static final类型的. 他们的主要不同点是:注解在interface前加上@字符 ...

  2. 跟着刚哥梳理java知识点——枚举和注解(十四)

    enum Season{ SPRING("spring","春暖花开"), SUMMER("summer","夏日炎炎" ...

  3. Java SE 枚举,注解,增强for循环

    Java SE 进阶 1.Enum 枚举对象名通常使用全部大写,常量的命名规范 构造器私有化 本类内部创建一组对象 对外暴露对象(通过为对象添加 public final static 修饰符) 可以 ...

  4. Effective java -- 5 枚举和注解

    第三十条:用enum代替int常量enum的简单用法. enum Operation { PLUS("+") { double apply(double x, double y) ...

  5. java之枚举和注解

    JDK1.5新增的enum关键字用于定义枚举类. 枚举类和普通类的区别: 使用enum定义的枚举类默认继承了java.lang.Enum类: 枚举类的构造器只能使用private修饰符: 枚举类的所有 ...

  6. 《Effective Java》学习笔记 —— 枚举、注解与方法

    Java的枚举.注解与方法... 第30条 用枚举代替int常量 第31条 用实例域代替序数 可以考虑定义一个final int 代替枚举中的 ordinal() 方法. 第32条 用EnumSet代 ...

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

    建议88:用枚举实现工厂方法模式更简洁 工厂方法模式(Factory Method Pattern)是" 创建对象的接口,让子类决定实例化哪一个类,并使一个类的实例化延迟到其它子类" ...

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

    声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...

  9. Java笔记---枚举类和注解

    Java笔记---枚举类和注解 一.枚举类 自定义枚举类 方式一:JDK5.0之前自定义枚举类 class Seasons { //1. 声明Seasons对象的属性 private final St ...

随机推荐

  1. Spring报错: org.springframework.beans.factory.support.BeanDefinitionValidationException: Couldn't find an init method named 'init' on bean with name 'car'(待解答)

    在Spring工程里,有一个Car类的bean,Main.java主程序,MyBeanPostProcessor.java是Bean后置处理器. 文件目录结构如下: Car.java package ...

  2. node 适合 5000 人同时在线左右的 游戏开发

    游戏开发性能的一些讨论 上面这个问题是在游戏上线前的一个性能顾虑 (但他确实是node多进程通讯间的一个比较麻烦的问题,数据一大就会出现性能上的瓶颈) 我们项目(手游)已经上线了,单服最高同时在线4. ...

  3. SQL 动态PIVOT查询

    DECLARE @sql_str VARCHAR(8000)DECLARE @sql_col VARCHAR(8000) SELECT @sql_col = ISNULL(@sql_col + ',' ...

  4. TypeError: pivot_table() got an unexpected keyword argument 'rows'

    利用Python进行数据分析>第二章,处理MovieLens 1M数据集,有句代码总是报错: mean_rating = data.pivot_table('rating', rows='tit ...

  5. [置顶] kubernetes1.8发布跟踪

    一.Kubernetes发布历史回顾 1.        Kubernetes 1.0 - 2015年7月发布 2.        Kubernetes 1.1 - 2015年11月发布 3.     ...

  6. iOS-Core Data 详解

    使用Core Data 框架 Core Data框架本质就是一个ORM(对象关系映射(英语:Object Relational Mapping,简称ORM,或O/RM,或O/R mapping),是一 ...

  7. 通过反编译让SpecFlow支持多层属性值的验证

    需求:在使用SpecFlow时,我希望能对目标对象所关联的对象属性进行验证,但SpecFlow(Version 1.9.0)无法实现.如图中红框,可以对专户所属的金融机构的名称进行验证. 反编译步骤 ...

  8. html(对php也有效)页面自动刷新和跳转(简单版本)

    <html>    <head><title>html页面自动刷新和跳转</title><meta http-equiv="Refres ...

  9. HDU4035 Maze(师傅逃亡系列•二)(循环型 经典的数学期望)

    When wake up, lxhgww find himself in a huge maze. The maze consisted by N rooms and tunnels connecti ...

  10. 多文件的Makefile

    Linux下编写一般采用gcc编译工具,但gcc无法满足大量的文件同时编译,这是就用到Makefile,首先先介绍一下gcc GCC编译的四个步骤 1.预处理,生成预编译文件(.文件): Gcc –E ...