Java反射

反射的概念:

  • 作用:在Java中,如果想要在除了编译器之外的运行期也能够检查类,接口,变量以及方法的信息就可以通过反射动态的进行获取。并且在Java大量的流行框架中例如Spring,都是以反射为基础来进行构建。所以反射的地位在Java中非常重要。
反射的一个demo(通过反射获取类对象中的方法集)
   //定一一个类对象
   public class Cluber {

     public void join() {

     }

     public void exit(){

     }
   }
   
  //demo
  public class BootStrapDemo {

    public static void main(String[] args) {
        Method[] methods = Cluber.class.getDeclaredMethods();

        List methodNames = Stream.of(methods).map(Method::getName).collect(Collectors.toList());
        System.out.println(methodNames);
    }
}

 //结果
 [exit, join]

反射的具体使用:

通过反射主要可以如下的类的信息:

  • Class对象
  • 类名
  • 修饰符
  • 包信息
  • 父类
  • 实现的接口
  • 构造器
  • 方法
  • 变量
  • 注解

1. 简单介绍Class类以及你能从Class类中获取哪些信息

        //获取类对象
        Class cluberClass = Cluber.class;

        try {
            Class cluberClass2 = Class.forName("Java_Reflection.demo.Cluber");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
        }

        //获取类名
        String className = cluberClass.getName();
         
        //获取类的修饰符 返回的是整型标识符
        int modifiers = cluberClass.getModifiers();
        //通过Modifier类来检测具体的修饰符
        boolean isPublic = Modifier.isPublic(modifiers);
        
        //通过类对象获取包信息
        Package aPackage = cluberClass.getPackage();
        aPackage.getName();

        //获取父类
        Class superclass = cluberClass.getSuperclass();
       
        //获取实现的接口
        Class[] interfaces = cluberClass.getInterfaces();

        //获取构造器
        Constructor[] constructors = cluberClass.getConstructors();

        //获取所有方法
        Method[] methods1 = cluberClass.getMethods();

        //获取所有变量
        Field[] fields = cluberClass.getFields();

        //获取所有注解
        Annotation[] annotations = cluberClass.getAnnotations();
    }

2. 反射-构造器详解

  • 通过Java中的反射可以获取类的构造器并且在运行期初始化对象。相关类java.reflect.Constructor
  1. 通过getConstructor()方法可以获取类的所有public构造方法,每一个构造方法都对应一个Constructor对象

    Constructor[] constructors = cluberClass.getConstructors();

  2. 如果已知精确的构造器参数类型,可以通过参数类型直接获取特定的构造方法对象。并且如果没有该构造方法会抛出NoSuchMethodException的异常。

         try {
             cluberClass.getConstructor(new Class[]{String.class,Integer.class});
         } catch (NoSuchMethodException e) {
             e.printStackTrace();
         }
    
  3. 获取构造器中的参数(通过Constructor对象可以获取构造函数的参数类型)

    Class[] parameterTypes = constructor.getParameterTypes();

  4. 通过构造器对象示例化对象

        try {
              Cluber cluber = constructor.newInstance("test", 16);
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
         }
    

