浅谈 Class.forName() 的用法

news2025/1/24 8:39:05

目录

  • 什么是class对象

  • 获得class对象的三种方法

  • class的作用和方法

  • Class.forName()用法

    • 什么时候用Class.forName()

    • newInstance和new关键字的区别

  • 应用问题解析

    • 情景一:载入数据库驱动的时候

    • 情景二:使用AIDL与电话管理Servic进行通信

1.什么是class对象

类是程序的一部分,每个类都有一个class对象。换言之,每当编写并且编译了一个新类,就会产生一个class对象(更恰当的说,是被保存在一个同名的class文件中)。为了生成这个类的对象,运行这个程序的Java虚拟机(jvm)将使用被称为“类加载器”的子系统。

所有的类都是在对其第一次使用的时候被加载到JVM中。如当程序创建对第一个静态成员的引用时,就会加载这个类。或者使用new关键字创建新的对象的时候。

因此java程序在它运行之前并非完全加载,其各个部分是在必须的时候才加载的。类加载器首先检查这个类的class对象是否已经加载。如果尚未加载,默认的类加载器就会根据类名查找.class文件。

实际上在Java中每个类都有且只有一个Class对象。

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

Class类被创建后的对象就是Class对象,注意,Class对象表示的是自己手动编写类的类型信息,比如创建一个Shapes类,那么,JVM就会创建一个Shapes对应Class类的Class对象,该Class对象保存了Shapes类相关的类型信息。

实际上在Java中每个类都有一个Class对象,每当我们编写并且编译一个新创建的类就会产生一个对应Class对象并且这个Class对象会被保存在同名.class文件里(编译后的字节码文件保存的就是Class对象),那为什么需要这样一个Class对象呢?

是这样的,当我们new一个新对象或者引用静态成员变量时,Java虚拟机(JVM)中的类加载器子系统会将对应Class对象加载到JVM中,然后JVM再根据这个类型信息相关的Class对象创建我们需要实例对象或者提供静态变量的引用值。

需要特别注意的是,手动编写的每个class类,无论创建多少个实例对象,在JVM中都只有一个Class对象,即在内存中每个类有且只有一个相对应的Class对象,挺拗口,通过下图理解(内存中的简易现象图):

到这我们也就可以得出以下几点信息:

  • Class类也是类的一种,与class关键字是不一样的。

  • 手动编写的类被编译后会产生一个Class对象,其表示的是创建的类的类型信息,而且这个Class对象保存在同名.class的文件中(字节码文件),比如创建一个Shapes类,编译Shapes类后就会创建其包含Shapes类相关类型信息的Class对象,并保存在Shapes.class字节码文件中。

  • 每个通过关键字class标识的类,在内存中有且只有一个与之对应的Class对象来描述其类型信息,无论创建多少个实例对象,其依据的都是用一个Class对象。

  • Class类只存私有构造函数,因此对应Class对象只能有JVM创建和加载

  • Class类的对象作用是运行时提供或获得某个对象的类型信息,这点对于反射技术很重要(关于反射稍后分析)。

2.获得class对象的三种方法

1、调用Object类的getClass()方法来得到Class对象,这也是最常见的产生Class对象的方法。比如:

MyObject x;
Class c1 = x.getClass();

Object.getClass(); Object中自带的方法,getclass(),返回一个class对象。

2、使用Class类的中静态forName()方法获得与字符串相应的Class对象。比如:

Class c2=Class.forName("MyObject"),MyObject必须是接口或者类的名字。

class.forname()

Class c=Class.forName("类的全限定名")

传入string类型参数,要求jvm查找并加载指定的类,返回的是一个class对象的引用。

3、获取Class类型对象的第三个方法很easy。假设T是一个Java类型。那么T.class就代表了匹配的类对象。

比如

Class cl1 = Manager.class;
Class cl2 = int.class;
Class cl3 = Double[].class;

