java基础之注解

学习的过程是不断深入的过程,但有时也需要对基础知识重新深入的学习一遍。
java注解Annotation

1 注解的概念

《java编程思想》中注解的定义:
注解(也被称为元数据)为我们在代码中添加信息提供了一种形式化的方法,使我们可以在稍后某个时刻非常方便地使用这些数据。
元数据:元始的意思,元数据就是描述数据的数据,注解的可以称为描述源码的数据。
不太好理解,我自己的理解是注解类似注释,相同点就是都不会影响源代码逻辑,但注解可以利用注解解析器获取,然后利用注解标识的信息生成新的代码从而对整体产生影响。所以注解类似某些标记,编译代码时利用工具读取这些标记作相应的操作。还有就是类似IOC框架注解可以简化配置文件。

2 默认提供注解和元注解

java语言提供的默认注解:
@Override 继承时标识重写的注解,如果添加了该注解,拼写错误或者父类中不存在都会提示错误信息。
@Deprecated过时注解,标识了该注解的程序,使用时编译期会发出过时警告

@SuppressWarnings,该注解关闭编译期发出的警告信息,

java还提供了四种基础的注解(其实是五种1.8添加了重复注解),被称为元注解,专门负责新注解的创建:

@Target

表示该注解可以用于什么地方,可能的ElementType参数有:
ElementType.ANNOTATION_TYPE 可以给一个注解进行注解
ElementType.CONSTRUCTOR 可以给构造方法进行注解
ElementType.FIELD 可以给属性进行注解
ElementType.LOCAL_VARIABLE 可以给局部变量进行注解
ElementType.METHOD 可以给方法进行注解
ElementType.PACKAGE 可以给一个包进行注解
ElementType.PARAMETER 可以给一个方法内的参数进行注解
ElementType.TYPE 可以给一个类型进行注解,比如类、接口、枚举

@Retention

表示需要在什么级别保存该注解信息。可选的RetentionPolicy参数包括:

SOURCE:注解将被编译器丢弃,编译完成之后什么都不会留下,类似@Override, @SuppressWarnings都属于这类注解。

CLASS:注解在class文件中可用,但会被VM丢弃,所以再类加载时会被丢弃,在字节码文件的处理中有用。注解默认使用这种方式。

RUNTIME:VM将在运行期间保留注解(注解信息一致会保留),因此可以通过反射机制读取注解的信息。

@Document

将注解包含在Javadoc中

@Inherited

允许子类继承父类中的注解

jdk8 提供了一种新的元注解:

@Repeatable
定义注解重复,是java8 提供的新特性。

什么样的注解会多次应用呢?通常是注解的值可以同时取多个。
重复注解不利用@Repeatable也可以实现,就是定义注解的数组,有了@Repeatable之后就会很方便,类似语法糖。
什么时候会用到重复注解呢?有时候一个对象或者函数它的属性可以是一种也可以是另外一种,像一个人既可以是学生也可以是司机。

3 创建注解

创建新的注解一般至少会用到@Target和@Retention注解,也可以不添加:

3.1 注解简单定义:

注解定义很简单利用@interface 类似接口:

public @interface Demo {

}

java提供的@Override注解源码:

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

@Override注解竟然什么都没有做,那它是怎么实现功能的呢,这个实现功能的人是谁呢?他就是程序员编写的注解解析器,这里需要再次重复,注解什么都没有做,它只是标识了某些信息。

如何使用注解,就跟我们使用@Override一样,直接写在相应的函数或者类或者构造函数上就可以了。

3.2 带有元素的注解

没有元素的注解称为标记注解类似@Test,@Override等
注解带有元素,类似方法定义:

@Retention(RUNTIME)
@Target(METHOD)
public @interface Demo1 {
	public int id();
	public String desc() default "no info";
}

注解的元素可以有默认值,如果在使用注解时没有指定注解参数的值,就会使用默认值,如果定义注解时没有默认值,则使用时必须给定值。
在这里插入图片描述

	@Demo1(id=1)
	public void getData() {
	}

如果只有一个参数,类似只有一个value,则使用时可以不写value=1,直接写值就可以了。

//定义
public @interface Demo {

	public int value();
}
//使用
	@Demo(1)
	public void getData2() {
		
	}

3.3 重复注解

不使用重复注解:

public @interface Demo {
	public int value();
}

@Retention(RUNTIME)
@Target(METHOD)
public @interface Demos {

	public Demo[] value();
}
//使用
@Demos({
		@Demo(1),
		@Demo(2)
	})
	public void getDat3() {
		
	}

