反射机制

反射机制用于动态创建对象并动态调用方法的机制。

一、Class类

  • java.lang.Class类的实例用于描述java应用程序中的类和接口,可以表示一种数据类型
  • 该类没有构造方法,该类的实例有java虚拟机和类加载器自动构造完成,是加载到内存中的运行时类,只要有一个类加载到java虚拟机内存中,就会有对应的信息(运行时类)即Class对象
  • 获取Class对象的方式
    • 使用数据类型.Class的方式获取对应类型的Class对象,数据类型包括基本数据类型和引用数据类型,所以类,接口,数组都可以(Integer.class ---- class java.lang.Ineger)
    • 使用引用/对象.getClass()的方式获取对应类型的Class对象,类/接口的实例.getClass()
    • 使用包装类.TYPE的方式可以获取对应基本数据类型的Class对象,返回的是基本数据类型(Integer.TYPE ---- int)
    • 使用Class.forName()的方式获取指定参数类型的Class对象, 必须写完类名 (Class.forName(java.lang.String)正确,而Class.forName(String)找不到类信息 ),且不能获取基本数据类型
    • 使用类加载器ClassLoader的方式获取指定类型的Class对象
 import java.util.List;

  public class ClassTest {

      public static void main(String[] args) {
          //获取Class对象的方式
          //1. 使用数据类型.class的方式可以获取对应类型的Class对象
          Class<Integer> integerClass = int.class;
          System.out.println(integerClass); //int
          Class<String> stringClass = String.class;
          System.out.println(stringClass); // class java.lang.String
          Class<Integer> integer = Integer.class;
          System.out.println(integer); //class java.lang.Integer
          Class<ClassTest> classTestClass = ClassTest.class;
          System.out.println(classTestClass);// class ClassTest
          Class<List> listClass = List.class;
          System.out.println(listClass); //interface java.util.List
          System.out.println("------------------------");
          //2.使用引用/对象.getClass()的方式可以获取对应类型的Class对象
          String str="hello";
          System.out.println(str.getClass());//class java.lang.String
          Integer num=1;
          System.out.println(num.getClass());//class java.lang.Integer
          int[] arr=new int[3];
          System.out.println(arr.getClass());//class [I
          int n=1;
          // System.out.println(n.getClass());  没有getClass()方法,不是引用数据类型
          System.out.println("------------------------");
          //3.使用包装类.TYPE的方式可以获取对应基本数据类型的Class对象
          // System.out.println(String.TYPE); String不是包装类,无法反射
          System.out.println(Integer.TYPE); //返回的是基本数据类型 int
          System.out.println(Boolean.TYPE);//boolean
          System.out.println("------------------------");
          //4.使用Class.forName()的方式来获取参数指定类型的Class对象
          Class<?> string = null;
          try {
              //string = Class.forName("String");  //ClassNotFoundException: String,必须是完整类名,格式: 包名.类名
              string=Class.forName("java.lang.String");
          } catch (ClassNotFoundException e) {
              e.printStackTrace();
          }
          System.out.println(string); //class java.lang.String
          System.out.println("------------------------");
          //5.使用类加载器ClassLoader的方式获取指定类型的Class对象,使用方式必须是已加载的类.class.getClassLoader()
          ClassLoader classLoader = String.class.getClassLoader();//null,说明String类还未加载到内存中
          classLoader=ClassTest.class.getClassLoader();//jdk.internal.loader.ClassLoaders$AppClassLoader@2437c6dc说明已加载
          System.out.println(classLoader);
          Class<?> aClass=null;
          try {
               aClass=classLoader.loadClass("java.lang.String");//通过loadClass可以获取指定类型的Class对象
          } catch (ClassNotFoundException e) {
              e.printStackTrace();
          }
          System.out.println(aClass);//class java.lang.String

      }
  }
  • 反射机制创建对象
    • 适用于读取配置文件通过反射创建对象
      方法声明 功能介绍
      static Class<?> forName(String className) 用于获取参数指定类型对应的Class对象并返回
      T newInstance() 用于创建该Class对象所表示类的新实例
    • 通过Constructor 类创建对象,java.lang.reflect.Constructor类用于描述获取到的构造方法信息
方法声明 功能介绍
Constructor getConstructor(Class<?>...
parameterTypes)
用于获取此Class对象所表示类型中参数指定的
公共构造方法
Constructor<?>[] getConstructors() 用于获取此Class对象所表示类型中所有的公共
构造方法
方法声明 功能介绍
T newInstance(Object...
initargs)
使用此Constructor对象描述的构造方法来构造Class对象代表类
型的新实例
int getModifiers() 获取方法的访问修饰符
String getName() 获取方法的名称
 import com.rf.Person;

    import java.lang.reflect.Constructor;
    import java.lang.reflect.InvocationTargetException;
    import java.util.Arrays;

    public class PersonConstructerTest {

        public static void main(String[] args) throws Exception {
            //1.使用原有方式创建无参person对象
            Person person = new Person();
            System.out.println(person);//Person{name='null', age=0}
            //2. 反射机制1 T newInstance()创建无参person对象
            Class<?> aClass = Class.forName("com.rf.Person");
            System.out.println(aClass.newInstance());//Person{name='null', age=0}, 方法已过时

            //3. 反射机制2 Constructor类创建无参person对象
            Constructor<?> constructor = aClass.getConstructor();
            System.out.println(constructor.newInstance());//Person{name='null', age=0},

            //4. 原始方式创建有参person对象
            person = new Person("张飞", 12);//Person{name='张飞', age=12}
            System.out.println(person);
            //5. 反射机制Constructor类创建有参person对象
            //获取Class对象对应的有参构造方法,传递参数传入形参Class对象
            constructor = aClass.getConstructor(String.class, int.class);
            System.out.println(constructor.newInstance("张飞", 12));//Person{name='张飞', age=12}

            //6.不知道类对象的中的构造方法形参类型,通过constructors获取所有公共构造方法
            Constructor<?>[] constructors = aClass.getConstructors();
            for (Constructor constructor1:constructors) {
                System.out.println("构造器名称"+constructor1.getName());
                System.out.println("访问修饰符"+constructor1.getModifiers());
               // System.out.println("方法参数类型"+ Arrays.toString(constructor1.getParameterTypes())); //constructor1没有重写toString方法,所以不能直接打印
                Class[] types = constructor1.getParameterTypes();
                for (Class c:types) {
                    System.out.print(c+" ");//class java.lang.String int 构造器名称com.rf.Person
                }
                System.out.println();
            }
            //后续在反射创建

        }
    }
  • Filed类获取单个成员变量信息 java.lang.reflect.Field类
方法声明 功能介绍
Field getDeclaredField(String
name)
用于获取此Class对象所表示类中参数指定的单个成员变量
信息
Field[] getDeclaredFields() 用于获取此Class对象所表示类中所有成员变量信息
    • filed常用方法
方法声明 功能介绍
Object get(Object obj) 获取参数对象obj中此Field对象所表示成员变量的数值
void set(Object obj, Object
value)
将参数对象obj中此Field对象表示成员变量的数值修改为参数
value的数值
void setAccessible(boolean
flag)
当实参传递true时,则反射对象在使用时应该取消 Java 语言访
问检查
int getModifiers() 获取成员变量的访问修饰符
Class<?> getType() 获取成员变量的数据类型
String getName() 获取成员变量的名称
  • Method类:java.lang.reflect.Method类主要用于描述获取到的单个成员方法信息
方法声明 功能介绍
Method getMethod(String name,
Class<?>... parameterTypes)
用于获取该Class对象表示类中名字为name参数为
parameterTypes的指定公共成员方法
Method[] getMethods() 用于获取该Class对象表示类中所有公共成员方法
    • method常用方法