3. 反射-变量

  • 通过反射可以在运行期获取到类的成员变量并且对它们进行set/get操作。相关类==java.lang.reflect.Field
    1.获取所有的可访问属性(此种方式可以获取所有可以访问的变量的集合)
    Field[] fields = Cluber.class.getFields();
  1. 获取特定变量
        Field field = null;
        Field count = null;
        //获取特定属性
        try {
            field = Cluber.class.getField("name");
            count = Cluber.class.getField("count");
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
  1. 获取属性名

     `System.out.println(field.getName());`
    
  2. 变量类型

     `Class type = field.getType();`
    
  3. 获取或者设置属性值(注意如果是设置static,则不用指定对象)

    //get/set属性
    Cluber cluber = new Cluber();
    try {
          field.set(cluber, "zjf");
          count.set(null, 100);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

    System.out.println(cluber.getName() + "===" + Cluber.count);

4. 反射-方法

  • 通过反射可以在运行期获取类的方法对象并且可以调用该方法。相关类java.lang.reflect.Method

1.获取所有Method对象

Method[] methods = cluberClass.getMethods();

2.获取指定Method(需要指定方法名和参数类型如果没有则为null)

    //获取指定方法
    try {
        test = cluberClass.getMethod("test", new Class[]{String.class});
    } catch (NoSuchMethodException e) {
        e.printStackTrace();
    }

    try {
         exit = cluberClass.getMethod("exit", null);
    } catch (NoSuchMethodException e) {
    }

3.获取方法参数和返回值

    Class[] parameterTypes = test.getParameterTypes();

    Class returnType = test.getReturnType();

4.调用方法(如果是非静态方法需要指定调用的对象和参数,如果是静态方法则调用对象是null)

    Cluber cluber = new Cluber();
    try {
        test.invoke(cluber, "zjf");
        exit.invoke(cluber,null);
        staticMethod.invoke(null);
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    } catch (InvocationTargetException e) {
        e.printStackTrace();
    }

5. 反射-私有变量和方法

  • 通过反射也可以检查私有方法和私有变量
       Class cluberClass = Cluber.class;

        //获取所有的方法包括私有方法
        Method[] declaredMethods = cluberClass.getDeclaredMethods();
        System.out.println(Arrays.toString(declaredMethods));

        try {
            Field address = cluberClass.getDeclaredField("address");
            Method init = cluberClass.getDeclaredMethod("init");
            
            //需要设置setAccessible 为true 才能对private属性和方法进行操作
            init.setAccessible(true);
            address.setAccessible(true);
            Cluber cluber = new Cluber();
            init.invoke(cluber);

            String addr = (String) address.get(cluber);
            System.out.println("===private Field===" + address.getName() + "===values===" + addr);
        } catch (Exception e) {
            e.printStackTrace();
        }

5. 反射-注解

  • 通过反射在运行时获取类的注解的信息,需要注意的是getDeclaredAnnotations得到的是当前成员所有的注释,不包括继承的。而getAnnotations得到的是包括继承的所有注释。
        Class cluberClass = Cluber.class;
        //获取类的所有注解
        Annotation[] annotations = cluberClass.getAnnotations();
        System.out.println(Arrays.toString(annotations));

        //获取指定类的注解
        MyAnnotation myAnnotation = cluberClass.getAnnotation(MyAnnotation.class);
        //获取注解的属性
        int age = myAnnotation.age();
        String name = myAnnotation.name();
        System.out.println("name is " + name + ",age is " + age);


        try {
            //获取方法的注解
            //获取参数的注解  首先需要获取指定方法的对象 通过方法来获取参数的注解信息
            Method test = cluberClass.getMethod("test", new Class[]{String.class});

            Annotation[] declaredAnnotations = test.getDeclaredAnnotations();
            System.out.println(Arrays.toString(declaredAnnotations));
            //获取方法的指定注解
            MyAnnotation declaredAnnotation = cluberClass.getDeclaredAnnotation(MyAnnotation.class);
            System.out.println("方法的注解myAnnotation,属性 name is " + declaredAnnotation.name() + ",age is " + declaredAnnotation.age());

            //参数的注解返回的是一个二维数组以此来表示多个参数可能有多个注解的情况
            Annotation[][] parameterAnnotations = test.getParameterAnnotations();

            Class[] parameterTypes = test.getParameterTypes();

            for (Annotation[] annos : parameterAnnotations) {

                for (Annotation annotation : annos) {
                    if (annotation instanceof MyAnnotation) {
                        System.out.println("方法参数的注解myAnnotation,属性 name is " + declaredAnnotation.name() + ",age is " + declaredAnnotation.age());
                    }
                }
            }

        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }


        //获取属性的注解
        Field field = null;
        try {
            field = cluberClass.getField("name");
            Annotation[] fieldDeclaredAnnotations = field.getDeclaredAnnotations();
            for (Annotation annotation : fieldDeclaredAnnotations) {
                if (annotation instanceof MyAnnotation) {
                    System.out.println("属性的注解myAnnotation,属性 name is " + ((MyAnnotation) annotation).name() + ",age is " + ((MyAnnotation) annotation).age());
                }
            }

        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }

5. 反射-泛型

  • 通过反射可以在运行期动态的获取泛型参数的信息,泛型方法的返回值的信息和泛型参数的信息。

ParameterizedType表示的是参数化类型对象

  1. 定义一个泛型类
  public class GenericDemo {

    public List list;

    public List getStringList(List param) {
        return null;
    }
}
  1. 通过反射获取泛型的相关信息
        Class genericDemoClass = GenericDemo.class;
        try {
            //1.获取泛型方法的返回值的参数化类型信息
            Method getStringList = genericDemoClass.getMethod("getStringList", new Class[]{List.class});
            //获取泛型返回值
            Type genericReturnType = getStringList.getGenericReturnType();

            System.out.println(genericReturnType.getTypeName());

            if (genericReturnType instanceof ParameterizedType) {
                ParameterizedType parameterizedType = (ParameterizedType) genericReturnType;
                //获取返回值的类型参数
                Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
                System.out.println("泛型参数类型: " + Arrays.toString(actualTypeArguments));
            }


            //2.获取方法泛型参数的类型信息
            //获取方法的所有的泛型参数类型
            Type[] genericParameterTypes = getStringList.getGenericParameterTypes();
            for (Type type : genericParameterTypes) {
                if (type instanceof ParameterizedType) {
                    Type[] actualTypeArguments = ((ParameterizedType) type).getActualTypeArguments();
                    System.out.println("方法的泛型参数的类型信息: " + Arrays.toString(actualTypeArguments));
                }
            }

            //获取泛型变量类型
            Field list = genericDemoClass.getField("list");
            Type genericType = list.getGenericType();
            if (genericType instanceof ParameterizedType) {
                Type[] actualTypeArguments = ((ParameterizedType) genericType).getActualTypeArguments();
                System.out.println("泛型变量的类型信息:" + Arrays.toString(actualTypeArguments));
            }
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }

6. 反射-数组

  • 通过反射可以动态地创建数组、操作数组并且也可以获取数组的类型对象信息。核心对象是java.lang.reflect.Array
  
    public static Class getClass(String className) {
        if ("int".equals(className)) {
            return int.class;
        }
        if ("long".equals(className)) {
            return long.class;
        }

        if ("short".equals(className)) {
            return short.class;
        }

        try {
            return Class.forName(className);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        return null;
    }

    public static void main(String[] args) {

        //1 通过反射来创建一个数组
        int[] intArray = (int[]) Array.newInstance(int.class, 10);

        //2.通过反射访问数组
        for (int i = 0; i < intArray.length; i++) {
            Array.set(intArray, i, i);
        }

        System.out.println(Arrays.toString(intArray));
        int first = (int) Array.get(intArray, 0);
        System.out.println("第一个元素为: " + first);

        //获取数组的Class对象
        //不通过反射
        Class aClass = String[].class;

        //通过反射
        try {
            //原生数据类型的获取
            Class intClass = Class.forName("[I");
            Class stringArrayClass = Class.forName("[Ljava.lang.String;");

            //通过反射获取数组类型对象
            Class aClass1 = getClass("int");
            Class arrayClassType = Array.newInstance(aClass1, 0).getClass();

            //验证是否为数组类型对象
            boolean array = arrayClassType.isArray();
            System.out.println(array == true ? "是数组类型" : "不是数组类型对象");


            //获取数组的成员类型
            Class aClass2 = intArray.getClass();
            Class componentType = aClass2.getComponentType();
            System.out.println("数组成员类型:" + componentType);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

你可能感兴趣的:(Java,Java)