Java — 反射

程序在运行中也可以获取类的变量和方法信息,并通过获取到的信息来创建对象。程序不必再编译期就完成确定,在运行期仍然可以扩展。

示例:学生类

public class Student {
    // 成员变量:公共、受保护、默认、私有各一个
    public String name;
    protected String pwd;
    String sex;
    private int age;

    // 构造方法:公共两个,受保护、默认、私有各一个
    public Student() {
    }

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

    Student(String name, String pwd) {
        this.name = name;
        this.pwd = pwd;
    }

    private Student(String name, String pwd, String sex) {
        this.name = name;
        this.pwd = pwd;
        this.sex = sex;
    }

    public Student(String name, String pwd, String sex, int age) {
        this.name = name;
        this.pwd = pwd;
        this.sex = sex;
        this.age = age;
    }

    // 成员方法:公共、受保护、默认、私有各一个
    public void method1() {
        System.out.println("public成员方法:method1");
    }

    protected void method2() {
        System.out.println("protected成员方法:method2");
    }

    void method3() {
        System.out.println("default成员方法:method3");
    }

    private void method4() {
        System.out.println("private成员方法:method4");
    }

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

类名: Class<t></t>

包名: java.lang.Class<t></t>

Class 类和 Class 文件的关系: java.lang.Class &#x7C7B;&#x7528;&#x4E8E;&#x8868;&#x793A;&#x4E00;&#x4E2A;&#x7C7B;&#x7684;&#x5B57;&#x8282;&#x7801;&#xFF08;.class&#xFF09;&#x6587;&#x4EF6;

通过反射获取对象的方式有以下三种:

方式 描述 类名.class 当该类被加载成 .class 文件时,此时该类变成了 .class,再获取该字节码文件对象,也就是获取自己, 该类处于字节码阶段 对象.getClass() 通过类的实例获取该类的字节码文件对象,该类处于创建对象阶段 Class.forName(“全限定类名”) 通过 Class 类中的静态方法 forName 直接获取到该类的字节码文件对象,此时该类还是源文件阶段,并没有变为字节码文件

测试:

public class Test_01 {
    public static void main(String[] args) throws ClassNotFoundException {
        // 类名.class
        Class s1 = Student.class;

        // 对象.getClass()
        Student student = new Student();
        Class s2 = student.getClass();

        // Class.forName("包名.类名")
        Class s3 = Class.forName("A_11_reflect.Student");

        System.out.println(s1 + "\n" + s2 + "\n" + s3);
        System.out.println(s1 == s2 && s1 == s3 && s2 == s3);
    }
}

运行:

class A_11_reflect.Student
class A_11_reflect.Student
class A_11_reflect.Student
true

3.1、获取构造方法

修饰符和类型 方法 秒速 Constructor[] getConstructors() 返回该类所有的公共构造方法 Constructor getConstructor(Class… parameterTypes) 返回该类指定的公共构造方法 Constructor[] getDeclaredConstructors() 返回该类所有的构造方法 Constructor getDeclaredConstructor(Class… parameterTypes) 返回该类指定的构造方法

测试:

public class Test_02 {
    public static void main(String[] args) throws NoSuchMethodException {
        Class s = Student.class;

        // 获取该类所有的公共构造方法
        Constructor[] constructors = s.getConstructors();
        for (Constructor constructor : constructors) {
            System.out.println("constructor = " + constructor);
        }
        System.out.println("--------");

        // 获取该类指定的公共构造方法
        Constructor c1 = s.getConstructor();
        Constructor c2 = s.getConstructor(String.class, String.class, String.class, int.class);
        System.out.println("c1 = " + c1);
        System.out.println("c2 = " + c2);
        System.out.println("--------");

        // 获取该类所有的构造方法
        Constructor[] declaredConstructors = s.getDeclaredConstructors();
        for (Constructor declaredConstructor : declaredConstructors) {
            System.out.println("declaredConstructor = " + declaredConstructor);
        }
        System.out.println("--------");

        // 获取该类指定的构造方法
        Constructor c3 = s.getDeclaredConstructor();
        Constructor c4 = s.getDeclaredConstructor(String.class);
        Constructor c5 = s.getDeclaredConstructor(String.class, String.class);
        Constructor c6 = s.getDeclaredConstructor(String.class, String.class, String.class);
        Constructor c7 = s.getDeclaredConstructor(String.class, String.class, String.class, int.class);
        System.out.println("c3 = " + c3 + "\nc4 = " + c4 + "\nc5 = " + c5 + "\nc6 = " + c6 + "\nc7 = " + c7);
    }
}

运行:

constructor = public A_11_reflect.Student(java.lang.String,java.lang.String,java.lang.String,int)
constructor = public A_11_reflect.Student()
declaredConstructor = public A_11_reflect.Student(java.lang.String,java.lang.String,java.lang.String,int)
declaredConstructor = private A_11_reflect.Student(java.lang.String,java.lang.String,java.lang.String)
declaredConstructor = A_11_reflect.Student(java.lang.String,java.lang.String)
declaredConstructor = protected A_11_reflect.Student(java.lang.String)
declaredConstructor = public A_11_reflect.Student()
name1 = public java.lang.String A_11_reflect.Student.name
name = public java.lang.String A_11_reflect.Student.name
pwd = protected java.lang.String A_11_reflect.Student.pwd
sex = java.lang.String A_11_reflect.Student.sex
age = private int A_11_reflect.Student.age

4.2、调用成员变量

类名: Field

包名: java.lang.reflect.Field

修饰符和类型 成员方法 描述 Object set(Object obj, Object value) 将 value 赋值给 obj 对象的成员变量 Object get(Object obj) 返回 obj 对象的成员变量值

测试:

public class Test_05 {
    public static void main(String[] args) throws Exception {
        Class s = Student.class;
        // 先获取所有成员变量
        Field name = s.getDeclaredField("name");
        Field pwd = s.getDeclaredField("pwd");
        Field sex = s.getDeclaredField("sex");
        Field age = s.getDeclaredField("age");
        // 调用无参构造方法
        Constructor c = s.getConstructor();
        // 实例化
        Student student = c.newInstance();
        // 成员变量赋值
        name.set(student, "张三");
        pwd.set(student, "123");
        sex.set(student, "男");
        age.setAccessible(true); // 私有成员需取消访问检查
        age.set(student, 23);
        System.out.println("student = " + student);
        System.out.println("--------");
        // 获取成员变量值
        System.out.println(name.get(student));
        System.out.println(pwd.get(student));
        System.out.println(sex.get(student));
        System.out.println(age.get(student));
    }
}

运行:

student = Student{name='张三', pwd='123', sex=男, age=23}
method1 = public void A_11_reflect.Student.method1()
method1 = public void A_11_reflect.Student.method1()
method2 = protected void A_11_reflect.Student.method2()
method3 = void A_11_reflect.Student.method3()
method4 = private void A_11_reflect.Student.method4()

5.2、调用成员方法

类名: Method

包名: java.lang.reflect.Method

修饰符和类型 成员方法 描述 Object invoke(Object obj, Object… args) obj:调用方法的对象,args:方法的参数

测试:

public class Test_07 {
    public static void main(String[] args) throws Exception {
        Class s = Student.class;
        // 获取类的无参构造方法
        Constructor constructor = s.getConstructor();
        // 实例化
        Student student = constructor.newInstance();
        // 调用方法
        Method[] declaredMethods = s.getDeclaredMethods();
        for (Method declaredMethod : declaredMethods) {
            declaredMethod.setAccessible(true); // 取消私有成员方法访问检查
            declaredMethod.invoke(student);
        }
    }
}

运行:

protected成员方法:method2
default成员方法:method3
private成员方法:method4
public成员方法:method1

6.1、示例1

需求:往 ArrayList<integer></integer> 集合中添加字符串数据。

示例:

// 越过泛型检查
public class Test_08 {
    public static void main(String[] args) throws Exception {
        ArrayList arrayList = new ArrayList<>();
        arrayList.add(1);
        arrayList.add(2);
        arrayList.add(3);
        System.out.println("arrayList = " + arrayList);
        Class arrayListClass = arrayList.getClass();
        Method add = arrayListClass.getMethod("add", Object.class);
        add.invoke(arrayList, "张三");
        add.invoke(arrayList, "李四");
        add.invoke(arrayList, "王五");
        System.out.println("arrayList = " + arrayList);
    }
}

运行:

arrayList = [1, 2, 3]
arrayList = [1, 2, 3, 张三, 李四, 王五]

6.2、示例2

需求:通过 properties.txt 配置文件运行类中的方法。

示例:

className=A_11_reflect/demo/Student
methodName=study
parameter=张三
public class Student {
    public void study(String name) {
        System.out.println(name + "同学爱学习!");
    }
}
public class Teacher {
    public void study(String name) {
        System.out.println(name + "老师爱学习!");
    }
}

测试:

public class Test_01 {
    public static void main(String[] args) throws Exception {
        // 加载数据
        Properties p = new Properties();
        // 读取配置
        FileReader fr = new FileReader(".\\properties.txt");
        p.load(fr);
        fr.close();

        // 获取类名
        String className = p.getProperty("className");
        // 获取方法名
        String methodName = p.getProperty("methodName");
        // 获取参数
        String parameter = p.getProperty("parameter");

        // 反射获取类的实例
        Class clazz = Class.forName(className);
        // 获取类的构造方法
        Constructor con = clazz.getConstructor();
        // 类实例化
        Object o = con.newInstance();
        // 获取方法对象,指定参数类型
        Method m = clazz.getMethod(methodName, String.class);
        // o对象调用m方法传入parameter参数
        m.invoke(o, parameter);
        System.out.println("o = " + o);
    }
}

运行:

张三同学爱学习!

Original: https://www.cnblogs.com/bybeiya/p/16251826.html
Author: 北涯
Title: Java — 反射

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/585897/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • shell脚本 -d 是目录文件,那么-e,-f分别是什么?还有”! -e”这又是什么意思呢?

