java 反射学习

原创 2013年12月04日 10:20:39

同一个JVM的所有线程、所有变量都处于同一个进程里,他们都使用该JVM进程的内存区。

 

当系统出现以下几种情况时,JVM进程将被终止:

1、程序运行到最后正常结束

2、程序运行到使用System.exit()或Runtime.getRuntime().exit()代码处结束程序。

3、程序执行过程中遇到未捕获的异常或错误而结束

4、程序所在平台强制结束了JVM进程

 

依此运行下面的两个main方法,说出结果?

public class A {
	public static int a=6;
}

 

public class ATest1 {

	public static void main(String[] args) {
		A a = new A();
		a.a++;
		System.out.println(a.a);//7
	}

}

 

public class ATest2 {

	public static void main(String[] args) {
		A b = new A();
		System.out.println(b.a);//7
	}

}

 

备注:第一个main显示7没有问题,但是第二个结果也许会说是8,但是运行的结果是7;实际上两次运行JAVA程序处于两个不同的JVM进程中,两个JVM之间并不会共享数据

 

一、类的加载

当程序主动使用某个类时,如果该类还没有被加载到内存中,则系统会通过加载、连接、初始化3个步骤来对该类进行初始化。如果没有意外,JVM将会连续完成这3个步骤,所以有时候也把这3个步骤统称为类加载或类初始化。

 

类加载指的是将类的class文件读入内存,并为之创建一个java.lang.Class对象,也就是说,当程序中使用任何类时,系统都会为之创建一个java.lang.Class对象。

 

类的加载由类加载器完成,类加载器通常由JVM提供,这些类加载器也是前面所有程序运行的基础,JVM提供的这些类加载器通常被称为系统类加载器。除此之外,开发者可以通过几成ClassLoader基类来创建自己的类加载器。

 

类加载通常无须等到“首次使用”该类时候才加载该类,java虚拟机规范允许系统预先加载某些类

 

二、类的连接

当类被加载之后,系统为之生成一个对应的Class对象,接着将会进入连接阶段,连接阶段负责把类的二进制数据合并到JRE中。类的连接又可分为如下3个阶段:

1、验证:验证阶段用于检测被加载的类是否有正确的内部结构,并和其他类协调一致。

2、准备:负责为类的静态Field分配内存,并设置默认初始值

3、解析:将类的二进制数据中的符合引用替换成直接引用。

 

三、类的初始化

在类的初始化阶段,虚拟机负责对类进行初始化,主要就是对静态Field进行初始化。

对静态Field指定初始化值有两种方式:

1、声明静态Field时指定初始化值

2、使用静态初始化块为静态Field指定初始值

 

JVM初始化一个类包含如下几个步骤

1、如果这个类还没有被加载和连接,则程序先加载并连接该类

2、假如该类的直接父类还没有被初始化,则先初始化其直接父类

3、假如类中有初始化语句,则系统依此执行这些初始化语句

当执行第2个步骤时,系统对直接父类的初始化步骤也遵循此步骤1~3;如果该直接父类又有直接父类,则系统再次重复这3个步骤来先初始化这个父类......依此类推,所有JVM最先初始化的总是java.lang.Object类。当程序主动使用任何一个类时,系统会保证该类以及所有父类(包括直接父类和间接父类)都会被初始化。

 

类初始化的时机

当JAVA程序首次通过下面6种方式来使用某个类或者接口时,系统就会初始化该类或者接口。

1、创建类的实例。使用new操作符来创建实例,通过反射来创建实例,通过反序列化的方式创建实例

2、调用某个类的静态方法

3、访问某个类或接口的静态Field,或者为该静态Field赋值

4、使用反射方式来强制创建某个类或者接口对应的java.lang.Class对象。例如:Class.forName("Person"),如果系统还没有初始化Person类,则这行代码将会导致该Person类被初始化,并返还Person类对应的java.lang.Class对象

5、初始化某个子类。当初始化某个子类,该子类的所有父类都会被初始化

6、直接使用java.exe命令来运行某个主类。当运行某个主类时,程序会先初始化该主类。

 

需要特别指出:

对于一个final型的静态Field,如果该Field的值在编译时就可以确定下来,那么这个Field相当于“宏变量”。java编译器会在编译时就直接把这个Field出现的地方替换成它的值,因此即使程序使用该静态的Field,也不会导致该类的初始化。

 

例如

public class MyTest {

	static{
		System.out.println("静态初始化块...");
	}
	static final String compileConstant = "疯狂java讲义";
}

 

public class CompileConstantTest {

	public static void main(String[] args) {
		System.out.println(MyTest.compileConstant);
	}

}

 

运行结果:疯狂java讲义

 

备注:当某个静态Field使用了final修饰,而且它的值可以在编译时就确定下来,那么程序其他地方使用该静态Field时,实际上并没有使用该静态Field,而是相当于使用常量

 

当使用ClassLoader类的loadClass()方法来加载某个类时,该方法只是加载该类,并不会执行该类的初始化。使用Class的forName()静态方法才会导致强制初始化该类。

 

package hb.reflect;

public class Tester{
	static{
		System.out.println("初始化块");
	}
}

 

package hb.reflect;

public class ClassLoaderTest {

	public static void main(String[] args) throws ClassNotFoundException {
		
		ClassLoader c1 = ClassLoader.getSystemClassLoader();
		//不会执行初始化
		c1.loadClass("hb.reflect.Tester");
		
		System.out.println("系统加载Tester类");
		//执行初始化内容
		Class.forName("hb.reflect.Tester");
		
	}

}

 

相关文章推荐

Java反射机制的学习

  • 2012年11月29日 21:25
  • 40KB
  • 下载

java反射学习

  • 2012年05月09日 00:27
  • 22KB
  • 下载

Java反射学习总结一(基础篇)

1.使用反射的第一步, 找到class对象(1.Class.forName(); 2.object.class.newInstance(); 3.object.getClass()) //获取某个类...

Java反射机制的学习

  • 2012年06月06日 13:41
  • 38KB
  • 下载

java学习之路 之 反射机制综合练习题、动态代理实例

在上一篇博文中我们已经进行了反射机制的习题练习,这里我们在做一个考察比较全面的练习,如下: 写一个类ReflectUtil类, 类中写一个静态方法Object methodInvoker(Strin...

Java反射相关学习

  • 2011年09月05日 15:16
  • 79KB
  • 下载

Java反射机制的学习

概念反射就是把Java的各种成分映射成相应的Java类。  Class类的构造方法是private,由JVM创建。  反射是java语言的一个特性,它允程序在运行时(注意不是编译的时候)来进行自我检查...

Java反射机制的使用和学习方法

  • 2011年07月27日 10:47
  • 230KB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:java 反射学习
举报原因:
原因补充:

(最多只允许输入30个字)