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

Java基础之注解和反射

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

Java基础之注解和反射

Java基础之注解和反射
  • 注解
    • 元注解及参数
      • 元注解之一@Target
      • 元注解之二@Retention
      • 元注解之三Documented
      • 元注解之四Inherited
    • 自定义注解
  • 反射
    • 通过反射获取类对象
    • 类对象方法

注解

注解就是作用于类,方法以及字段上的特殊标记,这些标记可以在编译、类加载、运行时被读取,从而做相对应的处理。注解跟注释很像,区别是注释是给人看的,而注解是给程序看的,它可以被编译器读取。
注解格式为

元注解
public @interface 注解名称{
    数据类型 参数名();   //参数名默认为value
}
元注解及参数

元注解就是修饰注解的注解

元注解之一@Target

由源代码可以知道,@Target注解用来指定注解的作用域(如方法、类或字段),其中 ElementType 是枚举类型,也代表可能的取值范围。要注意的是value()不是方法,而是参数,value为参数名。

ElementType的值可以是:

public enum ElementType {
    
    //类、接口(包括注释类型)或枚举声明
    TYPE,

    
    //字段声明(包括枚举常量)
    FIELD,

    
    //方法声明
    METHOD,

    
    //形式参数声明
    PARAMETER,

    
    //构造方法声明
    CONSTRUCTOR,

    
    //局部变量声明
    LOCAL_VARIABLE,

    
    //注解类型声明
    ANNOTATION_TYPE,

    
    //包声明
    PACKAGE,

    
     //类型参数声明,起源于1.8
    TYPE_PARAMETER,

    
     //类型的使用,起源于1.8
    TYPE_USE
}
元注解之二@Retention


@Retention用来指定注解的生命周期,它有三个值,对应 RetentionPolicy 中的三个枚举值,分别是:源码级别(source),类文件级别(class)或者运行时级别(runtime)

  • SOURCE:作用于源码中
  • CLASS:作用于.class 文件中,但会被虚拟机丢弃(该类型的注解信息会保留在源码里和 class 文件里,在执行的时候,不会加载到虚拟机中)
    当注解未定义 Retention 值时,默认值是 CLASS,如 Java 内置注解,@Override、@Deprecated、@SuppressWarnning 等
  • RUNTIME:在源码,.class,运行时均可用,因此可以通过反射机制读取注解的信息(源码、.class 文件和执行的时候都有注解的信息),如 SpringMVC 中的 @Controller、@Service、@Mapping 等。此外,我们自定义的注解也大多在这个级别。
元注解之三Documented

执行 javaDoc 的时候,标记这些注解是否包含在生成的用户文档中。

元注解之四Inherited

标记这个注解具有继承性

自定义注解

自定义注解其实很简单,但要用到这个注解,讲这个注解使用起来就可以通过后面的反射机制来实现。
这是我自己定义的一个注解:关于使用可以继续往后看。

import java.lang.annotation.*;

