Java反射探索-从类加载说起
摘要:本文主要讲了Java类加载的机制,这是学习反射的入门基础。 1、类加载
JVM和类 类的生命周期
类的加载/类初始化 加载:查找并加载类的2进制数据
1、通过1个类的全限定名来获得定义此类的2进制字节流。
注意:将编译后的java类文件(也就是.class文件)中的2进制数据读入内存,并将其放在运行时数据区的方法区内,然后再堆区创建1个Java.lang.Class对象,用来封装类在方法区的数据结构。即加载后终究得到的是Class对象,并且更加值得注意的是:该Java.lang.Class对象是单实例的,不管这个类创建了多少个对象,他的Class对象时唯1的! 注意:连接和初始化阶段,其实静态变量经过了两次赋值:第1次是静态变量类型的默许值;第2次是我们真正赋给静态变量的值。 我简单画了个图,其进程以下:
类加载指的是将类的class文件读入内存,并为之创建1个java.lang.Class对象,也就是说当程序中使用任何类时,系统都会为之建立1个java.lang.Class对象。事实上,每一个类是1批具有相同特点的对象的抽象(或说概念),而系统中所有的类,它们实际上也是对象,它们都是java.lang.Class的实例。
Java程序对类的使用方式
对象初始化
2、Class.forName、实例对象.class(属性)、实例对象getClass()的区分
1、相同点:
package com.lin;
/**
* 功能概要:
*
* @author linbingwen
* @since 2015年10月20日
*/
public class people {
/**
* @author linbingwen
* @since 2015年10月20日
* @param args
*/
public static void main(String[] args) throws Exception {
System.out.println("..............使用不同的方式加载类...................");
System.out.println(people.class);//通过类.class取得Class对象
people a = new people();
System.out.println(a.getClass());//通过 实例名.getClass()取得Class对象
System.out.println(Class.forName("com.lin.people"));//通过Class.forName(全路径)取得Class对象
System.out.println("..............使用不同的方式创建对象...................");
System.out.println(a);//使用不同的方式创建对象
System.out.println(people.class.newInstance());
System.out.println(a.getClass().newInstance());
System.out.println(Class.forName("com.lin.people").newInstance());
}
}
结果: 从上面可以看到不同的方式加载类。其实这1进程只产生1次! 2、区分: 下面用1个实例来讲说它们的区分 以下新建1个类
package com.lin;
/**
* 功能概要:
*
* @author linbingwen
* @since 2015年10月20日
*/
public class Cat {
static {
System.out.println("生成了1只猫");
}
}
然后开始使用:
package com.lin;
/**
* 功能概要:
*
* @author linbingwen
* @since 2015年10月20日
*/
public class CatTest {
/**
* @author linbingwen
* @since 2015年10月20日
* @param args
*/
public static void main(String[] args) throws Exception{
System.out.println("---------------Cat.class开始------------------");
System.out.println(Cat.class);//通过类.class取得Class对象
System.out.println("---------------Cat.class结束------------------");
System.out.println("---------------Class.forName开始------------------");
System.out.println(Class.forName("com.lin.Cat"));//通过Class.forName(全路径)取得Class对象
System.out.println("---------------Class.forName结束------------------");
System.out.println("---------------cat.getClass()开始------------------");
Cat cat = new Cat();
System.out.println(cat.getClass());//通过Class.forName(全路径)取得Class对象
System.out.println("---------------cat.getClass()结束------------------");
}
}
输出结果:
如果,将Class.forName()去掉: 以下:
package com.lin;
/**
* 功能概要:
*
* @author linbingwen
* @since 2015年10月20日
*/
public class CatTest {
/**
* @author linbingwen
* @since 2015年10月20日
* @param args
*/
public static void main(String[] args) throws Exception{
System.out.println("---------------Cat.class开始------------------");
System.out.println(Cat.class);//通过类.class取得Class对象
System.out.println("---------------Cat.class结束------------------");
// System.out.println("---------------Class.forName开始------------------");
// System.out.println(Class.forName("com.lin.Cat"));//通过Class.forName(全路径)取得Class对象
// System.out.println("---------------Class.forName结束------------------");
System.out.println("---------------cat.getClass()开始------------------");
Cat cat = new Cat();
System.out.println(cat.getClass());//通过Class.forName(全路径)取得Class对象
System.out.println("---------------cat.getClass()结束------------------");
}
}
结果又变成: 所以,可以得出以下结论:
1)Class cl=Cat.class; JVM将使用类Cat的类装载器,将类A装入内存(条件是:类A还没有装入内存),不对类A做类的初始化工作.返回类A的Class的对象 3、new和newInstance()从JVM的角度看,我们使用关键字new创建1个类的时候,这个类可以没有被加载。但是使用Class对象的newInstance()方法的时候,就必须保证: 1、这个类已加载;
2、这个类已连接了。而完成上面两个步骤的正是Class的静态方法forName()所完成的,这个静态方法调用了启动类加载器,即加载 java API的那个加载器。 Class.forName().newInstance()和通过new得到对象的区分
5、Class.forName(“”).newInstance()返回的是object 。 6、newInstance( )是1个方法,而new是1个关键字; 注:1般在通用框架里面用的就是class.forName来加载类,然后再通过反射来调用其中的方法,比方Tomcat源码里面,这样就避免了new关键字的耦合度,还有让不同的类加载器来加载不同的类,方便提高类之间的安全性和隔离性. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |