Java-反射

反射概念

反射是框架的灵魂。
反射:将类的各个组成部分封装成为其他对象,就是反射机制。
下图是java从写到运行进过的阶段,第一个阶段当你写完后就会自动编译,然后通过类加载器变为类对象(java里面一起皆是对象)。
第二阶段是将字节码文件加载到内存中,内存Class类是用来描述字节码文件的类。
所以我们可以通过Class里面的方法直接来创建对象和调用类的方法而不用new对象。
反射可以在程序的运行中操作对象。
在这里插入图片描述

获取Class对象的方式(字节码对象)

  • Class.forName()方式
    Class.forName(“全类名”)将字节码文件加载进内存,返回类对象。(因为此时还还字节码未加载入内存生成类对象)。
    多用于配置文件,将类名定义在配置文件中,读取文件,加载类。

  • 类名.class
    通过类名的属性进行获取。
    多用于参数的传递

  • 对象.getClass()
    因为这个.getClass()是封装在Object类里面的,而我们知道所有的类的都继承自Object。
    多用于对象的字节码获取方式。

public class Reflect_Demo1 {
    public static void main(String[] args) throws Exception {

        //方式1Class的静态方法forName
        Class clas1 = Class.forName("reflect.Person");
        System.out.println(clas1);
        //方式2类名.class
        Class clas2 = Person.class;
        System.out.println(clas2);
        //方式3对象.
        Person person=new Person();
        Class clas3 = person.getClass();
        System.out.println(clas3);

        //判断三个获取的class对象
        System.out.println(clas1==clas2);
        System.out.println(clas2==clas3);
    }
}

输出结果
结论:同一个.class生成的class对象是同一个对象,在一次程序的加载中只会被加载一次,不论通过哪一种方式获取的class对象都是同一个。*

Class对象用处

从我们文章开始那张图中就可以得到答案

  • 1:获取成员方法 Method[] getDeclaredMethods() 、Method[] getMethods()
  • 2:获取构造方法 Constructor<?>[] getConstructors() 、Constructor<?>[] getDeclaredConstructors() 、Constructor getConstructor(类<?>… parameterTypes)
  • 3:获取成员变量 Field[] getFields() 、Field[] getDeclaredFields() 、Field getDeclaredField(String name) 、Field getField(String name)
  • 4:获取类名 String getName()
  • 5:获取包名 软件包 getPackage()
    上面那些都是对应的带Declared可以获取所有,不带Declared只能获取public修饰的。
    在这里插入图片描述
public static void main(String[] args) {
        Class<Person> personClass = Person.class;
        Field[] fields = personClass.getFields();
        for (Field field: fields ) {
            System.out.println(field);
        }
    }

在这里插入图片描述
在这里插入图片描述
**这里这个getFields只能获取public修饰的成员变量。**其他还有别的方法属性请大家到Class类中查看。

获取到成员变量

获取到成员变量、成员方法、、、后可以用来干嘛?

  • 获取到成员变量
    可以设置和获取成员变量的值
    具体方法到Filed类中查看。
    Object get(Object obj)
    返回该所表示的字段的值 Field ,指定的对象上。
    这里参数是你需要的到成员变量所属的对象。
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
        Class<Person> personClass = Person.class;
        Field name = personClass.getField("name");
        Person person=new Person();
        //得到person的name,因为String默认值为null
        Object value = name.get(person);
        System.out.println(value);
        //设置person对象的name
        name.set(person,"张三");
        System.out.println(person.name);
    }

在这里插入图片描述
对于加了Declared的personClass.getDeclaredFields()方法这种是得到所有的成员变量(包括私有,保护),但是当要设置和得到时候那就要用暴力反射,忽略访问权限修饰符的安全检查。

Field age = personClass.getDeclaredField("id");
        age.setAccessible(true);//暴力反射,这样可以设计和得到私有成员
        age.set(person,10);
        System.out.println(person.getId());

加粗样式

获取到构造方法

获取构造方法 Constructor<?>[] getConstructors() 、Constructor<?>[] getDeclaredConstructors()
构造Constructor是用来创建对象的。

Class<Person> personClass = Person.class;
        Constructor<Person> constructor = personClass.getConstructor(String.class,int.class);
        Person person = constructor.newInstance("张三", 10);
        System.out.println(person);

在这里插入图片描述
上面那个方法也可以用空参构造方法创建对象,但是当需要使用空参构造方法时Class类里面的new会更加便捷。

Class<Person> personClass = Person.class;
        Constructor<Person> constructor = personClass.getConstructor();

        Person person1 = constructor.newInstance();
        System.out.println(person1);

        Person person2 = personClass.newInstance();
        System.out.println(person2);

Constructor constructor = personClass.getConstructor();注意这行代码getConstructor()你要创建用无参数的构造方法创建对象那个这个getConstructor()也要无参数。
在这里插入图片描述
构造器方法里面也有暴力反射,有setAccesss方法,当需要用到带Declared的方法时可以用到,这里和上面获取成员变量用法相同,大家可以自行查阅。

获取成员方法

用来的到Method对象执行成员方法。这里通过方法名和参数类型.class来确定是类中的哪个函数,然后确定是哪个对象的函数。

Person person=new Person();
        Class<Person> personClass = Person.class;
        //无餐eat
        Method eat = personClass.getMethod("eat");
        eat.invoke(person);
        //有餐eat
        Method eatapple = personClass.getMethod("eat", String.class);
        eatapple.invoke(person,"apple");

Person类中的l两个eat方法

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

在这里插入图片描述

案例-反射的运用

案例需求:写一个类,可以帮我们创建任意类的对象,并且执行任意的方法。

package reflect;

public class student {
    public void sleep(){
        System.out.println("睡觉");
    }
}
package reflect;

public class ReflectMain {
    public static void main(String[] args) throws Exception {
        Object getobject = ReflectTest.setObject("reflect.student");
        ReflectTest.getMethod("reflect.student","sleep",getobject);
    }
}
public class ReflectTest {
    //创建指定类对象
    static public Object setObject(String classallname) throws Exception {
         Class<?> makeClass = Class.forName(classallname);
        Constructor<?> constructor = makeClass.getConstructor();
        Object newobject = makeClass.newInstance();
        return newobject;
    }

    //调用指定类的方法
    static public void getMethod(String classallname,String methodname,Object object) throws Exception {
        Class<?> makeClass = Class.forName(classallname);
        Method method = makeClass.getMethod(methodname);
        method.invoke(object);
    }
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值