Class.forName()的作用与使用总结

2025-07-16 20:31:54

Class.forName()的作用与使用总结

转自:https://www.cnblogs.com/ljbguanli/p/7107058.html

Java程序在执行时,Java执行时系统一直对全部的对象进行所谓的执行时类型标识。这项信息纪录了每一个对象所属的类。虚拟机通常使用执行时类型信息选择正确方法去执行,用来保存这些运行时类型信息的类是Class类。Class类封装一个对象和接口执行时的状态,当装载类时。Class类型的对象自己主动创建。

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

虚拟机为每种类型管理一个独一无二的Class对象。也就是说,每一个类(型)都有一个Class对象。执行程序时。Java虚拟机(JVM)首先检查是否所要载入的类相应的Class对象是否已经载入。假设没有载入,JVM就会依据类名查找.class文件,并将其Class对象载入。

主要的 Java 类型(boolean、byte、char、short、int、long、float 和 double)和keyword void 也都相应一个 Class 对象。

每一个数组属于被映射为 Class 对象的一个类,全部具有同样元素类型和维数的数组都共享该 Class 对象。

一般某个类的Class对象被加载内存,它就用来创建这个类的全部对象。

一、怎样得到Class的对象呢?有三种方法能够的获取:

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

MyObject x;

Class c1 = x.getClass();

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

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

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

比如

Class cl1 = Manager.class;

Class cl2 = int.class;

Class cl3 = Double[].class;

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

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

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

二、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 对象是否表示一个数组类。

三、Class的一些使用技巧

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

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

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

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

2、 Class.forName()方法:

Class.forName:返回与给定的字符串名称相关联类或接口的Class对象。

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

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

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

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

static Class

forName(String className)

Returns the Class object associated with the class or interface with the given string name.

static Class

forName(String name, boolean initialize, ClassLoader loader)

Returns the Class object associated with the class or interface with the given string name, using the given class loader.

说明:

publicstatic Class forName(String className)

Returns the Class object associated withthe class or interface with the given string name. Invokingthis method is equivalent to:

Class.forName(className,true, currentLoader)

where currentLoader denotes the definingclass loader of the current class.

For example, thefollowing code fragment returns the runtime Class descriptor for theclass named java.lang.Thread:

Class t =Class.forName("java.lang.Thread")

A call to forName("X") causes theclass named X to beinitialized.

Parameters:

className - the fully qualifiedname of the desired class.

Returns:

the Class object for the classwith the specified name.

从官方给出的API文档中能够看出:

Class.forName(className)实际上是调用Class.forName(className,true, this.getClass().getClassLoader())。第二个參数。是指Class被loading后是不是必须被初始化。能够看出,使用Class.forName(className)载入类时则已初始化。

所以Class.forName(className)能够简单的理解为:获得字符串參数中指定的类,并初始化该类。

一.首先你要明确在java里面不论什么class都要装载在虚拟机上才干执行。

1. forName这句话就是装载类用的(new是依据载入到内存中的类创建一个实例,要分清楚)。

2. 至于什么时候用。能够考虑一下这个问题,给你一个字符串变量,它代表一个类的包名和类名,你怎么实例化它?

A a = (A)Class.forName("pacage.A").newInstance();这和 A a =new A();是一样的效果。

3. jvm在装载类时会运行类的静态代码段,要记住静态代码是和class绑定的,class装载成功就表示运行了你的静态代码了,并且以后不会再运行这段静态代码了。

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

5. 动态载入和创建Class 对象,比方想依据用户输入的字符串来创建对象

String str = 用户输入的字符串

Class t = Class.forName(str);

t.newInstance();

二.在初始化一个类,生成一个实例的时候。newInstance()方法和newkeyword除了一个是方法,一个是keyword外,最主要有什么差别?

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

2.那么为什么会有两种创建对象方式?

这主要考虑到软件的可伸缩、可扩展和可重用等软件设计思想。

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就能够。

3.从JVM的角度看,我们使用keywordnew创建一个类的时候。这个类能够没有被载入。 可是使用newInstance()方法的时候。

就必须保证:

1、这个类已经载入;

2、这个类已经连接了。

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

如今能够看出。newInstance()实际上是把new这个方式分解为两步。即首先调用Class载入方法载入某个类,然后实例化。这样分步的优点是显而易见的。我们能够在调用class的静态载入方法forName时获得更好

的灵活性,提供给了一种降耦的手段。

三.最后用最简单的描写叙述来区分newkeyword和newInstance()方法的差别:

1. newInstance: 弱类型。低效率。仅仅能调用无參构造。

2. new: 强类型。相对高效。

能调用不论什么public构造。

3、应用情景:

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

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()。为什么会有这两种写法呢?

刚才提到,Class.forName("");的作用是要求JVM查找并载入指定的类,假设在类中有静态初始化器的话,JVM必定会运行该类的静态代码段。

而在JDBC规范中明白要求这个Driver类必须向DriverManager注冊自己。即不论什么一个JDBCDriver的Driver类的代码都必须类似例如以下:

public classMyJDBCDriver implements Driver {

static{

DriverManager.registerDriver(new MyJDBCDriver());

} }

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

情景二:使用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();