反射注解基本操作

本文介绍了Java中的注解和反射机制。详细讲解了元注解的使用,如何通过反射读取注解信息,以及Java反射的功能,包括动态创建对象、获取类信息、调用方法等。同时,讨论了反射的优缺点,并展示了如何通过反射操作泛型。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

注解和反射

1.注解-annotation

1.1 元注解

元注解的作用就是负责注解其他注解(@Target、@Retention、@Documented、@Inherited)

@Target:描述注解的使用范围(方法、类、参数上等)——多个使用范围,必须加上{ }

@Retention: 定义了注解保持有效的 使命周期阶段(runtime(默认写这个) >class>sources)

@Documented: 表示是否将我们的注解生成在JavaDoc中

@Inherited: 子类可以继承父类的注解

//@Retention 定义了注解保持有效的 使命周期阶段
@Retention(RetentionPolicy.RUNTIME)
//@Target 表示注解能使用的目标
@Target({ElementType.TYPE,ElementType.METHOD,ElementType.PARAMETER})
//@Documented:表示是否将我们的注解生成在JavaDoc中
@Documented
//@Inherited:子类可以继承父类的注解
@Inherited
public @interface MyAnnotation {
    //成员
    String userName() default "张三";  

    int age();

    boolean flag() default true;

    //枚举
    Color color() default Color.RED;

    //注解
    OtherAnnotation othanno();
}

注意:

  1. 注解:主要作用就在程序中传值(在运行阶段完成:结合反射使用)

  2. 在注解中参数可以用default来定义默认值

  3. 调用自定义自定义注解,注解有一个成员参数可以直接写参数值,注解有多个成员参数,必须用参数名value= ;

  4. 注解中有默认值,可以不用给其赋值·

  5. 注解中的成员参数是数组且数组只有一个元素时,{}可以省略,否则{}不能省略

    @MyAnnotation(userName = "李四",age = 16,color = Color.RED,othanno = @OtherAnnotation(1))
    public class annotationDemo {
        public static void main(String[] args) {
            System.out.println("   ");
        }
    }
    
1.2 通过基本反射读取注解

annotationDemo类:设置注解

@MyAnnotation(userName = "王啊五",age = 4,flag = true,color = Color.RED,othanno = @OtherAnnotation(1))
public class annotationDemo {

    @MyAnnotation(userName = "李四",age = 5,othanno = @OtherAnnotation(4))
    private static void print(@MyAnnotation(age = 1,othanno = @OtherAnnotation(1))String userName,@MyAnnotation(age = 7,userName = "刘六")Integer id){
        
        System.out.println("你好");
    }

}

TestGetValue类:分别读取类上、方法上、参数上的注解

public class TestGetValue {
    public static void main(String[] args) throws NoSuchMethodException {
        Class<TestAnnotation> annotationClass = TestAnnotation.class;

        //获取方法参数中的注解
        Method print = annotationClass.getDeclaredMethod("print", String.class, Integer.class);
        Parameter[] parameters = print.getParameters();
        for (Parameter parameter : parameters) {
            boolean annotationPresent = parameter.isAnnotationPresent(MyAnnotation.class);
            if (annotationPresent) {
                MyAnnotation annotation = parameter.getAnnotation(MyAnnotation.class);
                int age = annotation.age();
                String userName = annotation.userName();
                System.out.println(age+"  "+userName);
            }
        }


        System.out.println("============================");
        //获取方法上的注解
        Method print1 = annotationClass.getDeclaredMethod("print", String.class,Integer.class);
        boolean isAnnotation2 = print1.isAnnotationPresent(MyAnnotation.class);
        if (isAnnotation2) {
            MyAnnotation annotation = print1.getAnnotation(MyAnnotation.class);
            int age = annotation.age();
            String userName = annotation.userName();
            System.out.println(age + "  " + userName);
        }



        System.out.println("============================");
        //获取类上的注解
        boolean isAnnotation = annotationClass.isAnnotationPresent(MyAnnotation.class);
        if (isAnnotation) {
            MyAnnotation annotation = annotationClass.getAnnotation(MyAnnotation.class);
            int age = annotation.age();
            String userName = annotation.userName();
            System.out.println(userId + "  " + userName);
        }


    }
}

