Java之Class.forName方法详解

2023-10-27

一、前言:

在说明Class类的静态方法forName()之前,先清楚有关Class类的几个概念:

1、 Class类封装了类或接口的运行时状态

Java程序在运行时,Java运行时系统一直对所有的对象进行所谓的运行时类型标识,这些标示纪录了每个对象所属的类。
虚拟机通常使用运行时类型信息选择正确方法去执行,用来保存这些类型信息的类是Class类。

2、Class类型的对象,是加载类时自动创建的

Class 没有公共构造方法。Class 对象是在加载类时,由Java 虚拟机以及通过调用类加载器中的 defineClass 方法自动构造的,因此不能显式地声明一个Class对象。

3、虚拟机为每种类型管理一个独一无二的Class对象

每个类(型)都有一个Class对象。
运行程序时,Java虚拟机(JVM)首先检查所要加载的类对应的Class对象是否已经加载。如果没有加载,JVM就会根据类名查找.class文件,并将其Class对象载入。

1.基本的 Java 类型(boolean、byte、char、short、int、long、float 和 double)和关键字 void 也都对应一个 Class 对象。
2.每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该 Class 对象。
3.一般某个类的Class对象被载入内存,它就用来创建这个类的所有对象。

以上说法查看Class源码会发现,Book.class.getName()最终调用的:

private transient String name;
public String getName() {
    String name = this.name;
    if (name == null)
        this.name = name = getName0();
    return name;
}

此时Book也是一个独一无二的Class对象,即对象中的对象。



二、案例:

Book.java类

package com.junit.demo;

public class Book {
    private static final String defName = "《程序猿植发》";

    static {
        System.out.println("我是静态代码块,输出: " + defName);
    }

    //打印生产日期:
    public static String printProduceDate(String name) {
        return "我是静态方法printProduceDate,输出: " + name + ", produce is:" + System.currentTimeMillis();
    }

    private String name;

    public Book() {
        System.out.println("我是Book声明的构造方法!");
        name = defName;
    }

    public String toString(String msg) {
        return name + msg;
    }
}

执行方法:

public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException {
    //1-将指定类加载到JVM中(ClassNotFoundException)
    Class aClass = Class.forName("com.junit.demo.Book");
    System.out.println(aClass);
    //2.1-访问静态方法:NoSuchMethodException,InvocationTargetException
    Method method = aClass.getMethod("printProduceDate", String.class);
    String result = (String) method.invoke(aClass, "《程序猿的颈椎自传》");
    System.out.println(result);
    System.out.println("---------------------------\n");
    //2.2-初始化对象:
    Book obj = (Book) aClass.newInstance();
    System.out.println("得到对象后访问get方法:" + obj.toString(""));
    System.out.println("---------------------------\n");
    //2.3-初始化对象后访问方法:
    Method method3 = aClass.getMethod("toString", String.class);
    String result3 = (String) method3.invoke(aClass.newInstance()/*obj*/, "这本书是我的伙伴!");
    System.out.println(result3);
    System.out.println("---------------------------\n");

    System.out.println(Book.class.getName());
}

输出:

我是静态代码块,输出: 《程序猿植发》
class com.junit.demo.Book
我是静态方法printProduceDate,输出: 《程序猿的颈椎自传》, produce is:1626682894095
---------------------------

我是Book声明的构造方法!
得到对象后访问get方法:《程序猿植发》
---------------------------

我是Book声明的构造方法!
《程序猿植发》这本书是我的伙伴!
---------------------------

com.junit.demo.Book



三、详解:

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

getMethod()返回某个类的所有公用(public)方法包括其继承类的公用方法,当然也包括它所实现接口的方法。

getDeclaredMethod()对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。当然也包括它所实现接口的方法。

详细举例:

Class aClass = Class.forName("com.junit.demo.Book");
1、访问静态方法:
// 由Class获取方法:第一个参数为方法名,第二个参数为方法的参数类型。
// 如add(int a,int b)则getMethod("add",int.class,int.class)。当然,也可以是Java对象。
Method method = aClass.getMethod("printProduceDate", String.class);
// 引用方法:(引用实例/调用静态方法可为null,参数值/有多个用逗号隔开),参数值要和参数类型的数量匹配!
String result = (String) method.invoke(aClass, "《程序猿的颈椎自传》");

简写:

aClass.getMethod("printProduceDate", String.class).invoke(null, "《程序猿的颈椎自传》");
2、访问实例方法:
  • 重要:aClass.newInstance();,实例化指定对象。
    和 new Book() 效果一样。
