枚举

枚举就是让某些变量的取值只能是若干固定值中的一个,否则编译器就会报错,枚举可以让编译器在编译阶段就控制程序的值,这一点是普通变量无法实现的。枚举是作为一种特殊的类存在的,使用的是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. 剑指offer--42.孩子们的游戏(圆圈中最后剩下的数)

    约瑟夫环,用链表,队列,总之模拟过程 ----------------------------------------------------------------- 时间限制:1秒 空间限制:32 ...

  2. 20165202 2017-2018-2 《Java程序设计》第1周学习总结

    20165202 2017-2018-2 <Java程序设计>第1周学习总结 教材学习内容总结 Ubuntu环境下安装JDK 简单Java程序编写 反编译器javap.exe Git安装及 ...

  3. 数据库连接错误:CannotAcquireResourceException: A ResourcePool could not acquire a resource from its primary factory or source.

    学习Spring整合Hibernate的知识,新建一个工程,代码结构如下: 按如下步骤整合: 代码如下: hibernate.cfg.xml: <?xml version="1.0&q ...

  4. python爬虫入门(1)-urllib模块

    作用:用于读取来自网上(服务器上)的数据   基本方法:urllib.request.urlopen(url,data=None,[]timeout]*,cafile=None,cadefault=F ...

  5. 【剑指offer】06从尾到头打印链表,C++实现

    本文是原创文章,转载请注明出处! 0.前言 # 本文为牛客网<剑指offer>刷题笔记 1.题目 # 输入一个链表,从尾到头打印链表每个节点的值 2.思路 # 不改变链表结构的情况下,首先 ...

  6. Maven部署Jetty服务器pom.xml

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/20 ...

  7. WebForm、MVC图片加载失败处理

    还是那个该死的WebFrom项目,部分功能替换为MVC后感觉好多了,但是WebForm.MVC都有图片加载失败时显示提示图片的需求,并且统一在js中处理.问题来了,js中图片路径怎么处理呢?现场有可能 ...

  8. C++面向对象的编程思想机器人

    C++的面向对象的编程思想如下,一般情况为一个类中包含了这个对象的所有属性与函数,直接调用这个对象就可以对这个对象执行它可以使用的任何操作. #include <iostream> cla ...

  9. BZOJ3930 [CQOI2015]选数【莫比乌斯反演】

    Description 我们知道,从区间[L,H](L和H为整数)中选取N个整数,总共有(H-L+1)^N种方案.小z很好奇这样选出的数的最大公约数的规律,他决定对每种方案选出的N个整数都求一次最大公 ...

  10. 进阶的Redis之数据持久化RDB与AOF

    大家都知道,Redis之所以性能好,读写快,是因为Redis是一个内存数据库,它的操作都几乎基于内存.但是内存型数据库有一个很大的弊端,就是当数据库进程崩溃或系统重启的时候,如果内存数据不保存的话,里 ...