7.1 枚举类
枚举类的对象只有有限个确定数值,如星期、性别、季节等。构造器必须使用private
,所有实例必须在枚举类中显式列出,系统将自动为其添加public static final修饰,且必须在枚举类的第一行声明枚举类对象。
switch表达式中可使用enmu定义的枚举类对象作为表达式, case 子句可以直接使用枚举值的名字。
public enum SeasonEnum {
SPRING("春天","春风又绿江南岸"),
SUMMER("夏天","映日荷花别样红"),
AUTUMN("秋天","秋水共长天一色"),
WINTER("冬天","窗含西岭千秋雪"); // 注意这里的符号
private final String seasonName;
private final String seasonDesc;
private SeasonEnum(String seasonName, String seasonDesc) {
this.seasonName = seasonName;
this.seasonDesc = seasonDesc;
}
public String getSeasonName() {
return seasonName;
}
public String getSeasonDesc() {
return seasonDesc;
}
}
// 例子
SeasonEnum summer = SeasonEnum.SUMMER;
SeasonEnum[] values = SeasonEnum.values(); // 返回枚举类型的对象数组
7.2 注解
注解(Annotation)是代码里的特殊标记,可在编译、 类加载、 运行时被读取, 并根据注解类型执行相应处理。通过使用注解,程序员可以在不改变原有逻辑的情况下, 在源文件中嵌入一些补充信息,代码分析工具、开发工具和部署工具可以通过这些补充信息进行验证或部署。
7.2.1 注解的使用情景
注解通常用于标记过时功能,忽略警告,配置应用程序(如XML配置)等。未来的开发模式都是基于注解的,一定程度上可以说:框架 = 注解 + 反射 + 设计模式。
示例一:生成文档相关的注解
@author
@version
@see // 相关主题
@since // 从哪个版本开始增加的
@Description // 功能描述
@date
// 仅用于方法的标记,@param和@exception可以并列多个
@param // 对方法中某参数的说明
@return // 对方法返回值的说明
@exception // 对方法可能抛出的异常进行说明
@param 形参名 形参类型 形参说明
@return 返回值类型 返回值说明
@exception 异常类型 异常说明
package com.annotation.javadoc;
/**
* @author shkstart
* @version 1.0
* @see Math.java
*/
public class JavadocTest {
/**
* 程序的主方法,程序的入口
* @param args String[] 命令行参数
*/
public static void main(String[] args) {
}
/**
* 求圆面积的方法
* @param radius double 半径值
* @return double 圆的面积
*/
public static double getArea(double radius){
return Math.PI * radius * radius;
}
}
示例二:在编译时进行格式检查(JDK内置的三个基本注解)
@Override // (凌驾、覆盖)标明是重写方法,不写也可能为重写方法
@Deprecated // (过时)表明不推荐使用
@SuppressWarnings // 抑制编译器警告
package com.annotation.javadoc;
public class AnnotationTest{
public static void main(String[] args) {
@SuppressWarnings("unused")
int a = 10;
}
@Deprecated
public void print(){
System.out.println("过时的方法");
}
@Override
public String toString() {
return "重写的toString方法()";
}
}
示例三:跟踪代码依赖性,实现替代配置文件功能
在Java Web中会用到Servlet接口,通过注解则无需在web.xml中进行Servlet部署
7.2.2 自定义注解
自定义注解使用 @interface
关键字,其自动继承java.lang.annotation.Annotation
接口,注解的成员变量以无参数方法声明,我们称为配置参数。类型只能是八种基本数据类型、String、Class、Enum、Annotation。
可以在定义注解的成员变量时为其指定初始值,指定成员变量的初始值使用 default
,如果只有一个参数成员,建议使用参数名value
。如果定义的注解含有配置参数,那么使用时必须指定参数值,除非它有默认值。格式是“参数名 = 参数值”,如果只有一个参数成员,且名称为value,可以省略“value=” 。
没有成员定义的注解称为标记; 包含成员变量的注解称为元数据 Annotation。
// 例子1 成员变量无参
public @interface MyAnnotation{
String value(); // 成员变量以无参方法声明,定义名字和类型
}
@MyAnnotation( value = "hello") // 注解无默认配置参数,必须指定参数
@MyAnnotation("hello") // 仅一个变量且名称为value,省略变量名
// 例子2 成员变量有参数
public @interface MyAnnotation{
String value() default "hello"; // 成员变量以无参方法声明,定义名字和类型并指定初始值
}
@MyAnnotation( value = "hi")
@MyAnnotation
// 例子三 无成员变量作为特殊标识
public @interface MyAnnotation{
}
@MyAnnotation
7.2.3 JDK中的元注解
元注解是对现有的注解进行解释说明的注解。
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override{
}
- Retention(留存):指定注解的生命周期,其包含一个 RetentionPolicy 类型的成员变量:
- RetentionPolicy.SOURCE:在源文件中有效,在class文件中不再加载
- RetentionPolicy.CLASS:在class文件中有效,不会将此注解加载到内存。 这是默认值
- RetentionPolicy.RUNTIME:在运行时有效,当运行程序时, JVM会保留注释。程序可以通过反射获取该注释。
Target(目标):指定注解能用于修饰哪些程序元素。可用
,
进行多种修饰:CONSTRUCTOR:用于描述构造器
PACKAGE:用于描述包
FIELD:用于描述域
PARAMETER:用于描述参数
LOCAL_VARIABLE:用于描述局部变量
TYPE:用于描述类、接口(包括注解类型)或enum声明
METHOD:用于描述方法
Documented:指定注解类将被javadoc工具提取成文档。默认情况下,javadoc是不包括注解的。 定义为Documented的注解必须设置Retention值为RUNTIME。
Inherited:修饰的注解将具有继承性。如果某个类使用了其修饰的 Annotation, 则其子类将自动具有该注解。
7.2.4 JDK8中注解的新特性
可重复注解: ```java // JDK8前声明重复注解 public @interface MyAnnotations{ MyAnnotation[] value(); } @MyAnnotations({@MyAnnotation(value=”hi”),@MyAnnotation(value=”hello”)})
// JDK8写法
@Repeatable(MyAnnotations.class) // 此时两种注解声明周期应当相同,修饰类型也应当相同,即Retention、Target等元注解必须相同
public @interface MyAnnotation{
String value();
}
public @interface MyAnnotations{
MyAnnotation[] value();
}
2. 用于类型的注解:在Java 8之前,注解只能在声明的地方所使用,Java8开始,注解可以应用在任何地方。
```java
/* jdk8新加入的Target枚举值
* TYPE_PARAMETER:表示该注解能写在类型变量的声明语句中(如:泛型声明)
* TYPE_USE:表示该注解能写在使用类型的任何语句中。
*/
// 例子1
public class TestTypeDefine<@TypeDefine() U> {
private U u;
public <@TypeDefine() T> void test(T t){
}
}
@Target({ElementType.TYPE_PARAMETER})
@interface TypeDefine{
}
// 例子2
@MyAnnotation
public class AnnotationTest<U> {
@MyAnnotation
private String name;
public static void main(String[] args) {
AnnotationTest<@MyAnnotation String> t = null;
int a = (@MyAnnotation int) 2L;
}
public static <@MyAnnotation T> void method(T t) {
}
public static void test(@MyAnnotation String arg) throws @MyAnnotation Exception {
}
}
@Target(ElementType.TYPE_USE)
@interface MyAnnotation {
}