【Java】反射简介,利用反射打印一个类当中的构造函数,方法和属性。

news2024/11/26 13:45:28

  📝个人主页:哈__

期待您的关注 

我想要通过反射来打印如下效果的类信息。

Student类如下代码所示。

package com.my.reflect;

public class Student {
    public String name;
    public int age;

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

    private void test(String str){
        System.out.println("哈哈哈"+str);
    }
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

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

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

 你是否有思路?如果你不了解反射的话,我来给大家简单的介绍一下反射的使用方法。

一、反射简介

1、Java反射机制的核心是在程序运行时动态加载类并获取类的详细信息,从而操作类或对象的属性和方法。本质是JVM得到class对象之后,再通过class对象进行反编译,从而获取对象的各种信息。
2、Java属于先编译再运行的语言,程序中对象的类型在编译期就确定下来了,而当程序在运行时可能需要动态加载某些类,这些类因为之前用不到,所以没有被加载到JVM。通过反射,可以在运行时动态地创建对象并调用其属性,不需要提前在编译期知道运行的对象是谁。

在具体的东西,本文章不在这里叙述,总而言之,我们可以通过反射获取一个类的class对象,并且通过这个class对象获得这个类当中的信息。就是说,只要我能知道是哪个类,那么这个类对于我来说基本上就是透明的了。

二、反射的一些常用方法

1.获取一个类的class对象的三种方法

通过包名获取。

Class clazz = Class.forName("com.my.reflect.Student");

通过类获取。

Class clazz = Student.class;

通过类的对象获取 (能够拿到这个类的对象但是不知道是什么类,你可以假定下边的代码没有第一行,只有第二行,那么你能否知道s是哪个类的对象?)。

Student s = new Studnet();
Class clazz = s.getClass();

以上三种获取方式相同,但是需要区分不同的场景采取不同的获取方式。 

2.获取一个类的构造函数

通过class对象我们可以获取这个类的构造函数。传入的参数是一些class对象,通过这些class对象能确定你要获取的是哪个构造函数,例如下边代码。我们获取的构造函数有两个参数,第一个参数是String类型,第二个参数是int类型,通过这两个class对象,我们能够正确的获取构造参数。

//class.getConstructor(Class<?>... parameterTypes)
Constructor constructor= clazz.getConstructor(String.class,int.class);
//public Student(String name,int age){}

//获取类的全部构造函数
Constructor [] constructors= clazz.getConstructors();

 3.获取一个类的方法

通过调用如下代码获取一个类的方法。注意参数,第一个参数是name,代表着你想要获取的方法的名称,第二个参数不陌生了吧,在上边我们获取构造函数的时候见过,这个参数就代表着你要获取的方法的参数类型都是什么,防止方法重载的影响。

//getMethod(String name, Class<?>... parameterTypes)
Method method = clazz.getMethod();
//获取全部的方法 不需要传参
Method [] method = clazz.getMethods();

我们都知道在一个类中,方法有public修饰也有private修饰,还有protected和什么都不写,那么我们在获取Method的时候,我们只能获得类中的公有方法,私有方法我们是无法获取的,这时候就要用到下边的方法来获取一个类中的私有方法。

Method method = clazz.getDeclaredMethod();
//获取全部的方法,包括私有 不需要传参
Method [] methods = clazz.getDeclaredMethods();

 写了这行代码,不管你的方法是共有的还是私有的都可以获取到。

4.获取一个类中的属性

通过下边的代码来获取一个类当中的属性。传入的name就是要获取的属性的名称。当然除了获取单个的属性外我们还可以获取全部的属性。如果你想要获取私有属性同样的要调用带有Declared的方法。

//getField(String name)
Field field =  clazz.getField();
//不需要传入参数
Field [] fields =  clazz.getFields();
// 获取单个私有属性  
Field  privateField =  clazz.getDeclaredField(name);
// 获取全部私有属性 不要参数
Field  [] allPrivateField =  clazz.getDeclaredField();

5.获取一个类、方法和属性的修饰符 

我们都知道类、方法和属性都是有修饰符的,如public、final、private、static等,我们可以通过调用以下的方法来获取。

Class clazz = Class.forName("com.my.reflect.Student");
        Constructor constructor = clazz.getConstructor(String.class, int.class);
        int modifiers = constructor.getModifiers();
        System.out.println(modifiers);
        System.out.println(Modifier.toString(modifiers));

