JavaSE之反射

Class类

Class类创建的对象我们称为Class对象/类对象/字节码对象

Class对象会保存类中的信息(构造方法, 成员方法, 成员变量等)
有了Class对象就能得到类中的所有信息。

反射的概念

在程序的运行过程中, 通过Class对象得到类中的信息(构造方法, 成员方法, 成员变量), 并操作他们

这种动态获取信息以及动态调用对象方法的功能称为Java语言的反射机制。非正常的手段操作对象。

反射的好处

使用反射创建对象,代码更复杂,无视修饰符,
功能更强大灵活

反射的应用场景

IDEA的智能提示
框架Spring/SpringMVC/Mybatis

三种获取Class对象的方式

类名.class

对象.getClass()

Class.forName(“类全名”);

注意:三种方式获取到的是同一个Class对象

public static void main(String[] args) throws ClassNotFoundException {
        // 类名.class    Class<Employee>:
        Class<Employee> cls1 = Employee.class;
        System.out.println(cls1);
        // 对象.getClass()    Class<? extends Employee>:
        Employee employee = new Employee();
        Class<? extends Employee> cls2 = employee.getClass();
        System.out.println(cls2);
        // Class.forName("类全名"); 包名.类名  第三种使用最灵活(常用),因为类不存在也能通过编译
        Class<?> cls3 = Class.forName("com.itheima.bean.Employee");
        System.out.println(cls3);
    }

Class类中的方法

String getSimpleName(); 获得类名字符串:类名

String getName(); 获得类全名:包名.类名

public static void main(String[] args) {
        // 1.得到Class对象
        Class<Employee> cls = Employee.class;
        // 2.得到类中的信息
        String name = cls.getName();
        System.out.println(name);
        String simpleName = cls.getSimpleName();
        System.out.println(simpleName);
    }

Class中获取构造器的方法

getConstructors()

getConstructor (Class<?>… parameterTypes)

getDeclaredConstructors()

getDeclaredConstructor (Class<?>… parameterTypes)

反射得到的构造器可以做什么?

创建对象

public newInstance(Object… initargs)

如果是非public的构造器,需要打开权限(暴力反射),然后再创建对象
setAccessible(boolean)

反射可以破坏封装性,私有的也可以执行了。

public class Demo06 {
    // 得到所有public的构造器: getConstructors
    @Test
    public void test01() {
        // 1.得到Class对象
        Class<Employee> cls = Employee.class;
        // 2.得到所有public的构造器
        Constructor<?>[] constructors = cls.getConstructors();
        for (Constructor o:constructors){
            System.out.println(o);
        }
    }

    // 得到一个public的构造器: getConstructor
    @Test
    public void test02() throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        // 1.得到Class对象
        Class<Employee> cls = Employee.class;
        // 2.得到一个public的构造器
        Constructor<Employee> constructor = cls.getConstructor();
        System.out.println(constructor);
        Constructor<Employee> constructor1 = cls.getConstructor(String.class, int.class);
        System.out.println(constructor1);
        // Constructor<Employee> c = cls.getConstructor(); // 匹配无参 public Employee()

        // 3.使用构造器创建对象
        Employee employee = constructor.newInstance();
        Employee employee1 = constructor1.newInstance("张三", 88);
        System.out.println(employee);
        System.out.println(employee1);

    }

    // 得到所有存在的构造器: getDeclaredConstructors
    @Test
    public void test03() {
        // 1.得到Class对象
        Class<Employee> cls = Employee.class;
        // 2.得到所有存在的构造器     Declared:声明的,存在的
        //包括私有,protected等
        Constructor<?>[] constructors = cls.getDeclaredConstructors();
        for (Constructor o : constructors){
            System.out.println(o);
        }
    }

    // 得到一个存在的构造器: getDeclaredConstructor
    @Test
    public void test04() throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        // 1.得到Class对象
        Class<Employee> cls = Employee.class;
        // 2.得到一个存在的构造器
        Constructor<Employee> constructor = cls.getDeclaredConstructor();
        Constructor<Employee> constructor1 = cls.getDeclaredConstructor(String.class);
        // 3.使用构造器创建对象
        Employee employee = constructor.newInstance();
        constructor1.setAccessible(true);
        Employee employee1 = constructor1.newInstance("王五");
        System.out.println(employee);
        System.out.println(employee1);
    }
}

获取成员方法对象

Class中获取成员方法的方法

getMethods()

getMethod(String name, Class<?>… parameterTypes)

getDeclaredMethods()

getDeclaredMethod (String name, Class<?>… parameterTypes)

反射得到成员方法可以做什么?

依然是在某个对象中触发该方法执行。

Object invoke​(Object obj, Object… args)

如果某成员方法是非public的,需要打开权限(暴力反射),然后再触发执行
setAccessible(boolean)

