JavaSE学习笔记(15.Java之注解)

Java可以通过@Interface形式定义一个注解,用于修饰包定义、类、构造器、方法、成员、参数、局部变量等,并通过反射获取注解中的信息!

1. 元注解:

Java注解的定义,需要使用元注解修饰(元注解本身也是ElementType.ANNOTATION_TYPE类型的注解)!格式如下:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}

1.1 @Retention元注解:

@Retention元注解有一个RetentionPolicy枚举类型的value成员,用于指示被修饰的注解保留时长!

  • RetentionPolicy.SOURCE:指示该注解为编译期注解,仅仅在编译期间使用,编译后丢失;程序运行时期不可通过反射获取!
  • RetentionPolicy.CLASS:指示该注解只记录在class文件中,仅仅在类加载的时候使用,Class对象中丢失;程序运行时期不可用通过反射获取;该值为value的默认值!
  • RetentionPolicy.RUNTIME:指示该注解为运行期注解,在程序运行期间可以通过反射获取注解信息!

1.2 @Target元注解:

@Target元注解有一个String类型的value成员,用于指示注解修饰那种成员类型!

  • ElementType.ANNOTATION_TYPE:修饰注解类型
  • ElementType.CONSTRUCTOR:修饰构造器
  • ElementType.LOCAL_VARIABLE:修饰局部变量
  • ElementType.PACKAGE:修饰包定义
  • ElementType.PARAMETER:修饰方法参数
  • ElementType.METHOD:修饰方法
  • ElementType.FIELD:修饰成员
  • ElementType.TYPE:修饰类、接口、或者枚举定义
  • ElementType.TYPE_PARAMETER:修饰泛型类的泛型定义
public class AnnotationTypeParameter<@TestTypeParam T> {}
  • ElementType.TYPE_USE:修饰类型使用的地方;Java8新增类型,Java8前注解使用的位置只能在类型定义处,引入TPYE_USE类型后,注解可以在任何类型使用的地方!

List<@Test Comparable> list1 = new ArrayList<>();

List<? extends Comparable> list2 = new ArrayList<@Test Comparable>();

@Test String text;

text = (@Test String)new Object();

java.util. @Test Scanner console;

console = new java.util.@Test Scanner(System.in);

1.3 @Documented元注解:

被@Documented元注解修饰的注解,将被javadoc工具提取到被修饰类的API文档中!

1.4 @Inherited元注解:

被@Inherited元注解修饰的注解,将具有继承性,父类被具有@Inherited元注解修饰的注解修饰后,子类自动被该注解修饰!

1.5 @Repeatable元注解:

Java8之前,如果想用同一个注解重复修饰的时候,只能定义一个注解数组,如下:

//AnnotationTest注解数组定义
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface AnnotationTests {
	AnnotationTest[] a();
}


//AnnotationTest注解定义
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface AnnotationTest {
	/*给name成员,赋初始值为"hello"*/
	String name() default "hello";
	
	/*定义num成员,未赋初始值*/
	String value();
}

//AnnotationTest注解使用
class Atest 
{
	@AnnotationTests(a = {@AnnotationTest("test1"),@AnnotationTest("test2")})
	public void fun()
	{
		System.out.println("fun()");
	}	
}

Java8提供了一个@Repeatable元注解,对上述语法进行了简化:

//AnnotationTest注解定义
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
@Repeatable(AnnotationTests.class)
public @interface AnnotationTest {
	/*给name成员,赋初始值为"hello"*/
	String name() default "hello";
	
	/*定义num成员,未赋初始值*/
	String value();
}

//AnnotationTests注解定义
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface AnnotationTests {
	/*当使用@Repeatable(AnnotationTests.class)的时候,AnnotationTests中必须有value成员*/
	AnnotationTest[] value();
}

//AnnotationTest注解使用
class Atest 
{
	@AnnotationTest("test1")
	@AnnotationTest("test2")
	public void fun()
	{
		System.out.println("fun()");
	}	
}

PS:Java8后,还提供了针对于重复注解信息提取的反射接口!

 

2. 自定义注解

注解定义,代码示例:

import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface AnnotationTest {
	/*给name成员,赋初始值为"hello"*/
	String name() default "hello";
	
	/*定义num成员,未赋初始值*/
	String value();
}

Ps:注解中有一个元素名为value的成员,当给注解成员赋值的时候,可以将(value="XXX")简化为("XXX")

注解信息获取,代码示例:

public class Main 
{
	public static void main(String[] args)
	{
		/*通过反射结合注解调用Atest中的方法*/
		Atest a = new Atest();
		
		/*遍历Atest中方法,结合注解配置进行区别处理*/
		Method[] m = Atest.class.getMethods();
		for (int i = 0; i < m.length; i++)
		{
			
			if (m[i].isAnnotationPresent(AnnotationTest.class))
			{
				if ("Test".equals(m[i].getAnnotation(AnnotationTest.class).value()))
				{
					System.out.println(m[i].getAnnotation(AnnotationTest.class).name());
					try 
					{
						m[i].invoke(a);
					} 
					catch (Exception e) 
					{
						e.printStackTrace();
					}
				}
			}			
		}			
	}	
}

class Atest 
{
	@AnnotationTest("Test")
	public void fun1()
	{
		System.out.println("fun1()");
	}
	
	@AnnotationTest(value = "NoTest", name = "test")
	public void fun2()
	{
		System.out.println("fun2()");
	}
}

Ps:通过反射获取注解信息已经在<JavaSE学习笔记(14.Java之反射机制)>中具体阐述过了,这里补充一点Class、Constructor、Field、Method、Package等类都是AnnotatedElement接口的实现类,AnnotatedElement接口提供了所有注解信息获取的方法能力!

 

3. 编译期处理注解:

JSR 269中提供了一组API用于专门编译期处理注解,相当于一组可以插入Java编译流程的插件!并再结合JSR 175 Java元数据规范可以实现类似Lombok一样在编译期间根据注解,生成Java代码的编译期注解代码生成插件!

实现流程:

1. 继承javax.annotation.processing.AbstractProcessor类,并实现process方法(方法内部为注解处理逻辑);

2. 使用@SupportedAnnotationTypes注解指定该Processor类具体处理那个注解;

3. 使用@SupportedSourceVersion注解指定编译版本;

4. 通过Javac命令中 -processor参数指定Processor类

5. 或者在META-INF/services/javax.annotation.processing.Processor中增加Processor类

6. 或者通过Maven Plugin配置Processor类

<plugin>
     <groupId>org.apache.maven.plugins</groupId>
     <artifactId>maven-compiler-plugin</artifactId>
     <version>3.5.1</version>
     <configuration>
        <source>1.8</source>
        <target>1.8</target>
        <encoding>UTF-8</encoding>
                <annotationProcessors>
                    <annotationProcessor>
                        XXXXXProcessor
                    </annotationProcessor>
                </annotationProcessors>
      </configuration>
</plugin>

Ps:值得注意的是,在编译期间处理注解的时候,自定义的Processor类不能是java文件,需要将Processor类编译成为class文件,否则在编译期间会报Class not found的错误!

推荐一篇Pluggable Annotation Processing API描述比较细致的文章<Java奇技淫巧-插件化注解处理API(Pluggable Annotation Processing API)>

 

4. 常用注解:

java.lang包中提供了几个常用注解:

4.1 @Override:

编译期注解,修饰方法,通过编译约束子类中必须重写该方法!

4.2 @Deprecated:

运行期注解,可修饰所有类型,用于修饰已经过时的成员;当已过时成员被调用的时候,编译器会输出编译告警!

4.3 @SuppressWarnings:

编译期注解,抑制编译器告警,@SuppressWarnings("unchecked")

4.4 @SafeVarargs:

运行期注解,针对泛型的类型擦除引发的编译告警,提供的抑制该告警的注解!

Ps:泛型的类型擦除引发的编译告警,可以使用@SafeVarargs消除、@SuppressWarnings("unchecked")消除、也可以在Javac命令增加-Xlint:varargs告警屏蔽项!

4.5 @FunctionalInterface:

运行期注解,修饰接口为函数式接口,可以与lamda表达式组合使用,详细见<JavaSE学习笔记(7.Lamda表达式)>

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值