Java高级-反射

2023-09-20 23:23:25

1.介绍

反射

  • 加载类,并允许以编程的方式解剖类的各种成分(成员变量、方法、构造器等)

反射步骤

  • 1.加载类,获取类的字节码:Class对象
  • 2.获取类的构造器:Constructor对象
  • 3.获取类的成员变量:Field对象
  • 4.获取类的成员方法:Method对象

2.获取Class对象的三种方法

获取Class对象的三种方法

  • Class c1 = 类名.class
  • 调用Class的方法: public static Class forName(String package);
  • Object提供的方法:public Class getClass(); Class c3 = 对象.getClass;
public class Test1Class {
    public static void main(String[] args) throws ClassNotFoundException {
        // 第一种
        Class c1 = Student.class;
        System.out.println(c1.getName()); // 全类名 advanced.reflex.Student
        System.out.println(c1.getSimpleName()); // 类名 Student

        // 第二种
        Class<?> c2 = Class.forName("advanced.reflex.Student");

        // 第三种
        Student s = new Student();
        Class<? extends Student> c3 = s.getClass();
        System.out.println(c3 == c2);
    }
}

3.获取类的构造器

  • getDeclaredConstructors (推荐)
  • getDeclaredConstructor (推荐)
  • 不建议在反射中加泛型,为了通用性
    在这里插入图片描述
/**
 * 目标:获取类的构造器,并对其进行操作
 */
public class Test2Constructor {

    @Test
    public void testGetConstructors() {
        // 1.必须先得到类的class对象
        Class<Cat> catClass = Cat.class;
        // 2.获取类的全部构造器
		// Constructor[] constructors = catClass.getConstructors();
        Constructor[] constructors = catClass.getDeclaredConstructors();
        // 3.遍历数组的中构造器对象
        for (Constructor constructor : constructors) {
            System.out.println(constructor.getName() + "--->" + constructor.getParameterCount());
        }
    }

    @Test
    public void testGetConstructor() throws NoSuchMethodException {
        // 1.必须先得到类的class对象
        Class<Cat> catClass = Cat.class;
        // 2.获取类的某个构造器
		// Constructor<Cat> constructor = catClass.getConstructor();
        Constructor<Cat> constructor = catClass.getDeclaredConstructor();
        System.out.println(constructor.getName() + "--->" + constructor.getParameterCount());

        // 3.获取有参的构造器
        Constructor<Cat> constructor2 = catClass.getDeclaredConstructor(String.class, int.class);
        System.out.println(constructor2.getName() + "--->" + constructor2.getParameterCount());
    }
}

获取类构造器的作用
获取类构造器的作用:依然是初始化对象返回
在这里插入图片描述

@Test
public voidtestGetConstructor() throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
    // 1.必须先得到类的class对象
    Class<Cat> catClass = Cat.class;
    // 2.获取类的某个构造器
    Constructor constructor = catClass.getDeclaredConstructor();
    constructor.setAccessible(true);
    Cat cat = (Cat) constructor.newInstance();
    System.out.println(cat);

    // 3.获取有参的构造器
    Constructor constructor2 = catClass.getDeclaredConstructor(String.class, int.class);
    constructor2.setAccessible(true);
    Cat cat2 = (Cat) constructor2.newInstance("叮当猫", 12);
    System.out.println(cat2);
}

4.获取类的成员变量

在这里插入图片描述

public class Cat {
    private static int a;
    public static final String COUNTRY = "中国";
    private String name;
    private int age;
}
@Test
public void getGetFields() throws NoSuchFieldException {
    // 1.获取Class对象
    Class catClass = Cat.class;
    // 2.获取类的全部成员变量
    Field[] fields = catClass.getDeclaredFields();
    // 3.遍历成员变量数组
    for (Field field : fields) {
        System.out.println(field.getName() + "---" + field.getType());
    }

    // 4.定位某个成员变量
    Field fName = catClass.getDeclaredField("name");
    System.out.println(fName.getName() + "-->" + fName.getType());

    Field fAge = catClass.getDeclaredField("age");
    System.out.println(fAge.getName() + "-->" + fAge.getType());
}

获取成员变量的作用
获取成员变量的作用:赋值和取值
在这里插入图片描述

