Java注解原理

一、Java注解的定义
1.定义:注解是代码的特殊标志,使用于包、类、接口、字段、方法参数、局部变量等。注解可以作用于编译检查、编译时、运行时。
注意:注解不是注释。

二、Java注解的分类及使用
1.Java自带的标准注解
包括@Override、@Deprecated和@SuppressWarnings,分别用于标明重写某个方法、标明某个类或方法过时、标明要忽略的警告,用这些注解标明后编译器就会进行检查。

public class Test {  
    @Override
    public String tostring() {        
       return "override it";
    }
}

2.元注解
元注解是用于定义注解的注解,包括@Retention用于标明注解被保留的阶段;@Target用于标明注解使用的范围;@Inherited用于标明注解可继承;@Documented用于标明是否生成javadoc文档;

3.自定义注解,可以根据自己的需求定义注解,并可用元注解对自定义注解进行注解。

// 创建Test自定义注解,声明作用于类并保留到运行时,默认值为default
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Test {    
String value() default "default";
}

三、Java注解的作用与原理
1.注解的作用
a.生成文档,通过代码里标识的元数据生成javadoc文档,例如@Documented;
b.编译检查,通过代码里标识的元数据让编译器在编译期间进行检查验证,例如@Override、@Deprecated和@SuppressWarnings;
c.编译时动态处理,编译时通过代码里标识的元数据动态处理,例如动态生成代码;
d.运行时动态处理,运行时通过代码里标识的元数据动态处理,例如使用反射注入实例,如下代码所示

// 自定义注解
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD})
public @interface MyAnno {   
    String value();   
}

// 注解的使用
@MyAnno("class")
public class MyClass {
    @MyAnno("feild")
    private String str;
    @MyAnno("method")
    public void method() { }
}

// 反射获取注解   使用Annotation接口
public class Test {
    public static void main(String[] args) throws Exception {
        MyClass obj = new MyClass();
        Class<?> clazz = obj.getClass();
        
        // 获取对象上的注解
        MyAnno anno = clazz.getAnnotation(MyAnno.class);
        System.out.println(anno.value());
        
        // 获取属性上的注解
        Field field = clazz.getDeclaredField("str");
        anno = field.getAnnotation(MyAnno.class);
        System.out.println(anno.value());
        
        // 获取方法上的注解
        Method method = clazz.getMethod("method");
        anno = method.getAnnotation(MyAnno.class);
        System.out.println(anno.value());
    }
}   

2.注解的原理
原理:编译器将注解信息添加到class结构的属性中,同时注解可以作用于编译检查、编译时和运行时。
利用下面例子分析其原理。

@Test("annotationTest01 ")
public class AnnotationTest {    
    public void test(){
    }
}

编译器:java源码通过编译器转换为class字节码。在此过程中,编译器也会处理注解符号并附加到class结构。根据JVM的规范,class结构是严格有序的,保存到class结构的attributes属性是唯一可以附加信息的方式。类、字段、方法在class结构中都有特定的表结构,同时都有attributes属性。因此,注解作用在类、字段、方法,就是编译器将注解信息存放到类、字段、方法的attributes属性。例如,AnnotationTest.java被编译成AnnotationTest.class,其中包含一个RuntimeVisibleAnnotations属性。@Test("test")的键值对value=test就是添加到类的RuntimeVisibleAnnotations属性。

JVM:类加载过程中,加载AnnotationTest.class时,将RuntimeVisibleAnnotations属性值保存到AnnotationTest的Class对象。因此,AnnotationTest.class.getAnnotation(Test.class)获取到Test注解对象,从而获取到Test注解中的属性值annotationTest01。

说明:Test注解对象是一个继承Annotation接口的接口,即@Test实质是“public interface Test extends Annotation”。当运行AnnotationTest.class.getAnnotation(Test.class)时,JDK会通过动态代理生成一个实现了Test接口的对象,并把将RuntimeVisibleAnnotations属性值设置进此对象中,从而调用value()方法就可以获取到属性值annotationTest01。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容