//方法一:直接转化实例化后的对象,直接调用方法
Book book= (Book) aClass.newInstance();
// book.setName('xxx'); or book.getName(); or more...

//方法二:使用invoke调用指定实例a的指定方法b
Method method3 = aClass.getMethod("toString", String.class);
//这里的book可以是已实例化的对象,或者使用 aClass.newInstance() 传入,详见简写:
String result3 = (String) method3.invoke(book, "这本书是我的伙伴!");

简写:

aClass.getMethod("toString", String.class).invoke(aClass.newInstance(), "xxx");

值得注意的是,如果是类似于工具类可用于全部类访问的,可以使用一个实例化对象,而不需要每次都newInstance。

另外,方法一适用于需要映射的类是已知或少数时,反之需要统一按指定字符串反射调用方法的话,需使用方法二。

3、访问私有方法:

一睹为快:


举例:

package com.junit.demo;

public class Netbar {
    private Double random = Math.random();

    public Double getRandom() {
        return random;
    }

    private Netbar createNew() {
        return new Netbar();
    }

    private static Netbar getInstance() {
        return new Netbar();
    }

    public static void main(String[] args) {
        Netbar netbar = new Netbar();
        System.out.println("Random:: " + netbar.getRandom());
        Netbar netbar2 = netbar.createNew();
        System.out.println("Random2:: " + netbar2.getRandom());
        Netbar netbar3 = Netbar.getInstance();
        System.out.println("Random3:: " + netbar3.getRandom());
    }
}

结果为打印的3个值都是不同的,这是正常的访问方式,下面用反射来访问。

  • 获取私有非静态方法:
public static void main(String[] args) throws Exception {
    Class aClass = Class.forName("com.junit.demo.Netbar");
    Method method = aClass.getDeclaredMethod("createNew");//这里可以带参数
    method.setAccessible(true);//对所有属性设置访问权限  当类中的成员变量为private时 必须设置此项
    Netbar netbar = (Netbar) method.invoke(aClass.newInstance());
    System.out.println("Random2:: " + netbar.getRandom());
}
  • 获取私有静态方法:
public static void main(String[] args) throws Exception {
    Class aClass = Class.forName("com.junit.demo.Netbar");
    Method method = aClass.getDeclaredMethod("getInstance");//这里可以带参数
    method.setAccessible(true);//对所有属性设置访问权限  当类中的成员变量为private时 必须设置此项
    Netbar netbar = (Netbar) method.invoke(null);
    System.out.println("Random2:: " + netbar.getRandom());
}






end.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java之Class.forName方法详解 的相关文章