        Method method = clazz.getDeclaredMethod("test",String.class);
        int modifiers1 = method.getModifiers();
        System.out.println(modifiers1);
        System.out.println(Modifier.toString(modifiers1));

结果如下所示。

 

这个modifers到底该如何使用呢,别急这里有一张表格。

 

modifier的值是一个累加的结果,大家可以自己试一试。在上边的代码中我们能够看到,构造方法和普通方法都可以调用 getModifiers()方法,当然属性也可以。

以上就要反射的简单介绍,在这片文章中我并没有介绍通过class获取的constructor、method和field该如何使用,以后有机会的话我会发一篇文章介绍,我这篇文章主要的目的是解决一开始的问题。

三、问题解决

有了上面的基础之后,我们来解决问题,要打印一个类的信息,我们先要打印这是哪个类。这里用到了一个getSuperclass方法,获取这个类的父类的class对象,帮助我们打印继承关系。下边我们先打印了这个类的修饰符public 然后打印了类名,通过调用getName方法。

try{
            Class c1 = Class.forName("com.my.reflect.Student");
            Class superc1 = c1.getSuperclass();

            //获取类的修饰符
            String modifiers = Modifier.toString(c1.getModifiers());
             System.out.print(modifiers);
            System.out.print(" class "+c1.getName());
            if(modifiers.length()>=0) System.out.println(" extends "+superc1.getName());
            System.out.print("\n{\n");
            System.out.print("\n}\n");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

 结果如下。是不是有些样子了?

现在我们打印构造函数。构造方法不止一个,我们调用的是getDeclaredConstructors(),之后进行for循环遍历,每一个获取到的constructor对象我们获取他的名称,获取这个构造方法的修饰符,然后打印。这时问题来了,一个方法是有参数的,我们需要获取这个构造方法的所有参数信息。这里调用getParameterTypes()方法,然后对所有的参数类型进行for循环进行遍历,然后打印这个方法的所有的参数的类型。

public static void printConstrctors(Class c1){
        Constructor[] constructors = c1.getDeclaredConstructors();
        for(Constructor c:constructors){
            String name = c.getName();
            System.out.print("   ");
            //获取构造方法的作用域
            String modifiers = Modifier.toString(c1.getModifiers());
            if(modifiers.length()>0) System.out.print(modifiers+" ");
            System.out.print(name+"(");

            Class[] paramTypes = c.getParameterTypes();
            for(int j = 0;j< paramTypes.length;j++){
                if(j>0) System.out.print(", ");
                System.out.print(paramTypes[j].getName());
            }
            System.out.println(")");
        }
    }

看结果。 

之后就是我们的方法了,既然构造函数会打印了,方法是一个道理。不在讲解了。注意一个resType,也就是返回值类型。

 public static void printMethods(Class c1){

        Method[] methods = c1.getDeclaredMethods();
        for(Method m:methods){
            Class resType = m.getReturnType();
            String name = m.getName();
            System.out.print("    ");
            String modifiers = Modifier.toString(m.getModifiers());
            if(modifiers.length()>0) System.out.print(modifiers+" ");
            System.out.print(resType.getName()+" "+name+"(");
            Class [] paramTypes = m.getParameterTypes();
            for(int j = 0;j< paramTypes.length;j++){
                if(j>0) System.out.print(", ");
                System.out.print(paramTypes[j].getName());
            }
            System.out.println(")");
        }
    }

 

最后就是我们的属性了。

public static void printFields(Class c1){
        Field [] fields = c1.getDeclaredFields();
        for (Field field : fields) {
            Class type = field.getType();
            String name = field.getName();
            System.out.print("    ");
            String modifiers = Modifier.toString(field.getModifiers());
            if(modifiers.length()>0) System.out.print(modifiers+" ");
            System.out.println(type.getName()+" "+name+";");
        }
    }

完美解决。

 四、完整代码

public class ReflectTest {
    public static void main(String[] args) {
        try{
            Class c1 = Class.forName("com.my.reflect.Student");
            Class superc1 = c1.getSuperclass();

            //获取类的作用域
            String modifiers = Modifier.toString(c1.getModifiers());
            System.out.print(modifiers);
            System.out.print(" class "+c1.getName());
            if(modifiers.length()>=0) System.out.println(" extends "+superc1.getName());
            System.out.print("\n{\n");
            printConstrctors(c1);
            System.out.println();
            printMethods(c1);
            System.out.println();
            printFields(c1);
            System.out.print("\n}\n");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
    public static void printConstrctors(Class c1){
        Constructor[] constructors = c1.getDeclaredConstructors();
        for(Constructor c:constructors){
            String name = c.getName();
            System.out.print("   ");
            //获取构造方法的作用域
            String modifiers = Modifier.toString(c1.getModifiers());
            if(modifiers.length()>0) System.out.print(modifiers+" ");
            System.out.print(name+"(");

            Class[] paramTypes = c.getParameterTypes();
            for(int j = 0;j< paramTypes.length;j++){
                if(j>0) System.out.print(", ");
                System.out.print(paramTypes[j].getName());
            }
            System.out.println(")");
        }
    }

    public static void printMethods(Class c1){

        Method[] methods = c1.getDeclaredMethods();
        for(Method m:methods){
            Class resType = m.getReturnType();
            String name = m.getName();
            System.out.print("    ");
            String modifiers = Modifier.toString(m.getModifiers());
            if(modifiers.length()>0) System.out.print(modifiers+" ");
            System.out.print(resType.getName()+" "+name+"(");
            Class [] paramTypes = m.getParameterTypes();
            for(int j = 0;j< paramTypes.length;j++){
                if(j>0) System.out.print(", ");
                System.out.print(paramTypes[j].getName());
            }
            System.out.println(")");
        }
    }

    public static void printFields(Class c1){
        Field [] fields = c1.getDeclaredFields();
        for (Field field : fields) {
            Class type = field.getType();
            String name = field.getName();
            System.out.print("    ");
            String modifiers = Modifier.toString(field.getModifiers());
            if(modifiers.length()>0) System.out.print(modifiers+" ");
            System.out.println(type.getName()+" "+name+";");
        }
    }


}

如果对您有帮助,希望可以博主一个关注。

 

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

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

相关文章

探索组合总和问题(力扣39,40,216)

文章目录 题目前知LinkedList和ArryayList 组合总和I一、思路二、解题方法三、Code 组合总和II一、思路二、解题方法三、Code 组合总和III一、思路二、解题方法三、Code 总结 先看完上一期组合问题再看这一期更加容易理解喔&#x1f92f; 在算法和编程的世界中&#xff0c;组合…

走向国际:区块链行业项目海外市场宣传与运营攻略

随着区块链技术的不断发展和应用&#xff0c;越来越多的区块链项目开始将目光投向海外市场。在全球范围内寻找用户和投资者&#xff0c;扩大品牌知名度&#xff0c;是许多区块链项目的共同目标。然而&#xff0c;要成功进军海外市场&#xff0c;并不是一件容易的事情。本文将深…

Vscode运行python

按住 xtrlshiftp&#xff0c;会出现下面的界面&#xff1a; 然后选择第一个选项&#xff0c;会出现如下的界面&#xff1a; 选择某个环境后就可以使用了。可以右键&#xff0c;如下所示&#xff1a; 就可以运行python程序了

如何在Ubuntu系统部署Z-blog博客结合cpolar实现无公网IP访问本地网站

文章目录 1. 前言2. Z-blog网站搭建2.1 XAMPP环境设置2.2 Z-blog安装2.3 Z-blog网页测试2.4 Cpolar安装和注册 3. 本地网页发布3.1. Cpolar云端设置3.2 Cpolar本地设置 4. 公网访问测试5. 结语 1. 前言 想要成为一个合格的技术宅或程序员&#xff0c;自己搭建网站制作网页是绕…

基于WEB的花卉养殖知识平台

基于WEB的花卉养殖知识平台的设计与实现 摘要 随着人们生活水平及生活质量要求的日益提升&#xff0c;花卉也成为了人们日常生活的调味剂&#xff0c;同时对于花卉的养殖及养护不再是老年人的专利&#xff0c;很多年轻人也在通过花卉的养护来舒缓工作压力&#xff0c;同时通过…

Centos7.X服务器搭建VOS系统的REC录音转换MP3,并支持外呼系统wav转换MP3

由于有的公司客户需要自己下载录音或做话务质检等工作需要&#xff0c;需要从VOS系统中把录音下载到其它服务器使用&#xff0c;但是VOS录音格式是REC格式的&#xff0c;就算下载下来了也无法直接播放&#xff0c;因此我们需要搭建一台转换MP3的服务器来完成需求&#xff01; 外…

EfficientSAM 项目排坑

EfficientSAM 项目排坑 任务过程记录创建环境运行示例 任务 跑通这个项目代码 过程记录 创建环境 readme里没有说具体怎么配置环境&#xff0c;所以可能对我来说还挺困难的。 现把项目git下来&#xff1a; git clone https://github.com/yformer/EfficientSAM.git cd Effi…

插值字符串格式化代码中的感叹号(Python)

在csdn上读到&#xff0c;插值字符串格式化代码中有“!”&#xff0c;进行了一番探究&#xff0c;了解到其中的一点“隐秘”&#xff0c;在此共享。&#x1f92a; (笔记模板由python脚本于2024年03月31日 09:27:59创建&#xff0c;本篇笔记适合对Python字符串格式化有一定认知的…

【C语言】联合体、枚举: 联合体与结构体区别,枚举的优点

目录 1、联合体 1.1、什么是联合体 1.2、联合体的声明 1.3、联合体的特点 1.4、联合体与结构体区别 1.5、联合体的大小 2、枚举 2.1、枚举类型的声明 2.2、枚举类型的优点 3、三种自定义类型&#xff1a;结构体、联合体、枚举 正文 1、联合体 1.1、什么是联合体 联…

OpenHarmony实战:命令行工具hdc安装应用指南

一、工具概述 hdc&#xff08;OpenHarmony Device Connector&#xff09;是为开发人员提供的用于设备连接调试的命令行工具&#xff0c;该工具需支持部署在 Windows/Linux/Mac 等系统上与 OpenHarmony 设备&#xff08;或模拟器&#xff09;进行连接调试通信。 简言之&#xf…

开启 Sora 知识免费课,探索文生视频大模型

4 月 1 日&#xff0c;中国网游先锋&#xff0c;火石控股董事长、风险投资人吴渔夫开启了“跟我学 Sora 知识”的免费课程。他表示&#xff0c;讲述的知识涵盖了 Sora 的产品、技术及未来走向。自 2 月 16 日 Sora 文生视频模型问世以来&#xff0c;我已查阅众多的 Sora 中英文…

记一次对Codis的无知引起的逻辑变更

先提前说明&#xff0c;对Codis的无知是因为Codis不支持一些Redis的命令&#xff0c;而这次的逻辑变更&#xff0c;就是因为使用了PUBLISH&#xff0c;而Codis又不支持PUBLISH导致的。 1. 前言 前段时间的一次需求中&#xff0c;因为设计到多个服务的注册问题&#xff0c;在项…

docker容器添加新端口映射的步骤及`wsl$`目录的作用

在Docker容器已经创建后&#xff0c;需要添加新的端口映射&#xff0c;即对已经存在的Docker容器添加新的端口映射&#xff0c;可以通过以下步骤来添加&#xff0c;即通过修改配置文件的方法。 如何新增端口映射&#xff1f; 查找容器的hash值 docker inspect [容器id或名称…

机器学习在智能音箱中的应用探索与实践:让声音更懂你

&#x1f9d1; 作者简介&#xff1a;阿里巴巴嵌入式技术专家&#xff0c;深耕嵌入式人工智能领域&#xff0c;具备多年的嵌入式硬件产品研发管理经验。 &#x1f4d2; 博客介绍&#xff1a;分享嵌入式开发领域的相关知识、经验、思考和感悟,欢迎关注。提供嵌入式方向的学习指导…

椋鸟数据结构笔记#5:树、二叉树基础

文章目录 树树的相关概念树的表示 二叉树基础二叉树分类满二叉树完全二叉树 二叉树的性质二叉树的存储结构顺序存储链式存储 萌新的学习笔记&#xff0c;写错了恳请斧正。 树 树是一种非线性的数据结构&#xff0c;它是由 n 个节点组成的一个具有层次关系的数据集合。其大概结…

算法学习——LeetCode力扣补充篇3(143. 重排链表、141. 环形链表、205. 同构字符串、1002. 查找共用字符、925. 长按键入)

算法学习——LeetCode力扣补充篇3 143. 重排链表 143. 重排链表 - 力扣&#xff08;LeetCode&#xff09; 描述 给定一个单链表 L 的头节点 head &#xff0c;单链表 L 表示为&#xff1a; L0 → L1 → … → Ln - 1 → Ln 请将其重新排列后变为&#xff1a; L0 → Ln → …

题目:小蓝的神秘行囊(蓝桥OJ 3937)

问题描述&#xff1a; 解题思路&#xff1a; 二维优化01背包模板题。与一维优化01背包不同在于多增加一维。 代码&#xff1a; #include <bits/stdc.h> using namespace std;const int N 1e2 9; int dp[N][N]; //二维的01背包&#xff0c;dp[i][j]&#xff1a;i是体…

【SpringCloud】一文详谈Nacos

&#x1f3e1;浩泽学编程&#xff1a;个人主页 &#x1f525; 推荐专栏&#xff1a;《深入浅出SpringBoot》《java对AI的调用开发》 《RabbitMQ》《Spring》《SpringMVC》《项目实战》 &#x1f6f8;学无止境&#xff0c;不骄不躁&#xff0c;知行合一 文章目录 …

metasploit使用及内网笔记

1 基本操作 Metasploit就是一个漏洞框架。它的全称叫做The Metasploit Framework&#xff0c;简称叫做MSF。Metasploit作为全球最受欢迎的工具&#xff0c;不仅仅是因为它的方便性和强大性&#xff0c;更重要的是它的框架。它允许使用者开发自己的漏洞脚本&#xff0c;从而进行…

Dockerfile和Docker-compose

一、概述 Dockerfile和Docker Compose是用于构建和管理 Docker 容器的两个工具&#xff0c;但它们的作用和使用方式不同。 Dockerfile Dockerfile 是一个文本文件&#xff0c;用于定义 Docker 镜像的构建规则。它包含一系列指令&#xff0c;如 FROM&#xff08;指定基础镜像…