类加载器(ClassLoader),用来加载 Java 类(.class)到 Java虚拟机(JVM)中的 一个java类。
Java源程序(.java文件)在经过 Java编译器 编译之后就被转换成 Java字节代码(.class 文件)。
类加载器负责读取Java字节代码,并将其转换成 java.lang.Class 类的一个实例。
Class.forName(xxx.xx.xx) 返回一个类
首先你要明白在java里面任何class都要装载在虚拟机上才能运行。这句话就是装载类用的(和new 不一样,要分清楚)。
至于什么时候用,可以考虑一下这个问题,给出一个字符串变量,它代表一个类的包名和类名,怎么实例化它?只有提到的这个方法了,不过要再加一点。
A a = (A)Class.forName("pacage.A").newInstance();
这和
A a = new A();
是一样的效果。
相关的补充问题
JVM会执行静态代码段,要记住一个概念,静态代码是和class绑定的,class装载成功就表示执行了静态代码了,以后也就不会再走这段静态代码了。
Class.forName(xxx.xx.xx) 返回的是一个类
Class.forName(xxx.xx.xx);的作用是要求JVM查找并加载指定的类,也就是说JVM会执行该类的静态代码段,动态加载和创建Class 对象,比如想根据用户输入的字符串来创建对象
String str = 用户输入的字符串
Class t = Class.forName(str);
t.newInstance();
在初始化一个类,生成一个实例的时候,newInstance()方法和new关键字除了一个是方法,一个是关键字外,最主要有什么区别?
它们的区别在于创建对象的方式不一样,前者是使用类加载机制,后者是创建一个新类。
那么为什么会有两种创建对象方式?
这主要考虑到软件的可伸缩、可扩展和可重用等软件设计思想。
Java中工厂模式经常使用newInstance()方法来创建对象,因此从为什么要使用工厂模式上可以找到具体答案。 例如:
class c = Class.forName(“Example”);
factory = (ExampleInterface)c.newInstance();
其中ExampleInterface是Example的接口,可以写成如下形式:
String className = "Example";
class c = Class.forName(className);
factory = (ExampleInterface)c.newInstance();
进一步可以写成如下形式:
String className = readfromXMlConfig;//从xml 配置文件中获得字符串
class c = Class.forName(className);
factory = (ExampleInterface)c.newInstance();
上面代码已经不存在Example的类名称,它的优点是,无论Example类怎么变化,上述代码不变,甚至可以更换Example的兄弟类Example2 , Example3 , Example4……,
只要它们继承ExampleInterface也就是factory就可以。
从JVM的角度看,使用关键字new创建一个类的时候,这个类可以没有被加载。但是使用newInstance()方法的时候,就必须保证:
1、这个类已经加载;2、这个类已经连接了。
而完成上面两个步骤的正是Class的静态方法forName()所完成的,这个静态方法调用了启动类加载器,即加载 java API的那个加载器。
现在可以看出,newInstance()实际上是把new这个方式分解为两步,即首先调用Class加载方法加载某个类,然后实例化。
分步的好处是显而易见的:可以在调用class的静态加载方法forName时获得更好的灵活性,提供给了一种降耦的手段。
最后用最简单的描述来区分new关键字和newInstance()方法的区别:
newInstance: 弱类型。低效率。只能调用无参构造。
new: 强类型。相对高效。能调用任何public构造。
forName() 和 ClassLoader 的 loadClass 方法。
为什么 forName()是会执行static语句?
因为默认情况它总是初始化这个被装载的类。
关于forName()方法
这个方法总是返回要加载的类的Class类的实例
1、forName(String className)单参数时, initialize=true
a.总是使用当前类装载器(也就是装载执行forName()请求的类的类装载器)
b.总是初始化这个被装载的类(当然也包括:装载、连接、初始化)
2、forName(String className, boolean initialize, ClassLoader loader)
a.loader指定装载参数类所用的类装载器,如果null则用bootstrap装载器。
b.initialize=true时,肯定连接,而且初始化了;
c.false时,绝对不会初始化,但是可能被连接了,有个例外,如果在调用这个forName()前,已经被初始化了,那么返回的类型也肯定是被初始化的(当然,暗含着:
被同一个loader所装载的,而且该类被初始化了)
关于用户自定义的类装载器的loadClass()方法
1、loadClass(String name)单参数时, resolve=false
a.如果该类已经被该类装载器所装载,那么,返回这个已经被装载的类型的Class的实例,否则,就用这个自定义的类装载器来装载这个class,这时不知道是否被连接。绝对不会被初始化
b.这时唯一可以保证的是,这个类被装载了。但是不知道这个类是不是被连接和初始化了
2、loadClass(String name, boolean resolve)
a.resolve=true时,则保证已经装载,而且已经连接了。
resolve=falses时,则仅仅是去装载这个类,不关心是否连接了,所以此时可能被连接了,也可能没有被连接
Class.forName和ClassLoader.loadClass方法都用来动态的加载一个类(都返回一个java.lang.Class对象),区别在于他们使用的ClassLoader和是否执行类的初始化。
1.1 Class.forName
这是一个类方法,该方法除了加载类到JVM中,还会执行类的初始化,即类的静态初始化。
使用Class.forName最常用的形式是Class.forName(String qualifiedClassName),如写JDBC程序常用到的加载某个数据库Driver到jvm的代码:
Class.forName("com.mysql.jdbc.Driver");
该函数使用调用者的ClassLoader, 即调用该行代码的类所使用的ClassLoader,返回一个参数名所对应的Class对象。
另外还有一个带三个参数的forName方法, Class.forName(String, boolean, ClassLoader),参数分别用来指定类名,是否初始化和要使用的ClassLoader。
1.2 ClassLoader.loadClass
这是一个实例方法,可以使用一个特定的ClassLoader来加载一个类。该方法不会执行类的初始化,只有当该类第一次被使用时才会执行类的初始化,比如调用该类的一个静态方法或创建该类的一个对象。
1.3 使用哪一个方法
1.3.1 ClassLoader
不同的ClassLoader加载类时会从不同的位置来查找类的.class文件,所以如果要加载的类不在默认的查找位置时,就应该指定要使用的ClassLoader,否则会得到java.lang.ClassNotFoundException的错误。为了灵活性,你应该总是提供一个来参数指定ClassLoader而不是使用默认的ClassLoader,即使用带三个参数的forName或loadClass方法。关于不同的ClassLoader如何查找及加载类请参考ClassLoder一文。
1.3.2 是否要执行类初始化
在上面加载Mysql Driver的例子中,我们本身并不需要创建MySqlDriver对象,只需要加载Driver到JVM,并执行类的初始化(可能执行注册自己到Driver Manger的代码)。所以可以使用forName方法,如果使用ClassLoader.loadClass则需要像下面这样:
ClassLoader cl = …;
cl.loadClass("com.mysql.jdbc.Driver").newInstance(); //创建对象仅仅为了执行类初始化,对象本身并不会被使用。
如果已知类的初始化是一个比较耗时的过程,则可以将其初始化推迟到该类被一次使用时。另外执行类的初始化代码失败会抛出java.lang.ExceptionInInitializerError异常。此时加载的类就变得不可用。类的初始化错误往往很难跟踪,所以如果要在一个特定点捕获并处理该异常就可以使用Class.forName并放在一个try块中。但是不要试图重新加载该类,因为一个类只能被同一个ClassLoader加载一次。
下面给你说几种获取Class对象的方法:
Class对象的获取
1.所有的引用数据类型(类-类型)的类名、基本数据类型都可以通过.class方式获取其 Class对象(
对于基本数据类型的封装类还可以通过.TYPE 的方式获取其 Class 对象,但要注意:
TYPE 实际上获取的封装类对应的 基本类型 的 Class 对象的引用,
那么你可以判断出int.class==Integer.TYPE 返回 true,int.class==Integer.class 返回 false),
通过这种方式不会初始化静态域,使用.class、.TYPE 的方式获取 Class对象叫做类的字面常量;
2.Class 的 forName(String name)传入一个类的完整类路径也可以获得 Class 对象,
但由于使用的是字符串,必须强制转换才可以获取泛型的Class<T>的 Class对象,
并且你必须获取这个方法可能抛出的ClassNotFoundException异常。这种方法可以初始化静态域。
3.还可通过类的对象实例下的getClass()方法来获取Class对象,即 实例名.getClass()
1)Class cl=A.class; JVM将使用类A的类装载器,将类A装入内存(前提是:类A还没有装入内存),不对类A做类的初始化工作.返回类A的Class的对象
2)Class cl=对象引用o.getClass();返回引用o运行时真正所指的对象(因为:儿子对象的引用可能会赋给父对象的引用变量中)所属的类的Class的对象
3)Class.forName("类名"); .装入类A,并做类的初始化
getClass()是动态的,其余是静态的。
.class class.forName()只能返回类内field的默认值,getClass可以返回当前对象中field的最新值
Class.forName(xxx.xx.xx) 返回的是一个类, .newInstance() 后才创建一个对象 Class.forName(xxx.xx.xx);的作用是要求JVM查找并加载指定的类,也就是说JVM会执行该类的静态代码段
相关推荐
本文主要对 NT 式驱动的三类加载方式进行了详细的介绍:工具加载、手动加载、代码加载。下面是对每种加载方式的详细解释: 工具加载方式 工具加载方式是使用 Driver Monitor 工具来加载 NT 式驱动。首先,需要打开...
5. 类加载方式: - 本地加载:直接从本地磁盘加载已编译的`.class`文件。 - 网络加载:使用`java.net.URLClassLoader`从网络指定的URL加载类。 - 压缩文件加载:从`.jar`、`.zip`等压缩文件中查找并加载类,自动...
类加载器不仅能够加载类,还能够根据不同的需求定制加载方式,如从特定位置加载类或实施类的安全性检查等。 #### 二、JDK简介 **JDK(Java Development Kit)**是Java语言的软件开发工具包(SDK)。JDK包含了Java运行...
类加载器的设计遵循双亲委派模型,它分为三个主要部分:启动类加载器、扩展类加载器和应用类加载器。 #### 二、类加载过程 类加载过程主要包括三个步骤: 1. **加载**:通过类的全限定名找到该类的二进制字节流。...
总之,使用URLClassLoader加载本地JAR文件是一种灵活的类加载方式,它允许我们动态扩展应用程序的功能,加载自定义的类库。正确理解和运用这个机制,可以极大地提升Java应用程序的可扩展性和灵活性。
自定义类加载器允许开发人员根据特定需求定制加载类的方式,比如从非标准位置(如网络、数据库或本地磁盘)加载类。本文将深入探讨自定义类加载器的基本概念、工作原理以及如何创建一个简单的基于磁盘的自定义类加载...
Java 虚拟机类加载器的工作方式来深入理解。这一机制确保了核心类库的唯一性,防止用户自定义的类覆盖了 Java 核心类。例如,当我们尝试加载 `java.lang.Object` 类时,首先会由启动类加载器加载,如果它找不到,会...
总的来说,ModRunJava 类加载器提供了一种新的、灵活的方式来管理和运行Java应用程序,特别适合于敏捷开发和持续集成的场景,它简化了依赖管理,提升了开发效率,同时也为构建更复杂、可扩展的应用提供了可能。
通过阅读和分析该文件,你可以更直观地了解每个类加载器的角色及其交互方式。 总之,理解Java类加载器和Tomcat的类加载机制对于开发和调试基于Tomcat的应用程序至关重要。它涉及到类的查找、加载、初始化等过程,...
类加载方式有两种:隐式加载和显式加载。隐式加载是在程序运行过程中,当碰到通过new等方式生成对象时,隐式调用类装载器加载对应的类到JVM中。显式加载是通过class.forName()等方法,显式加载需要的类。 类加载器 ...
系统类加载器在加载类时,会先尝试让扩展类加载器加载,如果扩展类加载器无法加载,则再由系统类加载器自己尝试加载。这样的设计是为了保证核心类库的唯一性和安全性,避免用户自定义的类覆盖了 JDK 内置的核心类。 ...
### Java 类加载机制详解 Java 类加载机制是Java运行时环境的一个核心组成部分,它负责将编译后的Java字节码加载到JVM中,并确保Java应用程序能够正确地运行。类加载机制不仅涉及到类的加载、验证、准备、解析和...
### RAD 类加载器序列知识点详解 #### 一、概述 在使用WebSphere Application Server (WAS)部署企业级应用时,经常会遇到类加载器(ClassLoader)的问题。类加载器负责加载应用程序所需的类,并且有不同的模式来...
总结来说,类加载器是Java运行时环境的关键组件,它决定了类的生命周期和加载方式,是理解和优化JVM性能、实现动态加载、保障系统安全等方面不可或缺的知识点。深入理解类加载器的工作原理和机制,对于开发高效、...
Java类加载器是Java虚拟机(JVM)的关键组成部分,它负责查找并加载类到内存中,使得程序能够运行。自定义Java类加载器允许我们根据特定需求扩展默认的加载机制,例如,从非标准位置加载类或者实现动态加载。在Java...
例如,`MemoryClassLoader.java`可能就是一个自定义类加载器的实现,它可以在内存中动态加载或更新类。 **JarinJAR**是一种打包技术,它可以将多个JAR文件打包成一个大的JAR文件。在热加载场景下,JarinJAR使得在...
类加载方式 类加载有两种方式:隐式加载和显式加载。隐式加载是程序在运行过程中,当碰到通过new等方式生成对象时,隐式调用类加载器加载对应的类到JVM中;显式加载是通过class.forName()等方法,显式加载需要的类...
与exe4j等工具相比,应用程序类加载器提供了一种更标准、跨平台的方式来启动Java程序。通过配置类路径,开发者可以自定义加载顺序和加载来源,例如从网络、文件系统或特定的jar中加载类。 **配置灵活性**: 在开发...
类加载机制是Java虚拟机(JVM)运行时的核心机制之一,它负责将类的.class文件从磁盘或网络中加载到内存,并转化为可以执行的Java对象。这一过程包括加载、验证、准备、解析和初始化五个阶段,下面我们来详细探讨...