方法声明 功能介绍
Object invoke(Object obj,
Object... args)
使用对象obj来调用此Method对象所表示的成员方法,实
参传递args
int getModifiers() 获取方法的访问修饰符
Class<?> getReturnType() 获取方法的返回值类型
String getName() 获取方法的名称
Class<?>[] getParameterTypes() 获取方法所有参数的类型
Class<?>[] getExceptionTypes() 获取方法的异常信息
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class FieldTest {
    public static void main(String[] args) throws Exception {
        Class<?> aClass = Class.forName("com.rf.Person");
        Constructor<?> constructor = aClass.getConstructor(String.class, int.class);
        Object o = constructor.newInstance("zhangfei", 20);
        //field获取单个成员变量的信息
        //1.通过Class对象获取该对象的成员变量,
        Field field = aClass.getDeclaredField("name");//成员变量名称,该成员变量的访问权限是private
        //获取任意访问权限的成员变量时必须设置成员变量的获取属性为true,否则java.lang.IllegalAccessException
        field.setAccessible(true);//证明反射机制可以获取任意访问权限的成员变量和方法
        //2.获取对应成员变量的变量值,传入的object是实例化类的对象
        System.out.println(field.get(o));//张飞
        //3.修改成员变量属性
        field.set(o,"guanyu");
        System.out.println(field.get(o));//guanyu
        //4.获取多个成员变量
        Field[] fields = aClass.getDeclaredFields();
        for (Field f:fields) {
            System.out.println("成员变量名称为"+f.getName());
            System.out.println("成员变量属性为"+f.getModifiers()); //1 表示public 2 表示private 3 表示package 4 表示protected
            System.out.println("成员变量参数为"+f.getType());
        }
        System.out.println("----------------------");
        //method获取单个成员方法的信息
        //1.通过Class对象获取该对象的成员方法,传入参数1. 方法名,2形参类型
        Method getName = aClass.getMethod("getName");
        System.out.println(getName.invoke(o));//返回姓名,guanyu
        //2.调用对应成员方法获取返回值,传入参数有1,object是实例化类的对象 2,形参
        Method setAge = aClass.getMethod("setAge", int.class);
        setAge.invoke(o,25);
        Field fage=aClass.getDeclaredField("age");
        fage.setAccessible(true);
        System.out.println(fage.get(o));//25
        //4.获取多个成员方法及属性
        Method[] methods = aClass.getMethods(); //把继承实现的所有方法和子类独有方法都打印
        for (Method method:methods) {
            System.out.println("方法名为"+method.getName());
            System.out.println("方法权限"+method.getModifiers());
            System.out.println("方法返回值类型"+method.getReturnType());
            System.out.println("方法传递形参为");
            Class<?>[] parameterTypes = method.getParameterTypes();
            for ( Class<?> p:parameterTypes) {
                System.out.print(p+"  ");
            }
            System.out.println("方法可能抛出的异常类型为");
            Class<?>[] exceptionTypes = method.getExceptionTypes();
            for ( Class<?> e:exceptionTypes) {
                System.out.print(e+"  ");
            }
        }
    }
}
  • 通过类对象获取结构信息,Class.forName("com.rf.Person");的Class对象
方法声明 功能介绍
Package getPackage() 获取所在的包信息
Class<? super T> getSuperclass() 获取继承的父类信息
Class<?>[] getInterfaces() 获取实现的所有接口
Annotation[] getAnnotations() 获取注解信息
Type[] getGenericInterfaces() 获取泛型信息
import java.lang.reflect.Constructor;

public class ConstructTest {
    public static void main(String[] args) throws Exception {
        Class<?> aClass = Class.forName("com.rf.Person");
        Constructor<?> constructor = aClass.getConstructor(String.class, int.class);
        Object o = constructor.newInstance("guanyu", 29);
        //Package getPackage() 获取所在的包信息
        System.out.println("所在的包信息"+aClass.getPackage());
        System.out.println("所在的包名"+aClass.getPackageName());
        //Class<? super T> getSuperclass() 获取继承的父类信息
        System.out.println("继承的父类信息"+aClass.getSuperclass());
        System.out.println("继承的指定的泛型父类"+aClass.getGenericSuperclass());
        //Class<?>[] getInterfaces() 获取实现的所有接口
        System.out.println("实现的所有接口"+aClass.getInterfaces()); //所有接口,未指定泛型
        //Annotation[] getAnnotations() 获取注解信息
        System.out.println("注解信息"+aClass.getAnnotations());
        //Type[] getGenericInterfaces() 获取泛型信息
        System.out.println("实现的指定的泛型接口"+aClass.getGenericInterfaces());
    }
}
posted @ 2021-03-18 15:52  forever_fate  阅读(254)  评论(0)    收藏  举报