栏目分类:
子分类:
返回
文库吧用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
文库吧 > IT > 软件开发 > 后端开发 > Java

Java 注解

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java 注解

注解是什么

注解是JDK1.5引入的新特性,用于对代码进行说明。注解是一种元数据,用于对代码进行说明,可以对包、类、接口、字段、方法、参数、局部变量等进行注解,可以理解为一种特殊的注释。这个注释是用来给程序看的。

注释是写给人看的,注解是写给程序看的。

为什么要使用注解

在没有注解之前,各种框架中几乎所有的配置以XML方式进行配置,因为XML方式可以降低配置和代码的耦合度,但是随着项目越来越庞大,XML的内容越来越复杂,维护成本变高。所有就有人提出了一种标记式的高耦合的配置方式,这是方式就是注解

注解:与源代码紧绑定,耦合度高,但它便捷,易于维护修改。
XML:与源代码无绑定,耦合度低,更容易扩展,但XML内容复杂,不易维护。

各有优劣!!!

注解作用

生成文档:通过代码里的标识的元数据生成javadoc文档。
编译检查:通过代码里的标识的元数据让编译器在编译期间进行检查验证。
编译动态处理:编译时通过代码里的标识的元数据动态处理,比如说用作动态代码生成。
运行动态处理:运行时通过代码里标识的元数据动态处理,比如说使用反射注入实例。

注解分类

Java提供了3种注解。
元注解:用于定义注解的注解,指定某个注解的生命周期以及作用目标等信息。

  1. @Target 标明注解使用的范围(作用的目标),有以下取值范围
public enum ElementType {
    
    TYPE,
    
    FIELD,
    
    METHOD,
    
    PARAMETER,
    
    CONSTRUCTOR,
    
    LOCAL_VARIABLE,
    
    ANNOTATION_TYPE,
    
    PACKAGE,
    
    TYPE_PARAMETER,
    
    TYPE_USE
}
  1. @Retention 表明注解被保留的阶段,有以下取值范围
public enum RetentionPolicy {
	//源码(只能再编译期可加,编译后会被丢弃)
    
    SOURCE,

	//字节码(会被编译器编译进class文件中,类加载时会被丢弃)-----默认值
    
    CLASS,
	
	//运行期(永久保存)
    
    RUNTIME
}
  1. @Documented 被标识的注解,在执行javadoc文档打包时会被保存进doc文档。
  2. @Inherited 标明注解可继承,也就是说我们的注解修饰了一个类,该类的子类将自动继承父类的该注解。

Java自带标准注解:
@Override 标明重写某个方法,编译器在对Java文件进行编译成字节码的过程中,一旦检测到某个方法上被修饰了该注解,就会去匹配对父类中是否具有一个同样方法签名的函数,如果没有,则不能通过编译。
@Deprecated 标明某个类或方法过时
@SuppressWarnings 标明要忽略的警告

**自定义注解:**可以根据自己的需求定义注解

注解实现

实现方式有基于Spring框架和不基于Spring框架两种方式。

不管采用哪种方式,都是按照以下步骤实现和使用注解的

1. 声明注解
2. 实现注解处理器
借助反射,获取注解对象(通常是Class对象,Method对象,Field对象,Constructor对象,Annotation对象),读取注解的属性值,然后根据注解及其属性的值做相应处理。
在这一步骤中最重要的是获取指定包路径下的所有的Class对象,只要获取到Class对象,其他对象都可以获取到,就可以任意操作。
3. 使用注解

先声明一个注解
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.TYPE, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotion {

    String value() default "";
}
不基于Spring框架获取Class对象:

1.借助Spring提供的工具包
首先引入4个jar包:

代码如下:

 public static Class[] getAllClass1(String packName) throws ClassNotFoundException {
     
     ClassPathScanningCandidateComponentProvider classPathScanningCandidateComponentProvider =
             new ClassPathScanningCandidateComponentProvider(false);
     //设置自定义的typeFilter
     classPathScanningCandidateComponentProvider.addIncludeFilter(new AnnotationTypeFilter(MyAnnotion.class));
     //根据自定义的typeFilter,在指定的包下获取满足条件的bean的定义
     Set beanDefinitions =  classPathScanningCandidateComponentProvider.findCandidateComponents(packName);
     if (beanDefinitions.isEmpty()) {
         return null;
     }
     Class[] clazzes = new Class[beanDefinitions.size()];
     //根据bean的定义获取bean的名称,然后通过反射获取bean的class对象,将class对象放入数组中
     int i = 0;
     for (BeanDefinition beanDefinition : beanDefinitions) {
         Class clazz = Class.forName(beanDefinition.getBeanClassName());
         if (Objects.isNull(clazz)) {
             continue;
         }
         clazzes[i++] = clazz;
     }
     return clazzes;
 }

2.借助reflections反射工具包
首先引入3个jar包:

代码如下:

 public static Class[] getAllClass2(String packName) {
     Reflections reflections = new Reflections(PATH);
     Set> typesAnnotatedWith = reflections.getTypesAnnotatedWith(MyAnnotion.class);
     Class[] classes = new Class[typesAnnotatedWith.size()];
     int i = 0;
     for (Class c : typesAnnotatedWith) {
         classes[i++] = c;
     }
     return classes;
 }

3.自己实现(采用JDK的API)
只需依赖JDK 1.8即可
代码如下:

 public static Class[] getAllClass3(String packName) throws IOException, ClassNotFoundException {
     URL resource = Thread.currentThread().getContextClassLoader().getResource(packName.replace('.', '/'));
     String[] files = new File(resource.getFile()).list();
     Class[] clazzs = new Class[files.length];
     for (int i = 0; i < files.length; i++) {
         clazzs[i] = Class.forName(packName + "." + files[i].replace(".class", ""));
     }
     return clazzs;
 }
不基于Spring框架获取Class对象:

待补充

注解本质(实现原理)

首先定义一个注解的关键字为"@interface",格式如下:

public @interface 注解名称{
	属性列表;
}

首先我们先按照注解的定义创建一个注解MyAnnotation.java,编译之后得到MyAnnotation.class文件

然后再用javap -c MyAnnotation.class命令进行反编译,结果如下


可以看出反编译之后的注解其实就是一个接口,它继承了Annotation接口。

没错,注解的本质就是一个继承了Annotation接口的接口。

解析一个类或者方法的注解有两种方式,一种是编译器的直接扫描,一种是运行期反射。

编译器的扫描指的是编译器在对Java代码编译成字节码的过程中检测到某个类或方法被一下注解修饰,这时会对这些注解进行处理。

运行期反射将会在下面进行详细说明

对于一个类或者接口来说,Class类对象中提供了以下方法用于反射注解。

  • getAnnotation:返回指定的注解
  • isAnnotationPresent:判断当前元素是否被指定注解修饰
  • getAnnotations:返回所有的注解
  • getDeclaredAnnotation:返回本元素的指定注解
  • getDeclaredAnnotations:返回本元素的所有注解,不包含父类继承而来的。

首先

转载请注明:文章转载自 www.wk8.com.cn
本文地址:https://www.wk8.com.cn/it/1039590.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 wk8.com.cn

ICP备案号:晋ICP备2021003244-6号