注意:Class对象实际上描写叙述的仅仅是类型。而这类型未必是类或者接口。

比如上面的int.class是一个Class类型的对象。

因为历史原因。数组类型的getName方法会返回奇怪的名字。

3.class的作用和方法

  • getname():以string类型返回class对象表示的实体(类,接口,数组,基本类型,void等)名称

  • newInstance():创建一个实例,只能调用默认构造器。

  • getsuperclass():返回class表示的实体超类的名称

  • getSimpleName():不办含包名的类名。

  • isInterfence:告诉你这个class对象是否表示某个接口。

1、getName()

一个Class对象描写叙述了一个特定类的属性,Class类中最经常使用的方法getName以 String 的形式返回此 Class 对象所表示的实体(类、接口、数组类、基本类型或 void)名称。

2、newInstance()

Class另一个实用的方法能够为类创建一个实例,这种方法叫做newInstance()。比如:

x.getClass.newInstance(),创建了一个同x一样类型的新实例。newInstance()方法调用默认构造器(无參数构造器)初始化新建对象。

3、getClassLoader()

返回该类的类载入器。

4、getComponentType()

返回表示数组组件类型的 Class。

5、getSuperclass()

返回表示此 Class 所表示的实体(类、接口、基本类型或 void)的超类的 Class。

6、isArray()

判定此 Class 对象是否表示一个数组类。

1、forName和newInstance结合起来使用,能够依据存储在字符串中的类名创建对象。比如

Object obj = Class.forName(s).newInstance();

2、虚拟机为每种类型管理一个独一无二的Class对象。因此能够使用==操作符来比較类对象。比如:

if(e.getClass() == Employee.class)...

4 Class.forName()用法

主要功能

  • Class.forName(xxx.xx.xx)返回的是一个类。

  • Class.forName(xxx.xx.xx)的作用是要求JVM查找并加载指定的类,也就是说JVM会执行该类的静态代码段。

Class.forName是一个静态方法,相同能够用来载入类。

该方法有两种形式:Class.forName(String name, boolean initialize, ClassLoader loader)Class.forName(String className)

第一种形式的參数 name表示的是类的全名;initialize表示是否初始化类。loader表示载入时使用的类载入器。

另外一种形式则相当于设置了參数 initialize的值为 true。loader的值为当前类的类载入器

4.1 什么时候用Class.forName()?

先来个热身,给你一个字符串变量,它代表一个类的包名和类名,你怎么实例化它?你第一想到的肯定是new,但是注意一点:

A a = (A)Class.forName(“pacage.A”).newInstance();

这和你 A a = new A();是一样的效果。

现在言归正传。

动态加载和创建Class 对象,比如想根据用户输入的字符串来创建对象时需要用到:

  • String str = “用户输入的字符串” ;

  • Class t = Class.forName(str);

  • t.newInstance();

在初始化一个类,生成一个实例的时候,newInstance()方法和new关键字除了一个是方法,一个是关键字外,最主要有什么区别?

它们的区别在于创建对象的方式不一样,前者是使用类加载机制,后者是创建一个新类。

4.2 newInstance和new关键字的区别

Java中工厂模式经常使用newInstance()方法来创建对象,因此从为什么要使用工厂模式上可以找到具体答案。例如:

class c = Class.forName(“Example”);
factory = (ExampleInterface)c.newInstance();

其中ExampleInterface是Example的接口,可以写成如下形式:

String className = “Example”;
class c = Class.forName(className);
factory = (ExampleInterface)c.newInstance();

进一步可以写成如下形式:

String className = readfromXMlConfig;//从xml 配置文件中获得字符串
class c = Class.forName(className);
factory = (ExampleInterface)c.newInstance();

上面代码已经不存在Example的类名称,它的优点是,无论Example类怎么变化,上述代码不变,甚至可以更换Example的兄弟类Example2 , Example3 , Example4……,只要他们继承ExampleInterface就可以。

