83.【反射】

1. 概述

反射:框架设计的灵魂

  • 框架:半成品软件。可以在框架的基础上进行软件开发,简化代码

  • 反射:将类的各个组成部分封装为其他对象,这就是反射机制

  • 反射面前没有隐私!(暴力反射)

好处

  • 可以在程序运行中,操作这些对象。
  • 可以解耦,提高程序的可扩展性。

Java代码在计算机中经历的三个阶段

在这里插入图片描述

2. 获取class(字节码对象)对象的方式

  • Class.forName("全类名"):将字节码文件加载进内存,返回class对象

    多数用于配置文件,将类名定义在配置文件中,读取文件,加载类。

  • 类名.class:通过类名的属性class获取。

    多用于参数的传递。

  • 对象.getClass()getClass()方法在Object类中定义。

    多用于对象的获取字节码的方式

package cn.luis.demo03.reflect;

public class Demo01Reflect {
    public static void main(String[] args) throws Exception {
        // 1. Class.forName("全类名")
         Class cls1 =  Class.forName("cn.luis.demo03.reflect.Person");  // ClassNotFoundException
        System.out.println(cls1);
        // 2. 类名.class
        Class cls2 = Person.class;
        System.out.println(cls2);
        // 3. 对象.getClass()
        Person p = new Person();
        Class cls3 = p.getClass();
        System.out.println(cls3);

        Class cls4 = Student.class;
        System.out.println(cls4);

        // 比较三个对象
        System.out.println(cls1 == cls2);
        System.out.println(cls1 == cls3);
        System.out.println(cls1 == cls4);
    }
}

结果:

class cn.luis.demo03.reflect.Person
class cn.luis.demo03.reflect.Person
class cn.luis.demo03.reflect.Person
class cn.luis.demo03.reflect.Student
true
true
false

结论

  • 同一个字节码文件*.class在一次程序运行过程中,只会被加载一次

  • 不论通过哪一种方式获取的class对象都是同一个。

3. Class对象功能

获取功能

1. 获取成员变量
  • Field[] getFields():获取所有public修饰的成员变量

  • Field[] getField(String name):获取指定public修饰的成员变量

  • Field[] getDeclaredFields():获取所有的成员变量,不考虑修饰符

  • Field[] getDeclaredField(String name):获取指定的成员变量,不考虑修饰符。

    (String name):传递成员变量名。

获取成员变量后都能进行哪些操作

Field:成员变量

  • 设置值:void set(Object obj, Object value)
  • 获取值:get(Object obj)
  • 忽略访问权限修饰符的安全检查 : setAccessible(true); // 暴力反射

演示代码:

package cn.luis.demo03.reflect;

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

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

    //...

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

Demo02Reflect

package cn.luis.demo03.reflect;

import java.lang.reflect.Field;

public class Demo02Reflect {

    public static void main(String[] args) throws Exception {
       // 获取Person的class对象
        Class personClass = Person.class;
        // 1.Field[] getFields():获取所有public修饰的成员变量
        Field[] fields = personClass.getFields();
        for (Field field : fields) {
            System.out.println(field);
        }
        System.out.println("==================");
        // 2.Field[] getField(String name):获取指定public修饰的成员变量
        Field a = personClass.getField("a");//  NoSuchFieldException
        // 3. 获取成员变量a的值
        Person p = new Person();
        Object value = a.get(p);
        System.out.println(value); // null 默认值
        // 4. 设置成员变量a的值
        a.set(p,"钢铁侠");
        System.out.println(p);
        System.out.println("==================");
        // 5.Field[] getDeclaredFields():获取所有的成员变量,不考虑修饰符
        Field[] declaredFields = personClass.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            System.out.println(declaredField);
        }
        // 6.Field[] getDeclaredField(String name):获取指定的成员变量,不考虑修饰符
        Field d = personClass.getDeclaredField("d");
        // 7. 忽略访问权限修饰符的安全检查 : IllegalAccessException
        d.setAccessible(true); // 暴力反射
        Object value2 = d.get(p);
        System.out.println(value2);
        d.set(p,"浩克");
        System.out.println(p);

    }
}

结果:

public java.lang.String cn.luis.demo03.reflect.Person.a
==================
null
Person{name='null', age=0, a='钢铁侠', b='null', c='null', d='null'}
==================
private java.lang.String cn.luis.demo03.reflect.Person.name
private int cn.luis.demo03.reflect.Person.age
public java.lang.String cn.luis.demo03.reflect.Person.a
protected java.lang.String cn.luis.demo03.reflect.Person.b
java.lang.String cn.luis.demo03.reflect.Person.c
private java.lang.String cn.luis.demo03.reflect.Person.d
null
Person{name='null', age=0, a='钢铁侠', b='null', c='null', d='浩克'}
2. 获取构造方法
  • Constructor<?>[] getConstructors()

  • Constructor<?>[] getConstructor(类<?>... parameterTypes)

  • Constructor<?>[] getDeclarefConstructors()

  • Constructor<?>[] getDeclaredConstructor(类<?>... parameterTypes)

    ():每个小括号内传递的参数不同,可以形成重载关系

获取构造方法能做什么

Constructor:构造方法

  • 创建对象:T newInstance(Object... initargs)

  • 若使用空参构造方法创建对象,操作可以简化:

    • 使用Class对象里的newInstance()方法
  • 忽略访问权限修饰符的安全检查 : setAccessible(true); // 暴力反射

演示代码:

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

public class ReflectDemo03 {

