Java 反射用法和8道练习题

news2024/12/23 23:41:12

目录

  • 一、什么是反射
  • 二、反射的核心接口和类
  • 三、测试代码 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.coloradmin.cn/o/1929500.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

在python里构建你的投资组合portfolio--最好用的pandas零基础

有人可能觉得软件数据分析门槛很高&#xff0c;自学也坚持不下来&#xff0c; 其实分解成一个小的功能和任务&#xff0c;对零基础自学者非常有帮助。 今天用python中最好用的数据分析包pandas为例&#xff1a; 用最简单的代码完成全流程 构建投资组合 → 获取数据 → 进行分…

均匀性大于98%均匀光源积分球

在光学技术的浩瀚星空中&#xff0c;均匀光源积分球犹如一颗璀璨的明珠&#xff0c;以其卓越的均匀性能&#xff0c;照亮了科研、检测、照明等多个领域的探索之路。当谈及均匀性超过98%的积分球时&#xff0c;我们不禁要深入其内部&#xff0c;探索这一科技奇迹背后的原理与应用…

phenocycler发现免疫治疗反应关键的肿瘤微环境区域

T 细胞介导的抗原特异性反应对于有效的免疫监视至关重要。然而T细胞如何进入肿瘤微环境并操纵局部组织微环境来实现效应器功能&#xff0c;以及这些局部的细胞结构如何对T细胞疗法或者其他免疫治疗做出反应仍然不清楚。近期来自斯坦福大学的研究者利用小鼠模型和临床患者样本&a…

10位工程师做SW大装配设计工作站怎么选

在日益复杂的工程环境中&#xff0c;SolidWorks&#xff08;SW&#xff09;作为一款全球装机量较大的三维设计、动画、仿真模拟计算软件&#xff0c;已成为工程师们不可或缺的工具。 对于涉及大型装配设计的项目&#xff0c;选择一款合适的SW工作站显得尤为关键。在选择SW大装…

【0630开发者活动】机器学习算法在存内计算芯片WTM2101上的部署

前言 WTM2101芯片是由Witin知存科技开发的高性能存内计算芯片&#xff0c;专为加速AI计算设计&#xff0c;如图1.1所示。存内计算作为一种革命性技术&#xff0c;其主要优势在于将计算功能直接集成到存储器中&#xff0c;从而显著减少数据在芯片内部的传输距离&#xff0c;降低…

【学术会议征稿】2024年第三届信息学,网络与计算技术国际学术会议(ICINC2024)

2024年第三届信息学&#xff0c;网络与计算技术国际学术会议(ICINC2024) 2024 3rd International Conference on Informatics,Networking and Computing (ICINC 2024) 2024年第三届信息学&#xff0c;网络与计算技术国际学术会议(ICINC2024)将于2024年10月25-27日于中国郑州召…

Django任务管理:项目定时执行及简单管理界面

1、用django-admin命令创建一个Django项目 django-admin startproject task_manager 2、进入到项目下用命令创建一个应用 cd task_manager python manage.py startapp tasks 3、进入models.py定义数学模型 第2步得到的只是应用的必要空文件&#xff0c;要开始增加各文件实际…

PostgreSQL的学习心得和知识总结(一百四十八)|查看 PostgreSQL 17 中的新内置排序规则提供程序

目录结构 注&#xff1a;提前言明 本文借鉴了以下博主、书籍或网站的内容&#xff0c;其列表如下&#xff1a; 1、参考书籍&#xff1a;《PostgreSQL数据库内核分析》 2、参考书籍&#xff1a;《数据库事务处理的艺术&#xff1a;事务管理与并发控制》 3、PostgreSQL数据库仓库…

MongoDB Atlas Vector Search再度荣获最受欢迎的向量数据库称号

最新发布的《2024 年 Retool AI 现状报告》显示&#xff0c;MongoDB Atlas Vector Search 再次荣获最受欢迎的向量数据库称号&#xff0c;这已是它连续第二年获此殊荣。 Atlas Vector Search 在净推荐值 &#xff08;NPS&#xff09;方面斩获最高分&#xff0c;这一指标精准反映…