@Test
public void getGetFields() throws Exception {
    // 1.获取Class对象
    Class catClass = Cat.class;
    // 2.定位某个成员变量
    Field fName = catClass.getDeclaredField("name");
    System.out.println(fName.getName() + "-->" + fName.getType());
    
    // 赋值
    Cat cat = new Cat();
    fName.setAccessible(true);
    fName.set(cat, "加菲猫");
    System.out.println(cat);

    // 取值
    String name = (String) fName.get(cat);
    System.out.println("name = " + name);
}

5.获取类的成员方法

在这里插入图片描述

private void run() {
   System.out.println("猫跑的很快");
}

private void eat() {
    System.out.println("猫爱吃猫粮");
}
private String eat(String name) {
    return "猫爱吃" + name;
}
@Test
public void testGetMethods() throws Exception {
    // 1.获得Class对象
    Class catClass = Cat.class;
    // 2.获取类的全部成员方法
    Method[] methods = catClass.getDeclaredMethods();
    // 3.遍历
    for (Method method : methods) {
        System.out.println(method.getName() + "---" +
                method.getParameterCount() + "---" +
                method.getReturnType());
    }

    // 4.获取某个方法对象
    Method run = catClass.getDeclaredMethod("run");
    System.out.println(run.getName() + "---" +
            run.getParameterCount() + "---" +
            run.getReturnType());

    Method eat = catClass.getDeclaredMethod("eat", String.class);
    System.out.println(eat.getName() + "---" +
            eat.getParameterCount() + "---" +
            eat.getReturnType());
}

获取成员方法的作用
获取成员方法的作用:执行此方法在这里插入图片描述

@Test
public void testGetMethods() throws Exception {
    // 1.获得Class对象
    Class catClass = Cat.class;
    // 2.获取某个方法对象
    Method run = catClass.getDeclaredMethod("run");
    Method eat = catClass.getDeclaredMethod("eat", String.class);

    // 执行方法
    Cat cat = new Cat();
    run.setAccessible(true);
    Object rs = run.invoke(cat);// 调用无参数的run方法,用cat对象触发调用
    System.out.println("rs = " + rs);
    
    eat.setAccessible(true);
    rs = eat.invoke(cat, "火腿肠");
    System.out.println("rs = " + rs);
}

6.反射的作用和应用场景

反射的作用

  • 基本作用:可以得到一个类的全部成分然后操作
  • 可以破坏封装性
  • 最重要的用途:适合做Java的框架

案例:使用反射做一个简易版的框架
需求:

  • 对于任意一个对象,该框架都可以把对象的字段名和对应的值,保存到文件中去

实现步骤

  • 1.定义一个方法,可以接收任意对象
  • 2.每收到一个对象后,使用反射获取该对象的Class对象,然后获取全部的成员变量
  • 3.遍历成员变量,然后提取成员变量在该对象中的具体值
  • 4.把成员变量名、值,写出到文件中去即可
public class Student {
    private String name;
    private char sex;
    private int age;
    private double height;
    private String hobby;
}

public class Teacher {
    private String name;
    private double salary;
}
/**
 * 使用反射技术,设计一个保存对象的简易版框架
 */
public class Test5Frame {
    @Test
    public void save() throws Exception{
        Student s1 = new Student("吴彦祖", '男', 45, 185.3, "乒乓球");
        Teacher t1 = new Teacher("黄子韬", 999.9);

        // 需求:任意一个对象,该框架都可以把对象的字段名和对应的值,保存到文件中去
        ObjectFrame.saveObject(s1);
        ObjectFrame.saveObject(t1);
    }
}
/**
 * 保存任意对象的字段和数据到文件中去
 */
public class ObjectFrame {

    public static void saveObject(Object obj) throws Exception {
        PrintStream ps = new PrintStream(new FileOutputStream("F:\\Code\\JetBrains-Work\\Java\\2022study\\src\\advanced\\reflex\\data.txt", true));
        // obj是任意对象,到底有多少个字段要保存
        Class c = obj.getClass();
        String cName = c.getSimpleName();
        ps.println("-------------------" + cName + "-------------------");
        // 2.从该类中提取全部成员变量
        Field[] fields = c.getDeclaredFields();
        // 3.变量每个成员变量
        for (Field field : fields) {
            // 4.拿到成员变量的名字
            String name = field.getName();
            // 5.拿到这个成员变量在该对象的值
            field.setAccessible(true);
            String value = field.get(obj).toString();
            ps.println(name + "=" + value);
        }
        ps.close();
    }
}
更多推荐

redis群集

