Java反射

66 阅读6分钟

什么是反射

  • java反射就是通过Class类(反射入口),在程序运行状态下获得类的名称、package信息、所有属性、方法、注解、类型、类加载器并可对其进行操作的一种机制。

什么是Class类

  • java.lang.Class类是提供java反射机制的核心类之一,它是java程序在初始化(initialization)后存放在堆区的一个储存了对应类所有属性、方法、构造器等信息的类(class类就像它所对应的java类在镜子中的倒影一样将java类所有的信息以对象的形式储存下来,由此来提供一个接口供程序员访问方法区中的Class数据)。

反射存在的意义

  • 我们利用传统的new关键字进行类的实例化时,需要写明需要实例化的类,此时如果需要实例化的类名有所变化,我们就不得不去修改源码。如果应用反射机制,就可以靠读入配置文件进行对象的实例化,而需要实例化的类发生变化时,只需要修改配置文件即可。降低了代码的耦合,充分体现了java的动态特性。
    例子:
import java.io.FileInputStream;
import java.lang.reflect.Method;
import java.util.Properties;

public class Test {
    public static void main(String[] args) throws Exception {
        //读取配置文件
        Properties properties=new Properties();
        properties.load(new FileInputStream("src\\classInfo.property"));
        String classPath = properties.get("classPath").toString();
        String classMethod = properties.get("classMethod").toString();

        //获取类对应的Class文件
        Class clazz=Class.forName(classPath);
        //利用反射加载对象实例
        Object obj= clazz.newInstance();
    }
}

配置文件classInfo.property:

classPath=com.per.lander.Animal
classMethod=cry

获取Class类的常用方式

1)Class.forname("全类名")

条件:在全类名可知的情况下,且该类在类路径下

2)类名.class

条件:在已知类名的情况下的情况下,且该类在类路径下

3)实例名.getClass() 条件:有一个已经实例化的类

Class类的常用方法

当我们拿到一个类的class对象是就可以通过class获取其对应类的各种信息
获取类名:
1) getName:获取全类名
2) getSimpleName:获取简单类名
获取属性:
1) getField(“String fieldName”):以Field类型返回public修饰指定的属性,包含本类以及父类的
2) getDeclaredField(“String fieldName”):以Field类型返回本类中指定的属性
3) getFields():以Field[]返回所有public修饰的属性,包含本类以及父类的
4) getDeclaredFields():以Field[]返回本类中所有方法
获取方法:
1) getMethod(“String methodName”,方法参数列表的class对象):以Method类型返回指定public修饰的方法,包含本类以及父类的
2) getDeclaredMethod(“String methodName”,方法参数列表的class对象):以Method类型返回本类中指定的方法(包括非public)
3) getMethods():以Method[]返回所有public修饰的方法,包含本类以及父类的
4) getDeclaredMethods():以Method[]返回本类中所有方法
获取构造器:
1) getConstructor(“参数列表的class对象”,构造器参数列表的class对象):以Constructor返回本类中public修饰的构造器
2) getDeclaredConstructor(“参数列表的class对象”,构造器参数列表的class对象):以Constructor返回本类中指定的构造器
3) getConstructors():以Constructor[]返回本类中所有public修饰的构造器
4) getDeclaredConstructors():以Constructor[]返回本类中所有的构造器
获取其他:
1) getPackage():以Package形式返回包信息
2)getSuperClass():以Class形式返回父类信息
3)getInterfaces():以Class[]形式返回接口信息
4)getAnnotations():以Annotation[]形式返回注解信息

通过反射创建实例对象

使用类的public无参构造器创建对象:
步骤:
1)获取类的class对象
2)调用class的newInstance()方法即可
示例代码:

        Class clazz2=Class.forName("com.per.lander.Animal"); //获取类的Class对象
        Object o=clazz2.newInstance(); //利用newInstance()方法获取类的Class对象

