83.【反射】

news/2024/5/19 2:43:58 标签: 反射

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...

http://www.niftyadmin.cn/n/1850270.html

相关文章

QT5中使用QFtp类(添加ftp模块)

QT5中如何使用QFtp类(添加ftp模块) 但是&#xff0c;从 Qt5.x 之后&#xff0c;Qt Network 发生了很大的变化&#xff0c;助手中关于此部分描述如下&#xff1a; The QFtp and QUrlInfo classes are no longer exported. Use QNetworkAccessManager instead. Programs that re…

站内短消息的数据库设计

2019独角兽企业重金招聘Python工程师标准>>> 目前很多的短消息功能都允许群发。在群发数量大的情况下&#xff0c;该如何有效的处理呢&#xff1f;我在工作中遇到这样的问题&#xff0c;参考网上一些方案&#xff0c;想了几种设计方式&#xff0c;记录一下&#xff…

UvaOJ 10014 - Simple calculations

在HUST上开了个比赛&#xff0c;加了几道刘汝佳书里的简单数学题。 Uva今天我这上不去&#xff0c;诶&#xff0c;还是老样子没变么&#xff0c;时不时抽风。HUST那里交了题也返回Judging Error 1 。 也罢&#xff0c;先把这题解写了。 题目 这题给了个公式 ai (ai–1 ai1)/2…

我的相亲日记_5(原创连载)

2019独角兽企业重金招聘Python工程师标准>>> 42次了&#xff0c; 下班&#xff0c;收拾东西。 同事戏谑的问我&#xff1a;又去相啊&#xff1f; 我哈哈一笑&#xff0c;对啊&#xff1a;大宝&#xff0c;天天相。 每一次我都很认真的去相。 但是最后的结果确不是太…

windows下基于QT5.9.8的Android开发环境搭建

由于对Clang不甚了解&#xff0c;不知道怎么修改clang配置&#xff0c;只能用NDK r17- 版本 2. 配饰 “Android for armeabi-v7a (Clang Qt 5.9.8 for Android ARMv7)” 环境 &#xff08;但是(ARM64-v8a)&#xff09; Add... 按钮 “Target API 不能选择”,不知道怎么弄 Nati…

Freebsd rc.conf语法错误导致不能开机解决

因为使用拷贝粘贴的方式编辑rc.conf系统配置文件导致系统开机报错&#xff0c;/etc/rc.conf: 25: Syntax error: Unterminated quoted string。 网上查到解决办法如下&#xff1a; 命令行输入&#xff1a; # mount -u # mount -a 然后编辑rc.conf&#xff0c;重启即可。 主…

qml 使用自定义插件

使用 《QmlBook》章节Extending QML with C &#xff08;C扩展QML&#xff09;的例子。 http://qmlbook.github.io/assets/ch17-extensions-assets.tgz 1.运行fileio项目生成dll插件 步骤参考&#xff1a;QML插件扩展 2.修改CityUI配置,代码 2.1 .pro 修改 QML_IMPORT_PAT…

mark:改变Terminal模板颜色

vpsee.com:适合阅读的 Terminal.app 配色方案 把自己Terminal的颜色改了下&#xff0c;用吸管取的&#xff0c;不知道正不正宗&#xff0c;呵呵&#xff0c;差不多&#xff0c;眼睛舒服多了。 字体颜色&#xff1a;FFF6A6 背景颜色&#xff1a;111E49转载于:https://blog.51cto…