    public static void main(String[] args) throws Exception {
        // 获取Person的class对象
        Class personClass = Person.class;
        Constructor constructor = personClass.getConstructor(String.class, int.class);
        System.out.println(constructor);
        // 创建对象
        Object person = constructor.newInstance("方一凡", 18);
        System.out.println(person);

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

        Constructor constructor1 = personClass.getConstructor();
        System.out.println(constructor1);
        // 创建对象
        Object person1 = constructor1.newInstance();
        System.out.println(person1);

        // 简化空参构造创建对象写法
        Object o = personClass.newInstance();
        System.out.println(o);

    }
}

结果:

public cn.luis.demo03.reflect.Person(java.lang.String,int)
Person{name='方一凡', age=18, a='null', b='null', c='null', d='null'}
======================
public cn.luis.demo03.reflect.Person()
Person{name='null', age=0, a='null', b='null', c='null', d='null'}
Person{name='null', age=0, a='null', b='null', c='null', d='null'}
3. 获取成员方法
  • Method[] getMethods()

  • Method[] getMethods(String name, 类<?>... parameterTypes)

  • Method[] getDeclaredMethods()

  • Method[] getDeclaredMethods(String name, 类<?>... parameterTypes)

    ():传递方法名和参数列表,可以形成重载关系

获取成员方法做什么

Method:方法对象

  • Object invoke(Object obj,Object... args):执行方法。—>(真实的对象,方法的参数列表)
  • String name:获取方法名
4. 获取类名
  • String getName()
package cn.luis.demo03.reflect;

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

public class ReflectDemo04 {

    public static void main(String[] args) throws Exception {
        // 获取Person的class对象
        Class personClass = Person.class;
        // 获取指定名称的方法
        Method eat_method = personClass.getMethod("eat");// ()内传递方法名和参数列表
        Person p = new Person();
        // 执行方法
        eat_method.invoke(p);

        // 获取指定名称的方法
        Method eat_method1 = personClass.getMethod("eat",String.class);// ()内传递方法名和参数列表
        // 执行方法
        eat_method1.invoke(p,"泡面");
        System.out.println("=====================");

        // 获取所有public修饰的方法(会显示出:Person自己的方法和Object中的方法)
        Method[] methods = personClass.getMethods();
        for (Method method : methods) {
            System.out.println(method);
//            method.setAccessible(true);
            String name = method.getName();
            System.out.println(name);

        }

        // 获取类名
        String className = personClass.getName();
        System.out.println(className);

    }
}

结果:

eat...
eat...泡面
=====================
public void cn.luis.demo03.reflect.Person.eat(java.lang.String)
eat
public void cn.luis.demo03.reflect.Person.eat()
eat
public java.lang.String cn.luis.demo03.reflect.Person.toString()
toString
public java.lang.String cn.luis.demo03.reflect.Person.getName()
getName
public void cn.luis.demo03.reflect.Person.setName(java.lang.String)
setName
public int cn.luis.demo03.reflect.Person.getAge()
getAge
public void cn.luis.demo03.reflect.Person.setAge(int)
setAge
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
wait
public final void java.lang.Object.wait() throws java.lang.InterruptedException
wait
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
wait
public boolean java.lang.Object.equals(java.lang.Object)
equals
public native int java.lang.Object.hashCode()
hashCode
public final native java.lang.Class java.lang.Object.getClass()
getClass
public final native void java.lang.Object.notify()
notify
public final native void java.lang.Object.notifyAll()
notifyAll
cn.luis.demo03.reflect.Person

Process finished with exit code 0

案例:写一个”框架“

写一个”框架“,在不改变该类任何代码的前提下,可以帮我们创建任意类型的对象,并且执行其中任意方法。

实现

  1. 配置文件
  2. 反射

步骤

  1. 将需要创建的对象的全类名和需要执行的方法定义在配置文件中
  2. 在程序中加载读取配置文件
  3. 使用反射技术来加载类文件进入内存
  4. 创建对象
  5. 执行方法

代码演示:

配置文件

pro.properties (在src路径下)

className = cn.luis.demo04.ReflectTest.Student ---> 全类名,第一时间想到的就是反射
methodName = sleep

Student

package cn.luis.demo04.ReflectTest;

public class Student {
    public void sleep() {
        System.out.println("sleep...");
    }
}

框架类

package cn.luis.demo04.ReflectTest;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.Properties;

public class ReflectTest {
    public static void main(String[] args) throws Exception {
        // 在不改变该类任何代码的前提下,可以创建任意类的对象,可以执行任意方法
        /*Person p = new Person();
        p.eat();*/
        // 1. 加载配置文件
        // 1.1 创建Properties对象
        Properties pro = new Properties();
        // 1.2 加载配置文件,转换为一个集合
        // 1.2.1 获取class目录下的配置文件
        ClassLoader classLoader = ReflectTest.class.getClassLoader();// 获取字节码文件对应的类加载器
        InputStream is = classLoader.getResourceAsStream("pro.properties");// getResource():获取资源的路径 |  getResourceAsStream():获取资源对应的字节流
        pro.load(is); // IOException

        // 2. 获取配置文件中定义的数据
        String className = pro.getProperty("className"); // 全类名
        String methodName = pro.getProperty("methodName"); // 方法名

        // 反射
        // 3. 加载该类进入内存
        Class<?> cls = Class.forName(className);
        // 4. 创建对象
        Object obj = cls.newInstance();
        // 5. 获取方法
        Method method = cls.getMethod(methodName);
        // 6. 执行方法
        method.invoke(obj);
    }
}

结果:

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值