目录redis群集模式主从复制主从复制的作用主从复制流程主从复制模型搭建Redis主从复制哨兵模式哨兵模式原理哨兵结构故障转移机制主节点选举机制搭建Redis哨兵模式群集模式集群的作用集群的数据分片搭建群集模式redis群集模式redis群集有三种模式,分别是主从同步/复制、哨兵模式、Cluster,下面会讲解一下三种

Qt5开发及实例V2.0-第九章-Qt文件及磁盘处理

Qt5开发及实例V2.0-第九章-Qt文件及磁盘处理第9章Qt5文件及磁盘处理9.1读写文本文件9.1.1QFile类读写文本9.1.2QTextStream类读写文本9.2读写二进制文件9.3目录操作与文件系统9.3.1文件大小及路径获取实例9.3.2文件系统浏览9.4获取文件信息9.5监视文件和目录变化本章相关例程

基于Java+SpringBoot+vue前后端分离校园周边美食探索分享平台设计实现

博主介绍:✌全网粉丝30W+,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌🍅文末获取源码联系🍅👇🏻精彩专栏推荐订阅👇🏻不然下次找不到哟2022-2024年最全的计算机软件毕业设计选题

Neutron — DHCP Agent 实现原理

目录文章目录目录DHCPDHCP协议格式DHCP报文类型DHCP协议流程DHCPAgent关键配置dnsmasq服务进程高可用方案DHCPDHCP(DynamicHostConfigurationProtocol,动态主机配置协议)用于当Host加入一个L3网络的时候动态的从一个IPPool中为Host租用一个IP地址

系统架构设计师(第二版)学习笔记----需求工程

【原文链接】系统架构设计师(第二版)学习笔记----需求工程文章目录一、需求定义1.1需求包含的内容1.2软件需求的3个不同层次1.3需求工程的阶段1.4需求管理的主要内容二、需求获取2.1需求获取的基本步骤2.2需求获取方法2.3需求讨论会参与人员2.4专题讨论会的优点三、需求变更3.1需求变更管理过程3.2需求变更

上海亚商投顾:沪指震荡调整 两市成交金额跌破6000亿

上海亚商投顾前言:无惧大盘涨跌,解密龙虎榜资金,跟踪一线游资和机构资金动向,识别短期热点和强势个股。一.市场情绪三大指数昨日集体调整,创业板指续创3年多以来新低。ST板块继续走强,*ST柏龙、ST恒久等十余股涨停。华为产业链午后活跃,捷荣技术涨停,股价创出历史新高。减肥药概念股逆势走强,翰宇药业20cm涨停。脑机接口概

Django(18):中间件原理和使用

目录概述Django自带中间件Django的中间件执行顺序自定义中间件函数使用类其它中间件钩子函数process_viewprocess_exceptionprocess_template_response如何使用这3个钩子函数?全局异常处理小结概述中间件(middleware)是一个镶嵌到Django的request

网络爬虫-----http和https的请求与响应原理

目录前言简介HTTP的请求与响应浏览器发送HTTP请求的过程:HTTP请求主要分为Get和Post两种方法查看网页请求常用的请求报头1.Host(主机和端口号)2.Connection(链接类型)3.Upgrade-Insecure-Requests(升级为HTTPS请求)4.User-Agent(浏览器名称)5.Ac

Spring Cloud Gateway快速入门(一)——网关简介

文章目录前言一、什么是网关1.1gateway的特点1.2为什么要使用gateway二、使用Nginx实现网关服务什么是网关服务?为什么选择Nginx作为网关服务?如何使用Nginx实现网关服务?1.安装Nginx2.配置Nginx3.启动Nginx4.测试网关服务总结代码编写三、使用Gateway实现网关服务什么是网

【Java 基础篇】Java后台线程和守护线程详解

在Java多线程编程中,有两种特殊类型的线程:后台线程(DaemonThread)和守护线程(DaemonThread)。这两种线程在一些特定的场景下非常有用,但也需要谨慎使用。本文将详细介绍后台线程和守护线程的概念、特性、用法,以及注意事项。什么是后台线程和守护线程?后台线程(DaemonThread)后台线程是一种

数组和指针笔试题解析之【指针】

目录🍂笔试题1:🍂笔试题2:🍂笔试题3:🍂笔试题4:🍂笔试题5:🍂笔试题6:🍂笔试题7:🍂笔试题8:🍂笔试题1:intmain(){inta[5]={1,2,3,4,5};int*ptr=(int*)(&a+1);printf("%d,%d",*(a+1),*(ptr-1));return0;}运行结

热文推荐