java中的反射

反射原理

首先有个Student.java文件,编译后得到Student.class文件,程序运行加载到内存中时,jvm会为每个类创建一个Class对象,Student为Class<Student>,Teacher类为Class<Teacher>,Class对象中包含了该类的成员变量,构造方法,成员方法等信息。

反射应用

开发工具,如idea,eclipse

各种框架,如spring,mybatis

Class对象的获取方式

  1. 类名.class

  1. 对象.getClass(从object继承过来的)

  1. Class.forName(“全限定类名”)

Class对象的常用方法

package com.itheima;

/**
 * 反射
 *
 * 任王胡
 * 2023-03-05 13:09
 */
public class TestStudent {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        // 通过反射获得某个类的对象的三个方法

        // 方法一:类名.class
        Class<Student> studentClass = Student.class;

        // 方法二:对象名.getClass----继承object类中的方法
        Student student = new Student();
        Class<? extends Student> studentClass1 = student.getClass();

        // 方法三:Class.forName("全限定类型")
        Class<?> studentClass2 = Class.forName("com.itheima.Student");

        System.out.println(studentClass);
        System.out.println(studentClass1);
        System.out.println(studentClass2);

        // Class对象的常用方法
        System.out.println(studentClass.getSimpleName());
        System.out.println(studentClass.getName());
        Student student1 = studentClass.newInstance(); // 对象.newInstance就是在调用类的公有无参构造,如果该类没有公有无参构造方法,则报错
        System.out.println(student1);
    }
}

执行结果

class com.itheima.Student
class com.itheima.Student
Student
com.itheima.Student
com.itheima.Student@4554617c

Process finished with exit code 0

反射操作类的构造方法

目的:类中的每个构造方法都对应一个Constructor对象,先获取到Constructor对象,再用Constructor对象创建该类的对象

好处:创建对象不用new了,可以用反射,在程序运行期间获取某个类的对象,降低耦合度

package com.itheima;

/**
 * 任王胡
 * 2023-03-05 13:08
 */
public class Student {
    private String name;
    private int age;

    public Student() {
    }

    public Student(String name) {
        this.name = name;
    }

    private Student(int age) {
        this.age = age;
    }

    private Student(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;
    }

    public void study(){
        System.out.println("好好学习,天天向上");
    }

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

学生类,公有无参,公有name,私有age,私有name和age

package com.itheima;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;

/**
 * 任王胡
 * 2023-03-05 15:39
 */
public class TestStudent1 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        Class<?> studentClass = Class.forName("com.itheima.Student");
        Constructor<?> cons = studentClass.getConstructor(); // 获取公有无参
        System.out.println(cons);
        Constructor<?> cons1 = studentClass.getConstructor(String.class); // 获取公有的带name的构造方法
        System.out.println(cons1);
        System.out.println("--------------");
        Constructor<?>[] consList = studentClass.getConstructors(); //获取所有公有
        Arrays.stream(consList).forEach(System.out::println);
        System.out.println("--------------");


        Constructor<?> cons2 = studentClass.getDeclaredConstructor(); //获取公有无参
        System.out.println(cons2);
        Constructor<?> cons3 = studentClass.getDeclaredConstructor(String.class, int.class); // 获取私有name和age
        System.out.println(cons3);
        System.out.println("--------------");
        Constructor<?>[] consList1 = studentClass.getDeclaredConstructors(); // 获取所有构造
        Arrays.stream(consList1).forEach(System.out::println);
        System.out.println("--------------");


        // 创建对象
        /*
        * cons  公有无参
        * cons1 公有name
        * cons2 公有无参
        * cons3 私有name和age
        *
        * */
        Object object = cons.newInstance();
        System.out.println(object);
        Object object1 = cons1.newInstance("jack");
        System.out.println(object1);
        // Object object2 = cons3.newInstance("tom", 18);
        //如果像上一行那样直接设置值,会报错,因为私有构造不能直接访问,需要设置暴力访问
        cons3.setAccessible(true); // 设置允许暴力访问
        Object object3 = cons3.newInstance("jack", 20);
        System.out.println(object3);
    }
}

执行结果

public com.itheima.Student()
public com.itheima.Student(java.lang.String)
--------------
public com.itheima.Student(java.lang.String)
public com.itheima.Student()
--------------
public com.itheima.Student()
private com.itheima.Student(java.lang.String,int)
--------------
private com.itheima.Student(java.lang.String,int)
private com.itheima.Student(int)
public com.itheima.Student(java.lang.String)
public com.itheima.Student()
--------------
Student{name='null', age=0}
Student{name='jack', age=0}
Student{name='jack', age=20}

Process finished with exit code 0

反射操作类的成员方法

目的:类中的每个成员方法都对应一个Method对象,先获取Method对象,再操作Method对象执行成员方法

作用:可以进行泛型擦除

invoke方法参数:第一个,该类的实例对象,第二个,成员方法的参数

操作成员方法和操作构造方法一样,只是方法名不同而已

演示:泛型擦除(泛型只针对编译期间,运行期间无效)

package com.itheima;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/**
 * 泛型擦除
 *
 * 任王胡
 * 2023-03-05 16:47
 */
public class Demo1 {
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        List<String> list=new ArrayList<>();
        list.add("it");
        list.add("java");
        // list.add(666); // 编译报错
        System.out.println(list);
        
        // 1.获取ArrayList类的字节码对象
        Class<? extends List> clazz = list.getClass();
        // 2.获取ArrayList的实例对象(不需要,已经有了list)
        // 3.获取成员方法对应的Method对象
        Method add = clazz.getMethod("add", Object.class);
        add.invoke(list,666);
        System.out.println(list);
    }
}

执行结果

[it, java]
[it, java, 666]

Process finished with exit code 0

反射操作类的成员变量

类似构造方法和成员方法

对应的类:Field

对应的方法:

getField

getFields

getDeclaredField

getDeclaredFields

目的:给成员变量设置值,获取对象的成员变量

package com.itheima;

/**
 * 任王胡
 * 2023-03-05 13:08
 */
public class Student {
    private String name;
    private int age;

    public Student() {
    }

    public Student(String name) {
        this.name = name;
    }

    private Student(int age) {
        this.age = age;
    }

    private Student(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;
    }

    public void study(){
        System.out.println("好好学习,天天向上");
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
package com.itheima;

import java.lang.reflect.Field;

/**
 * 任王胡
 * 2023-03-05 17:36
 */
public class TestStudent2 {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchFieldException {
        // 获取字节码对象
        Class<?> clazz = Class.forName("com.itheima.Student");
        // 获取Student类的对象
        Object student = clazz.newInstance();
        // 获取成员变量对应的Field类对象
        Field name = clazz.getDeclaredField("name");
        // 暴力反射
        name.setAccessible(true);
        // 给实例对象设置值
        name.set(student,"rose");
        Field age = clazz.getDeclaredField("age");
        age.setAccessible(true);
        age.set(student,18);
        System.out.println(student);
        // 获取某个对象的成员变量的值
        Object o = name.get(student);
        System.out.println(o);
    }
}

执行结果

Student{name='rose', age=18}

Process finished with exit code 0

总结

使用反射的步骤

  1. 获取某个类的Class对象

  1. 通过Class对象获取某个类的实例对象

  1. 通过Class对象获取类的成员方法Method对象

  1. 调用Method对象的invoke方法,执行成员方法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值