我是靠谱客的博主 顺心面包,最近开发中收集的这篇文章主要介绍java注解与反射学习[狂神说java-注解和反射笔记]概要注解 Annotation反射 Reflection,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

java注解与反射

  • 概要
  • 注解 Annotation
    • 元注解
    • 自定义注解
  • 反射 Reflection
    • 了解类
    • 反射常用的使用方式
      • 获取类的运行时结构
      • 动态创建对象并操作
      • 反射操作泛型
    • 注解与反射的结合运用


概要

所有的资料来源都是以【狂神说Java】注解和反射 为基础
【狂神说Java】注解和反射
建议看视频,这篇博客是笔记


注解 Annotation

作用: 是帮助程序&编译器识别然后做出结束

格式: @注解名, 也可以在后面加括号添加参数值

使用位置: package,class,method,field

常用内置注解:

  • override 重写
  • Deprecated 不推荐使用
  • SuppressWarmings 镇压警告

在这里插入图片描述


元注解

作用: 注解其他注解

四个标准的meta-annotation类型:

  • @Target

    用于描述注解的使用范围(即: 被描述的注解可以用在什么地方)

  • @Retention

    表示需要在什么级别保存该注释信息,用于描述注解的生命周期

    • (SOURCE < CLASS < RUNTIME)
  • @Document

    说明该注解将被包含在javadoc中

  • @Inherited

    说明子类可以继承父类中的该注解

使用样例:

package cn.livorth.Annotation;

import java.lang.annotation.*;

//定义注解的应用范围,样例中为:模块、类型(包括类等)
@Target(value = {ElementType.MODULE, ElementType.TYPE})

//定义注解有效的范围 runtime>class>sources
@Retention(value = RetentionPolicy.RUNTIME)

//决定是否将注解生成到javadoc中
@Documented

//决定是否要让子类继承父类的注解
@Inherited

/**
 * 定义注解类,然后再进行相关配置
 */
public @interface Test01 {
}

自定义注解

对于自定义注解:

  • 继续采用元注解进行相关配置

  • 注解的参数格式为:

    类型 + 参数名+ () + ;

    当只有一个参数的时候建议用value

  • 可以使用default设置默认值,比如:

    String name() default "livorth";

注意: 在使用的时候,注解中的参数没有先后顺序

使用样例:

package cn.livorth.Annotation;

import java.lang.annotation.*;

public class Test02 {
    @TestAnnotation(id = 1)
    public void  test(){
    }
}


@Target(value = {ElementType.MODULE, ElementType.TYPE})
@Retention(value = RetentionPolicy.RUNTIME)
@interface TestAnnotation {
    //注解参数的格式
    String name() default "livorth";
    int id();
}

对于这种注解而言,需要配合反射一起使用

从而实现对元数据的读取



反射 Reflection

了解类

1. 能够获取类的结构

// 利用类路径获取类
Class c1 = Cless.forName("类的详细地址") ;
// 利用具体类的Class属性获取
Class c2 = Person.class;
// 通过实例获取
Class c3 = person.getClass();
// 一个加载类在JVM中只有一个Class示例

2. 类的初始化:

  1. 主动引用:
    1. 虚拟机启动,先初始化main方法所在类
    2. new 一个类的对象
    3. 调用类的静态成员(除了final常量)和静态方法
    4. 使用java.long.reflect包的方法对类进行反射调用
    5. 初始化某类时其父类未初始化,则先初始化父类
  2. 被动引用:
    1. 访问一个静态域时,只有真正申明这个域的类才会被初始化
    2. 数组定义类引用
    3. 引用常量

3. 拥有Class对象的类型:

class、interface、数组、enum、annotation、基础数据类型、void


反射常用的使用方式

获取类的运行时结构

也就是通过反射获取类相关的信息

  1. 获取目标类的class对象
  2. 直接.getxxx获取相关信息

常用方法相关样例:

package cn.livorth.Annotation;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class Test03 {

    public static void main(String[] args) throws Exception {
        Class userClass = Class.forName("cn.livorth.Annotation.User");

        // 获取类的名字
        System.out.println(userClass.getName());
        // 带包名一起:
        System.out.println(userClass.getSimpleName());
        // 进类名:

        // 获取类的属性
        Field[] publicFields = userClass.getFields();// 仅找到public属性
        Field[] declaredFields = userClass.getDeclaredFields();// 能获取到private属性
        Field name = userClass.getDeclaredField("name");// 获取具体属性

        // 获取类的方法
        Method[] methods = userClass.getMethods();// 获取本类以及父类全部的public方法
        Method[] declaredMethods = userClass.getDeclaredMethods();// 仅获取本类全部的方法,包括private方法
        Method setId = userClass.getDeclaredMethod("setId", int.class);// 获取单个方法
        Method getName = userClass.getDeclaredMethod("getName", null); // 传入参数的类型主要是为了避免在重载时出现问题

        // 获取类的构造器
        Constructor[] declaredConstructors = userClass.getDeclaredConstructors();
        Constructor declaredConstructor = userClass.getDeclaredConstructor(String.class, int.class); // 获取指定构造器,通过传参控制
    }
}


动态创建对象并操作

package cn.livorth.Annotation;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class Test04 {
    public static void main(String[] args) throws Exception {
        Class userClass = Class.forName("cn.livorth.Annotation.User");

        // 通过类的无参构造器创建对象,如果目标类没有构造器那么就
        User user = (User) userClass.newInstance();

        // 通过指定构造器构建对象
        Constructor declaredConstructor = userClass.getDeclaredConstructor(String.class, int.class);
        User user1 = (User) declaredConstructor.newInstance("livorth", 1);

        // 通过反射调用类的方法
        Method setName = userClass.getDeclaredMethod("setName", String.class);
        setName.invoke(user, "steve");
        System.out.println(user.getName());     // 输出steve

        // 通过反射操作属性
        Field name = userClass.getDeclaredField("name");
        name.setAccessible(true);   //设置权限检测,使得反射能够访问private属性
        name.set(user, "Alex");
        System.out.println(user.getName()); //返回Alex,但是要是不修改权限检测,那么就会报错
    }
}

注意:

  • 普通方式调用方法, 运行速度远高于下面两种
  • 反射调用, 很慢很慢
  • 关闭权限检测的反射, 虽然慢,但是比直接反射快

反射操作泛型

表示不能被归一到Class类中的类型但是又和原始类型齐名的类型

  • ParameterizedType :表示一种参数化类型,比如Collection
  • GenericArrayType :表示一种元素类型是参数化类型或者类型变 量的数组类型
  • TypeVariable :是各种类型变量的公共父接口
  • WildcardType :代表一种通配符类型表达式
package cn.livorth.Annotation;

import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;

public class Test05 {
   public Map<String, User> test(Map<String, User> map, List<User> list){
       list = null;
       return map;
   }

   public static void main(String[] args) throws Exception {
       // 获取方法
       Method test = Test05.class.getMethod("test", Map.class, List.class);
       System.out.println(test);
       // 获取传入的类型数组
       Type[] parameterTypes = test.getGenericParameterTypes();
       // 获取返回值参数类型
       Type returnType = test.getGenericReturnType();

       for (Type type : parameterTypes) {
           System.out.println(type);
           // java.util.Map<java.lang.String, cn.livorth.Annotation.User>
           // java.util.List<cn.livorth.Annotation.User>

           // 如果是参数化类型
           if(type instanceof ParameterizedType){
               // 获取真实的泛型参数信息
               Type[] actualTypeArguments = ((ParameterizedType) type).getActualTypeArguments();
               for (Type actualTypeArgument : actualTypeArguments) {
                   System.out.println(actualTypeArgument);
                   // class java.lang.String
                   // class cn.livorth.Annotation.User
               }
           }
       }
   }
}

注解与反射的结合运用

反射操作注解

利用注解和反射完成类和表结构的映射关系,也就是使用反射通过注解将数据映射到数据库中的表内

  1. 获取类

  2. 获取类的注解:Annotation[] annotations = class.getAnnotations()

  3. 获取类注解的value:

    User user = (User)c1.getAnnotation(User.class);

    value = user.value;

  4. 获得类中指定属性的注解:

    Field f = c1ass.getDeclaredField( name: "id"); User annotation = f.getAnnotation(User.class);

最后

以上就是顺心面包为你收集整理的java注解与反射学习[狂神说java-注解和反射笔记]概要注解 Annotation反射 Reflection的全部内容,希望文章能够帮你解决java注解与反射学习[狂神说java-注解和反射笔记]概要注解 Annotation反射 Reflection所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(67)

评论列表共有 0 条评论

立即
投稿
返回
顶部