JAVA中类文件加载是动态的。JVM指令是被封装在了.class文件里面,而.class文件的加载过程是动态的,也就是说当我们用到的时候才会去加载,如果不用的话,就不会去加载我们的类。
JAVA中类文件加载是动态的。JVM指令是被封装在了.class文件里面,而.class文件的加载过程是动态的,也就是说当我们用到的时候才会去加载,如果不用的话,就不会去加载我们的类。这里所说的用到包括两种方式,第一种就是new一个对象的时候(这个时候要特别注意,当设计到多态的时候,就会有一点点变化,这时候编译器会做一些优化,这样以来当加载的时候会提前加载设计到多态的类,关于这一点下面有个例子(example 1)来说明。另一种就是当一个类的静态代码被调用的时候。
java 代码
//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(){
tiger = new Tiger();
am = new Dog();
}
public static void main(String [] args){
System.out.println("new Zoo before");
Zoo z = new Zoo();
System.out.println("new Zoo after ");
}
}
我们可以看出:当我们将子类对象赋值给父类时,编译器会做一点优化,于是加载器在还没有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的情况:
java 代码
//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 ");
}
}
类加载完成后并没有立即执行静态初始化代码,而是到了实例化的时候才进行了静态初始化。有时候我们会说静态代码是在类第一次被加载时执行的,并且只执行一次。其实这是对与new一个对象,第一次访问类的静态代码以及第二个参数为true时而言的,对于动态的加载来说,如果forName方法的第二个参数设置为false,那么就是在实例化的时候才会执行静态初始化。当然默认情况下第二个参数是true。
第二种方法:利用Class对象获取的ClassLoader装载
下面是一个简单的例子:
java 代码
//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();
}
}
loader完成以后并没有立即进行静态代码的执行。只有当newInstance()的时候才执行静态初始化,这和把public static Class forName(String name, boolean initialize, ClassLoader loader)的第二个参数指定为false的情况完全一样。其实每当我们写完一个编译单元以后就会得到一个.calss文件,这个文件中就包含了该类的Class对象。JVM就是利用这个class对象来进行动态装载类的。
JAVA中类文件加载是动态的。JVM指令是被封装在了.class文件里面,而.class文件的加载过程是动态的,也就是说当我们用到的时候才会去加载,如果不用的话,就不会去加载我们的类。这里所说的用到包括两种方式,第一种就是new一个对象的时候(这个时候要特别注意,当设计到多态的时候,就会有一点点变化,这时候编译器会做一些优化,这样以来当加载的时候会提前加载设计到多态的类,关于这一点下面有个例子(example 1)来说明。另一种就是当一个类的静态代码被调用的时候。
java 代码
//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(){
tiger = new Tiger();
am = new Dog();
}
public static void main(String [] args){
System.out.println("new Zoo before");
Zoo z = new Zoo();
System.out.println("new Zoo after ");
}
}
我们可以看出:当我们将子类对象赋值给父类时,编译器会做一点优化,于是加载器在还没有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的情况:
java 代码
//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 ");
}
}
类加载完成后并没有立即执行静态初始化代码,而是到了实例化的时候才进行了静态初始化。有时候我们会说静态代码是在类第一次被加载时执行的,并且只执行一次。其实这是对与new一个对象,第一次访问类的静态代码以及第二个参数为true时而言的,对于动态的加载来说,如果forName方法的第二个参数设置为false,那么就是在实例化的时候才会执行静态初始化。当然默认情况下第二个参数是true。
第二种方法:利用Class对象获取的ClassLoader装载
下面是一个简单的例子:
java 代码
//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();
}
}
loader完成以后并没有立即进行静态代码的执行。只有当newInstance()的时候才执行静态初始化,这和把public static Class forName(String name, boolean initialize, ClassLoader loader)的第二个参数指定为false的情况完全一样。其实每当我们写完一个编译单元以后就会得到一个.calss文件,这个文件中就包含了该类的Class对象。JVM就是利用这个class对象来进行动态装载类的。
发表评论
-
tomcat手动配置
2011-01-06 12:03 781为了快速开发,不用Eclipse部署项目,而用手动配置,优点启 ... -
Java Socket编程
2011-01-04 11:56 676第一步 充分理解Socket ... -
多线程JavaSocket示例
2011-01-04 11:53 818这篇做为学习孙卫琴<<Java网络编程精解> ... -
群发邮件程序
2011-01-04 11:51 720import java.io.*; import java. ... -
Java过滤器
2011-01-04 11:50 704一、 使浏览器不缓存页面的过滤器 import javax.s ... -
Java中的String类(二)
2011-01-04 11:31 7352、String的常用操作方法 2.1、字符与字符串 ... -
Java中的String类(一)
2011-01-04 11:30 6561、String类 1.1、String的两种实例化方式 ... -
Java位移运算符原理
2011-01-04 11:27 903* 总体概念: * 1.位移运算符只对位进行操作 * ... -
Java堆栈
2011-01-04 11:24 5991 . 栈(stack)与堆(heap)都是Java用来在Ra ... -
Java字符串比较
2011-01-04 11:22 1332字符串比较 Java代码 String str1=&quo ... -
Java读取Properties文件方法
2011-01-04 11:16 676使用J2SE API读取Properties文件的六种方法 ... -
学习Java30个目标
2011-01-04 11:09 5921.你需要精通面向对象分析与设计(OOA/OOD)、设计模式( ... -
Java时间类以及函数
2011-01-04 10:27 6221.计算某一月份的最大天数 Calendar time=Ca ... -
Java入门需要掌握的30个基本概念
2011-01-04 10:06 647这是在网上看到的一份 ...
相关推荐
### Java反射机制与动态加载实例类 在Java中,反射是一种强大的工具,允许程序在运行时检查和修改其结构和行为。通过反射,我们可以动态地加载类、创建对象、访问和修改字段、调用方法等。本文将深入探讨Java反射...
Java的类加载机制:加载,连接,初始化。JAVA类加载器: Bootstrap ClassLoader : 根类加载器, Extension ClassLoader: 扩展类加载器, System ClassLoader : 系统类加载器, Java反射
在“java 类加载器 加密”这个主题中,我们将探讨如何利用类加载器实现类的加密和解密,以及如何通过反射执行main方法。 首先,我们理解一下类加载器的工作原理。Java中的类加载器主要有三种:Bootstrap ...
理解并熟练掌握类加载机制和反射是提升Java开发能力的关键步骤,它们可以帮助我们编写更灵活、更具扩展性的代码,同时也能更好地理解和解决运行时出现的问题。在实际开发中,如Spring框架就大量应用了反射机制,使得...
Java 类加载与反射是Java开发中的重要概念,它们在后端开发中扮演着核心角色,尤其是在框架和库的实现中。下面将详细解释这两个主题。 ### 类加载 #### 类加载器 类加载器是Java虚拟机(JVM)的一个组成部分,它...
通过阅读资料,你可以了解到注解的应用场景、反射的API用法、字节码的结构以及类加载机制的工作流程。而源代码分析将加深你对这些概念的实际运用。 总之,掌握Java注解、反射、字节码和类加载机制对于提升Java开发...
在“反射,动态加载指定类调用类中的方法”这个主题中,我们将深入探讨如何使用反射来实现动态加载和执行类的方法。首先,我们需要理解几个关键的反射API: 1. `Class<?>`: 这是所有Java类的通用表示,通过`Class....
2. **反射调用**:使用 `java.lang.reflect` 包的方法对类进行反射调用时,例如使用 `Class.forName()` 方法。 3. **父类初始化**:当初始化一个类时,如果其父类尚未初始化,则需要先初始化父类。 4. **虚拟机启动...
2. **Extension ClassLoader**: 这个类加载器负责加载扩展的Java类库(例如所有以`javax.*`开头的类以及存放在JRE的`ext`目录下的类)。它是一个Java类,继承自`java.lang.ClassLoader`。 3. **Application ...
JAVA 类加载机制是Java平台核心特性之一,它关乎到程序的运行时环境和代码的动态加载。理解这一机制有助于开发者解决与对象创建、配置问题、应用程序发布等相关的问题。以下是关于JAVA 类加载机制的详细分析: 首先...
这个过程展示了如何利用Java的反射API和自定义类加载器实现JAR文件的动态加载和执行。在实际应用中,可能还需要考虑类的版本冲突、安全性和性能优化等问题。例如,使用服务发现框架(如OSGi)来管理类加载和依赖,...
总之,Java动态加载jar包涉及到反射、自定义类加载器以及插件系统等多个核心概念。通过这些技术,开发者可以构建出高度可扩展和灵活的应用程序,适应不断变化的需求。在具体实现过程中,还需要考虑安全性、性能优化...
Java 反射机制允许 Java 程序在运行时动态地加载和调用类的方法。通过反射机制,可以实现动态地加载和执行 Java 类文件。 除了实现动态类加载机制外,还可以应用于网络教学环境中。通过开发基于 C/S 结构模式的...
类加载器通常包括Bootstrap ClassLoader(引导类加载器)、Extension ClassLoader(扩展类加载器)和App ClassLoader(应用程序类加载器),以及用户自定义的类加载器。 2. **验证**:验证阶段确保.class文件的数据...
理解类加载器的工作原理对于深入学习Java平台、优化应用程序性能以及实现自定义加载器至关重要。 1. **类加载器层次结构** Java中的类加载器分为三个主要层次:启动类加载器(Bootstrap ClassLoader)、扩展类加载...
这个特性使得Java具有了高度的灵活性和动态性,尤其是在处理元数据、创建对象、调用私有方法以及访问未导出的类等方面显得尤为有用。以下是对"JAVA反射机制的入门代码"的详细解释。 首先,我们要理解反射的基本概念...
在Java编程中,动态编译和加载类是一种高级特性,它允许程序在运行时编译源代码并将其加载到Java虚拟机(JVM)中。这种能力对于开发灵活性高、可扩展性强的应用程序非常有用,比如在服务器端处理动态生成的代码、...
动态加载则是利用反射技术,在程序运行时动态地加载类并实例化对象,这为Java应用程序提供了高度的灵活性和可扩展性。下面将深入探讨Java类的反射与动态加载相关知识点。 首先,我们要了解什么是类的反射。在Java中...
Java 类加载机制是Java虚拟机(JVM)的核心组成部分,负责将类的定义从Class文件加载到内存,并对其进行校验、解析和初始化。这个过程确保了程序运行时能够正确使用类的静态和动态特性。本文将深入探讨Java类加载的...