目录
2.如何自定义注解(参照@SuppressWarnings定义)
一、枚举类
枚举类的理解:类的对象只有有限个,确定的。我们称此类为枚举类。
1.如何定义枚举类
定义枚举类两种方式:
方式一:jdk5.0之前,自定义枚举类
方式二:jdk5.0,可以使用enum关键字定义枚举类
方式一:自定义枚举类
public class SeasonTest1 {
public static void main(String[] args) {
Season1 spring = Season1.SPRING;
System.out.println(spring);
}
}
/**
* 枚举类的属性
* 1.枚举类对象的属性不应允许被改动,所以应该使用private final修饰
* 2.枚举类的使用private final修饰是属性应该在构造器中为其赋值
* 3.若枚举类显式的定义了带参的构造器,则在列出枚举值时也必须对应的传入参数
*/
//自定义枚举类
class Season1{
//声明对象的属性:private final修饰
private final String SEASONNAME;//季节的名称
private final String SEASONDESC;//季节的描述
//私有化类的构造器,保证不能在类的外部创建其对象
private Season1(String SEASONNAME, String SEASONDESC) {
this.SEASONNAME = SEASONNAME;
this.SEASONDESC = SEASONDESC;
}
//在类的内部创建枚举类的实例。声明为public static final
public static final Season1 SPRING = new Season1("春天","春暖花开");
public static final Season1 SUMMER = new Season1("夏天","夏日炎炎");
public static final Season1 AUTUMN = new Season1("秋天","秋高气爽");
public static final Season1 WINTER = new Season1("冬天","白雪皑皑");
@Override
public String toString() {
return "Season1{" +
"SEASONNAME='" + SEASONNAME + '\'' +
", SEASONDESC='" + SEASONDESC + '\'' +
'}';
}
}
方式二:enum关键字定义枚举类
public class SeasonTest2 {
public static void main(String[] args) {
Season2 spring = Season2.SPRING;
System.out.println(spring);//SPRING
}
}
//使用enum定义枚举类
enum Season2{
//提供当前枚举类的对象,多个对象之间用","隔开,末尾对象";"结束
//系统会自动添加public static final
//必须在枚举类的第一行声明枚举类对象
//enum定义的枚举类默认继承了java.lang.Enum类,因此不能再继承其他类
SPRING("春天","春暖花开"),
SUMMER("夏天","夏日炎炎"),
AUTUMN("秋天","秋高气爽"),
WINTER("冬天","白雪皑皑");
//声明对象的属性:private final修饰
private final String SEASONNAME;//季节的名称
private final String SEASONDESC;//季节的描述
//私有化类的构造器,保证不能在类的外部创建其对象
private Season2(String SEASONNAME, String SEASONDESC) {
this.SEASONNAME = SEASONNAME;
this.SEASONDESC = SEASONDESC;
}
}
2.枚举类的使用
1.当需要定义一组常量时,强烈建议使用枚举类
2.如果枚举类中只有一个对象,则可以作为单例模式的实现方式。
3.Enum类
使用enum关键字定义枚举类默认继承于java.lang.Enum类
Enum类中的常用方法:
values()方法:返回枚举类型的对象数组。该方法可以很方便地遍历所有的枚举值。
valueOf(String str):可以把一个字符串转为对应的枚举类对象。
要求字符串必须是枚举类对象的“名字”。如不是,会有运行时异常:IllegalArgumentException。
toString():返回当前枚举类对象常量的名称
4.使用enum关键字定义的枚举类实现接口的情况
情况一:实现接口,在enum类中实现抽象方法
情况二:让枚举类的对象分别实现接口中的抽象方法
public class SeasonTest2 {
public static void main(String[] args) {
Season2 spring = Season2.SPRING;
System.out.println(spring);//SPRING
System.out.println(Season2.class.getSuperclass());//class java.lang.Enum //默认继承对象是java.lang.Enum
spring.show();//情况一:这是一个季节//情况二:这是一个春天
//==========
Season2[] values = Season2.values();
for(int i = 0;i < values.length;i++){
System.out.println(values[i]);
values[i].show();
}
//==========
Season2 winter = Season2.valueOf("WINTER");
System.out.println(winter);
winter.show();
}
}
interface Info{
void show();
}
//使用enum定义枚举类
enum Season2 implements Info{
//提供当前枚举类的对象,多个对象之间用","隔开,末尾对象";"结束
SPRING("春天","春暖花开"){
//情况二:
@Override
public void show() {
System.out.println("这是一个春天");
}
},
SUMMER("夏天","夏日炎炎"){
@Override
public void show() {
System.out.println("这是一个夏天");
}
},
AUTUMN("秋天","秋高气爽"){
@Override
public void show() {
System.out.println("这是一个秋天");
}
},
WINTER("冬天","白雪皑皑"){
@Override
public void show() {
System.out.println("这是一个冬天");
}
};
//声明对象的属性:private final修饰
private final String SEASONNAME;//季节的名称
private final String SEASONDESC;//季节的描述
//私有化类的构造器,保证不能在类的外部创建其对象
private Season2(String SEASONNAME, String SEASONDESC) {
this.SEASONNAME = SEASONNAME;
this.SEASONDESC = SEASONDESC;
}
//情况一:
@Override
public void show() {
System.out.println("这是一个季节");
}
}
二、注解
注解(Annotation)概述:
① jdk 5.0 新增的功能
② Annotation 其实就是代码里的特殊标记, 这些标记可以在编译, 类加载, 运行时被读取, 并执行相应的处理。通过使用 Annotation,程序员可以在不改变原有逻辑的情况下, 在源文件中嵌入一些补充信息。
③在JavaSE中,注解的使用目的比较简单,例如标记过时的功能,忽略警告等。
注解是一种趋势。
1.注解的使用
例1:生成文档相关的注解
@author 标明开发该类模块的作者,多个作者之间使用,分割
@version 标明该类模块的版本
@see 参考转向,也就是相关主题
@since 从哪个版本开始增加的
@param 对方法中某参数的说明,如果没有参数就不能写
@return 对方法返回值的说明,如果方法的返回值类型是void就不能写
@exception 对方法可能抛出的异常进行说明,如果方法没有用throws显式抛出的异常就不能写
例2:在编译时进行格式检查(JDK内置的三个注解)
@Override: 限定重写父类方法, 该注解只能用于方法
@Deprecated: 用于表示所修饰的元素(类, 方法等)已过时。通常是因为所修饰的结构危险或存在更好的选择
@SuppressWarnings: 抑制编译器警告
例3:跟踪代码依赖性,实现替代配置文件功能
//注解替换配置文件
@Transactional(propagation=Propagation.REQUIRES_NEW, isolation=Isolation.READ_COMMITTED,readOnly=false,timeout==3)
public void buyBook(String username, String isbn){
int price = bookShopDao.findBookPriceByIsbn(isbn);
}
2.如何自定义注解(参照@SuppressWarnings定义)
①注解声明为:@interface
② 内部定义成员,通常使用value表示
③ 可以指定成员的默认值,使用default定义
④ 如果自定义注解没有成员,表明是一个标识作用。
⑤自定义注解自动继承了java.lang.annotation.Annotation接口
注:如果注解有成员,在使用注解时,需要指明成员的值。
自定义注解必须配上注解的信息处理流程(使用反射)才有意义。
自定义注解通常都会指明两个元注解:Retention、Target
3.JDK提供的4种元注解
元注解:对现有的注解进行解释说明的注解
Retention:指定所修饰的 Annotation 的生命周期:SOURCE\CLASS(默认行为)\RUNTIME
只有声明为RUNTIME生命周期的注解,才能通过反射获取。
Target:用于指定被修饰的 Annotation 能用于修饰哪些程序元素
Documented:表示所修饰的注解在被javadoc解析时,保留下来。
Inherited:被它修饰的 Annotation 将具有继承性。
4.JDK8中注解的新特性:
①可重复注解、②类型注解
可重复注解:注解在定义时要声明@Repeatable,成员为注解名.class,为了声明可重复注解的类型
/**
* The annotation type {@code java.lang.annotation.Repeatable} is
* used to indicate that the annotation type whose declaration it
* (meta-)annotates is <em>repeatable</em>. The value of
* {@code @Repeatable} indicates the <em>containing annotation
* type</em> for the repeatable annotation type.
*
* @since 1.8
* @jls 9.6 Annotation Types
* @jls 9.7 Annotations
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Repeatable {
/**
* Indicates the <em>containing annotation type</em> for the
* repeatable annotation type.
* @return the containing annotation type
*/
Class<? extends Annotation> value();
}
类型注解:
ElementType.TYPE_PARAMETER 表示该注解能写在类型变量的声明语句中(如:泛型声明)。 ElementType.TYPE_USE 表示该注解能写在使用类型的任何语句中。
/**
* Type parameter declaration
*
* @since 1.8
*/
TYPE_PARAMETER,
/**
* Use of a type
*
* @since 1.8
*/
TYPE_USE
import java.lang.annotation.*;
import java.util.ArrayList;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.ElementType.TYPE_USE;
public class AnnotationTest {
public static void main(String[] args) {
@SuppressWarnings("unused")
int num = 10;
@SuppressWarnings({ "unused", "rawtypes" })
ArrayList list = new ArrayList();
Class clazz = Student.class;
Annotation[] annotations = clazz.getAnnotations();
for(int i = 0;i < annotations.length;i++){
System.out.println(annotations[i]);
}
//类型注解
int num1 = (@MyAnnotation int) 10L;
ArrayList<@MyAnnotation String> list1 = new ArrayList<>();
}
}
//jdk8之前写法
//@MyAnnotations({@MyAnnotation(value="你好"),@MyAnnotation(value="hi,你好")})
//jdk8可重复写注解
@MyAnnotation(value="你好")
@MyAnnotation(value="hi,你好")
class Student{
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public void walk(){
System.out.println("学生走路");
}
}
//自定义注解
@Inherited
@Repeatable(MyAnnotations.class)//可重复性:MyAnnotations生命周期必须和MyAnnotation相同
@Retention(RetentionPolicy.RUNTIME)
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE,TYPE_PARAMETER,TYPE_USE})//TYPE_PARAMETER,TYPE_USE类型注解
@interface MyAnnotation{
String value() default "hello";
}
//自定义注解
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@interface MyAnnotations{
MyAnnotation[] value();
}
5.通过反射获取注解信息
Pstudy
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Pstudy {
public int id();
}
PstudyTracker
public class PstudyTracker {
public static String initPstudy(Class<?> cl) {
Field[] fields = cl.getDeclaredFields();
for (Field field:fields) {
Pstudy annotation = field.getAnnotation(Pstudy.class);
Class<?> type = field.getType();
Object o = null;
try {
o = field.get(cl);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
System.out.println( o + "---"+ type + "-->annotation.id=" + annotation.id());
}
return "";
}
}
PtnNo
import lombok.Data;
@Data
public class PtnNo {
@Pstudy(id=1)
public static boolean p1=false;
@Pstudy(id=2)
public static String p2="P2";
}
Test
public class Test {
public static void main(String[] args) {
PstudyTracker.initPstudy(PtnNo.class);
}
}
输出:
false---boolean-->annotation.id=1
P2---class java.lang.String-->annotation.id=2