- 浏览: 847339 次
- 性别:
- 来自: 草帽海贼团
文章分类
最新评论
-
大维啊:
估计只有你自己能明白
Java安全沙箱机制 -
moonljt521:
第五种方式,如果构造里想传入参数怎么做,例如android的 ...
单例模式的七种写法 -
javaDADY:
怎么感觉在讨论茴香豆的茴字有几种写法?
单例模式的七种写法 -
Wallen_Han:
Mr.Cheney 写道这样的:Mr.Cheney 写道还有一 ...
单例模式的七种写法 -
Wallen_Han:
60love5 写道第三种稍微有点Java基础就知道是错的,被 ...
单例模式的七种写法
class对象是java.lang.Class<T>这个类生成的对象,Class
类的实例表示正在运行的 Java 应用程序中的类和接口。枚举是一种类,注释是一种接口。每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该 Class
对象。基本的 Java 类型(boolean
、byte
、char
、short
、int
、long
、float
和 double
)和关键字 void
也表示为 Class
对象。 上面这段话是API对class类的解释,不免有点不解。
实际上,每个类都有一个class对象。换言之,每当编写并且编译了一个新类,就会产生一个class对象(被保存在一个同名的.class文件中)。在运行时,当我们想生成这个类的对象时,运行这个程序的Java虚拟机首先检查这个类的class对象是否已经加载。如果尚未加载,JVM就会根据类名查找.class文件,并将其载入,一旦某个类的class对象被载入内存,它就被用来创建这个类的所有对象。
class类用的比较多的方法就是forName(String className) ,getName() 还有newInstance() 等等,关于他们的详细用法你可以去查查API,我在这里就不赘述。我要说的是他们的返回值,forName(String className)返回的是一个对class对象的引用,getName() 返回的是类名(也可以是接口名),而newInstance()返回的是对一个普通对象的引用。
考虑下面一段代码:
public class TestStatic { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub System.out.println("用这种方式加载类:Static test = new Static()"); Static test = new Static(); System.out.println("生成test对象的class对象的类加载器是:"+test.getClass().getClassLoader()); System.out.println("生成test对象的class对象的类加载器的委托的父类加载器是:"+test.getClass().getClassLoader().getParent()); System.out.println("判定指定的 Object 是否与此 Class 所表示的对象赋值兼容:" +test.getClass().isInstance(test)); if (test instanceof Static) System.out.println("test是类Static的实例!"); System.out.println(); System.out.println("用这种方式加载类:Class.forName()"); try { Class testForName = Class.forName("Static"); Static testNew =(Static) testForName.newInstance(); System.out.println("class对象testForName的类加载器是:"+testForName.getClassLoader()); System.out.println("class对象testForName的类加载器的委托的父类加载器是:"+testForName.getClassLoader().getParent()); System.out.println("判定指定的 Object 是否与此 Class 所表示的对象赋值兼容:" +testForName.isInstance(test)); if (testNew instanceof Static) System.out.println("testNew是类Static的实例!"); System.out.println(); } catch(ClassNotFoundException e) { e.getMessage(); } catch(InstantiationException e) { e.getMessage(); } catch(IllegalAccessException e) { e.getMessage(); } System.out.println("用这种方式加载类:Static.class"); Class testClass = Static.class; System.out.println("class对象testClass的类加载器是:"+testClass.getClassLoader()); System.out.println("class对象testClass的类加载器的委托的父类加载器是:"+testClass.getClassLoader().getParent()); System.out.println("判定指定的 Object 是否与此 Class 所表示的对象赋值兼容:" +testClass.isInstance(test)); try { Static testClassNew =(Static) testClass.newInstance(); if (testClassNew instanceof Static) System.out.println("testClassNew是类Static的实例!"); } catch(InstantiationException e) { e.getMessage(); } catch(IllegalAccessException e) { e.getMessage(); } } } class Static { public Static() { System.out.println("执行构造器!"); } static { System.out.println("初始化静态变量!"); } { System.out.println("初始化非静态变量!"); } static void print() { System.out.println("为静态方法配置!"); } }
运行结果为:
代码多,但其实还是很简单的,我想表达的是:
这里有三种不同的加载类的方式,但是聪明的读者就会发现其实整个过程只有一个class对象,它产生于第一次对它的加载,也就是说,类加载器要加载一个类,它首先检查此类是否已被加载,然后再委托双亲加载器加载此类,它的双亲加载器再委托它的双亲,这样一直委托到启动加载器,启动加载器在从核心API查找此类,如果有就返回此类,否则就他的子加载器就查找此类,如果都没有就抛出ClassNotFound的异常。
第一次加载的时候初始化此类,所以我们看到在第一次加载类的时候输出了“初始化静态变量”,然后第二次用Class.ForName()加载的时候,类加载器检查到这个类已经被加载,那么就返回对这个class对象的引用,所以自始自终,虽然有不止一个的class对象的引用,但是class对象却只有一个!
如果你对加载类的顺序迷惑的话,那么就请看类加载器的一个方法吧:
loadClass
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException
-
调用
findLoadedClass(String)
来检查是否已经加载类。 -
在父类加载器上调用
loadClass
方法。如果父类加载器为 null,则使用虚拟机的内置类加载器。 -
调用
findClass(String)
方法查找类。
如果使用上述步骤找到类,并且 resolve 标志为真,则此方法将在得到的 Class 对象上调用 resolveClass(Class)
方法。
鼓励用 ClassLoader 的子类重写 findClass(String)
,而不是使用此方法。
ClassLoader具体加载类的顺序是:
# 调用 findLoadedClass 来查看是否存在已装入的类。
# 如果没有,那么采用那种特殊的神奇方式来获取原始字节。
# 如果已有原始字节,调用defineClass将它们转换成Class对象。
# 如果没有原始字节,然后调用findSystemClass查看是否从本地文件系统获取类。
# 如果resolve参数是true,那么调用resolveClass解析Class对象。
# 如果还没有类,返回ClassNotFoundException。
# 否则,将类返回给调用程序。
所以不管用哪种方式加载类,它们实际上都执行了上面这个方法,如果这个类已经加载了,那么就返回对这个class对象的引用,然后用这个class对象可以创建实例,这个实例又可以通过getClass()得到这个class对象的引用,而这个class对象的引用又可以通过getName()得到类名,也可以通过getClassLoader()得到加载这个class对象的加载器。- -!好像我都被搞糊涂了。。呵呵
发表评论
-
解决eclipse每次启动maven很慢
2012-11-14 12:31 17858好久没有用eclipse了,离开人人后maven私有仓库当然也 ... -
Debug控
2011-08-02 14:34 3587我是一个debug控,很 ... -
泛型のwhy&how
2011-07-21 18:35 1414Why,Java为什么需要 ... -
【分享】Findbugs反模式
2011-05-20 09:54 5266FindBugs解释 FindBugs 是一个静态分 ... -
Findbugs反模式
2011-05-20 09:46 0FindBugs介绍 FindBugs 是一个静态分 ... -
正则表达式Mini版
2010-10-27 12:14 13731.句点符号:. 条件 ... -
Eclipse下jar包版本不一致等常见问题
2010-09-15 20:18 7991我借这个平台简单说说Eclipse下配置环境需要注意的几点 ... -
我承认我没有if(xxx != null)
2010-09-08 12:08 3022昨天正在编码兴头时 ... -
jtextfield限制字数与数字输入
2010-02-21 15:40 64import javax.swing.text.*; p ... -
Swing线程机制以及invokeLater和invokeAndWait
2009-09-14 11:05 7120本人最近想写一个仿QQ,初学Swing对线程机制不太了解,所以 ... -
在重写了对象的equals方法后,还需要重写hashCode方法吗?
2009-08-19 21:08 2035首先说建议的情况: 比如你的对象想放到Set集合或者是想作为 ... -
第五惑:初始化和动态绑定之间的小小冲突
2009-04-04 23:46 1243今天骑车去都江堰了,很累很累,没准备好今天该发什么Tips,所 ... -
第四惑:属性是否被动态绑定?
2009-04-03 17:11 1162众所周知,方法可以被动态绑定,在子类被向上转型为父类时,虚拟机 ... -
第三惑:类型被动使用举例
2009-04-02 13:04 1426当类型属于被动使用的 ... -
第二惑:类型在没有被完全初始化之前就生成实例对象所表现的情况
2009-04-01 13:41 1487public class MainTest { publi ... -
第一惑:类初始化时,final修饰的静态字段的表现方式
2009-03-31 16:27 1836计划从今天开始,模仿一下jythoner大哥,不过不是Java ... -
Java动态绑定虚拟机实现
2009-03-25 20:19 1727今天在51CTO看到一篇很好的介绍Java动态绑定的文章。先转 ... -
Java虚拟机简单介绍
2009-03-25 20:17 110请参考:http://cantellow.iteye.com/ ... -
Java夜未眠·经典句子选载
2009-03-25 20:16 2853最近在读前辈蔡学镛《Java夜未眠·程序员的心声》,几天就看完 ... -
代码签名和认证
2009-03-25 20:06 1769要对一段代码作担保或 ...
相关推荐
4. **类加载器**:Class对象与类加载器息息相关。每个Class对象都关联了一个类加载器,通过`getClassLoader()`方法可以获取。类加载器负责找到、加载和验证类的字节码。默认的类加载器是bootstrap loader,当字段为...
#### 三、类与类加载器的关系 类加载器对于确定类在JVM中的唯一性至关重要。两个类只有当它们来自相同的类加载器时才被认为是相同类的不同实例。这意味着即使两个类来自相同的`.class`文件,如果它们是由不同的类...
- 类的唯一性:类加载器与类的关系是“一对多”,同一类加载器下的类名必须唯一,不同类加载器加载的同名类不冲突。 - 双亲委派模型的遵守:自定义类加载器通常应遵循双亲委派模型,除非有特殊需求,否则不应轻易...
当一个类加载器接收到加载类的请求时,它首先会委托其父类加载器去尝试加载,如果父类加载器无法加载,再由当前加载器尝试。这个过程一直向上,直到Bootstrap类加载器,如果Bootstrap也无法加载,再回退到原始的类...
4. 类加载器与类的关系: 每个类都与加载它的类加载器相关联。不同类加载器加载的相同类会被视为不同的类,即使它们的字节码完全相同。这是实现多版本库共存的基础。 5. 动态加载与插件系统: 类加载器使得在运行...
7. **类加载器与安全** 类加载器可以用于实现细粒度的访问控制,比如不同模块使用不同的类加载器加载各自的类,这样即使类名相同,只要加载器不同,它们就是两个不同的类,从而保证了安全性。 8. **热部署与类加载...
3. Application ClassLoader:也称为系统类加载器,负责加载用户类路径`-cp`或`-classpath`指定的所有类。 当一个类被加载时,如果它的父类加载器无法加载该类,那么会将任务委派给子类加载器。这就是著名的"委托...
在运行时,自定义类加载器接收到类的请求后,首先读取加密的字节码,然后通过预先设定的解密算法进行解密,最后将解密后的字节码转换成Class对象并返回给JVM。 反射是Java提供的一种强大的动态类型机制,允许我们在...
它会先尝试调用父类加载器的`loadClass()`方法,如果父类加载器未能加载,则会调用`findClass()`来加载类。这遵循了类加载的双亲委托模型,确保核心类库的唯一性和安全性。 3. **defineClass(String name, byte[] b...
创建自定义类加载器通常需要继承`java.lang.ClassLoader`,重写`findClass()`或`loadClass()`方法,从而控制类的查找和加载过程。这使得开发者能够在运行时根据需要加载特定的类,比如从网络、数据库或其他非传统...
默认的类加载器包括bootstrap classloader(引导类加载器)、extension classloader(扩展类加载器)和appclassloader(应用程序类加载器),它们按照双亲委托模型进行工作,从基础到具体逐层尝试加载类。...
接着,类加载器与类的关系需要深入理解。每个类都有一个对应的类加载器,而类加载器之间存在父子关系,形成了层次结构。不同类加载器加载的类被视为不同的类,即使它们的全限定名相同。这就是为什么我们常说"同一个...
* 缓存机制:保证所有加载过的Class都会被缓存,当程序需要使用某个Class对象时,类加载器先从缓存区中搜索该Class,只有当缓存区中不存在该Class对象时,系统才会读取该类对应的二进制数据,并将其转换成Class对象...
6. 类加载器与异常: 在类加载过程中,可能会遇到`ClassNotFoundException`和`NoClassDefFoundError`等异常。前者通常是因为类加载器无法找到指定的类,后者则可能发生在类已被加载但无法找到其定义的情况下。 7. ...
在Java编程中,静态代码块(Static Block)和类加载器(Class Loader)是两个重要的概念,它们在软件开发中有着广泛的应用。本案例聚焦于如何利用静态代码块结合类加载器来高效地获取资源文件,尤其是属性配置文件。...
在Java编程语言中,类加载器(ClassLoader)是至关重要的组成部分,它负责将类的字节码转换为可执行的Java对象。理解类加载器的工作原理对于深入掌握Java虚拟机(JVM)运行机制和进行高效的问题排查至关重要。在这个...
2. 链接:将这个字节流所代表的静态存储结构转换为方法区的运行时数据结构,并且在内存中生成一个代表这个类的java.lang.Class对象。 3. 初始化:这个阶段主要是执行类构造器方法(),它是javac编译器自动收集类中的...
### JAVA反射机制——Class类与Class对象的获取 #### 概述 在Java语言中,反射是一种强大的功能,允许程序在运行时动态地检查和修改自身的行为。这种能力是通过`java.lang.Class`类实现的,它提供了封装类或接口...