从JVM的角度看,我们使用关键字new创建一个类的时候,这个类可以没有被加载。但是使用newInstance()方法的时候,就必须保证:

  • 这个类已经加载;

  • 这个类已经连接了。

而完成上面两个步骤的正是Class的静态方法forName()所完成的,这个静态方法调用了启动类加载器,即加载 java API的那个加载器。

现在可以看出,newInstance()实际上是把new这个方式分解为两步,即首先调用Class加载方法加载某个类,然后实例化。

这样分步的好处是显而易见的。我们可以在调用class的静态加载方法forName时获得更好的灵活性,提供给了一种降耦的手段。

最后用最简单的描述来区分new关键字和newInstance()方法的区别:

  • newInstance:弱类型。低效率。只能调用无参构造。

  • new:强类型。相对高效。能调用任何public构造。

  • Class.forName(“”)返回的是类。

  • Class.forName(“”).newInstance()返回的是object

5 应用问题解析

情景一:载入数据库驱动的时候

Class.forName的一个非经常见的使用方法是在载入数据库驱动的时候

Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
Connection con=DriverManager.getConnection("jdbc:sqlserver://localhost:1433;DatabaseName==JSP","jph","jph");  

为什么在我们载入数据库驱动包的时候有的却没有调用newInstance()方法呢?

即有的jdbc连接数据库的写法里是Class.forName(xxx.xx.xx);而有一些:Class.forName(xxx.xx.xx).newInstance()。为什么会有这两种写法呢?

通过查询Java Documentation我们会发现使用Class.forName()静态方法的目的是为了动态加载类。通常编码过程中,在加载完成后,一般还要调用Class下的newInstance()静态方法来实例化对象以便操作。因此,单使用Class.forName( )是动态加载类是没有用的,其最终目的是为了实例化对象。

刚才提到,Class.forName("");的作用是要求JVM查找并加载指定的类,如果在类中有静态初始化器的话,JVM必然会执行该类的静态代码段。而在JDBC规范中明确要求这个Driver类必须向DriverManager注册自己,即任何一个JDBC Driver的 Driver类的代码都必须类似如下:

public class MyJDBCDriver implements Driver {
   static {
     DriverManager.registerDriver(new MyJDBCDriver());
  }
}

既然在静态初始化器的中已经进行了注册,所以我们在使用JDBC时只需要Class.forName(XXX.XXX);就可以了。

既然在静态初始化器的中已经进行了注册,所以我们在使用JDBC时只需要Class.forName(XXX.XXX);就可以了。

public class ProxoolDriver implements Driver {
 
    private static final Log LOG = LogFactory.getLog(ProxoolDriver.class);
 
    static {
        try {
            DriverManager.registerDriver(new ProxoolDriver());
        } catch (SQLException e) {
            System.out.println(e.toString());
        }
    }
 
}

情景二:使用AIDL与电话管理Servic进行通信

Method method =Class.forName("android.os.ServiceManager")
 
         .getMethod("getService",String.class);
 
// 获取远程TELEPHONY_SERVICE的IBinder对象的代理
 
IBinder binder =(IBinder) method.invoke(null, new Object[] { TELEPHONY_SERVICE});
 
// 将IBinder对象的代理转换为ITelephony对象
 
ITelephonytelephony = ITelephony.Stub.asInterface(binder);
 
// 挂断电话
 
telephony.endCall();

 

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

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

相关文章

[Spring Boot 5]安全管理

本文介绍了Spring Security 以及Shiro 在Spring Boot中的使用,对于Spring Security 有基于传统认证方式的Session认证,也有使用OAuth 协议的认证。一般来说,传统的Web架构中,使用Session 认证更加快速,但是&#xff0c…

2. 如何给在 SAP Business Application Studio 里开发的 OData 服务准备测试数据

