Java反射
Java.lang.Class
一、Class类是什么
Class是一个类,位于java.lang包下。在Java中每个类都有一个相对应的Class类的对象,换句话说:Java程序在启动运行时 一个XXX.java类经过编译生成XXX.class文件后,就会在JVM虚拟机中产生一个XXX类对应的Class类的对象,用于表示这个XXX类的类型信息。
二、Class类常用的方法
Class类是反射中的核心类,它有如下的方法:
获取类中的属性:
- getFields(): 获取类中public类型的属性
- getField(String name): 获取类特定的方法,name参数指定了属性的名称
- getDeclaredFields(): 获取类中所有的属性(public、protected、default、private),但不包括继承的属性。
- getDeclaredField(String name): 获取类特定的方法,name参数指定了属性的名称
获取类中的构造函数:
- getConstructors():获取类中的公共方法
- getConstructor(Class[] params): 获取类的特定构造方法,params参数指定构造方法的参数类型
- getDeclaredConstructors(): 获取类中所有的构造方法(public、protected、default、private)
- getDeclaredConstructor(Class[] params): 获取类的特定构造方法,params参数指定构造方法的参数类型
获取类中的方法:
- getMethods(): 获得类的public类型的方法
- getMethod(String name, Class[] params): 获得类的特定方法,name参数指定方法的名字,params参数指定方法的参数类型
- getDeclaredMethods(): 获取类中所有的方法(public、protected、default、private)
- getDeclaredMethod(String name, Class[] params): 获得类的特定方法,name参数指定方法的名字,params参数指定方法的参数类型
其它重要方法:
- newInstance(): 通过类的不带参数 的构造方法创建这个类的一个对象
- forName(String className): 获取className参数指定的类的class对象
- forName(String className,boolean initialize,ClassLoader): 使用指定的类加载器获取className参数指定的类的class对象
- getClassLoader(): 获取类加载器
- getName(): 获取类名
- getPackage(): 获取类所在的包名
三、获取Class对象的三种方法
第一种: 调用Class类的静态方法forName,比如 Class.forName('java.lang.String')
第二种: 使用类的.class语法,比如 : Class cls = String.class
第三种: 调用对象的getClass方法, 比如:String str = '123'; Class cls = str.getClass();
(PS:在java.lang.Object类中定义了getClass()方法,因此对于任意一个Java对象,都可以通过此方法获得对象的类型)
classloader和Class.forname的区别
Java中class是如何加载到JVM中的:
1.class加载到JVM中有三个步骤
装载:(loading)找到class对应的字节码文件。
连接:(linking)将对应的字节码文件读入到JVM中。
初始化:(initializing)对class做相应的初始化动作。
2.Java中两种加载class到JVM中的方式
2.1:Class.forName("className");
其实这种方法调运的是:Class.forName(className, true, ClassLoader.getCallerClassLoader())方法
参数一:className,需要加载的类的名称。
参数二:true,是否对class进行初始化(需要initialize)
参数三:classLoader,对应的类加载器
2.2:ClassLoader.laodClass("className");
其实这种方法调运的是:ClassLoader.loadClass(name, false)方法
参数一:name,需要加载的类的名称
参数二:false,这个类加载以后是否需要去连接(不需要linking)
2.3:两种方式的区别
forName("")得到的class是已经初始化完成的
loadClass("")得到的class是还没有连接的
一般情况下,这两个方法效果一样,都能装载Class。
但如果程序依赖于Class是否被初始化,就必须用Class.forName(name)了。
3.举例说明他们各自的使用方法
java使用JDBC连接数据库时候,我们首先需要加载数据库驱动。
Class.forName("com.mysql.jdbc.Driver");//通过这种方式将驱动注册到驱动管理器上
Connection conn = DriverManager.getConnection("url","userName","password");//通过驱动管理器获得相应的连接
查看com.mysql.jdbc.Driver源码:
public class Driver extends NonRegisteringDriver
implements java.sql.Driver
{
//注意,这里有一个static的代码块,这个代码块将会在class初始化的时候执行
static
{
try
{
//将这个驱动Driver注册到驱动管理器上
DriverManager.registerDriver(new Driver());
} catch (SQLException E) {
throw new RuntimeException("Can't register driver!");
}
}
}
Class.forName("com.mysql.jdbc.Driver")方法以后,他会进行class的初始化,执行static代码块。
也就是说class初始化以后,就会将驱注册到DriverManageer上,之后才能通过DriverManager去获取相应的连接。
但是要是我们使用ClassLoader.loadClass(com.mysql.jdbc.Driver)的话,不会link,更也不会初始化class。
相应的就不会回将Driver注册到DriverManager上面,所以肯定不能通过DriverManager获取相应的连接。