@Target({ElementType.TYPE,ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
    String name() default "张三";
    String id() default "1001";
    String desc() default "";
}
反射

Java是一门静态语言,但也有说可以称为准动态语言。这个说法其中就可也体现在Java的反射机制上。

实体类(以商品类为例):

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.base.annotationTest.MyAnnotation;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;

import java.time.LocalDateTime;

@Data
@TableName("product")
@MyAnnotation(name = "商品实体类",id = "1000",desc = "商品实体类")
public class Product {

    @MyAnnotation(name = "id",id = "1001",desc = "主键")
    @TableId(type = IdType.INPUT)
    private Long id;
    @MyAnnotation(name = "pro_name",id = "1002",desc = "商品名称")
    private String proName;
    @MyAnnotation(name = "pro_type",id = "1003",desc = "商品类型")
    private String proType;
    @MyAnnotation(name = "pro_price",id = "1004",desc = "价格")
    private float proPrice;
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @MyAnnotation(name = "date_of_manufacture",id = "1005",desc = "生产日期")
    private LocalDateTime dateOfManufacture;
    @MyAnnotation(name = "manufacturer",id = "1006",desc = "厂商")
    private String manufacturer;
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @MyAnnotation(name = "create_time",id = "1007",desc = "创建时间")
    private LocalDateTime createTime;
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @MyAnnotation(name = "last_modify_time",id = "1008",desc = "最后修改时间")
    private LocalDateTime lastModifyTime;
    @MyAnnotation(name = "status",id = "1009",desc = "是否上架")
    private boolean status;

}
通过反射获取类对象

如下代码所示的三种方法。

  • 通过对象的实例的getClass()方法来获取类对象;
  • 通过类名的.class直接获取类对象;
  • 通过全限类名调用Class.forName()方法。
import com.base.annotationTest.MyAnnotation;
import com.base.reflect.pojo.Product;

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


public class Test02 {

    public static void main(String[] args) throws ClassNotFoundException {
        //1,通过对象的实例的getClass()方法来获取类对象
        Product product = new Product();
        Class c1 = product.getClass();
        //2,通过类名的.class直接获取类对象
        Class c2 = Product.class;
        //3,通过全限类名调用Class.forName方法创建
        Class c3 = Class.forName("com.base.reflect.pojo.Product");

        System.out.println(c1.hashCode());
        System.out.println(c2.hashCode());
        System.out.println(c3.hashCode());

    }

}

由结果可知,三种方法创建的对象都为同一个对象。

类对象方法

通过反射创建的类对象可以调用方法来获取类的字段,方法,注解等信息。

举几个例子:
1,getName()与getSimpleName()

//获取类对象全限类名(包名+类名)
System.out.println(c1.getName());
//获取类对象名称
System.out.println(c1.getSimpleName());


2,getClassLoader()
获取类加载器。

ClassLoader classLoader = c1.getClassLoader();
ClassLoader parent = classLoader.getParent();
ClassLoader parent1 = parent.getParent();
System.out.println(classLoader);
System.out.println(parent);
System.out.println(parent1);

自定义的类加载器都是委托给AppClassLoader,而AppClassLoader委托给ExtClassLoader,ExtClassLoader委托给根加载器。这就是ClassLoader的委托链。可以看到类加载器的层次结构如下:

ClassLoader的双亲委派机制是这样的:

  • 当AppClassLoader加载一个class时,它首先不会自己去尝试加载这个类,而是把类加载请求委派给父类加载器ExtClassLoader去完成。
  • 当ExtClassLoader加载一个class时,它首先也不会自己去尝试加载这个类,而是把类加载请求委派给BootStrapClassLoader去完成。
  • 如果BootStrapClassLoader加载失败(例如在$JAVA_HOME/jre/lib里未查找到该class),会使用ExtClassLoader来尝试加载;
  • 若ExtClassLoader也加载失败,则会使用AppClassLoader来加载,如果AppClassLoader也加载失败,则会报出异常ClassNotFoundException。

3,getAnnotation();
该方法用来获取类,方法获取字段上的注解,以上面的商品类和之前的自定义注解MyAnnotation为例:

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


public class Test01 {

    public static void main(String[] args) throws ClassNotFoundException {
        Class clazz = Class.forName("com.base.reflect.pojo.Product");
        Annotation[] annotations = clazz.getAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println(annotation);
        }

        MyAnnotation annotation = (MyAnnotation) clazz.getAnnotation(MyAnnotation.class);
        System.out.println(annotation.name());

        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            MyAnnotation myAnnotation = field.getAnnotation(MyAnnotation.class);
            System.out.println(myAnnotation.id()+"==="+myAnnotation.name()+"==="+myAnnotation.desc());
        }
    }

}

结果如下图所示:

可以通过反射机制来获取注解里面参数的值,自然就可以对这些值进行其他操作了。

除了以上这些类方法还有其他的例如:getMethod(),getFiled()等,在Spring的框架中被大量用到。Spring的AOP原理就是动态代理+反射来实现的。

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

版权所有 (c)2021-2022 MSHXW.COM

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