public class Demo07 {
    // 得到所有public的方法: getMethods
    @Test
    public void test01() {
        // 1.得到Class对象
        Class<Employee> cls = Employee.class;
        // 2.得到所有public的方法
        Method[] methods = cls.getMethods();
        for (Method m : methods) {
            System.out.println(m);
        }
    }

    @Test
    // 得到所有存在的方法: getDeclaredMethods

    public void test02() {
        // 1.得到Class对象
        Class<Employee> cls = Employee.class;
        // 2.得到所有存在的方法
        Method[] methods = cls.getDeclaredMethods();
        for (Method m : methods) {
            System.out.println(m);
        }
    }

    // 得到一个public的方法: getMethod
    @Test
    public void test03() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException {
        // 1.得到Class对象
        Class<Employee> cls = Employee.class;
        // 2.得到一个public的方法
        Method setName = cls.getMethod("setName", String.class);
        // 3.调用方法
        // Object invoke(Object obj, Object... args)
        Employee instance = cls.getConstructor().newInstance();
        instance.setAge(19);
        setName.invoke(instance, "李四");

        Method getName = cls.getMethod("getName");
        Object invoke = getName.invoke(instance);
        System.out.println(invoke);
        // Object obj: 调用方法的对象
        // Object... args: 方法的参数
        // Object: 返回值

    }

    // 得到一个存在的方法: getDeclaredMethod
    @Test
    public void test04() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        // 1.得到Class对象
        Class<?> cls = Class.forName("com.itheima.bean.Employee");
        // 2.得到一个存在的方法
        Method sleep = cls.getDeclaredMethod("sleep", int.class);
        // 3.调用方法
        Object instance = cls.getConstructor().newInstance();
        sleep.setAccessible(true);
        Object hours = sleep.invoke(instance, 2);
        System.out.println(hours);
    }
}

获取成员变量

获取类中成员变量对象的方法

getFields()

getField(String name)

getDeclaredFields()

getDeclaredField(String name)

反射得到成员变量可以做什么?(不常用,因为我们一般通过方法来取值赋值,这样直接拿成员变量赋值效率低)

依然是在某个对象中取值和赋值。

void set​(Object obj, Object value):

Object get​(Object obj)

如果某成员变量是非public的,需要打开权限(暴力反射),然后再取值、赋值
setAccessible(boolean)

public class Demo08 {
    // 得到所有public的成员变量: getFields
    @Test
    public void test01() {
        // 1.得到Class对象
        Class<Employee> cls = Employee.class;
        // 2.得到所有public的成员变量
        Field[] fields = cls.getFields();
        for (Field f : fields) {
            System.out.println(f);
        }
    }

    // 得到所有存在的成员变量: getDeclaredFields
    @Test
    public void test02() {
        // 1.得到Class对象
        Class<Employee> cls = Employee.class;

        // 2.得到所有存在的成员变量
        Field[] declaredFields = cls.getDeclaredFields();
        for (Field f : declaredFields) {
            System.out.println(f);
        }
    }

    // 得到一个public的成员变量: getField
    @Test
    public void test03() throws NoSuchFieldException {
        // 1.得到Class对象
        Class<Employee> employeeClass = Employee.class;
        // 2.得到Field
        Field weight = employeeClass.getField("weight");
        System.out.println(weight);
    }

    // 得到一个存在的成员变量: getDeclaredField
    @Test
    public void test04() throws NoSuchFieldException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        // 1.得到Class对象
        Class<Employee> employeeClass = Employee.class;
        // 2.得到Field
        Field age = employeeClass.getDeclaredField("age");
        // 3.给成员变量赋值
        // set(Object obj, Object value);
        Employee employee = employeeClass.getConstructor().newInstance();
        age.setAccessible(true);
        age.set(employee, 99);
        // Object obj: 成员变量所在对象
        // Object value: 新的值

        // 4.获取成员变量的值

        Object o = age.get(employee);
        System.out.println(o);
        // Object get(Object obj);
        // Object obj: 成员变量所在对象
        // Object: 返回成员变量的值
    }
}

反射案例

需求: 利用反射根据文件中的不同类名和方法名,创建不同的对象并调用方法。
分析:

通过Properties加载配置文件

得到类名和方法名

通过类名反射得到Class对象

通过Class对象创建一个对象

通过Class对象得到方法

调用方法

public class Demo09 {
    public static void main(String[] args) throws Exception {
        Properties properties = new Properties();
        properties.load(new FileReader("D:\\it_workspace\\src\\config.properties"));
        String className = properties.getProperty("className");
        String methodName = properties.getProperty("methodName");
        Class<?> cls = Class.forName(className);
        Object instance = cls.getConstructor().newInstance();
        Method method = cls.getMethod(methodName);
        method.invoke(instance);
    }
}

在这里插入图片描述

Teacher
在这里插入图片描述

最后

如果你对本文有疑问,你可以在文章下方对我留言,敬请指正,对于每个留言我都会认真查看。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值