在这里插入图片描述

2.反射-Java Reflection

2.1 java反射机制功能
  1. 在运行时判断任意一个对象所属的类
  2. 在运行时构造任意一个类的对象
  3. 在运行时判断任意一个类所具有的成员变量和方法
  4. 在运行时获取泛型信息
  5. 在运行时调用任意一个对象的成员变量和方法
  6. 在运行时处理注解
  7. 生成动态代理
  8. 。。。。。。
2.2 反射优缺点

优点: 可以实现动态创建对象和编译,体现很大的灵活性

缺点: 对性能有影响;反射操作总是慢于直接执行相同的操作(就是所谓的解释操作,告诉JVM,希望它满足反射操作的要求

2.3 创建类的三种方式
//方式一:通过 forName 获取class类
Class userClass = Class.forName("entity.User");

//方式二:通过 对象 获得
User user = new User();
Class userClass2 = user.getClass();

//方式三:通过 类名.class 方式获取(靠谱安全)
Class userClass3 = User.class;
2.4 获取类名、属性、方法、构造器
Class userClass = Class.forName("entity.User");		
//获取类的名字
        System.out.println("============类的名字==============");
        String name = userClass.getName(); //包名+类名
        System.out.println("包名+类名:"+name);

        String simpleName = userClass.getSimpleName(); //类名
        System.out.println("只有类名:"+simpleName);

        System.out.println();

        //获取类的属性
        System.out.println("===========类的属性============");
        Field[] fields = userClass.getFields();  //只能找到public属性
        for (Field field : fields) {
            System.out.println("public属性:"+field);
        }

        Field[] declaredFields = userClass.getDeclaredFields(); //找到所有属性
        for (Field declaredField : declaredFields) {
            System.out.println("所有权限的属性:"+declaredField);
        }

        System.out.println();

        //获取指定属性的值
        System.out.println("============指定属性==================");
        Field userName = userClass.getField("userName"); //获取指定public属性的值
        System.out.println("指定public属性:"+userName);

        Field userName1 = userClass.getDeclaredField("userName");//可以获取所有属性的值
        System.out.println("指定所有权限的属性" + userName1);

        System.out.println();

        //获取类的方法
        System.out.println("=============类的方法================");
        Method[] methods = userClass.getMethods(); //获取本类及父类全部的public方法
        for (Method method : methods) {
            System.out.println("本类及父类全部的public方法:"+method);
        }

        Method[] declaredMethods = userClass.getDeclaredMethods(); //获取本类中所有的方法
        for (Method declaredMethod : declaredMethods) {
            System.out.println("本类中所有的方法:"+declaredMethod);
        }

        System.out.println();

        //获取指定类的方法
        System.out.println("===============指定类的方法===============");
        Method setUserId = userClass.getMethod("setUserId", Integer.class);//获取指定public方法
        Method getUserId = userClass.getMethod("getUserId");
        System.out.println("指定public方法setUserId:"+setUserId);
        System.out.println("指定public方法getUserId:"+getUserId);

        Method sleep = userClass.getDeclaredMethod("sleep", User.class);//获取指定所有权限的方法
        Method getUserId1 = userClass.getDeclaredMethod("getUserId");
        System.out.println("指定所有权限的方法sleep:"+sleep);
        System.out.println("指定所有权限的方法getUserId1:"+getUserId1);

        System.out.println();

        //获取构造器
        System.out.println("=============类的构造器=================");
        Constructor[] constructors = userClass.getConstructors();//获取public构造器
        for (Constructor constructor : constructors) {
            System.out.println("public构造器:"+constructor);
        }

        Constructor[] declaredConstructors = userClass.getDeclaredConstructors();//获取所有权限的构造器
        for (Constructor declaredConstructor : declaredConstructors) {
            System.out.println("所有权限的构造器:"+declaredConstructor);
        }

        System.out.println();

        //获取指定的构造器(单例模式中的构造器可以不是public)
        System.out.println("============指定类的构造器================");
        Constructor constructor = userClass.getConstructor(); //获取指定public构造器
        Constructor integerConstructor = userClass.getConstructor(Integer.class);
        System.out.println("指定的public无参构造器:"+constructor);
        System.out.println("指定public构造器:"+integerConstructor);

        Constructor declaredConstructor = userClass.getDeclaredConstructor(Integer.class, String.class);
        Constructor stringDeclaredConstructor = userClass.getDeclaredConstructor(String.class);//获取指定(所有权限)构造器
        System.out.println("指定(所有权限)构造器:"+declaredConstructor);
        System.out.println("指定(所有权限)构造器:"+stringDeclaredConstructor);

2.5 动态创建对象执行方法
2.5.1 创建对象的方法
//1.通过反射创建一个对象
User user = (User) userClass.newInstance();//本质调用无参构造器

//2.通过构造器创建对象
Constructor declaredConstructor = userClass.getDeclaredConstructor(Integer.class, String.class);
User user2 = (User) declaredConstructor.newInstance(15, "xiaolu");
2.5.2 通过反射调用某个方法、属性等

调用***私有方法、私有属性***时,要暴力反射 给参数/属性赋值;

暴力反射:方法名/属性.setAccessible(true);

例:以public权限方法 和 非public权限方法为例

实体User类: setUserName public方法sleep private方法

public String getUserName() {
        return userName;
    }

public void setUserName(String userName) {
    this.userName = userName;
}

private void sleep(User user){
    System.out.println(user.getUserId()+"在睡觉");
}
  • 调用public权限方法

    //通过反射获取一个方法
    Method setUserName = userClass.getDeclaredMethod("setUserName", String.class);
    //invoke(对象,参数赋值)
    setUserName.invoke(user,"xiaoli");
    System.out.println("获取值:"+user.getUserName());
    
  • 调用非public权限的方法

    //通过反射获取一个私有方法
    Method sleep = userClass.getDeclaredMethod("sleep", User.class);
    user.setUserId(1);
    user.setUserName("xiaolu");
    
      //不能直接操作非public权限,我们需要关闭程序的安全监测,即属性或方法的setAccessible(true)
    sleep.setAccessible(true);//暴力反射
    sleep.invoke(user, user);
    //System.out.println(invoke);
    
2.6 反射操作泛型
  • ParameterizedType:表示一种参数化类型 比如Collection
  • GenericArrayType:表示一种元素类型是参数化类型或者类型变量的数组类型
  • TypeVariable:是各种类型变量的公共父接口
  • WildcardType:代表一种通配符类型表达式

Reflection3 类 : 里面test01 和 test02两方法

public void test01(Map<String, User> map, List<User> list){
    System.out.println("test01");
}

public Map<String, User> test02(){
    System.out.println("test02");
    return null;
}
2.6.1 获取泛型的参数类型
Class<Reflection3> reflection3Class = Reflection3.class;

Method method = reflection3Class.getDeclaredMethod("test01", Map.class, List.class);
Type[] genericParameterTypes = method.getGenericParameterTypes();//获得泛型的参数类型
for (Type genericParameterType : genericParameterTypes) {
    System.out.println("##"+genericParameterType);
    if (genericParameterType instanceof ParameterizedType) {
        Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments(); //强转并获取真实的参数类型
        for (Type actualTypeArgument : actualTypeArguments) {
            System.out.println(actualTypeArgument); //遍历输出
        }
    }

}
2.6.2 获取泛型返回值的的类型
Class<Reflection3> reflection3Class = Reflection3.class;
Method method1 = reflection3Class.getDeclaredMethod("test02");
Type genericReturnType = method1.getGenericReturnType();//获取泛型返回值类型
System.out.println(genericReturnType);
if (genericReturnType instanceof ParameterizedType) {
    Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments();
    for (Type actualTypeArgument : actualTypeArguments) {
        System.out.println(actualTypeArgument); //遍历返回值的参数类型
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值