在开始本步骤的学习之前,请大家务必完成前一步骤1. SAP Business Application Studio 里创建一个基于 CAP 模型的最简单的 OData 服务的学习。换言之,大家已经在 SAP Business Technology Platform 上的 Business Application Studio 里,创建好了 Dev Space,并且拥有一个能…

JVM 别和我说你还不知道这几种垃圾回收器?Serial |Parallel|ParNew|CMS|G1|ZGC

Serial / Serial Old 从单词翻译过来看 serial 串行,每次它就是一款单线程收集器。 Serial 工作在新生代垃圾回收,Serial Old在老年代进行垃圾回收,Serial Old一般作为CMS 并发收集失败后的备选回收方案。 在垃圾收集器面前,它…

《Flowable流程引擎从零到壹》引入日志框架和部署流程定义

14天学习训练营导师课程: 邓澎波《Flowable流程引擎-基础篇【2022版】》 邓澎波《Flowable流程引擎-高级篇【2022版】》 学习笔记《Flowable流程引擎从零到壹》回城传送 ❤️作者主页:小虚竹 ❤️作者简介:大家好,我是小虚竹。Java领域优质创…

目标检测算法——YOLOv5/YOLOv7改进之结合​PP-LCNet(轻量级CPU网络)

>>>深度学习Tricks&#xff0c;第一时间送达<<< 目录 ​PP-LCNet——轻量级且超强悍的CPU级骨干网络&#xff01;&#xff01; &#xff08;一&#xff09;前沿介绍 1.PP-LCNet主要模块 2.相关实验结果 &#xff08;二&#xff09;YOLOv5/YOLOv7改进之结…

GreenPlum6.x之ETL工具

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录前言一、ETL是什么&#xff1f;二、数据加载工具GPLoad1.GPLoad安装部署2.编写控制文件test.yml总结前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#…

[Flask]Flask零基础项目---登录demo

借助Flask框架实现模拟用户登录操作&#xff1b; 一步一步的来实现这个登录接口 login.py from flask import Flask, render_template,requestapp Flask(__name__, template_folderlogin)app.route(/) def hello_flask():data request.get_data()print(data)return render_…

黑白图片和黑白图片上色系统毕业设计,AI黑背图像上色系统设计与实现,AI黑白照片上色系统论文毕设作品参考

功能清单 【后台管理员功能】 系统设置&#xff1a;设置网站简介、关于我们、联系我们、加入我们、法律声明 广告管理&#xff1a;设置小程序首页轮播图广告和链接 留言列表&#xff1a;所有用户留言信息列表&#xff0c;支持删除 会员列表&#xff1a;查看所有注册会员信息&a…

电子商务交易系统的设计与实现(javaee+mysql)

目录 1 概论 1 1.1电子商务交易发展 1 1.1.1电子商务交易 1 1.1.2发展前景&#xff1a; 1 2 系统可行性及需求分析 3 2.1 系统调研 3 2.2 系统可行性分析 3 2.2.1技术可行性分析 3 2.2.2 操作可行性分析 3 2.2.3 社会可行性分析 4 2.2.4可行性分析小结 4 2.3 系统需求分析 4 2.…

Windows10添加群晖磁盘映射,总是提示用户名密码不正确解决办法

在使用群晖NAS时&#xff0c;我们需要通过本地映射的方式把NAS映射成本地的一块磁盘使用。 通过winr键&#xff0c;输入\\NAS的IP地址&#xff0c;登录设备时总是提示”用户名或密码不正确”。但是实际密码是正确的。 原因描述&#xff1a;Windows 10&#xff08;或更早版本&a…

Android如何自定义服务器DynamicMockServer的使用

在平时开发时经常需要与服务器进行联调&#xff0c;但是服务器开发往往比前端的要滞后。这时候需要我们自己去mock数据来调通流程。 今天给大家介绍一款Android上的MockServer----DynamicMockServer&#xff0c;支持接口调用&#xff0c;静态文件。 DynamicMockServer&#x…

