第五章. Java注解

1. Java注解

注解:Annotation

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

主要用途:

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

1.1 Java 普通注解

注解含义用途
@Override继承和覆写修饰方法,检查该方法是父类的方法;强制该函数代码必须符合父类中该方法的定义;避免代码错误
@Deprecated废弃标注为废除,建议程序员不再使用这个类/元素/包
@SuppressWarnings压制警告压制各种不同类型的警告信息,使得编译器不显示警告;警告类型名称是编译器/IDE工具自己定义的,Java规范没有强制要求
@SafeVarargs不会对不定项参数做危险操作
@FunctionInterface声明功能性接口
  • @ SuppressWarnings
    – @SuppressWarnings(“unchecked”) 忽略unchecked警告信息
    – @SuppressWarnings(“deprecated”) 忽略过时方法的警告信息
    – @SuppressWarnings({“unchecked”,“deprecated”}) 忽略两种警告
    信息
    – @ SuppressWarnings(values={“unchecked”,“deprecated”}) 同上
    – @ SuppressWarnings( “all”) 忽略所有的警告信息
    – 其他的警告类型
    • all,忽略所有的警告
    • cast,忽略类转型警告
    • serial,忽略实现Serializable接口的,没有定义serialVersionUID
    • 使用javac -X 可以看当前的编译器使用哪些警告类型

1.2 Java 自定义注解

– Java是通过反射,来获取注解信息并运行注解
– 扩展java.lang.annotation.Annotation注解接口
– 注解可以包括的类型

  • 8种基本类型(int/short/long/float/double/byte/char/boolean)
  • 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();
}

Java自定义注解

import java.lang.annotation.*;

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

public @interface SingleTest {
	int value() default 0;
	//String para();
}

Java注解的运行与使用

public class Foo {
	@SingleTest(1)
	public static void m1(int a) {
		if(a<0)
		{
			throw new RuntimeException("Crash");
		}
	}

	public static void m2() {
	}

	@SingleTest(value=-2)
	public static void m3(int a) {
		if(a<0)
		{
			throw new RuntimeException("Crash");
		}
	}
}
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.single.Foo";
		for (Method m : Class.forName(className).getMethods()) {
			 
			if (m.isAnnotationPresent(SingleTest.class)) {//判读是否有SingleTest注解
				System.out.println(m.getName());
				SingleTest st = m.getAnnotation(SingleTest.class);				
				try {
					m.invoke(null,st.value());//传递注解的参数
					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);
	}
}

1.3 Java 元注解

元注解:修饰注解的注解
– 一般自定义注解时使用

元注解注解说明
@Target设置目标范围
@Retention注解的保存范围
@Inherited注解可继承
@Repeatable此注解可以重复修饰
@Document注解可以被Javadoc工具所解析

Retention(保留)
–这个注解用来修饰其他注解的存在范围
–示例:@Retention(RetentionPolicy.RUNTIME)

  • RetentionPolicy.SOURCE 注解仅存在源码,不在class文件。
  • RetentionPolicy.CLASS 这是默认的注解保留策略。注解存在于.class文件,但是不能被JVM加载。
  • RetentionPolicy.RUNTIME 这种策略下,注解可以被JVM运行时访问到。通常情况下,可以结合反射来做一些事情。

Target
–限定目标注解作用于什么位置
–@Target({ElementType.METHOD})

–ElementType.ANNOTATION_TYPE(注:修饰注解)
–ElementType.CONSTRUCTOR
–ElementType.FIELD
–ElementType.LOCAL_VARIABLE
–ElementType.METHOD
–ElementType.PACKAGE
–ElementType.PARAMETER
–ElementType.TYPE(注:任何类型,即上面的的类型都可以修饰)

Inherited
–普通的注解没有继承功能(子类继承父类,不会继承父类的注解)
–@Inherited 让一个类和它的子类都包含某个注解

@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface InheritAnnotation {

}

@InheritAnnotation
public class InheritFather {

}

//子类继承了父类的@InheritAnnotation注解
public class InheritSon extends InheritFather{

}

Repeatable
– 表示被修饰的注解可以重复应用标注
– 需要定义注解和容器注解

RepeatableAnnotation	//重复元注解
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(RepeatableAnnotations.class)
public @interface RepeatableAnnotation {
	
	int a() default 0;
	int b() default 0;
	int c() default 0;
}

RepeatableAnnotations	//重复元注解容器
@Retention(RetentionPolicy.RUNTIME)
public @interface RepeatableAnnotations {
	RepeatableAnnotation[] value();
}

Student	//方法类
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");
		}
	}
}

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());
                }
            }			
        }
    }
}

Documented
–指明这个注解可以被Javadoc工具解析,形成帮助文档


2. Java 注解解析

RetentionPolicy.RUNTIME:注解在class文件中,被JVM加载,可用反射解析注解

  • Class.getAnnotations() 获取注解数组
  • Class.isAnnotation() 是否有注解
  • Class.isAnnotationPresent(Class annotationClass) 是否是某个注解
  • Method/Field/Constructor.getAnnotations()/isAnnotationPresent(Class annotationClass)

RetentionPolicy.CLASS:注解在class文件中,但没有被JVM加载
– 只能使用字节码工具进行特殊处理

RetentionPolicy.SOURCEC:注解在java文件中,只有在源码级别进行注解处理
– Java提供注解处理器来解析带注解的源码,产生新的文件

3. Java注解应用

– Junit
– Spring,Springboot
– …各种应用框架,注解能够简化配置文件,提高程序灵活性

注解的优缺点:
优点:

1、节省配置,减少配置文件大小

2、编译时即可查看正确与否,提高效率

缺点:

1、增加了程序的耦合性,因为注解保存在class文件中,而且比较分散

2、若要对配置进行修改需要重新编译
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值