【python】pandas报错:UnicodeDecodeError详细分析,解决方案以及如何避免

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

一文带你看懂SAP-HANA的基本架构与原理

注&#xff1a;本篇主要对SAP HANA做了总结与论述&#xff0c;如有错误欢迎读者提出并补充 创作不易,希望大家一键三连支持!!!♥♥♥ 创作不易,希望大家一键三连支持!!!♥♥♥ 创作不易,希望大家一键三连支持!!!♥♥♥ 目录 一. 背景引入1.1 硬件与数据库系统1.2 行业现状 …

MongoDB自学笔记(一)

一、MongoDB简介 MongoDB是一款基于C开发的文档型数据库。与传统的关系型数据库有所不同&#xff0c;MongoDB面向的是文档&#xff0c;所谓的文档是一种名为BSON &#xff08;Binary JSON&#xff1a;二进制JSON格式&#xff09;是非关系数据库当中功能最丰富&#xff0c;最像…

萝卜快跑爆火的背后,美格智能如何助力无人车商业化?

近期&#xff0c;“订单量超过600万单”等夺人眼球的信息&#xff0c;让无人驾驶出租车“萝卜快跑”从江城武汉爆火出圈&#xff0c;在2024年的炎炎夏日为这座大火炉再添了一把火。热度背后&#xff0c;不少地方主管部门&#xff0c;近期也纷纷针对无人驾驶出租车、无人驾驶运输…

【C++】多态-最全解析(多态是什么?如何使用多态?多态的底层原理是什么?)

目录 一、前言 二、多态是什么&#xff1f; 三、多态的定义及实现 &#x1f525; 多态的构成条件&#x1f525; &#x1f525; 虚函数的重写&#x1f525; &#x1f525;虚函数重写的两个例外 &#x1f525; &#x1f34d; 协变返回类型 &#x1f95d; 析构函数的重写…

OpenMesh入门,安装,运行示例Hello World

安装 环境 win10&#xff0c;qt5 源码下载编译 进入OpenMesh官网OpenMesh官网 https://www.graphics.rwth-aachen.de/software/openmesh/download/ 使用cmake gui 注意&#xff1a;先安装qt5 使用 CMake-Gui 构建 vs 2019 项目 注意 where is the source code 是<project…

Zotero推荐插件

绝大多数插件下载网址&#xff1a;Zotero 插件商店 适配&#xff1a;Zotero6 1. Zotero-style&#xff1a;标签分栏与阅读进度可视化 右键任意一个列的名字&#xff0c;会弹出一个右键菜单&#xff0c;可以勾选/取消勾选一个列&#xff0c;并且在最后有两个操作按钮是【列设置…

html5——CSS背景属性设置

目录 背景颜色 background-color 背景图像 背景定位 背景样式简写 背景尺寸 ​编辑渐变属性 背景颜色 background-color 背景图像 background-image background-image:url(图片路径); 背景重复方式&#xff1a; background-repeat 属性&#xff1a; repeat&#…

Spring Web MVC入门(2)(请求2)

目录 1.传递JSON数据 传递JSON对象 2.获取URL中的参数PathVariable 3.上传文件RequestPart 4.获取Cookie/Session (1)获取Cookie 简洁获取Cookie (2)获取Session Sesson读取 简洁获取Session(1) 简洁获取Session(2) 5.获取Header 简洁获取Header 1.传递JSON数据 J…

详解MySQL中的递归查询

MySQL中的递归查询主要通过WITH RECURSIVE语句来实现&#xff0c;这在处理具有层级关系或树形结构的数据时非常有用。下面将通过一个具体的例子来详细解释如何在MySQL中使用递归查询。 示例场景 假设我们有一个部门表&#xff08;departments&#xff09;&#xff0c;其中包含…

【docker 部署springboot项目】

一、docker安装 1.检查Linux内核版本高于3.10才可安装 uname -r 2. 卸载旧版本 sudo yum remove docker docker-client docker-client-latest docker-common docker-latest docker-latest-logrotate docker-logrotate docker-engine 3. 使用docker仓库进行安装 安装所需的软…