`
xuyan2680
  • 浏览: 30789 次
  • 性别: 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,后面的一系列检查都不需要做了,因而没出异常。

相关推荐

    构建器数据加载器

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

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

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

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

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

    ngOnDemand:一种按需加载 AngularJS 控制器的方法

    一种按需加载 AngularJS 控制器的方法。 这是一种在需要时加载 AngularJS 控制器的方法。 当控制器被请求时,它将通过 xhr 加载脚本。 版本 0.0.3 都多的 添加测试 添加带有版本控制的离线存储 - 这个想法是在加载...

    ELDK使用与开发手册

    U-Boot加载Linux内核、Ramdisk或者其它映像时使用一种特殊的映像格式。这种格式包含了一些信息,如创建时间、操作系统、压缩格式、映像类型、映像名和CRC32校验和。 mkimage用来创建这种格式的映像文件或者显示它...

    baby-chrome:获取您的脚手架chrome扩展项目。 不再需要复制粘贴!

    例如, baby-chrome space-shuttle 在此命令上,您将看到一个复选框菜单,用于选择chrome扩展程序的性质,例如,该扩展程序是否需要在后台运行,是否需要jquery等, 选择适当的选项,然后单击Enter。 就是这样,...

    HGE_系列教材(1-9)

    HGE 系列教材(1) --- 简介 HGE 是一个硬件加速(Hardware accelerated)的2D 游戏引擎(Game Engine), HGE 是一个富有特性的中间件,可以用于开发任何类型的2D 游戏。...// 加载纹理 quad.tex =...

    内存管理内存管理内存管理

    对实际编程来说,理解您的内存管理器的能力与局限性至关重要。在大部分系统语言中,比如 C 和 C++,您必须进行内存管理。本文将介绍手工的、半手工的以及自动的内存管理实践的基本概念。 追溯到在 Apple II 上...

    Toad 使用快速入门

    定位到某一类对象上,这列对象允许的操作都会自动列出来。 特色: 支持Oracle数据库里面所有对象的新建、查看、修改,集成了几乎对所有数据库对象的管理所需要的功能。  按照 模式->对象类别 ->对象->对象可...

    Oracle8i_9i数据库基础

    §2.5.7 SPACE(列间空格) 84 §2.5.8 Termout (启/停屏幕显示) 84 §2.5.9 ECHO (启/停命令显示) 84 §2.5.10 TRANSACTION (启动事务) 85 §2.5.11 SHOW ALL(列出所有参数) 85 §2.6 格式化输出 87 §2.6.1 一般数据...

Global site tag (gtag.js) - Google Analytics