注解——Java

目录

 

一、注解

二、自带注解:

三、自定义注解

四、元注解

五、注解的解析

六、Runtime注解实现本质

七、注解的应用


一、注解

注解:位于源代码中,使用其他工作进行处理的标签;注解用来修饰程序元素,但不会对修饰的对象有直接的影响;只有通过某种配套的工作才会对注解信息进行访问和处理。

千万不要把注解和注释弄混淆!!!

注解的主要用途:

  • 提供信息给编译器和IDE工具
  • 可用于其他工具来产生额外的代码/配置文件等
  • 有一些注解可在程序运行时访问,增加程序的动态性

二、自带注解:

自带注解举例:

  • @SuppressWarning():压制警告
  • @Override():重写方法标记,若该方法父类里面没有则会报错。
  • @Deprecated:表示废弃的,建议不再使用所修饰的变量/方法
  • @SafeVarargs:表示不会对不定项参数做危险的操作
  • @FunctionInterface:声明功能性接口

 

 

补充:all:忽略所有警告k;cast:忽略类转型警告;serial:忽略实现Serializable接口的,没有定义serialVersionUID

三、自定义注解

jdk1.5引入,注解定义扩展java.lang.annotation.Annotation注解接口

注解中可以包含的类型有:

——String/Class/enum类型/注解类型/由这些类型组成的数组。

自定义注解定义:

@interface修饰,并且变量名后需要加(),可设默认值。

public @interface BugReport {
	enum Status {UNCONFIRMED, CONFIRMED, FIXED, NOTABUG};
	boolean showStopper() default true;
	String assiganedTo() default "[none]";
	Status status() default Status.UNCONFIRMED;
	String[] reportedBy();
}

注解的使用:格式为:@注解名(注解内变量赋值)如@test(a=1,b=2);

用元注解修饰自定义注解:

注解应用示例:

1.注解定义

import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
//表示该注解会保留在class文件中
@Target(ElementType.METHOD)   
//表示该注解只能用于方法

public @interface MultipleTest {
	int a() default 0;
	int b() default 0;
}

2.注解标记

public class Foo {
	@MultipleTest(a=1,b=1)
	public static void m1(int a, int b) {
		if(a+b<0)
		{
			throw new RuntimeException("Crash");
		}
	}

	@MultipleTest
	public static void m2(int a, int b) {
		//全部采用默认值
		if(a+b<0)
		{
			throw new RuntimeException("Broken");
		}
	}

	@MultipleTest(b=-2,a=1)
	public static void m3(int a, int b) {
		if(a+b<0)
		{
			throw new RuntimeException("Boom");
		}
	}
}

3.利用反射来判断注解

package annotations.multiple;

import java.lang.annotation.Annotation;
import java.lang.reflect.*;

public class Main {
	public static void main(String[] args) throws Exception {
		int passed = 0, failed = 0;
		String className = "annotations.multiple.Foo";
		for (Method m : Class.forName(className).getMethods()) {//获取所有方法
			
			if (m.isAnnotationPresent(MultipleTest.class)) {//判断该方法是否存在注解
				System.out.println(m.getName());
				MultipleTest st = m.getAnnotation(MultipleTest.class);	//获取注解			
				try {
					m.invoke(null,st.a(),st.b());
					passed++;
				} catch (Throwable ex) {
					System.out.printf("Test %s failed: %s %n", m, ex.getCause());
					failed++;
				}
			}
		}
		System.out.printf("Passed: %d, Failed %d%n", passed, failed);
	}
}
输出:
m3
Test public static void annotations.multiple.Foo.m3(int,int) failed: java.lang.RuntimeException: Boom 
m2
m1
Passed: 2, Failed 1

四、元注解

元注解举例:

  • @Target:设置目标范围
  • @Retention:设置保持性
  • @Documented:文档
  • @Inherited:注解继承
  • @Repeatable:此注解可以重复修饰。

说明:元注解是用来修饰注解的注解,一般修饰自定很诡异注解。

@Target:

4

 constructor构造函数/field成员变量/local_varible本地变量/method方法/package包/parameter参数

 

 

