回顾Java反射

本文详细介绍了Java反射机制,包括获取类信息、构造器、方法和字段,以及如何使用反射创建对象、调用方法和修改属性。同时,结合注解展示了如何在运行时通过反射获取注解信息并实现属性注入,提供了一个简单的注解驱动功能的例子。
摘要由CSDN通过智能技术生成

Java中的反射可以在程序运行期动态的获取程序信息。

关于反射,从下面的这段话仔细揣摩。

java.lang.reflect 库中包含类 Field、Method 和 Constructor(每一个都实现了 Member 接口)。这些类型的对象由 JVM 在运行时创建,以表示未知类中的对应成员。然后,可以使用 Constructor 创建新对象,get() 和 set() 方法读取和修改与 Field 对象关联的字段,invoke() 方法调用与 Method 对象关联的方法。此外,还可以调用便利方法 getFields()、getMethods()、getConstructors() 等,以返回表示字段、方法和构造函数的对象数组。(你可以通过在 JDK 文档中查找类 Class 来了解更多信息。)因此,匿名对象的类信息可以在运行时完全确定,编译时不需要知道任何信息。

这段文字摘自github上面的 Java编程思想

依我个人而言,反射就是一种技术,从Java的角度看,这种技术可以在程序的运行期获得对象的类信息和属性信息,结合面向接口编程,相同的接口引用指向不同的对象,只要拿到对象就可以拿到类里面的成员变量和成员方法,拿到方法后可以调用方法,拿到字段后可以设置字段的值

反射代码

使用反射得到类的访问修饰符,包名,类名以及判断类的属性:

 public static void main(String[] args) {
          Class clazz = TempTest.class;
          //获取访问修饰符
          int modify = clazz.getModifiers();
          System.out.println(Modifier.toString(modify));

          //获取包名和全限定类名
          Package p = clazz.getPackage();
          String name = clazz.getName();
          System.out.println("p : "+p+" \nname : "+name);

          System.out.println("isInterface(): "+clazz.isInterface());
          System.out.println("isEnum(): "+clazz.isEnum());
          System.out.println("isAnnotation(): "+clazz.isAnnotation());
          System.out.println("isArray(): "+clazz.isArray());
}

获取构造器对象,然后使用构造器对象创建实例

	  Class<?> clazz = Class.forName("com.llm.test.TempTest");
      //使用Class对象创建对象(默认是使用的无参构造方法)
      TempTest tem = (TempTest)clazz.newInstance();

      Constructor<?>[] cons = clazz.getDeclaredConstructors();
      for (int i = 0; i < cons.length; i++) {
           System.out.println(cons[i]);
      }
      Constructor<?> constructor = clazz.getConstructor();

      Object o = constructor.newInstance();
      System.out.println(o);

使用反射操作对象的方法

public static void main(String[] args) throws Exception {
          Class clazz = Student.class;
          //利用默认空参实例化一个对象
          Student stu = (Student)clazz.newInstance();

          //公有方法
          Method m = clazz.getMethod("sleep");
          m.invoke(stu,null);

          //私有方法
          Method m2 = clazz.getDeclaredMethod("run");
          m2.setAccessible(true); //不加的话报 IllegalAccessException
          m2.invoke(stu,null);

          //静态方法
          Method m3 = clazz.getDeclaredMethod("play");
          m3.invoke(null); //静态方法不需要对象就可以调用
     }

     static class Student{
          public void sleep(){
               System.out.println("sleep() ");
          }
          private void run(){
               System.out.println("run() ");
          }
          public static void play(){
               System.out.println("static::play() ");
          }
     }

反射操作成员变量

public static void main(String[] args) throws Exception {

          Class clazz = Student.class;
          Student stu = (Student)clazz.newInstance();

          System.out.println("获取public属性,并设置值");
          Field name = clazz.getField("name");
          name.set(stu,"小李");
          System.out.println(stu);

          System.out.println("获取private属性,并设置值");
          Field age = clazz.getDeclaredField("age");
          age.setAccessible(true); // 不加这一行会报 IllegalArgumentException
          age.set(stu,20);
          System.out.println(stu);

          System.out.println("获取静态属性,并设置值");
          Field password = clazz.getField("password");
          password.set(stu,"123");
          System.out.println(Student.password);
     }

     static class Student{
          private int age;
          public String name;
          public static String password;

          @Override
          public String toString() {
               return "Student{" +
                       "age=" + age +
                       ", name='" + name + '\'' +
                       '}';
          }

          public int getAge() {
               return age;
          }

          public void setAge(int age) {
               this.age = age;
          }

          public String getName() {
               return name;
          }

          public void setName(String name) {
               this.name = name;
          }

          public static String getPassword() {
               return password;
          }

          public static void setPassword(String password) {
               Student.password = password;
          }
     }

反射配合注解使用

反射最常用的技术可能就是搭配注解来做一些功能了,使用反射,可以使标注指定注解的类实现一些特别的功能

在研究反射配置注解的操作之前,可以先看一看如何自定义注解

自定义注解里面的参数可以设置为:
(String,数组,枚举,基本数据类型,Class类型)

下面结合注解和反射,可以完成一个简单的属性注入的功能

  1. 首先定义注解MyAnnotation
@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE,ElementType.METHOD})
public @interface MyAnnotation {
    String name();
    int[] ages() default {0};
    Gender man() default Gender.MAN;
    int age();
    Class clazz() default Integer.class;
}

enum Gender{
    MAN,WOMAN
}
  1. 然后再创建一个类Student 来测试操作:
public class Student {

    private String name;
    private int age;

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @MyAnnotation(name = "张三",age = 19)
    public void print(){
        System.out.println("我的名字是: "+name+" 我的年龄是:"+age);
    }
}
  1. 最后是使用反射的操作类:
public class AnnotationTest {

    public static void main(String[] args) throws Exception {
        Class clazz = Student.class;
        //获取所有的方法
        Method[] methods = clazz.getDeclaredMethods();
        MyAnnotation annotation = null;
        for (Method m :
                methods) {
            if (m.isAnnotationPresent(MyAnnotation.class)){
                annotation = m.getAnnotation(MyAnnotation.class);
            }
        }
        if (annotation == null){
            System.err.println("没有找到目标注解:");
            return;
        }
        int age = annotation.age();
        String name = annotation.name();

        System.out.println("使用实例化开始设置值,然后调用print()方法");
        Student o = (Student)clazz.newInstance();
        o.setAge(age);
        o.setName(name);
        o.print();
    }

}

完成了上面这三步,就可以实现把注解上的参数注入到指定的对象的操作。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值