    -e filename 如果 filename存在,则为真-d filename 如果 filename为目录,则为真 -f filename 如果 filename为常规文件,则…

    Linux 2023年5月28日
    0174
  • Java — 面向对象

    简介:类是对事物的一种描述,对象则为具体存在的事物。 类的定义: public class 类名 { // 成员变量 访问修饰符 数据类型 变量名; … // 成员方法 访问修…

    Linux 2023年6月8日
    084
  • centos 7 安装zabbix 4.0

    一、zabbix简介 1、简介 zabbix([`zæbiks])是一个基于WEB界面的提供分布式系统监视以及网络监视功能的企业级的开源解决方案。zabbix能监视各种网络参数如:…

    Linux 2023年6月7日
    0104
  • Docker搭建Redis Cluster集群及扩容和收容

    上一篇文章讲解了Redis集群原理及搭建,由于工作中使用docker较多,本文主要讲解使用docker搭建集群及对集群的扩展收容。环境:Centos7.6Docker:20.10….

    Linux 2023年6月13日
    069
  • 理论知识

    多线程的实现方式:1.继承Thread类;2.实现runnable接口;3.实现callable接口通过futrueTask包装器来创建Thread线程; 是继承Thread类号还…

    Linux 2023年6月7日
    0104
  • 三款优秀的替代Xshell的SSH软件

    在之前的文章介绍个, 由于公司禁止使用xshell, 让我很是难受了一阵, 因为一直无法找到好的工具来替代xshell, 前面文章中提到的那些对我来时功能还是太单一了, 界面也不够…

    Linux 2023年5月28日
    0842
  • CMU15-445 数据库导论 Storage01

    CMU15-445 01 Storage 1. 参考资料: [1] CMU15-445:Database Systems [Andy Pavlo] https://15445.co…

    Linux 2023年6月6日
    084
  • 【Prometheus+Grafana系列】监控MySQL服务

    前言 前面的一篇文章已经介绍了 docker-compose 搭建 Prometheus + Grafana 服务。当时实现了监控服务器指标数据,是通过 node_exporter…

    Linux 2023年6月7日
    087
  • 理清计算机中的数据表示方法–2’s complement

    Bits bits是信息的基本单元,计算机通过电压的高低来确定是0还是1;这里的电压是有一定范围的,0~a视为0, a~b视为1,具体数字不用记 Data Types 同一个数字有…

    Linux 2023年6月6日
    083
  • C语言传指针类型的形参

    今天在牛客网上做C语言专项练习题,遇到一个”函数传指针类型的形参”的题,我做错了,正确的为下面代码: #include <string.h> #…

    Linux 2023年6月13日
    067
  • jenkins pipeline中获取shell命令的输出

    //获取标准输出//第一种result = sh returnStdout: true ,script: ” Original: https://www.cnblogs…

    Linux 2023年5月28日
    084
  • 前端基础之JavaScript(一)

    一、JavaScript概述 1.1 ECMAScript和JavaScript的关系 1996年11月,JavaScript的创造者–Netscape公司,决定将Ja…

    Linux 2023年6月14日
    0105
  • 剑指offer计划31(数学困难)—java

    1.1、题目1 剑指 Offer 14- II. 剪绳子 II 1.2、解法 刚刚好结束了,这个专题,国庆休息,后面再改 1.3、代码 class Solution { publi…

    Linux 2023年6月11日
    094
  • vscode搜索所有文件夹中所有文件的方法

    最近在看opencv相关的内容,看到画图这一部分时,提示我 这些代码都来自OpenCV代码的sample文件夹。 按照他的提示,我打开了相应的文件夹,却发现,so many 文件 …

    Linux 2023年6月14日
    0262
  • 云主机搭建WordPress个人博客

    安装宝塔控制面板 宝塔面板是一个简单、好用的面板,它的功能就是将LNMP和服务器的各种管理集成到一个可视化的WEB环境来管理,通过面板,我们普通人不需要掌握具体的技术,只需要动动鼠…

    Linux 2023年6月8日
    091
  • 保罗·艾伦的故事

    上周,保罗·艾伦逝世。《财新周刊》约我写一篇纪念文章,发表在他们杂志上面 一些个人新闻:最近,我了解到我在2009年与之抗争的非霍奇金淋巴瘤已经复发。我已经开始治疗,我的医生很乐观…

    Linux 2023年6月14日
    099
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球