反射

反射:将类的各个组成部分封装为其他对象,这就是反射,或者说当加载完类之后,在堆内存的方法区就产生 一个Class类型的对象,(一个类只有一个Class对象),这个对象就包含了完整类型的结构信息,我们可以通过这个对象看到类的结构,这个对象就像一面镜子,通过镜子看到类的结构。
优点:1、可以在程序运行过程中,操作这些对象
2、可以解耦,提高程序的可扩展性。

类在程序中的三个阶段:
在这里插入图片描述

  • 获取Class对象的方式:
    /*多用于配置文件,将类名定义在配置文件中,读取文件,加载类/
    1、class.forName(“全限定类名”):将字节码加载进内存,返回class对象
    /**适用于参数的传递/
    2、类名.class:通过类名的属性class获取
    /*适用于对象获取字节码方式/
    3、对象.getClass(): getClass()方法在Object类中定义着。
    结论:同一个字节码(
    .class)在一次程序运行过程中,知会被加载一次,不论通过哪种方式获取的class对象都是同一个。
 @Test
    public void test() {
        try {
            //全限定类名获取class对象
            Class<?> c1 = Class.forName("com.dg.reflect.Person");
            //类名.class获取class对象
            Class<Person> c2 = Person.class;
            Person person = new Person();
            //对象.getClass获取Class对象
            Class<? extends Person> c3 = person.getClass();
            
            System.out.println(c1.hashCode());
            System.out.println(c2.hashCode());
            System.out.println(c3.hashCode());
        } catch (ClassNotFoundException e) {

        }
    }

分别打印三个Class对象的hash值,可见是一致的,这就说明一个类有且只有一个Class对象。

1837760739
1837760739
1837760739

我们获取了Class对象,就可以拿到封装在Class对象中的其他对象信息,如构造函数、成员变量、成员方法,下面一一举例说明。
1、Class对象获取成员变量
Field[ ] getFields(); 获取所有public修饰的成员变量。
Field[ ] getFidld(String name) 根据指定名称获取public修饰的成员变量。

Field[ ] getDeclaredFields(); 获取所有成员变量,包括私有。
Field getDeclaredField(String name); 根据名称获取成员变量

2、 Class对象获取构造方法
Constructor<?>[] getConstructors()
Constructor getConstructor(类<?>… parameterTypes)

Constructor getDeclaredConstructor(类<?>… parameterTypes)
Constructor<?>[] getDeclaredConstructors()
3、Class对象获取成员方法
// 获取public修饰的方法
Method[ ] getMethods();
//根据名称和参数类型获取public指定的方法
Method getMethod(String name,类<?> …parameterTypes)
//获取所有的成员方法
Method[ ] getDeclareMethods();
//根据名称和参数类型获取所有的方法
Method getDeclareMethod(String name,类<?>… parameterTypes);
4、 newInstance(); //获取对象实例
5、 String getName();//获取全类名
6、 Class<?>[] getInterfaces();//获取当前Class对象的接口 (本质调用了类的无参构造)
7、 ClassLoader getClassLoader();//获取Class对象的类加载器
8、getDeclaredAnnotation(Class annotationClass) //获取注解信息
9、RequestMapping annotation = c1.getAnnotation(RequestMapping.class);
annotation.value();

 @Test
    public void testGetNode() {

        //类名.class获取class对象
        Class<Person> c2 = Person.class;
        
        try {
            //获取对象实例
            Person person = c2.newInstance();
            //获取public修饰的变量
            Field[] fields = c2.getFields();
            for (int i = 0; i < fields.length; i++) {
                System.out.println("public修饰的属性:" + fields[i]);
            }
            //根据名称获取变量
            Field age = c2.getField("a");
            System.out.println("根据名称获取:" + age);

            System.out.println("...............................................");
            //获取所有的成员变量
            Field[] declaredFields = c2.getDeclaredFields();
            for (int i = 0; i < declaredFields.length; i++) {
                System.out.println(declaredFields[i]);
            }
            //根据名称获取私有变量
            Field a = c2.getDeclaredField("age");
            System.out.println("私有属性:" + a);

            System.out.println("...................................................");

            //获取public修饰的成员方法
            Method[] methods = c2.getMethods();
            for (int i = 0; i < methods.length; i++) {
                System.out.println(methods[i]);
            }
            //根据名称获取成员方法 无参
            Method getName = c2.getMethod("getName");
            //有参
            Method age1 = c2.getMethod("setName", String.class);
            System.out.println("根据名称获取:" + age1);
            System.out.println("...............................");
            //获取所有的成员方法
            Method[] declaredMethods = c2.getDeclaredMethods();
            for (int i = 0; i < declaredMethods.length; i++) {
                System.out.println(declaredMethods[i]);
            }
            //根据名称获取私有成员方法
            Method show = c2.getDeclaredMethod("show");
            System.out.println("私用方法:"+show);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }

    }

既然通过Class对象获取了成员变量、成员方法、构造函数,那么反射可不仅仅如此,能获取属性就能设置,这才是我们所关心的问题,我们逐个说明如何设置属性。
首先新建一个Person类

package com.dg.reflect;

public class Person {
  
    private String name;
    private int age;

    public String a;
    protected String b;
    String c;
    private String d;


    public Person() {
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

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

    private void show() {
        System.out.println("测试方法");
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", a='" + a + '\'' +
                ", b='" + b + '\'' +
                ", c='" + c + '\'' +
                ", d='" + d + '\'' +
                '}';
    }


    public void eat() {
        System.out.println("eat...");
    }

    public void eat(String food) {
        System.out.println("eat..." + food);
    }
}

需要说明的是,私用成员变量获取值的时候,必须加上setAccessible(true);否则会直接报异常。

  @Test
    public void test3() {

        //类名.class获取class对象
        Class<Person> c2 = Person.class;
        try {
            //根据指定名称获取成员变量
            Field field = c2.getField("a");
            Person p = new Person();
            //
            Object o = field.get(p);
            System.out.println("未赋值之前 a:" + o);
            /**给指定变量赋值
             *  Object obj, 反射所需要执行的 对象
             *  Object value 对象中的成员变量值
             */
            field.set(p, "helloworld");
            System.out.println("赋值之后 a:" + p.getA());

            System.out.println("........................");

            //根据指定名称获取私有成员变量
            Field d = c2.getDeclaredField("d");
            **//暴力反射 true:关闭检查,当 关闭之后能大大提高反射创建对象的性能。**
            d.setAccessible(true);
            Object value2 = d.get(p);
            System.out.println(value2);
            d.set(p, "hai");
            System.out.println("私有成员变量:" + p.getD());

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

    }

同样获取成员方法也是如此。

    @Test
    public void test4() {
        //全限定类名获取class对象
        try {
            Class<?> c1 = Class.forName("com.dg.reflect.Person");
            //根据名称获取public修饰的方法
            Method method = c1.getMethod("setName", String.class);
            Person person = new Person();
            //给定方法 反射传参数
            method.invoke(person, "helloworld");
            System.out.println("..................................");

            //根据方法名称获取private修饰的方法
            Method method2 = c1.getDeclaredMethod("setShow", String.class);
              //暴力反射 如果不设置,直接报异常
            method2.setAccessible(true);
            //给指定方法 反射传递参数
            method2.invoke(person, "陈晨");
            Method privateMethod = c1.getDeclaredMethod("getShow");

            System.out.println("setName方法:"+person.getName());
            System.out.println("show方法:"+person);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }

    }

反射是java中灵魂的技术,很多框架底层都使用到了反射,只是反射会一点点性能上损失,因为jvm在运行时动态的去获取这些对象。只要不是大量业务,反射还是可以使用的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值