一、枚举
一、概述
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:
- 子类会继承父类使用的注解中被@Inherited修饰的注解
- 接口继承关系中,子接口不会继承父接口中的任何注解,不管父接口中使用的注解有没有被@Inherited修饰
- 类实现接口时不会继承任何接口中定义的注解
//注解是否包含在文档中
@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



