`

JAVA类加载以及反射机制

阅读更多
     JAVA中类文件加载是动态的。JVM指令是被封装在了. class文件里面,而.class文件的加载过程是动态的,也就是说当我们用到的时候才会去加载,如果不用的话,就不会去加载我们的类。这里所说的用到包括两种方式,第一种就是new一个对象的时候(这个时候要特别注意,当设计到多态的时候,就会有一点点变化,这时候编译器会做一些优化,这样以来当加载的时候会提前加载设计到多态的类,关于这一点下面有个例子(example 1)来说明。另一种就是当一个类的静态代码被调用的时候。
     
//example 1
// Zoo.java

abstract class Animal {

	Animal(){
	
		 System.out.println("Animal constructor");
	}
}

class Tiger extends Animal {

	Tiger(){
    	
		System.out.println("Tig constructor ");
	}
		
}


class Dog extends Animal {

	Dog(){
	
		System.out.println("Dog Constructor ");
	}
}



public class Zoo {

	  private Animal am; //Example 1.1
	  //private Dog am;     Example 1.2
		private Tiger tiger;
		
		Zoo(){
                          am = new Dog();
                          tiger = new Tiger();
		       			
		}
		
	
	 public static void main(String [] args){
	
	     System.out.println("new Zoo before");
              Zoo z = new Zoo();
	     System.out.println("new Zoo after ");
		
	 }
}

运行此测试程序结果如Example1.1图 :
Example 1.1



当我们注释掉Example.1.1行时,运行Example1.2行,结果如下:

Example 1.2





分析以上两图的运行结果我们可以看出:当我们将子类对象赋值给父类时,编译器会做一点优化,于是加载器在还没有new 子类对象的时候已经加载了父类以及子类(example1.1结果),当不存在多态的时候,我们可以看到是当要new Dog()的时候才会加载Dog以及父类。无论何种方式,在new之前,类确实已经加载到了内存中。
      

      JAVA为我们提供了两种动态机制。第一种是隐式机制。其实new一个对象和调用类的静态方法时,就是隐式机制在工作。第二种是显示机制。显示的机制又有两种策略(第一种是用java.lang.Class的forName(String str)方法,第二种是用java.lang.ClassLoader的loadClass())。
 
      第一种:利用forName方法
      当我们查API文档就会发现forName方法有两种形式。分别如下:
      public static Class<?> forName(String className)
                        throws ClassNotFoundException
    
     
      public static Class<?> forName(String name,
                               boolean initialize,
                               ClassLoader loader)
                        throws ClassNotFoundException

      先来说说第二种方法:第二个方法值得注意的就是第二个参数boolean initialize,如果我们把这个参数设置为false,那么当我们加载完类后就不会执行静态代码和静态的初始化动作。只有当我们new一个对象的时候才会初始化。而第三个参数是用来指明类的加载器的。
      如果查看java.lang.Class类的源代码,上述两种方法最终都会调用Class类中的私有的native方法forName0(),此方法的声明如下:
      private static native Class forName0(String name, boolean  init , ClassLoader loader)
                  throws ClassNotFoundException;

所以当我们调用Class.forName(name )时,其实是在方法内部调用了:
                  forName0(name, true, ClassLoader.getCallerClassLoader());
    当我们调用Class.forName(name,  initialize, loader )的时候,实际上此方法内部调用了:
                 forName0(name, initialize, loader);
下面看一个例子,如果方法中第二个参数为false的情况:
//example 2.1 
// Zoo.java

abstract class Animal {
  
  static {
  
  	System.out.println("Animal static code block ");
  }
	Animal(){
	
		 System.out.println("Animal constructor");
	}
}

class Tiger extends Animal {

	Tiger(){
    	
		System.out.println("Tig constructor ");
	}
		
}


class Dog extends Animal {

	Dog(){
	
		System.out.println("Dog Constructor ");
	}
}



public class Zoo {

	
	 public static void main(String [] args)throws Exception {
	
	     System.out.println("new Zoo before");
	     Zoo z = new Zoo();
	     Class c = Class.forName("Dog",false,z.getClass().getClassLoader());
	     System.out.println("initilize before ");
	     Animal dog = (Animal)c.newInstance();
            System.out.println("new Zoo after ");
		
	 }
}

Example 2.1
  


从上图可以看出来类加载完成后并没有立即执行静态初始化代码,而是到了实例化的时候才进行了静态初始化。有时候我们会说静态代码是在类第一次被加载时执行的,并且只执行一次。其实这是对与new一个对象,第一次访问类的静态代码以及第二个参数为true时而言的,对于动态的加载来说,如果forName方法的第二个参数设置为false,那么就是在实例化的时候才会执行静态初始化。当然默认情况下第二个参数是true.

第二种方法:利用Class对象获取的ClassLoader装载。

下面是一个简单的例子:

//Example 2.2
//Zoo.java
abstract class Animal {
  
  static {
  
  	System.out.println("Animal static code block ");
  }
	Animal(){
	
		 System.out.println("Animal constructor");
	}
}

class Tiger extends Animal {

	Tiger(){
    	
		System.out.println("Tig constructor ");
	}
		
}


class Dog extends Animal {

	Dog(){
	
		System.out.println("Dog Constructor ");
	}
}



public class Zoo {

	
	 public static void main(String [] args)throws Exception {
	
	     
	     Class c = Zoo.class;
	     ClassLoader loader = c.getClassLoader();
	     System.out.println("loader before");
	     Class dog = loader.loadClass("Dog");
	     System.out.println("instance before ");
	     Animal an = (Animal)dog.newInstance();
	     
	     
		
	 }
}


Example 2.2



从上图可以看出loader完成以后并没有立即进行静态代码的执行。只有当newInstance()的时候才执行静态初始化,这和把
public static Class forName(String name, boolean initialize,  ClassLoader loader)的第二个参数指定为false的情况完全一样。其实每当我们写完一个编译单元以后就会得到一个.calss文件,这个文件中就包含了该类的Class对象。JVM就是利用这个class对象来进行动态装载类的。

呵呵终于总结玩了。如果有什么地方理解有误的,请各位前辈和各位兄弟指点。谢谢。。
分享到:
评论

相关推荐

    Java类加载机制与反射-PPT

    Java的类加载机制:加载,连接,初始化。JAVA类加载器: Bootstrap ClassLoader : 根类加载器, Extension ClassLoader: 扩展类加载器, System ClassLoader : 系统类加载器, Java反射

    java类加载器和反射学习要点ppt

    本学习讲义是关于java类加载和反射机制需要注意的要点学习,内容详细

    类加载机制及反射

    类加载机制及反射 类加载机制及反射

    java加载类与反射机制

    Java 程序在运行期间可以动态加载、解析和使用一些在编译阶段并不确定的类型数据,这一机制被称为反射(Reflection)。反射库(reflection library)提供了一个非常丰富且精心设计的工具类,以便编写能够动态操纵Java...

    java注解_反射_字节码_类加载机制.zip

    java 注解 反射 字节码 类加载 包括pdf资料以及全部源码文件,具有非常大参考价值和学习意义

    JAVA反射机制与类的加载

    JAVA反射机制与类的加载,详细的说明java反射机制的实例以及应用是入门级的课件

    Java反射机制——类的加载方法,创建对象,获取方法以及结构

    一、java反射机制概述 Reflection (反射)被视为动态语言的关键,为什么这么说呢,是因为它在运行时就确定下来了。反射机制允许程序在执行期间借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的...

    反射机制和类加载机制学习总结

    反射机制和类加载机制学习总结 Reflection 是 Java 程序开发语言的特征之一,它允许运行中的 Java 程序对自身进行检查,或者说“自审”,并能直接操作程序的内部属性。例如,使用它能获得 Java 类中各成员的名称并...

    JAVA反射机制详解视频

    (类的加载概述和加载时机) (类加载器的概述和分类) (获取class文件对象的三种方式) (通过反射获取无参构造方法并使用) (通过反射获取带参构造方法并使用) (通过反射获取私有构造方法并使用) (通过反射获取成员变量并...

    Java高级程序设计实战教程第三章-Java反射机制.pptx

    这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。 Java高级程序设计实战教程第三章-Java反射机制全文共15页,当前为第4页。 3.2.2 反射机制的功能 反射机制的功能如下: 在运行时判定任意...

    java 类加载机制和反射详解及实例代码

    主要介绍了java 类加载机制和反射详解及实例代码的相关资料,需要的朋友可以参考下

    JAVA反射机制的简单理解

    有时候我们说某个语言具有很强的动态性,有时候我们会区分动态和静态的不同技术与作法。我们朗朗上口动态绑定(dynamic binding)、动态链接(dynamic ...是可以通过反射机制来实现“动态”,用一个实例来说明一下:

    Java反射机制知识

    里面主要是介绍Java反射的只是,包括介绍Class类的初始化,如何通过反射动态加载类和获取类的信息等。

    Java的反射机制讲解案例代码 Class类、 获取类的结构信息:构造函数、方法和字段,动态创建对象、调用方法和设置属性

    Java的反射机制是指在运行时通过分析类的信息实现动态调用类的方法和访问类的属性的能力。它允许程序在运行时获取类的信息并操作类或对象的属性、方法和构造函数等。通过反射机制,可以实现很多高级特性,如动态代理...

    候捷谈Java反射机制

    JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。...

    java反射机制介绍

    这个字的意思是“反射、映象、倒影”,用在Java身上指的是我们可以于运行时加载、探知、使用编译期间完全未知的classes。换句话说,Java程序可以加载一个运行时才得知名称的class,获悉其完整构造(但不包括methods...

    利用JAVA的反射机制动态加载struts中的form

    利用java的反射机制动态加载form,以使得这部分代码能够被重用,是很好的一个重用代码机制的体现

    java反射机制

    该文件有如何动态加载类,动态获得属性,动态调用方法,动态创建对象等

    Java的反射机制深度解析

    ava语言允许通过程序化的方式间接的对Class操作,Class文件由类加载器加载后,在JVM中将形成一份描述Class的对象,通过该对象可以获知Class的结构信息,如构造函数,属性,方法等。并分别通过Java实例对这些信息进行...

Global site tag (gtag.js) - Google Analytics