Java中Class.forName()用法详解

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);就可以了。

时间: 2024-10-18 04:06:07

Java中Class.forName()用法详解的相关文章

Java 中 synchronized的用法详解

Java语言的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码. 1.方法声明时使用,放在范围操作符(public等)之后,返回类型声明(void等)之前.这时,线程获得的是成员锁,即一次只能有一个线程进入该方法,其他线程要想在此时调用该方法,只能排队等候,当前线程(就是在synchronized方法内部的线程)执行完该方法后,别的线程才能进入.例如: public synchronized void synMethod() { //方法体} 2.

Java中Map的用法详解

Map简介 将键映射到值的对象.一个映射不能包含重复的键:每个键最多只能映射到一个值.此接口取代 Dictionary 类,后者完全是一个抽象类,而不是一个接口. Map 接口提供三种collection 视图,允许以键集.值集或键-值映射关系集的形式查看某个映射的内容.映射顺序 定义为迭代器在映射的 collection 视图上返回其元素的顺序.某些映射实现可明确保证其顺序,如 TreeMap 类:另一些映射实现则不保证顺序,如HashMap 类. 注:将可变对象用作映射键时必须格外小心.当对

java中的instanceof用法详解

instanceof是Java的一个二元操作符(运算符),也是Java的保留关键字.它的作用是判断其左边对象是否为其右边类的实例,返回的是boolean类型的数据.用它来判断某个对象是否是某个Class类的实例. 用法: boolean result = object instanceof class 参数: result :boolean类型. object :必选项.任意对象表达式. class:必选项.任意已定义的对象类. 说明: 如果该object 是该class的一个实例,那么返回tr

Java下static关键字用法详解

Java下static关键字用法详解 本文章介绍了java下static关键字的用法,大部分内容摘自原作者,在此学习并分享给大家. Static关键字可以修饰什么? 从以下测试可以看出, static 可以修饰: 1. 语句块 2. 成员变量(但是不能修饰局部变量) 3. 方法 4. 接口(内部接口) 5. 类(只能修饰在类中的类, 即静态内部类) 6. jdk 1.5 中新增的静态导入 那么static 修饰的表示什么呢? 当创建一个类时,就是在创建一个新类型,描述这个类的对象的外观和行为,除

Java语言Socket接口用法详解

Socket接口用法详解   在Java中,基于TCP协议实现网络通信的类有两个,在客户端的Socket类和在服务器端的ServerSocket类,ServerSocket类的功能是建立一个Server,并通过accept()方法随时监听客户端的连接请求. 扩展: ServerSocket中常用的构造函数及方法 构造函数:ServerSocket(int port) 这是一个构造方法,用于在当前的服务器默认的IP地址上监听一个指定的端口,即在指定的IP和端口创建一个ServerSocket对象

Java中的main()方法详解

在Java中,main()方法是Java应用程序的入口方法,也就是说,程序在运行的时候,第一个执行的方法就是main()方法,这个方法和其他的方法有很大的不同,比如方法的名字必须是main,方法必须是public static void 类型的,方法必须接收一个字符串数组的参数等等. 在看Java中的main()方法之前,先看一个最简单的Java应用程序HelloWorld,我将通过这个例子说明Java类中main()方法的奥秘,程序的代码如下: 1 /** 2 * Java中的main()方法

java中的io系统详解

java中的io系统详解 分类: JAVA开发应用 笔记(读书.心得)2009-03-04 11:26 46118人阅读 评论(37) 收藏 举报 javaiostreamconstructorstringbyte 相关读书笔记.心得文章列表 Java 流在处理上分为字符流和字节流.字符流处理的单元为 2 个字节的 Unicode 字符,分别操作字符.字符数组或字符串,而字节流处理单元为 1 个字节,操作字节和字节数组. Java 内用 Unicode 编码存储字符,字符流处理类负责将外部的其他

PHP中的ob_start用法详解

用PHP的ob_start();控制您的浏览器cache Output Control 函数可以让你自由控制脚本中数据的输出.它非常地有用,特别是对于:当你想在数据已经输出后,再输出文件头的情况.输出控制函数不对使用 header() 或 setcookie(), 发送的文件头信息产生影响,只对那些类似于 echo() 和 PHP 代码的数据块有作用.我们先举一个简单的例子,让大家对Output Control有一个大致的印象:Example 1. 程序代码 程序代码<?phpob_start(

c++中vector的用法详解

c++中vector的用法详解 vector(向量): C++中的一种数据结构,确切的说是一个类.它相当于一个动态的数组,当程序员无法知道自己需要的数组的规模多大时,用其来解决问题可以达到最大节约空间的目的. 用法: 1.文件包含: 首先在程序开头处加上#include<vector>以包含所需要的类文件vector 还有一定要加上using namespace std; 2.变量声明: 2.1 例:声明一个int向量以替代一维的数组:vector <int> a;(等于声明了一个