`
xuyan2680
  • 浏览: 31741 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

类加载器与name-space

阅读更多
学习自定义类加载器与运行时包:
package test;

import java.io.InputStream;

public class NewClassLoader extends ClassLoader {
	public MySingleton createNewOne() throws Exception {
		InputStream is = getClass().getResourceAsStream("MySingletonImp.class");
		byte[] b = new byte[is.available()];
		is.read(b);
		Class clz = defineClass(null, b, 0, b.length);
		Object o = clz.newInstance();
		return (MySingleton) o;
	}

	public static void main(String[] args) throws Exception {
		NewClassLoader loader = new NewClassLoader();
		MySingleton newObj = loader.createNewOne();
		MySingletonImp instance = MySingletonImp.getInstance();
		System.out.println(MySingletonImp.class.getClassLoader());
		System.out.println(instance == newObj);
	}
}

class MySingletonImp implements MySingleton {
	private static final MySingletonImp instance = new MySingletonImp();

	public static MySingletonImp getInstance() {
		return instance;
	}
}

以上两个类是放在同一个文件下面
package test;

public interface MySingleton {

}

接口MySingleton 单独放在一个文件下面,此时执行mian方法,则抛异常:
Exception in thread "main" java.lang.IllegalAccessException: Class test.NewClassLoader can not access a member of class test.MySingletonImp with modifiers ""如果把 MySingletonImp 类提出来单独放一个文件
package test;

public class MySingletonImp implements MySingleton {
	private static final MySingletonImp instance = new MySingletonImp();

	public static MySingletonImp getInstance() {
		return instance;
	}
}

则执行不会抛异常,输出 false
baidu描述原因:
Java语言中的包访问成员(friendly)实际上指的是运行时包访问可见,而不是编译时。因此当你试图访问不在同一个runtime package的成员是(即便在编译时它们在同一个包内,但是却由不同的class loader加载)也同样会得到java.lang.IllegalAccessException: Class A can not access a member of class B with modifiers "" 这样的异常。

但是本人还是不是很理解,我把MySingletonImp 单独提出来时,也不是同一个 runtime package,因为加载器都不一样,NewClassLoader 是系统类加载器加载的,而MySingletonImp 是自定义加载器加载的。。很是不明白,
欢迎大家讨论...
分享到:
评论
13 楼 xuyan2680 2010-01-25  
xuyan2680 写道
bengan 写道
xuyan2680 写道
pengjunwu 写道
请问 为什么要用自定义加载器呢 我是小菜鸟

可以解决类似的问题:
比如:我们需要开发一个通用的执行引擎。可以执行实现某一特定接口的任何任务。当任务被提交到这个引擎,首先需要加载这个任务的代码。假设不同的客户对此引擎提交了不同的任务,凑巧,这些所有的任务都有一个相同的类名和包名。现在面临的问题就是这个引擎是否可以针对不同的用户所提交的信息而做出不同的反应
而使用了自定义加载器后,我们可以针对每个客户提交任务实例化一个加载器来加载客户提交的任务类,由于运行时包由 类加载器和包名决定,所以即使是客户都提交相同的任务类,在同一个jvm中,不同的运行包的类是不可见,所以jvm可以处理好即使每个客户提交一个相同的类名和包名。。
具体见下周贴代码示意..顺便我也是正在学习的小菜。。


这样是不是设计上有点问题啊?对用户上传的业务类是不是应该有个命名规则!

我是假设出现这种情况的话。当然出现这种情况是很小的,一般都会有个命名规则.


示意代码http://xuyan2680.iteye.com/admin/blogs/578939
12 楼 xuyan2680 2010-01-25  
bengan 写道
xuyan2680 写道
pengjunwu 写道
请问 为什么要用自定义加载器呢 我是小菜鸟

可以解决类似的问题:
比如:我们需要开发一个通用的执行引擎。可以执行实现某一特定接口的任何任务。当任务被提交到这个引擎,首先需要加载这个任务的代码。假设不同的客户对此引擎提交了不同的任务,凑巧,这些所有的任务都有一个相同的类名和包名。现在面临的问题就是这个引擎是否可以针对不同的用户所提交的信息而做出不同的反应
而使用了自定义加载器后,我们可以针对每个客户提交任务实例化一个加载器来加载客户提交的任务类,由于运行时包由 类加载器和包名决定,所以即使是客户都提交相同的任务类,在同一个jvm中,不同的运行包的类是不可见,所以jvm可以处理好即使每个客户提交一个相同的类名和包名。。
具体见下周贴代码示意..顺便我也是正在学习的小菜。。


这样是不是设计上有点问题啊?对用户上传的业务类是不是应该有个命名规则!

我是假设出现这种情况的话。当然出现这种情况是很小的,一般都会有个命名规则.
11 楼 xuyan2680 2010-01-25  
yongyuan.jiang 写道
pengjinwu 写道
请问 为什么要用自定义加载器呢 我是小菜鸟

比如web容器tomcat,jetty,他们的类装器是自行定义的,每个webapp的lib不会相互影响。


这位兄台描述的极是!
10 楼 yongyuan.jiang 2010-01-24  
pengjinwu 写道
请问 为什么要用自定义加载器呢 我是小菜鸟

比如web容器tomcat,jetty,他们的类装器是自行定义的,每个webapp的lib不会相互影响。
9 楼 坏孩子 2010-01-24  
inside jvm里面有讲
8 楼 bengan 2010-01-23  
xuyan2680 写道
pengjunwu 写道
请问 为什么要用自定义加载器呢 我是小菜鸟

可以解决类似的问题:
比如:我们需要开发一个通用的执行引擎。可以执行实现某一特定接口的任何任务。当任务被提交到这个引擎,首先需要加载这个任务的代码。假设不同的客户对此引擎提交了不同的任务,凑巧,这些所有的任务都有一个相同的类名和包名。现在面临的问题就是这个引擎是否可以针对不同的用户所提交的信息而做出不同的反应
而使用了自定义加载器后,我们可以针对每个客户提交任务实例化一个加载器来加载客户提交的任务类,由于运行时包由 类加载器和包名决定,所以即使是客户都提交相同的任务类,在同一个jvm中,不同的运行包的类是不可见,所以jvm可以处理好即使每个客户提交一个相同的类名和包名。。
具体见下周贴代码示意..顺便我也是正在学习的小菜。。


这样是不是设计上有点问题啊?对用户上传的业务类是不是应该有个命名规则!
7 楼 xuyan2680 2010-01-22  
pengjunwu 写道
请问 为什么要用自定义加载器呢 我是小菜鸟

可以解决类似的问题:
比如:我们需要开发一个通用的执行引擎。可以执行实现某一特定接口的任何任务。当任务被提交到这个引擎,首先需要加载这个任务的代码。假设不同的客户对此引擎提交了不同的任务,凑巧,这些所有的任务都有一个相同的类名和包名。现在面临的问题就是这个引擎是否可以针对不同的用户所提交的信息而做出不同的反应
而使用了自定义加载器后,我们可以针对每个客户提交任务实例化一个加载器来加载客户提交的任务类,由于运行时包由 类加载器和包名决定,所以即使是客户都提交相同的任务类,在同一个jvm中,不同的运行包的类是不可见,所以jvm可以处理好即使每个客户提交一个相同的类名和包名。。
具体见下周贴代码示意..顺便我也是正在学习的小菜。。
6 楼 pengjunwu 2010-01-22  
请问 为什么要用自定义加载器呢 我是小菜鸟
5 楼 dferto 2010-01-22  
推荐大家看一看加入我们的100937543,大家可以进行研究和商讨。
4 楼 xuyan2680 2010-01-22  
更改代码这部分代码
public MySingleton createNewOne() throws Exception {
		InputStream is = getClass().getResourceAsStream("MySingletonImp.class");
		byte[] b = new byte[is.available()];
		is.read(b);
		Class clz = defineClass(null, b, 0, b.length);
		Object o = clz.newInstance();
		return (MySingleton) o;
	}


public MySingletonImp createNewOne() throws Exception {
		InputStream is = getClass().getResourceAsStream("MySingletonImp.class");
		byte[] b = new byte[is.available()];
		is.read(b);
		Class clz = defineClass(null, b, 0, b.length);
		Object o = clz.newInstance();
		return (MySingletonImp) o;
	}

并更改
MySingletonImp newObj = loader.createNewOne();

执行后,会产生类型转换异常,这是由于 NewClassLoader 是系统类加载器加载的,而MySingletonImp 是 自定义加载器NewClassLoader 加载,而这两个加载器不存在父子关系,即不属于相同的namespace ,进而不可见。
子加载器包含所有父加载器的namespace,即子加载器加载类可以访问所有父加载器加载的类,反之则不然。
3 楼 xuyan2680 2010-01-21  
RednaxelaFX 写道
前后两次的差异源于你在把MySingletonImp提取到一个单独的文件后,把它的可访问性也改变了:原本是package,后来是public。

如你所知,只有当两个类是被同一个classloader加载,并且它们的包名相同时,它们所在的的“运行时包”才是相同的;拥有package可访问性的类从别的包无法直接访问。
在调用Class.newInstance()时,里面会对可访问性做检查。当它发现被实例化的类的可访问性为public,并且其默认构造器的可访问性也是public时,检查就算通过了;如果类的可访问性不是public(对于顶层类来说这意味这它是package可见),则要检查发起实例化的类与被实例化的类是否位于同一个“运行时包”内,如果不是则校验失败,抛出IllegalAccessException。

再回头看顶楼的例子,在修改代码前,test.MySingletonImp类的可访问性是package,其默认构造器没有写,由编译器自动生成public的默认构造器。加载NewClassLoader类的类加载器是当前线程的上下文类加载器。然后在NewClassLoader.createNewOne()中,NewClassLoader自定定义了一个test. MySingletonImp;被定义的MySingletonImp与NewClassLoader就不在同一个“运行时包”里了,因而未能通过可访问性检查。
在修改代码后,test. MySingletonImp的可访问性变为public,后面的一系列检查都不需要做了,因而没出一场。

这位兄台讲的够清楚了。。。赞一个,研究的够深!
2 楼 fireflyc 2010-01-21  
推荐你这个开源工具
http://classworlds.codehaus.org/
1 楼 RednaxelaFX 2010-01-21  
前后两次的差异源于你在把MySingletonImp提取到一个单独的文件后,把它的可访问性也改变了:原本是package,后来是public。

如你所知,只有当两个类是被同一个classloader加载,并且它们的包名相同时,它们所在的的“运行时包”才是相同的;拥有package可访问性的类从别的包无法直接访问。
在调用Class.newInstance()时,里面会对可访问性做检查。当它发现被实例化的类的可访问性为public,并且其默认构造器的可访问性也是public时,检查就算通过了;如果类的可访问性不是public(对于顶层类来说这意味这它是package可见),则要检查发起实例化的类与被实例化的类是否位于同一个“运行时包”内,如果不是则校验失败,抛出IllegalAccessException。

再回头看顶楼的例子,在修改代码前,test.MySingletonImp类的可访问性是package,其默认构造器没有写,由编译器自动生成public的默认构造器。加载NewClassLoader类的类加载器是当前线程的上下文类加载器。然后在NewClassLoader.createNewOne()中,NewClassLoader自行定义了一个test. MySingletonImp;被定义的MySingletonImp与NewClassLoader就不在同一个“运行时包”里了,因而未能通过可访问性检查。
在修改代码后,test. MySingletonImp的可访问性变为public,后面的一系列检查都不需要做了,因而没出异常。

相关推荐

    链接器与加载器

    ### 链接器与加载器相关知识点 #### 一、链接器与加载器的作用及概念 **链接器(Linker)**是一种将多个已编译的程序模块(如目标文件)组合成一个可执行程序的工具。它负责解决各模块间的符号引用,并进行地址空间...

    虚拟机内存图以及加载类的执行过程

    方法区也被称为永久代(PermGen space),主要用来存储已被虚拟机加载的类信息、常量、静态变量以及即时编译器编译后的代码等数据。值得注意的是,不同虚拟机实现对方法区的具体布局可能有所不同,这些差异取决于...

    grub4dos-V0.4.6a-2017-02-04更新

    --string=[x]=[y]=[color]=["string“] 字符串位置、颜色与内容,可用于标题,说明,帮助等。单位:列,行,24位色彩。 注:如果省略颜色,位于菜单框以上按标题颜色,位于菜单框以下按帮助文本颜色; 字符串头尾...

    构建器数据加载器

    请参考 切换到脚本文件夹光盘生成器数据加载器创建名为“ config_ {content_space_id} .ini”的构建器配置文件,并将其保存在“ BuilderConfig”目录中。 从pipfile安装依赖项pipenv安装激活Pipenv外壳皮壳这将产生...

    JVM性能优化相关问题-面试-进阶

    加载方式有隐式加载(如new关键字创建对象时)和显式加载(如通过class.forName())。JVM按需加载,仅加载必要的类,提高了速度并减少了内存占用。加载过程包括装载、链接(包含检查、准备和解析)、初始化等步骤。 ...

    2021Java字节跳动面试题——面向字节_JVM(下).pdf

    5. **初始化**:这是类加载的最后一步,在之前的类加载过程中,除了在加载阶段用户应用程序可以通过自定义类加载器参与外,其余动作完全由虚拟机主导和控制。到了初始化阶段,才真正开始执行类中定义的Java程序代码...

    JVM.pdf

    类加载器按需加载类,分为隐式加载(如`new`操作)和显式加载(如`Class.forName()`)。这种按需加载策略优化了加载速度和内存使用。 Java内存分配主要涉及以下几个区域: - **寄存器**:由硬件提供,不可直接控制...

    传智播客 方立勋 javaweb 完全笔记

    - **描述**: 最基础的类加载器,负责加载 JVM 自身需要的类库。 **7.23 Extension ClassLoader** - **作用**: 负责加载 Java 扩展类库。 **7.24 System ClassLoader** - **定义**: 负责加载应用程序类路径中的类。...

    proguide-draft.pdf

    Q2支持动态加载类文件,提高了系统的灵活性和扩展性。 ### 总结 本文详细介绍了jPOS项目的主要特性及其在ISO-8583标准下的应用。通过深入理解这些知识点,开发者可以更加高效地利用jPOS来构建可靠的支付系统和交易...

    JVM综合面试题汇总.docx

    Java类加载器是动态的,它根据需要加载类。加载方式分为隐式和显式:隐式加载发生在创建对象时,如`new`操作;显式加载则是通过`Class.forName()`等方法手动调用。每个类或接口都有对应的.class文件,它们作为独立的...

    Oracle学习笔记.doc

    - 去除空白字符: `TRIM(LEADING|TRAILING|BOTH 'space' FROM column_name)`. - 日期转换: `TO_DATE(value, format)`. - 字符串转日期: `TO_CHAR(date_column, format)`. - 数值转换: `TO_NUMBER(value)`. - ...

    JVM性能优化相关问题.pdf

    类加载器负责从硬盘读取.class文件到内存中,确保Java程序的动态加载。类的加载方式分为隐式加载(如通过new创建对象时)和显式加载(如调用class.forName())。 Java内存分配主要涉及以下区域: - 寄存器:程序员...

    (重要)AIX command 使用总结.txt

    F Format ->以用户指定格式输出,Format参数为预定义或自定义设备对象类中的列名,如:name status等 H ->显示列输出前面的头部分,即输出中包括列头部分 P ->列出预定义设备对象类中设备的有关信息,即支持的设备,...

    Java知识,JVM面试资料

    2. **JVM加载Class文件的原理**:类加载器(ClassLoader)负责加载类文件到JVM中,分为隐式加载(如new操作)和显式加载(如class.forName())。加载过程遵循“按需加载”原则,仅在需要时加载类,以提高性能并减少...

    ASP.NETWeb应用程序设计练习题

    - 正确答案: A (<%@Register TagPrefix="Mike" TagName="Space2" Src="myX.ascx"%>) - 解析: 在ASP.NET中,用户控件(ascx文件)需要在使用它的ASPX页面中进行注册。注册指令中,`TagPrefix` 指定了前缀,`TagName` ...

    数据库系统开发考试题目.doc

    - 用户控件注册:使用`<%Register>`指令,如`<%Register TagPrefix = "Space2" TagName = "Mike" Src = "myX.ascx"%>`。 - 数据库连接创建:如`SqlConnection con1 = new SqlConnection("连接字符串")`。 6. **...

    ruby 程序设计

    ##### §3.5 类变量与类方法 - **类变量**:以`@@`开头的变量可以在类的所有实例之间共享。 - **类方法**:使用关键字`self`定义的方法,只能由类调用而不是对象。 ##### §3.6 存取控制 - **访问级别**:Ruby支持...

Global site tag (gtag.js) - Google Analytics