随机推荐

  • MYSQL必知必会:格式化导入导出数据集

    在mysql中 我们可以把查询到的结果集通过自定义的格式打印到指定文件内 指定文件不存在 如果指定文件存在 则失败 下面是表结构合表数据 1 格式化导出数据 把表order info的所有记录的所有字段导入到 d 1 sql 文件内 sel
  • 2021-6-25 组态王与modbus rtu从机STM32精英开发板通信

    一 组态王与modbus rtu从机通信 1 安装组态王软件并搭建环境 1 安装组态王6 53 然后在哔哩哔哩上搜索组态王与MODBUS RTU通信视频 跟着视频 搭建环境 搭建过程如下 a 选择一个com 右侧窗口处选择一个新建 选择连接
  • MyBatis 后端对数据库进行操作

    目录 1 MyBatis 是什么 2 MyBatis 的重要性 3 MyBatis 查询 3 1 创建数据库和表 3 2 添加MyBatis框架 持 3 2 1 新项目添加MyBatis 3 2 1 老项 添加 MyBatis 3 3 配置
  • 基于特征的图像配准方法

    From 基于特征的图像配准方法 基于特征的图像配准过程 1 特征空间 基于特征的配准方法在进行图像预处理从图像中提取所选的特征之前 要先确定特征空间 通常 特征空间的选择要考虑下面五个因素 相似性 参考图像与待配准图像中要匹配的特征应该是
  • js创建全0数组

    1 创建一个长度为m的全0数组 var arr new Array m fill 0 2 创建一个m行n列的全0数组 var arr new Array m fill new Array n fill 0
  • 一些笔试题笔记1

    总结一些常见的笔试题 最小公约数和最大公倍数 这个其实很简单 记住概念就可以了 我们利用辗转相除法计算 最大公约数 摘自百度百科 一般地 如果求a和b的最大公约数 a gt b 那么 当时 得 这里表示b整除a 而表示b不能整除 当时 设余
  • PostgreSQL分区

    修改表 官网手册 表分区 官网手册 概述 分区是指将一个逻辑上大的表拆分为较小的物理块 分区可以提供以下好处 在某些情况下 尤其是当表中大多数被频繁访问的行位于单个分区或少量分区中时 查询性能可以得到显着提高 分区替代了索引的前几列 从而减
  • [物联网方案-2]:传感器LoRa无线采集终端通用模型

  • 组网学习之什么是链路冗余(二)

    为什么要有链路冗余 一 设计冗余的目的 提高可靠性 通信时一条路不通走另一条路即冗余链路 采用具有冗余的核心层 分布层和接入层 试图消除网络中的单点故障 二 实施冗余的注意事项 1 MAC数据库不稳定 MAC地址表中的内容不稳定性源于交换机
  • ElasticSearch学习5-- 使用RestClient查询文档

    1 查询基本步骤 1 创建SearchRequest对象 2 准备Request source 也就是DSL QueryBuilders来构建查询条件 传入Request source 的 query 方法 3 发送请求 得到结果 4 解析
  • lol老是闪退到桌面_lol闪退到桌面怎么解决

    LOLwin10闪退到桌面解决方法是 右键点击桌面底部任务栏的空白位置 然后在弹出菜单中选择 任务管理器 菜单项 依次点击 文件 运行新任务 菜单项 在窗口中输入命令gpedit msc 依次点 击 计算机配置 管理模板 Windows组件
  • web.xml顺序不对错误(The content of element type “web-app“ must match “)

    web xml顺序不对错误 如果web xml提示以下错误 The content of element type web app must match icon display name description distributable
  • Linux CentOS安装抓包解包工具Wireshark图形化界面

    1 Wireshark介绍 Wireshark 是一个开源的网络协议分析工具 它能够捕获和分析网络数据包 提供深入的网络故障排除 网络性能优化和安全审计等功能 它支持跨多个操作系统 包括 Windows macOS 和 Linux 2 Wi
  • 基本配置文件配置

    一个具有JWT的项目 最基本的配置文件 在resource中 一般其实是有四个配置文件和一个有关Mybatis的xml包 一 服务器的配置 设置端口号 编码格式 二 设置有关spring的相关配置 控制器以及profile的配置 三 配置M
  • win服务器隐藏版本信息,Apache防盗链和隐藏版本信息

    文章目录 隐藏 一 防盗链 二 隐藏版本信息 实验要求 三台虚拟机分别是 linux和两台windows虚拟机 linux虚拟机为服务器 Windows7 1为客户端 Windows7 2为盗链端 实验步骤 一 防盗链 1 把httpd a
  • [Pytorch系列-47]:工具集 - torchvision.transforms.Normalize和ToSensor的深入详解

    作者主页 文火冰糖的硅基工坊 文火冰糖 王文兵 的博客 文火冰糖的硅基工坊 CSDN博客 本文网址 https blog csdn net HiWangWenBing article details 121300054 目录 第1章 关于标
  • tensor2tensor自定义问题,训练模型(bpe篇)

    tensor2tensor自定义问题 训练模型 上一篇 https blog csdn net hpulfc article details 81172498 之前一篇文章简单介绍了如何使用 google 的SubwordTokenEnco
  • c++小项目:基于STL的演讲比赛流程管理系统

    一 项目目的 运用c 实现一个基于STL的演讲比赛流程管理系统 比赛方式 共两轮 第一轮为分组淘汰赛 第二轮为决赛 共有十名评委 打分方式为去掉最高分和最低分的平均分为基准 第一轮共两组 每组六人 为随机分组和抽签决定演讲顺序 每组取前三名
  • Linux下实现DNS的分离解析

    Linux下实现DNS的分离解析 一 DNS简介 什么是DNS DNS的基本概念 二 安装DNS解析Bind服务 BIND bind配置文件 安装bind bind chroot软件包 查看安装软件生成的配置文件 三 DNS分离解析案例 一
  • Java之Class.forName方法详解

    一 前言 二 案例 三 详解 一 前言 在说明Class类的静态方法forName 之前 先清楚有关Class类的几个概念 1 Class类封装了类或接口的运行时状态 Java程序在运行时 Java运行时系统一直对所有的对象进行所谓的运行时