Web 安全:PKI 扫盲

个人博客 在互联网世界&#xff0c;我们广泛采用 TLS 来保护通信安全&#xff0c;这里的安全主要包含两部分内容&#xff1a;身份鉴别、通信加密。身份鉴别是一切的基础&#xff0c;特别当发送消息比较敏感需要加密时&#xff0c;对接收方必然有一个身份“假设”&#xff0c;“…

MacBook Pro M1 Docker 环境安装 Nacos 2.x 版本

MacBook Pro M1 Docker 环境安装 Nacos 2.x 版本 前言 由于 rocksdb 暂不支持 M1 平台&#xff0c;所以使用 Zulu JDK 的小伙伴们运行 Nacos 2.x 版本会报错&#xff0c;网上通用的解决方案是使用 Oracle JDK 来运行 Nacos 2.x 版本&#xff0c;但对于强迫症的我来说&#xf…

图书管理系(统附源码PPT)

图书管理系统1 绪 论1.1 研究背景1.2 研究意义1.3 相关研究现状1.3.1 高校图书管理面临的问题1.3.2 信息化为图书管理带来新变化2 相关技术2.1 JSP 概述2.2 MySQL 数据库技术2.3 Spring2.4 SpringMVC2.5 Dbcp2.6 Maven3 系统分析3.1 需求分析3.1.1 系统的功能需求分析3.1.2 系统…

【Git】一文带你入门Git分布式版本控制系统(必要配置、工作原理、创建/克隆项目)

Git 系列文章目录 Git 专栏参考链接Git&#xff08;一&#xff09;【Git】一文带你入门Git分布式版本控制系统&#xff08;简介&#xff0c;安装&#xff0c;Linux命令&#xff09;文章目录Git 系列文章目录一、Git 的必要配置二、Git 的工作原理三、Git 项目创建1、创建本地项…

【kafka】十四、kafka生产者API

kafka Producer API 1.消息发送流程 kafka的producer发送消息采用的是异步发送的方式。在消息的发送过程中&#xff0c;涉及到了两个线程–main线程和sender线程&#xff0c;以及一个线程共享变量–RecordAccumulator。main线程将消息发送给RecordAccumulator&#xff0c;send…

单向环形链表介绍以及约瑟夫问题分析

❤️一名热爱Java的大一学生&#xff0c;希望与各位大佬共同学习进步❤️ &#x1f9d1;个人主页&#xff1a;周小末天天开心 各位大佬的点赞&#x1f44d; 收藏⭐ 关注✅&#xff0c;是本人学习的最大动力 感谢&#xff01; &#x1f4d5;该篇文章收录专栏—数据结构 目录 单…

不敲代码就能搭建个人博客?快解析内网穿透来助力

记得很多年前看到一句话&#xff0c;“博客是一个人的狂欢”。无论是享受搭建的过程&#xff0c;还是享受创作的乐趣&#xff0c;更多时候博客是在取悦自己。那么&#xff0c;在2022年的今天&#xff0c;搭建个人博客还有意义吗&#xff1f;答案是肯定的&#xff0c;当我们在搜…

Day4: 应用篇-1

应用篇-1 环境安装 应用开发交叉编译环境&#xff0c; 【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.7.pdf 章节4.3.1 在 Ubuntu 中创建目录&#xff1a;/usr/local/arm&#xff0c;命令如下&#xff1a; sudo mkdir /usr/local/arm令将交叉编译器复制到/usr/local/arm 中…

Arduino开发实例-DIY分贝测量仪

DIY分贝测量仪 1、应用介绍 分贝计,它通常用于测量声音的强度和水平。 声音响度是用分贝来衡量的。 从飞机到人类耳语的不同发声介质都有一定的声音响度,以分贝表示。 声波是具有来回运动的纵波,给出高音或低音,如图所示: 声音的响度取决于频率或波长或传播所需的时间。…