可以应用于多例测试场合。

示例:

1.定义注解:

import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
@Repeatable(RepeatableAnnotations.class)//绑定容器注解
public @interface RepeatableAnnotation {
	
	int a() default 0;
	int b() default 0;
	int c() default 0;
}

2.定义容器注解:

在里面定义原始注解的数组就行

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface RepeatableAnnotations {
	RepeatableAnnotation[] value();
}

3.重复注解:

public class Student {
	
	
	@RepeatableAnnotation(a=1,b=2,c=3)
	@RepeatableAnnotation(a=1,b=2,c=4)
	public static void add(int a, int b, int c)
	{
		if(c != a+b)
		{
			throw new ArithmeticException("Wrong");
		}
	}
}

4.获取注解并且测试:

package repeatable;

import java.lang.reflect.Method;

@CommonAnnotation
@RepeatableAnnotation
@RepeatableAnnotation

public class Main {

	public static void main(String[] a) throws Exception
	{
		String className = "repeatable.Student";
		for (Method m : Class.forName(className).getMethods()) 
		{
			if (m.isAnnotationPresent(RepeatableAnnotations.class)) 
			{
				RepeatableAnnotation[] annos = m.getAnnotationsByType(RepeatableAnnotation.class);
				for (RepeatableAnnotation anno : annos) 
				{
					System.out.println(anno.a() + "," + anno.b() + "," + anno.c());
					try 
					{
						m.invoke(null,anno.a(),anno.b(),anno.c());
					} catch (Throwable ex) {
						System.out.printf("Test %s failed: %s %n", m, ex.getCause());
					}
				}			
			}
		}
	}
	
}
输出:
1,2,3
1,2,4
Test public static void repeatable.Student.add(int,int,int) failed: java.lang.ArithmeticException: Wrong 

 

 五、注解的解析

  • Class.getAnnotations():类的有哪些注解修饰
  • Class.isAnnotation():类是否有注解修饰
  • Class.isAnnotationPresent(Class BClass):注解Bclass是否在此类上
  • Method.getAnnotations():方法的有哪些注解修饰
  • Method.isAnnotation():方法是否有注解修饰
  • Method.isAnnotationPresent(Class BClass):注解Bclass是否在此方法上
  • Field.getAnnotations():变量的有哪些注解修饰
  • Field.isAnnotation():变量是否有注解修饰
  • Field.isAnnotationPresent(Class BClass):注解Bclass是否在此变量上
  • Constructor.getAnnotations():构造方法的有哪些注解修饰
  • Constructor.isAnnotation():构造方法是否有注解修饰
  • Constructor.isAnnotationPresent(Class BClass):注解Bclass是否在此构造方法上

 用javac -processor命令来重新生成。注解处理器怎么写还不懂后续添加。

六、Runtime注解实现本质

注解经过反编译会生成一个接口类,接口类中的方法就是注解中的变量。

调用路线,注解的本质实现是通过调用路线:

  1. 采用接口中的方法来表示变量,注解。
  2. java为注解产生一个代理类。这个代理类包括一个AnnotationInvocationHandler变量。
  3. AnnotationInvocationHandler有一个Map的成员变量,用来存储所有的注解的属性赋值。

解释:在程序中,调用注解接口的方法,将会被代理类接管,然后根据方法名字,到Map里拿到相应的value返回。

七、注解的应用

 

 

 第三方库,Lombok

加载此第三方库后,在对应得类中使用注解@Data和@AllArgsConstructor可以不写构造函数和setter/getter方法

 依赖方法,在maven项目pox.xml中加上依赖.

	  <dependency>
	    <groupId>org.projectlombok</groupId>
	    <artifactId>lombok</artifactId>
	    <version>1.18.8</version>
		</dependency>

备注:此方法最好不要使用,我试了之后失败了,还是老老实实写构造函数和setter/getter方法吧

参考中国大学mooc《java核心技术》

发布了55 篇原创文章 · 获赞 17 · 访问量 4990

猜你喜欢

转载自blog.csdn.net/weixin_43698704/article/details/104214241