Class.forName()用法详解

主要功能 Class.forName(xxx.xx.xx)返回的是一个类 Class.forName(xxx.xx.xx)的作用是要求JVM查找并加载指定的类, 也就是说JVM会执行该类的静态代码段 下面,通过解答以下三个问题的来详细讲解下Class.forName()的用法。 一.什么时候用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关键字除了一个是方法,一个是关键字外,最主要有什么区别?它们的区别在于创建对象的方式不一样,前者是使用类加载机制,后者是创建一个新类。那么为什么会有两种创建对象方式?这主要考虑到软件的可伸缩、可扩展和可重用等软件设计思想。 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()方法的时候,就必须保证: 1、这个类已经加载; 2、这个类已经连接了。 而完成上面两个步骤的正是Class的静态方法forName()所完成的,这个静态方法调用了启动类加载器,即加载 java API的那个加载器。 现在可以看出,newInstance()实际上是把new这个方式分解为两步,即首先调用Class加载方法加载某个类,然后实例化。 这样分步的好处是显而易见的。我们可以在调用class的静态加载方法forName时获得更好的灵活性,提供给了一种降耦的手段。 二.new 和Class.forName()有什么区别? 其实上面已经说到一些了,这里来做个总结: 首先,newInstance( )是一个方法,而new是一个关键字; 其次,Class下的newInstance()的使用有局限,因为它生成对象只能调用无参的构造函数,而使用 new关键字生成对象没有这个限制。 简言之: newInstance(): 弱类型,低效率,只能调用无参构造。 new: 强类型,相对高效,能调用任何public构造。 Class.forName(“”)返回的是类。 Class.forName(“”).newInstance()返回的是object 。 三.为什么在加载数据库驱动包的时候有用的是Class.forName( ),却没有调用newInstance( )? 在Java开发特别是数据库开发中,经常会用到Class.forName( )这个方法。 通过查询Java Documentation我们会发现使用Class.forName( )静态方法的目的是为了动态加载类。 通常编码过程中,在加载完成后,一般还要调用Class下的newInstance( )静态方法来实例化对象以便操作。因此,单单使用Class.forName( )是动态加载类是没有用的,其最终目的是为了实例化对象。 有数据库开发经验朋友会发现,为什么在我们加载数据库驱动包的时候有的却没有调用newInstance( )方法呢? 即有的jdbc连接数据库的写法里是Class.forName(xxx.xx.xx);而有一 些:Class.forName(xxx.xx.xx).newInstance(),为什么会有这两种写法呢? 刚才提到,Class.forName(“”);的作用是要求JVM查找并加载指定的类,首先要明白,java里面任何class都要装载在虚拟机上才能运行,而静态代码是和class绑定的,class装载成功就表示执行了你的静态代码了,而且以后不会再走这段静态代码了。 而我们前面也说了,Class.forName(xxx.xx.xx)的作用就是要求JVM查找并加载指定的类,如果在类中有静态初始化器的话,JVM必然会执行该类的静态代码段。 而在JDBC规范中明确要求这个Driver类必须向DriverManager注册自己,即任何一个JDBC Driver的 Driver类的代码都必须类似如下: public class MyJDBCDriver implements Driver { static { DriverManager.registerDriver(new MyJDBCDriver()); } } 既然在静态初始化器的中已经进行了注册,所以我们在使用JDBC时只需要Class.forName(XXX.XXX);就可以了。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏noteless

[四] java虚拟机JVM编译器编译代码简介 字节码指令实例 代码到底编译成了什么形式

前文已经对虚拟机进行过了简单的介绍,并且也对class文件结构,以及字节码指令进行了详尽的说明

1882
来自专栏java学习

工程师笔试题2(答案解析)

一、单项选择题 1.二进制数 11101 转化为十进制数是( )。 A.23 B.17 C.26 D.29 2.以下可以对对象加互斥锁的关键字是( )。 ...

3316
来自专栏C/C++基础

C++11 原生字符串

原生字符串(Raw String)指不进行转义“所见即所得”的字符串。很多编程语言早已支持原生字符串,如C#、Python、Shell等。C++作为一门高级程序...

1912
来自专栏日常分享

Spring 学习笔记(七)—— 切入点表达式

  语法结构:   execution(   方法修饰符  方法返回值  方法所属类 匹配方法名 (  方法中的形参表 )  方法申明抛出的异常  )

601
来自专栏从流域到海域

《笨办法学Python》 第32课手记

《笨办法学Python》 第32课手记 本节课讲for循环和list,list里类似于c中的数组,但有区别很大。C语言中的数组是数据类型相同的值的集合,list...

2099
来自专栏程序员互动联盟

【编程基础】C语言位

位制就是为了减小存储大小,把一个char, unsigned int, int的存储空间进行拆分后,对每个进行操作。 给出一段代码: #include <st...

3287
来自专栏Python小屋

数学老师从没这么教过,乘法竖式中进位可以是多位(附Python实现与测试源码)

大概十五年前,曾经写过一个C语言版本的类似代码。核心思想是:在乘法竖式计算过程中,每次的进位实际上是可以超过一位的,虽然老师从来没有这么教过。 ? 这样的操作在...

3416
来自专栏我是业余自学C/C++的

redis_3.0.7_sds.c_sdsIncrLen()

1232
来自专栏编程坑太多

python--面向对象与模块补充,反射

1814
来自专栏Java学习网

Java面试中最常见的10个问题,Java底层知识,花点时间学习一下

1.什么是 Java 虚拟机?为什么 Java 被称作是“平台无关的编程语言”? Java 虚拟机是一个可以执行 Java 字节码的虚拟机进程。Java 源文...

2745

扫码关注云+社区

领取腾讯云代金券