使用类的public有参构造函数创建对象:
步骤:
1)获取类的Class对象
2)通过Class对象的getConstructor获取class对象对应的类的构造器对象
3)通过获得的构造器对象的newInstance(''参数列表的class对象'')方法创建有参构造器的类对象
示例代码:

        Class clazz3=Class.forName("com.per.lander.Animal");//获取类的Class对象
        //利用类的class对象获取类的类的有参构造器
        Constructor<?> constructor=clazz3.getConstructor(String.class);//获取类的有参构造器(参数列表中传入和有参构造器对应的参数的class对象)
        Object o1=constructor.newInstance("mammal");//利用有参构造器创建类的实例对象参数列表中传入实参

使用类的private有参构造函数创建对象:
步骤:
1)获取类的Class对象
2)通过Class对象的getDeclearConstructor获取class对象对应的类的私有构造器对象
3)调用构造器对象的setAccessible(true)使反射可以访问私有构造器
4)通过获得的构造器对象的newInstance(''参数列表的class对象'')方法创建有参构造器的类对象
示例代码:

        Class clazz4=Class.forName("com.per.lander.Animal");//获取类的class对象
        Constructor<?> constructorPte=clazz4.getDeclaredConstructor(int.class);//获取类的有参构造器(参数列表中传入和有参构造器对应的参数的class对象)
        constructorPte.setAccessible(true);//爆破使反射可以访问private构造器
        Object o2=constructorPte.newInstance(32);//利用有参构造器创建类的实例对象参数列表中传入实

其他反射相关的类及其方法

java.lang.reflect.Field类
1)getModifiers():以int形式返回属性修饰符
2)getType():以Class形式返回类型
3)getName():返回属性名
4)set(Object 属性所属的类实例对象名,value)
5)get(Object 属性所属的类实例对象名)
通过反射访问对象属性:

        Class clazz5 =Class.forName("com.per.lander.Animal");//创建类的Class对象
        Object o3=clazz5.newInstance();//通过Class对象创建类的实例对象
//当属性为public时
        Field field=clazz5.getDeclaredField("name");//通过Class对象获得类的指定Public的Field对象
        field.set(o,“Dog”);//通过field对象的set方法设置属性值
        field.get(o);//通过Field对象的get方法获得属性值
//当属性为private时
        Field field=clazz5.getField("weight");//通过Class对象获得类的指定Private的Field对象
        field.setAccessible(true);//将私有Field设置为反射可操作
        field.set(o,53);//通过field对象的set方法设置属性值
        field.get(o);//通过Field对象的get方法获得属性值
//当属性为static时可以不将类实例化直接操作属性
        Field field=clazz5.getDeclaredField("name");//通过Class对象获得类的指定Static的Field对象
        field.set(null,"StaticN")//设置static属性的值
        field.get(null)//获取static属性的值

java.lang.reflect.Method类
1)getModifiers():以int形式返回修饰符
2)getReturnType():以Class形式获取返回值
3)getName():返回方法名
4)getParameterTypes():以Class[]返回参数类型数组
4)invoke(Object 属性所属的类实例对象名,参数列表):以Class[]返回参数类型数组
通过反射访问对象方法:

Class clazz6 =Class.forName("com.per.lander.Animal");//创建类的Class对象
Object o4=clazz6.newInstance();//通过Class对象创建类的实例对象
//当方法为public且无形参
        Method method1=clazz6.getMethod("cry");//利用class对象获取method对象
        method1.invoke(o4);//执行方法
//当方法为private且有参数时
        Method method1=clazz6.getDeclaredMethod("run",String.class);//利用class对象获取method对象
        method1.setAccessible(true);//将私有method设置为反射可操作
        method1.invoke(o4,"fly");//执行方法
//当方法为static方法时可不用将方法所属的类实例化(此处run方法为static方法)
        Object reVal=method1.invoke(null,"fly");//执行static方法
        Object reVal=method1.invoke(null,"fly");//返回值为一个运行对象为实际返回类型的Object对象
  

java.lang.reflect.Constructor类
1)getModifiers:以int形式返回修饰符
2)getName:返回构造器名(全类名)
3)getParameterTypes:以Class[]返回参数类型数组