Java反射

2021-08-0787

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获取相应的连接。