Java 反射用法和8道练习题

目录

  • 一、什么是反射
  • 二、反射的核心接口和类
  • 三、测试代码 Bean 类和目录结构
    • Person 类
    • 代码目录结构
  • 四、获取 Class 对象
  • 五、获取构造方法 Constructor 并使用
  • 六、获取成员变量 Field 并使用
  • 七、获取成员方法 Method 并使用
  • 八、练习
    • 1. 使用反射获取String类的所有公有方法,并把方法名打印出来。
    • 2. 使用反射创建一个对象,并调用其无参构造方法。
    • 3. 使用反射修改一个对象的私有字段值。
    • 4. 使用反射获取一个ArrayList的所有父类(包括间接父类)。
    • 5. 使用反射调用一个类的静态方法。
    • 6. 使用反射获取某个类的所有公有成员变量,并打印出每个成员变量的名称和类型。
    • 7. 使用反射获取某个类的所有成员方法,并打印出每个方法变量的名称和返回值类型。
    • 8. 使用反射调用一个对象的公有方法,并传递参数。

一、什么是反射

解释一:

Java 反射机制是在运行状态中,对于任意一个,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个属性和方法。这种动态获取信息以及动态调用对象的方法的功能称为 Java 语言的反射机制。

解释二:
Java 反射是指在运行时动态检查和操作类的能力。通过反射,(对于一个对象)程序可以在运行时获取关于类、方法、属性、构造函数等的详细信息,并且可以动态地创建对象、调用方法以及访问和修改字段。反射提供了一种灵活的机制,使得程序可以在编译时不知道确切类型的情况下操作这些类型

二、反射的核心接口和类

Java 反射主要涉及以下几个核心类和接口,它们位于包 java.lang.reflect中:

Class:每个类和接口在 JVM 中都表示为一个 Class 对象。通过 Class 对象,程序可以获取类的全限定名、实现的接口、父类、构造函数、方法、字段等信息。
Constructor:表示类的构造函数。通过 Constructor 对象,程序可以创建类的新实例。
Field:表示类的属性。通过 Field 对象,程序可以获取或修改属性的值。
Method:表示类的方法。通过 Method 对象,程序可以调用方法。

三、测试代码 Bean 类和目录结构

Person 类

Person类有nameage属性,无参构造方法有参构造方法gettersettertoString以及自定义的sayHellosayGoodbye方法。

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

    public Person() {
        this.name = "unknown";
        this.age = 0;
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

	// 省略getter()和setter()

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

	// public类型
    public void sayHello() {
        System.out.println("Hello, my name is " + this.name);
    }

	// private类型
    private void sayGoodbye() {
        System.out.println("Goodbye, my name is " + this.name);
    }

}

代码目录结构

在这里插入图片描述

四、获取 Class 对象

Class 对象包含了类的结构信息,是反射的入口点。获取 Class 对象有三种方法,如下所示:

1. 类.class
2. 对象.getClass()
3. Class.forName()

