反射机制最重要的部分是准许你检查类的结构。java.lang.reflect包中的三个类Field、Method、Constructor相应的描述了一个类的字段、方法、构造函数。使用这些类的时候必须要遵循下面步骤:
第一步是获得你想操作的类的 java.lang.Class 对象。下面就是获得一个 Class 对象的方法之一:Class c = Class.forName("java.lang.String"); //这条语句得到一个 String 类的类对象。还有另一种方法:Class c = int.class; 或者Class c = Integer.TYPE; //可获得基本类型的类信息。
第二步是调用诸如 getDeclaredMethods 的方法,以取得该类中定义的所有方法的列表。
Method m[] = c.getDeclaredMethods();
System.out.println(m[0].toString()); //以文本方式打印出 String 中定义的第一个方法的原型。
Class.forName 的作用 ? 为什么要用 ?
答: Class是运行中的class类,forName(className)是将这个名为className的类装入JVM,这样就可以动态的加载类,通过Class的反射机制可以获得此类的一些信息。Class.forName 的作用动态加载和创建Class 对象。
类加载器是用来加载.class文件,读取.class文件的字节码并加载到内存中。
关于类的初始化(执行static程序段):
1、A a = new A();//在类加载的时候即进行初始化
2、Class.forName(A);//在类加载(载入class)的时候即进行初始化
3、Class.forName(A,false,classLoader);//在newInstance的时候进行初始化
4、classLoader.loadClass(A);//在newInstance的时候进行初始化
static块仅执行一次
(1) 使用Class.forName()
+- public static Class forName(String className)
+- public static Class forName(String className, boolean initialize,ClassLoader loader)
参数说明:
className - 所需类的完全限定名(包括全路径)
initialize - 是否必须初始化类(静态代码块的初始化)
loader - 用于加载类的类加载器
不管使用的是new 來实例化某个类、或是使用只有一个参数的Class.forName()方法,内部都隐含了“载入类 + 运行静态代码块”的步骤。而使用具有三个参数的Class.forName()方法时,如果第二个参数为false,那么类加载器只会加载类,而不会初始化静态代码块,只有当实例化这个类的时候,静态代码块才会被初始化,静态代码块是在类第一次实例化的时候才初始化的。
Class类和对象
类是程序的一部分,每个类都有一个Class对象。换言之,每次写一个新类时,同时也会创建一个Class对象(更恰当地说,是保存在一个完全同名的.class文件中)。在运行期,一旦我们想生成这个类的对象,运行这个程序的Java虚拟机(JVM)首先就会检查这个类的Class对象是否已经载入。若尚未载入,JVM就会根据类名查找.class文件,并将其载入。所以Java程序并不是一开始就被完全加载的,这一点与许多传统语言都不同。
一旦某个类的Class对象被载入内存,它就被用来创建这个类的所有对象。注意:Class对象仅在需要的时候才被加载。Class类没有公共构造方法。Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的 defineClass 方法自动构造的,因此不能显式地声明一个Class对象。
基本的 Java 类型(boolean、byte、char、short、int、long、float 和 double)和关键字 void 也都对应一个 Class 对象。每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该 Class 对象。
有三种方法可以获取Class的对象:
1、调用Object类的getClass()方法来得到Class对象。例如:
MyObject x; Class c1 = x.getClass();
2、使用Class类的中静态forName()方法获得与字符串对应的Class对象。例如:
Class c2=Class.forName("MyObject");//MyObject必须是接口或者类的名字。
3、如果T是一个Java类型,那么T.class就代表了匹配的类对象。例如
Class cl1 = Manager.class; Class cl2 = int.class; Class cl3 = Double[].class;
注意:Class对象实际上描述的只是类型,而这类型未必是类或者接口。例如上面的int.class是一个Class类型的对象。
二、Class类的常用方法
1、getName() 以 String 的形式返回此 Class 对象所表示的实体(类、接口、数组类、基本类型或 void)名称。
2、newInstance() 为类创建一个实例。例如: x.getClass.newInstance()。newInstance()方法调用默认构造器(无参数构造器)初始化新建对象。
3、getClassLoader() 返回该类的类加载器。
4、getSuperclass() 返回表示此 Class 所表示的实体的超类的 Class。
5、isArray() 判定此 Class 对象是否表示一个数组类。
三、Class的一些使用技巧
1、forName和newInstance结合起来使用,可以根据存储在字符串中的类名创建对象。例如 Object obj = Class.forName(s).newInstance();
2、虚拟机为每种类型管理一个独一无二的Class对象。因此可以使用==操作符来比较类对象。例如: if(e.getClass() == Employee.class)...
java classLoader原理
Java ClassLoader 是一个重要的Java运行时系统组件。它负责在运行时查找和装入类文件的类。类装载器是用来把类(class) 装载进 JVM 的。JVM 规范定义了两种类型的类装载器:启动内装载器 (bootstrap) 和用户自定义装载器。
bootstrap 是 JVM 自带的类装载器,用来装载核心类库,如 java.lang.* 。java.lang.Object 是由 bootstrap 装载的。Java 提供了抽象类 ClassLoader ,所有用户自定义类装载器都实例化自 ClassLoader 的子类。
System Class Loader 是一个特殊的用户自定义类装载器,由 JVM 的实现者提供,在编程者不特别指定装载器的情况下默认装载用户类。系统类装载器可以通过 ClassLoader.getSystemClassLoader() 方法得到。
类装载器把一个类装入 Java 虚拟机中,要经过三个步骤:装载、链接和初始化,其中链接又可以分成校验、准备和解析三步,除了解析外,其它步骤是严格按照顺序完成的,各个步骤的主要工作如下:
(1)装载:寻找一个类或是一个接口的二进制形式并用该二进制形式来构造代表这个类或是这个接口的 class 对象的过程。
(2)链接:就是把class类型数据合并到JVM得运行时状态中去。执行校验、准备和解析步骤;
校验:检查导入类或接口的二进制数据的正确性; 准备:给类的静态变量分配并初始化存储空间; 解析:将符号引用转成直接引用;
(3)初始化:初始化 Java 代码和静态 Java 代码块。初始化在JVM第一次主动使用该类型时进行的。所谓主动使用包括以下几种情况:
[1]创建类的新实例时(new指令或通过不明确的创建,反射,克隆或反序列化)
[2]调用类的静态方法时
[3]使用类的静态字段,或对该字段赋值时(final修饰的静态字段除外)
[4]初始化某个类的子类时
[5]JVM启动时某个被标明为启动类的类即含有main()方法的类
数组类的 Class 对象不是由类装载器创建的,而是由 Java 运行时根据需要自动创建。数组类的类装载器由Class.getClassLoader()返回,该装载器与其元素类型的类装载器是相同的;如果该元素类型是基本类型,则该数组类没有类装载器。
虚拟机加载类的途径:
1、Dog dog = new Dog();
2、Class clazz = Class.forName(“Dog”);
Object dog =clazz.newInstance();
3、Class clazz = classLoader.loadClass(“Dog”);
Object dog =clazz.newInstance();
那么,1和2和3究竟有什么区别呢?分别用于什么情况呢?
1和2使用的类加载器是相同的,都是当前类加载器。(即:this.getClass.getClassLoader)。
3由用户指定类加载器。如果需要在当前类路径以外寻找类,则只能采用第3种方式。第3种方式加载的类与当前类分属不同的命名空间。
另外,第1种和第2种都会导致执行类的静态初始化语句,而第3种情况不会。另外第1种抛出Error,第2、3种抛出Exception,它们分属于不同的异常/错误分支。