20 反射机制

87 阅读4分钟

1 反射机制

一般情况下编写的代码都是固定的,也就是说无论运行多少次执行的结果都是相同的,但是在某些特殊情况下编写代码时不确定要创建什么类型的对象,也不确定要调用什么方法,这时候希望可以通过运行时传递的参数来决定,该机制叫做动态编程技术,也叫做反射机制。

反射机制简单来说就是动态创建对象并且动态调用方法的机制,在实际开发中有很多框架就是基于java反射机制实现的。

2 Class类

Class类可以描述Java应用程序中的类和接口,也就是一种数据类型,且Class类是没有构造方法的,该类的实例是由Java 虚拟机和类加载器自动构造完成的,本质上就是加载到内存中的运行时类。

获取Class对象的五种方式:

  • 使用数据类型.class的方式获取对应类型的Class对象
  • 使用引用/对象.getClass()的方式获取对应类型的Class对象
  • 使用包装类.TYPE的方式可以获取对应基本数据类型的Class对象
  • 使用Class.forName()的方式可以获取参数指定类型的Class对象
  • 使用类加载器ClassLoader的方式获取指定类型的Class对象

Class类的常用方法:

方法声明功能介绍
static class<?> forName(String className)获取参数指定类型对应的Class对象并返回
T newInstance()创建该Class对象所表示的新实例
Constructor getConstructor(Class<?>... parameterTypes)获取此Class对象所表示类型中参数指定的公共构造方法
Constructor<?>[] getConstructors()获区此Class对象所表示类型中的所有公共构造方法
Filed getDeclaredFiled(String name)获取此Class对象所表示类中参数指定的单个成员变量信息
Filed[] getDeclaredFileds()获取Class对象所表示类中所有成员变量信息

获取Class对象的具体代码:

public class ClassTest {
    public static void main(String[] args) throws ClassNotFoundException {
        Class c1=String.class;
        System.out.println("c1= "+c1);
        String str=new String("hello");
        c1=str.getClass();
        System.out.println("c1= "+c1);
        c1=Integer.TYPE;
        System.out.println("c1= "+c1);
        c1=Class.forName("java.lang.String");
        System.out.println("c1= "+c1);
        ClassLoader cl=ClassTest.class.getClassLoader();
        c1=cl.loadClass("java.lang.String");
        System.out.println("c1= "+c1);


    }
}

3 Constructor类和Field类

Constructor类主要描述获取到的构造方法信息,其常用的方法有:

方法声明功能介绍
T newInstance(Object... init)使用此Constructor对象描述的构造方法来构造Class对象代表类型的新实例
int getModifiers()获取方法的访问修饰符
String getName()获取方法的名称
Class<?>[] getParameterTypes()获取方法的所有参数类型

Field类主要描述获取到的单个成员变量信息,其常用方法有:

常用方法功能介绍
Object get(Object ob)获取参数对象ob中此Field对象所表示成员变量的数值
void set(Object ob,Object value)将参数对象ob中此Field对象所表示成员变量的数值修改为参数value的数值
void setAccessible(boolean flag)当参数传递true时,则反射对象在使用时取消Java语言访问检查
int getModifiers()获取成员变量的访问修饰符
Class<?> getType()获取成员变量的数据类型
String getName()获取成员变量的名称

Constructor类和Field类使用实例:

import java.lang.reflect.Constructor;

public class ConstructorTest {
    public static void main(String[] args) throws  Exception {
        Class c=Class.forName("Person");
        Constructor constructor=c.getConstructor();
        System.out.println("使用无参方式构造对象是:"+constructor.newInstance());
        Constructor c1=c.getConstructor(int.class,String.class);
        System.out.println("使用有参方式构造对象是:"+c1.newInstance(22,"zhangfei"));
        Constructor[] c2=c.getConstructors();
        for(Constructor t:c2){
            System.out.println("构造方法访问修饰符"+t.getModifiers());
            System.out.println("构造方法的名称"+t.getName());
            System.out.println("所有构造方法的参数是:");
            Class[] par=t.getParameterTypes();
            for(Class cla:par){
                System.out.println("cla= "+cla);
            }
        }

    }
}

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


public class FieldTest {
    public static void main(String[] args) throws Exception {
        Class c=Class.forName("Person");
        Constructor constructor=c.getConstructor(int.class,String.class);
        Object obj = constructor.newInstance(22, "zhangfei");
        Field field = c.getDeclaredField("age");
        field.setAccessible(true);
        System.out.println("获取到的成员变量值是:"+field.get(obj));
        field.set(obj,33);
        System.out.println("修改后的成员变量值是:"+field.get(obj));
        Field[] declaredFields = c.getDeclaredFields();
        for(Field f:declaredFields){
            System.out.println("成员变量名"+f.getName());
            System.out.println("成员变量修饰符"+f.getModifiers());
            System.out.println("成员变量类型"+f.getType());
        }

    }
}

4 Method类以及获取其他结构信息

Method类主要用于描述获取到的单个成员方法信息,其常用方法如下:

方法声明功能介绍
Object invoke(Object ob,Object... args)使用对象ob调用此Method对象所表示的方法,实参传递args
int getModifiers()获取方法的访问修饰符
Class<?> getReturnType()获取方法的返回值类型
String getName()获取方法的名称
Class<?>[] getParameterTypes()获取方法所有参数的类型
Class<?>[] getExceptionTypes()获取方法的异常信息

获取其他结构信息的方法有:

方法声明功能介绍
Package getPackage()获取所在包信息
Class<? Super T> getSuperClass()获取继承的父类信息
Class<?>[] getInterfaces()获取实现的所有接口
Annotion[] getAnnotions()获取注解
Type[] getGenericInterfaces()获取泛型信息

关于Mthod类以及获取其他结构信息的实例代码如下:

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

public class MethodTest  {
    public static void main(String[] args) throws Exception {
        Class c=Class.forName("Person");
        System.out.println("获取到的包信息"+c.getPackage());
        System.out.println("获取到的父类信息"+c.getSuperclass());
        Constructor constructor = c.getConstructor(int.class, String.class);
        Object obj = constructor.newInstance(26, "guanyu");
        Method method = c.getMethod("getName");
        Object invoke = method.invoke(obj);
        System.out.println("调用方法返回的结果是:"+invoke);
        Method[] methods = c.getMethods();
        for(Method m:methods){
            System.out.println("方法的访问修饰符是:"+m.getModifiers());
            System.out.println("方法的返回类型是:"+m.getReturnType());
            System.out.println("方法的名称:"+m.getName());
            System.out.println("获取到的参数类型是");
            Class<?>[] parameterTypes = m.getParameterTypes();
            for(Class cl:parameterTypes){
                System.out.println("cl: "+cl);
            }
            System.out.println("---------------------------------");
            System.out.println();

        }


    }
}