public class Main {
    public static void main(String[] args) {

        // 方式1: 类.class语法
        Class<?> cls1 = Person.class;
        System.out.println(cls1);               // class Person
        System.out.println(cls1.getName());     // Person

        // 方式2: 对象.getClass()
        Class cls2 = new Person().getClass();
        System.out.println(cls2.getName());     // Person

        // 方式3: 使用静态方法Class.forName(),需要捕获ClassNotFoundException
        try {
            Class<?> cls3 = Class.forName("Person");
            System.out.println(cls3.getName()); // Person
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        
    }
}

五、获取构造方法 Constructor 并使用

cls.getDeclaredConstructor()获取 Class 对象的所有构造方法
cls.getConstructor()获取 Class 对象的公有构造方法
constructor.newInstance()使用 Class 构造方法创建对象

import java.lang.reflect.Constructor;

public class Main {
    public static void main(String[] args) {
        try {
            // 获取Person类的Class对象
            Class cls = Class.forName("Person");
            // Class personClass = Person.class;
            // Class personClass = new Person().getClass();

            // 获取无参构造方法
            Constructor<?> noArgsConstructor = cls.getConstructor();
            // 创建对象
            Object person1 = noArgsConstructor.newInstance();
            // 重写了Person的toString方法直接打印即可
            System.out.println(person1); // Person{name='unknown', age=0}

            // 获取带参数的构造方法
            Constructor<?> paramArgsConstructor = cls.getConstructor(String.class, int.class);
            // 创建对象,并传递参数
            Object person2 = paramArgsConstructor.newInstance("Alice", 30);
            System.out.println(person2); // Person{name='Alice', age=30}

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

六、获取成员变量 Field 并使用

cls.getDeclaredField(name)获取 Class 对象的所有成员变量
cls.getField(name)获取 Class 对象的所有公有成员变量
field.setAccessible(true)设置 Class 对象的属性值可访问
field.get()获取 Class 对象的属性值
field.set()设置 Class 对象的属性值

import java.lang.reflect.Field;

public class Main {
    public static void main(String[] args) {
        try {
            // 获取Person类的Class对象
            Class cls = Class.forName("Person");
            // Class personClass = Person.class;
            // Class personClass = new Person().getClass();

            // 创建Person对象
            Person person = new Person("Alice",30);

            // 获取name字段
            Field nameField = cls.getDeclaredField("name");
            // 设置可访问性,因为name是私有的
            nameField.setAccessible(true);
            // 获取name字段的值
            String name = (String) nameField.get(person);
            System.out.println("Name: " + name);        // Name: Alice

            // 获取age字段
            Field ageField = cls.getDeclaredField("age");
            // 设置可访问性,因为age是私有的
            ageField.setAccessible(true);
            // 获取age字段的值
            int age = ageField.getInt(person);
            System.out.println("Age: " + age);          // Age: 30

            // 修改age字段的值
            ageField.setInt(person, 31);
            // 再次获取age字段的值,验证修改是否成功
            age = ageField.getInt(person);
            System.out.println("Updated Age: " + age);  // Updated Age: 31

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

七、获取成员方法 Method 并使用

cls.getDeclaredMethod(name)获取 Class 对象的所有成员方法
cls.getMethod(name)获取 Class 对象的公有成员方法
method.setAccessible(true)设置 Class 对象的方法可访问
method.invoke()调用 Class 对象的成员方法

import java.lang.reflect.Method;

public class Main {
    public static void main(String[] args) {
        try {
            // 获取Person类的Class对象
            Class<?> cls = Class.forName("Person");

            // 创建Person对象
            Person person = (Person) cls
                    .getDeclaredConstructor(String.class, int.class)
                    .newInstance("Alice", 30);
            //或 Person person =new Person("Alice", 30);

            // 获取sayHello方法
            Method sayHelloMethod = cls.getMethod("sayHello");
            // 调用sayHello方法
            sayHelloMethod.invoke(person);

            // 获取sayGoodbye方法
            Method sayGoodbyeMethod = cls.getDeclaredMethod("sayGoodbye");
            // 设置可访问性,因为sayGoodbye是私有的
            sayGoodbyeMethod.setAccessible(true);
            // 调用sayGoodbye方法
            sayGoodbyeMethod.invoke(person);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

八、练习

1. 使用反射获取String类的所有公有方法,并把方法名打印出来。

import java.lang.reflect.Method;

public class Main {
    public static void main(String[] args) {
        Class<String> cls = String.class;
        Method[] methods = cls.getMethods();
        for (Method method : methods) {
            System.out.println(method.getName());
        }
    }
}


2. 使用反射创建一个对象,并调用其无参构造方法。

import java.lang.reflect.Constructor;

public class Main {
    public static void main(String[] args) {
        Class<String> cls = String.class;
        try {
            Constructor<String> constructor = cls.getConstructor(String.class);
            // 指定了String就可以不用Object
            String s = constructor.newInstance("Hello world!");
            System.out.println(s);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

3. 使用反射修改一个对象的私有字段值。

import java.lang.reflect.Field;

class Employee {
    private int age;

    public Employee() {
    }

    public Employee(int age) {
        this.age = age;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    private void printAge() {
        System.out.println(this.age);
    }
}


public class Main {
    public static void main(String[] args) {

        Employee employee = new Employee(30);
        Class cls = employee.getClass();
        try {
            Field ageField = cls.getDeclaredField("age");
            ageField.setAccessible(true);
            
            int age = ageField.getInt(employee);
            System.out.println(age);                // 30
            
            ageField.setInt(employee,31);
            System.out.println(employee.getAge());  // 31
            
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}

4. 使用反射获取一个ArrayList的所有父类(包括间接父类)。

import java.util.ArrayList;

public class Main {
    public static void main(String[] args) {
        Class cls = ArrayList.class;
        while (cls != null) {
            System.out.println(cls.getName());
            cls = cls.getSuperclass();
        }
    }
}

5. 使用反射调用一个类的静态方法。

import java.lang.reflect.Method;

class MyMath {
    public static <T extends Number> T add(T a, T b) {
        if (a instanceof Integer) {
            return (T) Integer.valueOf(a.intValue() + b.intValue());
        } else if (a instanceof Double) {
            return (T) Double.valueOf(a.doubleValue() + b.doubleValue());
        } else {
            throw new IllegalArgumentException("Unsupported number type");
        }
    }
}

public class Main {
    public static void main(String[] args) {
        Class cls = MyMath.class;
        try {
            // 由于泛型擦除,需要指定方法的确切参数类型
            Method method = cls.getDeclaredMethod("add", Number.class, Number.class);
            // 静态方法必须指定null
            Object invoke = method.invoke(null, 1, 2);
            System.out.println(invoke); // 3
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

6. 使用反射获取某个类的所有公有成员变量,并打印出每个成员变量的名称和类型。

import java.lang.reflect.Field;

class People {
    public int id;
    public int age;
    private String name;
}

public class Main {
    public static void main(String[] args) {
        Class<People> cls = People.class;
        Field[] PeopleFields = cls.getFields();
        for (Field peopleField : PeopleFields) {
            System.out.println(peopleField.getName() + " => " + peopleField.getType());
        }
        
        //id => int
        //age => int

    }
}

7. 使用反射获取某个类的所有成员方法,并打印出每个方法变量的名称和返回值类型。

import java.lang.reflect.Method;

class People {
    public void printHello() {
        System.out.println("Hello, Java");
    }

    public String getHello(String Hello) {
        return Hello + ", Java";
    }

    private int getMoney() {
        return 0;
    }

}

public class Main {
    public static void main(String[] args) {
        Class<People> cls = People.class;
        Method[] methods = cls.getDeclaredMethods();
        for (Method method : methods) {
            System.out.println(method.getName() + " => " + method.getReturnType());
        }

        //printHello => void
        //getHello => class java.lang.String
        //getMoney => int
    }
}


8. 使用反射调用一个对象的公有方法,并传递参数。

import java.lang.reflect.Method;

class MyMath {
    public int add(int a, int b) {
        return a + b;
    }
}

public class Main {
    public static void main(String[] args) {
        Class<MyMath> myMathClass = MyMath.class;
        try {
            Method addMethod = myMathClass.getMethod("add", int.class, int.class);
            MyMath myMath = new MyMath(); // 创建 MyMath 类的实例
            Object invoke = addMethod.invoke(myMath, 1, 2); // 传递 MyMath 类的实例
            System.out.println(invoke); // 3
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/801166.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

虚拟机:VMware功能,安装与使用

目录 一、虚拟机介绍 二、VMware 1.介绍 2.安装 &#xff08;1&#xff09;根据提示按步骤安装​编辑 &#xff08;2&#xff09;更改软件的安装地址​编辑 &#xff08;3&#xff09;根据自己的需求选择是否需要软件更新​编辑 &#xff08;4&#xff09;根据需求选择…

3. JavaSE ——【逻辑运算符】

&#x1f680; 开场白 亲爱的读者&#xff0c;大家好&#xff01;我是一名正在学习编程的高校生。在这个博客里&#xff0c;我将和大家一起探讨编程技巧、分享实用工具&#xff0c;并交流学习心得。希望通过我的博客&#xff0c;你能学到有用的知识&#xff0c;提高自己的技能&…

Billu_b0x靶机

信息收集 使用arp-scan 生成网络接口地址来查看ip 输入命令&#xff1a; arp-scan -l 可以查看到我们的目标ip为192.168.187.153 nmap扫描端口开放 输入命令&#xff1a; nmap -min-rate 10000 -p- 192.168.187.153 可以看到开放2个端口 nmap扫描端口信息 输入命令&…

【深度学习】PyTorch框架(2):激活函数

1.引言 在文中&#xff0c;我们将深入探讨流行的激活函数&#xff0c;并分析它们在神经网络优化特性中的作用。激活函数在深度学习模型中扮演着至关重要的角色&#xff0c;因为它们为网络引入了非线性特性。尽管文献中描述了众多的激活函数&#xff0c;但它们并非一视同仁&…

北京交通大学《深度学习》专业课,实验2-前馈神经网络

1. 源代码 见资源“北京交通大学《深度学习》专业课&#xff0c;实验2-前馈神经网络” 2. 实验内容 &#xff08;1&#xff09;手动实现前馈神经网络解决上述回归、二分类、多分类任务 分析实验结果并绘制训练集和测试集的loss曲线 &#xff08;2&#xff09;利用to…

发电机保护屏的工作原理和组成

发电机保护屏的工作原理和组成 发电机保护屏的工作原理是通过监测发电机的电气参数和运行状态&#xff0c;‌一旦发现异常或故障&#xff0c;‌及时采取相应的保护措施&#xff0c;‌以确保发电机的安全运行。‌ 发电机保护屏通常包含各种传感器、‌保护继电器和控制…

Golang | Leetcode Golang题解之第231题2的幂

题目&#xff1a; 题解&#xff1a; func isPowerOfTwo(n int) bool {const big 1 << 30return n > 0 && big%n 0 }

整数或小数点后补0操作

效果展示&#xff1a; 整数情况&#xff1a; 小数情况&#xff1a; 小编这里是以微信小程序举例&#xff0c;代码通用可兼容vue等。 1.在utils文件下创建工具util.js文本 util.js页面&#xff1a; // 格式…

docker desktop历史版本安装

1.安装choco Windows安装 choco包管理工具-CSDN博客 2.通过choco安装 下面例子为安装旧版2.3.0.2,其它版本类似 Chocolatey Software | Docker Desktop 2.3.0.2 https://download.docker.com/win/stable/45183/Docker%20Desktop%20Installer.exe choco install docker-des…

ESP32-S3多模态交互方案在线AI语音设备应用,启明云端乐鑫代理商

随着物联网&#xff08;IoT&#xff09;和人工智能&#xff08;AI&#xff09;技术的飞速发展&#xff0c;嵌入式设备正逐渐变得智能化&#xff0c;让我们的家庭生活变得更加智能化和个性化。 随着大型语言模型的不断进步和优化&#xff0c;AI语音机器人设备能够实现更加智能、…

绝缘子污秽comsol仿真参数

&#x1f3c6;本文收录于《CSDN问答解答》专栏&#xff0c;主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案&#xff0c;希望能够助你一臂之力&#xff0c;帮你早日登顶实现财富自由&#x1f680;&#xff1b;同时&#xff0c;欢迎大家关注&&收藏&…

Java+springboot+vue智慧班牌小程序源码,智慧班牌系统可以提供哪些服务?

智慧班牌全套源码&#xff0c;系统技术架构&#xff1a;Javaspringbootvue element-ui小程序电子班牌&#xff1a;Java Android演示正版授权。 智慧班牌在智慧校园的数字化建设中提供了多种服务&#xff0c;这些服务不仅丰富了校园的信息展示方式&#xff0c;还促进了家校互动…

渲染100农场有哪些优势?渲染100邀请码1a12

渲染100是知名的渲染农场&#xff0c;深受广大设计师欢迎&#xff0c;比起其他农场&#xff0c;它有什么优势呢&#xff1f;我们一起来看看。 1、资源丰富 渲染100拥有强大的计算集群&#xff0c;能多线处理大规模、超复杂的场景渲染需要&#xff0c;性能卓越。2、成本低廉 渲…

文件的顺序读写

文件读写函数介绍 文件顺序读写函数 函数名功能适用于fputc 字符输出函数 所有输出流 fgetc 字符输⼊函数 所有输⼊流 fputs ⽂本⾏输出函数 所有输出流fgets ⽂本⾏输⼊函数 所有输⼊流fprintf 格式化输出函数 所有输出流fscanf 格式化输⼊函数 所有输⼊流fwrite ⼆进制输出…

Multi-modal Information Fusion for Action Unit Detection in the Wild

标题&#xff1a;多模态信息融合用于野外动作单元检测 源文链接&#xff1a;https://openaccess.thecvf.com/content/CVPR2023W/ABAW/papers/Deng_Multi-Modal_Information_Fusion_for_Action_Unit_Detection_in_the_Wild_CVPRW_2023_paper.pdfhttps://openaccess.thecvf.com/…

【HarmonyOS开发】Tabs使用封装

背景 在写Tabs时&#xff0c;会使用很多个TabContent来实现不同页面的展示内容&#xff0c;但是如果TabContent数量很多时&#xff0c;会导致Tabs代码量大而且很臃肿&#xff0c;因此想着尝试去封装Tabs的使用&#xff0c;可以让界面整洁和对内容界面的解耦。 主要依托于wrap…

数据驱动下的私域运营战略布局

一、以用户为中心的组织重构或整合 发现&#xff0c;市场上大部分做的非常成功的私域项目&#xff0c;都是由CEO推动的、基于该战略的组织重构去驱动的。 我们也看到&#xff0c;在很多公司&#xff0c;私域运营是由品牌部门、CRM部门和Trade Marketing部门合作一起运营的。 …

SpringCloud教程 | 第十篇: 读取Nacos的配置

1、引入依赖 <dependency><groupId>com.alibaba.boot</groupId><artifactId>nacos-config-spring-boot-starter</artifactId><version>0.2.7</version></dependency> 2、在启动类加上 NacosPropertySource(dataId"nac…

芯课堂 | 基于ugui上位机工程怎么使用串口烧录素材

1、查看程序初始化串口引脚和波特率 串口引脚是PE7和PE5&#xff0c;默认初始化波特率是115200。可以使用串口模块连接串口引脚&#xff0c;如果用我们的开发板&#xff0c;板载有ch340串口模块&#xff0c;需要用杜邦线把串口模块连接串口引脚&#xff0c;具体可以查看原理图…

stm32学习:(寄存器1)控制寄存器来让led亮

开启时钟&#xff0c;先查找到开启时钟的寄存器&#xff0c;然后通过该寄存器操作时钟的开启或关闭&#xff0c;要打开的是GPIOA的时钟 在芯片手册&#xff0c;找到RCC寄存器描述章节找到APB2外设时钟使能寄存器&#xff08;RCC_APB2ENR)&#xff0c;现在算RCC_APB2ENR这个寄存…