//获取注解
public void getAnnoInfo2() {
		 
		 Class clazz = GetAnno.class;
		 //获得所有的方法
        Method[] methods = clazz.getMethods();
        for (Method method : methods) {
            method.setAccessible(true);//禁用安全机制
            if (method.isAnnotationPresent(Demos.class)) {//检查是否使用了Demo1注解
                Demos demos = method.getAnnotation(Demos.class);//获得注解实例
                Demo[] demo=demos.value();
		        for(Demo data : demo)
		        {
		           data.value();
		        }
            }
        }}

使用之后:

@Repeatable(Demos.class)
public @interface Demo {

	public int value();
}

/*@Demos({
		@Demo(1),
		@Demo(2)
	})*/
	@Demo(1)
	@Demo(2)
	public void getDat3() {
		
	}

4 注解的解析

注解的解析方式和@Retention有关,如果是源码级注解需要利用apt,如果是运行时注解可以利用反射解析。

4.1 获取运行时注解

@Retention(RetentionPolicy.RUNTIME)
RUNTIME 注解获取,首先使用注解,反射使用注解的类获取注解:

public void getAnnoInfo() {
		Class clazz = GetAnno.class;
		 //获得所有的方法
        Method[] methods = clazz.getMethods();
        for (Method method : methods) {
            method.setAccessible(true);//禁用安全机制
            if (method.isAnnotationPresent(Demo1.class)) {//检查是否使用了Demo1注解
                Demo1 demo1 = method.getAnnotation(Demo1.class);//获得注解实例
                String name = method.getName();//获得方法名称
                if (demo1.id() != 0) {
                   
                } else {
                   
                }
                
                if (demo1.desc() != null) {
                    
                } else {
                   
                }
            }
        }
	}

4.2 获取编译期注解

@Retention(RetentionPolicy.SOURCE)或者CLASS注解的获取,编译期注解只存在源码中,所以无法利用反射获取注解,想要获取注解需要使用APT工具,类似greendao,黄油刀等都是编译期注解,APT读取注解之后生成新的java源码文件完成逻辑。生成java源码比价好用的库就是

APT(Annotation Processing Tool)是一种注解解析工具,他对源代码进行检测,并找出源代码所包含的Annotation信息,然后针对Annotation信息进行额外的处理。使用APT工具处理Annotation时可以根据源文件中的Annotation生成额外的源文件和其他的文件(文件的具体内容由Annotation处理器的编写者决定),APT还会将编译生成的源代码文件和原来的源文件一起生成Class文件。

Java提供的javac.exe工具有一个-processor选项,该选项可指定一个Annotation处理器,如果在编译java源文件时指定了该Annotation处理器,那么这个Annotation处理器将会在编译时提取并处理Java源文件中的Annotaion.
每一个Annoataion处理器都需要实现javax.annotataion.processor包下的Processor接口,不过实现该接口必须实现该接口下的所有的方法,因此通常会采用继承AbstractProcessor的方式来实现Annotation的处理器。一个Annotation处理器可以处理一个或多个Annotaion注解。

下面提供一个解析的例子:

//apt处理源码注解,一般会生成新的java文件
//指定该注解支持java平台的最新版本为6.0
@SupportedSourceVersion(SourceVersion.RELEASE_6)
//指定可以处理的注解
@SupportedAnnotationTypes({"Demo2"})
public class ProcessorDemo extends AbstractProcessor{
    @Override
    public boolean process(Set<? extends TypeElement> annotations,
            RoundEnvironment roundEnv) {
        //定义文件输出流,用于生成额外的文件
       
        try{
            for(Element t:roundEnv.getElementsAnnotatedWith(Demo2.class)){
                //获取正在处理的类名称
                Name className=t.getSimpleName();
                //获得类定义前的注解
                Demo2 per= t.getAnnotation(Demo2.class);
              
                //遍历元素信息
                for(Element f:t.getEnclosedElements())
                {
                    //只处理成员变量上的Annotation
                    if(f.getKind()==ElementKind.FIELD)
                    {
                        //获取成员变量定义前的@Id Annotation
                        Demo1 demo1=f.getAnnotation(Demo1.class);
                        
                        //获取成员变量前的@Property Annotation
                        Demo demo=f.getAnnotation(Demo.class);
                        
                    }
                }
               
            }
        }catch(Exception e)
        {
            e.printStackTrace();
        }
        return true;
    }

5 注解的使用场景

注解可能大家使用的不太多,但是几乎每个框架都用到了,总结下注解的使用场景。
注解有许多用处,主要如下:

  • 源码注解提供信息给编译器: 编译器可以利用注解来探测错误和警告信息 ,也可以生成代码。
  • 编译阶段时的处理: 软件工具可以用来利用注解信息来生成java代码、xml配置文件和其他操作。
  • 运行时的处理: 某些注解可以在程序运行的时候接受代码的提取,进行必要逻辑。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值