反射

Posted 蓝雨晴天

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了反射相关的知识,希望对你有一定的参考价值。

1、什么是反射

反射是指在程序的运行状态中,可以获取任意一个类的全部信息(包括类名、类的字段、类的属性、类的方法等等),可以获取任意一个对象所属的类,并且可以调用对象的任意方法和属性。

简单来说,反射就是一开始我们并不知道要初始化的类对象是什么,所以就不能通过正常的new的方式来实例化一个对象,需要通过反射的方式加载指定的Class文件,然后再实例化对象,进行其他操作。

2、Person类

示例程序,方便后续举例说明。

package com.zhangh.reflect;

public class Person {

    public String name = "zhangh";

    protected Integer age = 1;

    private Byte sex = (byte) 1;

    Boolean isMarriage = true;

    public Person() {
    }

    public Person(String name, Integer age, Byte sex, Boolean isMarriage) {
        this.name = name;
        this.age = age;
        this.sex = sex;
        this.isMarriage = isMarriage;
    }

    public String getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }

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

    public Byte getSex() {
        return sex;
    }

    public void setSex(Byte sex) {
        this.sex = sex;
    }

    public Boolean getMarriage() {
        return isMarriage;
    }

    public void setMarriage(Boolean marriage) {
        isMarriage = marriage;
    }

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

3、Class文件

class文件包含了一个类的所有的信息,如下图所示:

4、获取Class对象的方式

  • 类名.class

    Class personClazz = Person.class;

  • Class.forName

    Class personClazz = Class.forName("com.zhangh.Person");

  • getClass方式

    Person person = new Person(); Class personClazz = person.getClass();

5、反射关键类图

6、类加载区别

7、生成对象的步骤

8、简单示例

package com.zhangh.reflect;

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

public class Test {
    public static void main(String[] args) throws Exception{
        // 获取Class类对象
        Class personClazz = Class.forName("com.zhangh.reflect.Person");
        // 获取无参构造方法
        Constructor constructor1 = personClazz.getConstructor();
        // 通过无参构造方法创建对象
        Object person1 = constructor1.newInstance();
        // 获取age属性
        Field field = personClazz.getDeclaredField("age");
        // 设置person对象的age属性
        field.set(person1,25);
        // 获取setName方法
        Method method = personClazz.getDeclaredMethod("setName",String.class);
        // 执行setName方法,为person1对象设置名称为test
        method.invoke(person1,"test");
        System.out.println(person1);

        // 也可以通过有参构造方法创建对象
        Constructor constructor2 = personClazz.getConstructor(String.class,Integer.class,Byte.class,Boolean.class);
        Object person2 = constructor2.newInstance("zhangsan",30,(byte)1,true);
        System.out.println(person2);
    }
}

9、反射中的常用方法

方法名 描述 代码示例
getName 获取类名(包含全路径) String name = personClazz.getName();
getSimpleName 获取类名(不包含路径) String simpleName = personClazz.getSimpleName();
getPackage 获取包名 String package = personClazz.getPackage();
getSuperClass 获取父类 Class superClass = personClazz.getSuperClass();
getInterfaces 获取所有父接口 Class[] interfaces = personClazz.getInterfaces();
newInstance 调用默认的无参构造,创建对象 Object obj = personClazz.newInstance();
getFields 获取所有的公有属性,包括继承的父类属性 Field[] fields = personClazz.getFields();
getField 获取指定的某个公有属性,包括继承的父类属性 Field field = personClazz.getField("age");
getDeclareFields 获取所有的属性,包括私有属性,但是不能获取到父类的属性 Field[] fields = personClazz.getDeclareFields();
getDeclareField 获取指定的某个属性,包括私有属性,但是不能获取到父类的属性 Field field = personClazz.getDeclareField("age");

10、反射的应用

反射的出现,大大增强了程序的灵活性和扩展性,在很多场景都使用到了反射,尤其是很多框架里,以下简单举几个例子。

  • Servlet接口

    每个Web应用程序都有自己的配置文件web.xml,可以在其中配置Servlet的实现类,包含名称、类路径、url等信息。Web容器会读取web.xml中配置的servlet信息,根据类路径,加载对应的Class文件到jvm中。

  • Spring

    Spring的很多地方都使用到了反射技术,例如通过xml配置的方式来装载bean。

11、BeanUtils工具类

通过反射来封装一个工具类,将一个对象的属性的值,赋值给另外一个属性名相同的对象,可以理解为是对象的拷贝。

package com.zhangh.reflect;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

public class BeanUtils {
    public static void convertor(Object originObj, Object targetObj) throws Throwable{
        // 第一步,获得class对象
        Class orginClazz = originObj.getClass();
        Class targetClazz = targetObj.getClass();

        // 第二步,获得Field
        Field[] orginFields =  orginClazz.getDeclaredFields();
        Field[] targetFields =  targetClazz.getDeclaredFields();

        Map<String,Field> orginMap = new HashMap<>();
        Map<String,Field> targetMap = new HashMap<>();
        for(Field field : orginFields){
            field.setAccessible(true);
            orginMap.put(field.getName(),field);
        }
        for(Field field : targetFields){
            field.setAccessible(true);
            targetMap.put(field.getName(),field);
        }
        // 第三步,赋值
        for(String key : orginMap.keySet()){
            if(targetMap.containsKey(key)){
                targetMap.get(key).set(targetObj,orginMap.get(key).get(originObj));
            }
        }

/*        // 第三步:赋值,能实现同样的效果,但是多次循环,效率比较低
        for (Field originField : orginFields) {
            for (Field targetField : targetFields) {
                if (originField.getName().equals(targetField.getName())) {
                    originField.setAccessible(true);
                    targetField.setAccessible(true);
                    targetField.set(targetObj, originField.get(originObj));
                }
            }
        }*/
    }

    public static void main(String[] args) throws Throwable{
        Person person = new Person("zhangh", 10, (byte)1, true);

        Person person1 = new Person();

        convertor(person, person1);

        System.out.println("person:" + person);

        System.out.println("person1:" + person1);

    }
}

以上是关于反射的主要内容,如果未能解决你的问题,请参考以下文章

OpenGL片段着色器不照亮场景

将 OpenGL 片段着色器设置为仅通过漫反射减少 vec4 色点的 RGB 值,而不是 alpha

反射机制

反射机制入门

反射机制入门

反射机制入门