一、序言
先啰嗦一下,上次,阿里面试的时候问到能否加载一个java.lang.xx 的类,我的回答的是不能- -!当然答案是正确的,但是不知道为什么。
还有一个问题:如果加载两个jar,里面含有相同路径的类,是可以的吗?我还是回答不能- -,估计会冲突,但是原因也是模模糊糊,这里我再回顾一自定义加载类的方法吧,至于原理和细节的介绍,在JVM 目录下有。
二、自定义类加载器:
这里还是先写一个简单的加载器,方便测试吧!
/** * 自定义加载器的工具类 * 临时写的,暂时不做过多控制 * @author Ran * */ public class ClassLoaderUtils extends ClassLoader{ // 获取二进制字节流 private byte[] getData(InputStream in){ byte[] data = null; try { data = new byte[in.available()]; in.read(data); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally{ try { if(in != null){ in.close(); } } catch (IOException e) { e.printStackTrace(); } } return data; } // 获得文件流 private InputStream getInputStream(String name){ name = name.replace(".", "/")+".class"; return getClass().getClassLoader().getResourceAsStream(name); } // 这个源码是直接抛出异常,并且是protected,好让我们重写findClass @Override protected Class<?> findClass(String name) throws ClassNotFoundException { InputStream in = getInputStream(name); if(in == null){ System.out.println("自定义加载失败!"); return super.loadClass(name); } byte[] data = this.getData(in); return super.defineClass(name,data, 0, data.length); } // 测试 public static void main(String[] args) throws Exception, IllegalAccessException, ClassNotFoundException { // String name = "com.T1"; ClassLoaderUtils cu = new ClassLoaderUtils(); System.out.println(cu.findClass(name).newInstance()); } }
2.1 尝试加载java.lang.下面的类,这里我创建了一个 java.lang.LangTest 类,JDK1.6 进行测试。
// 测试 public static void main(String[] args) throws Exception, IllegalAccessException, ClassNotFoundException { String name = "java.lang.LangTest"; ClassLoaderUtils cu = new ClassLoaderUtils(); System.out.println(cu.findClass(name).newInstance()); }
结果:Exception in thread "main" java.lang.SecurityException: Prohibited package name: java.lang
后面我继续测试,我同样用rt.jar 下面的目录结构,结果是:
java.io.xxx :异常同上
sun.nio.xxx: 没有异常。
也就说我们猜想,自定义加载器在加载rt.jar 里面,包含java 开头的会出错,从错误分析,有包名检测机制决定的。java 包下面的应该属于很核心的东西,不允许我们建立这些。
2.3 同一包下面的类,可以被多次加载吗?
String name = "com.Test3"; ClassLoaderUtils cu = new ClassLoaderUtils(); Object a = cu.findClass(name); System.out.println(a); Object b = cu.findClass(name); System.out.println(b);
结果:
loader (instance of ClassLoaderUtils): attempted duplicate class definition for name: "com/Test3"
可以看出:不能重复加载,我们换种方式呢?
String name = "com.Test3"; ClassLoaderUtils cu = new ClassLoaderUtils(); Object a = cu.findClass(name); System.out.println(a); // 从新创建一个加载器 ClassLoaderUtils cu1 = new ClassLoaderUtils(); Object b = cu1.findClass(name); System.out.println(b);
这个结果是正常的。
我们可以猜想:同一个加载器无法加载相同包的的同名类,在类加载机制里面,我们说到每个类在内存中只有一份,这里的一份是指拥有相同的类加载器的情况。因此很多第三方框架都喜欢用自己的类加载器,不至于重复。
小结:
1.关于类加载的东西,我是有些模糊的,比如第一个问题,我仅仅知道java.lang 下的不能自己加载,知道那是核心的东西,但是具体的原因,以及是实现过程,是没有研究的,比较清楚的大哥,希望可以介绍介绍。
2.关于类在内存中只有一份,这个概念,应该是规范要求的,毕竟我们存在积分相同的类是没意义的,会破坏我们的继承机制,比如有两份java.lang.Object 类,我们的子类到底属于哪个? 这里我尝试过,即使编译也通不过!
3.关于一个类多次加载的问题,我用 jar cvf 打包名.jar 目标.class 的命令打成两个不同的jar,然后放入工程,是没有错误的,但是只能调用其中一个类的方法, 比如a.jar 里面打印1,b.jar 打印2,那么我调方法的时候是打印的1,没有明确先后,都是App 的加载器。
4.上面仅仅是验证下效果,具体的原理没有详细分析,动动手,自己放心,详细的后面慢慢研究。
相关推荐
缺什么class文件,解压rt.jar后再放进去,用rar压缩工具重新打包成rt.zip,改名为rt.jar,然后替换自己的jre/lib目录下的rt.jar,这样反复执行,就得到了定制化的rt.jar。 其实依次方式也可以精简其他jar包。只要你肯...
`rt.jar` 的源码提供了深入理解这些类和方法工作原理的机会,对于Java开发者来说是极有价值的参考资料。 `rt_source_jdk1.8` 这个压缩包文件就是 JDK 1.8 版本中 `rt.jar` 的源代码,你可以通过解压并导入到IDE(如...
lib包中的jrt-fs.jar 和 rt.jar 包下载,rt.jar:Java基础类库,也就是Java doc里面看到的所有的类的class文件。dt.jar:dt.jar是关于运行环境的类库,主要是swing包。
破解java加密的rt.jar,在classloader...使用方法:只要下载本rt.jar,然后替换掉jdk1.8.0_25\jre\lib目录下的rt.jar。然后运行你需要破解的java程序即可,如果你的java程序用了自带的jre,那么替换掉该jre下的rt.java
在提供的压缩包文件中,虽然没有具体的子文件名,但通常`rt.jar`内部结构是按包(package)组织的,每个包下有多个类文件(.class),这些类文件代表了Java的类和接口。解压`rt.jar`后,可以看到以`.class`为扩展名...
rt.jar还包含了JVM运行时的一些组件,如ClassLoader、Class对象等,它们负责加载类、执行字节码和管理类的生命周期。 1. ClassLoader:负责加载类文件到JVM中,它是Java动态加载机制的基础。 2. Class对象:每个...
4. 自定义实现:对rt.jar源码的理解可以帮助开发者自定义Java库,提供特定功能或优化已有功能。 五、注意事项 虽然rt.jar源码公开,但并非所有部分都适合直接修改,因为这可能影响到JVM的兼容性和稳定性。通常,...
rt.jar文件通常位于JDK安装目录的`jre/lib`或`lib`子目录下,其内容是Java开发和运行所必需的。由于rt.jar是二进制形式的Java类文件集合,因此在默认情况下,我们无法直接查看其内部的源代码。然而,对于开发者来说...
在rt.jar中,`java.lang`包是最为核心的部分,它包含了所有Java程序的基础类,如`Object`、`String`、`Class`、`Thread`等。其中,`Object`是所有类的基类,定义了类的基本行为;`String`类是不可变的字符序列,是...
不过,要注意,直接修改rt.jar的源代码不会影响到JRE的运行,因为运行时加载的是已编译的.class文件。如果需要定制或扩展JDK的功能,通常需要通过编写自己的类库或使用Java扩展机制(如ServiceLoader)来实现。
1. 类加载机制:`java.lang.ClassLoader`是Java中负责加载类的类,理解其工作原理有助于我们了解类如何被找到并加载到JVM中,这对于理解和实现自定义类加载器非常重要。 2. 集合框架:深入源码可以让我们明白`...
默认情况下,JVM的根类加载器(Bootstrap ClassLoader)会自动加载这个jar,因此在Classpath设置中无需特别包含rt.jar。 其次,tools.jar包含了用于Java开发和维护的各种工具的类。这些工具包括javac(Java编译器)...
在学习rt.jar源码时,我们还需要关注`META-INF`目录,它包含了一些元数据信息,如`MANIFEST.MF`文件,记录了jar文件的基本信息和类加载配置。此外,`META-INF/services`子目录下的文件用于服务发现机制,允许通过...
针对可执行的jar 处理jdk中最大依赖包 rt.jar的文件,并删除其中不需要的依赖class,从而获取较小的rt.jar包。 最经发现一个问题: 1、裁剪之后的rt.jar存在问题,例如反射、动态加载的依赖包无法分析 2、裁剪之后...
在Java开发环境中,JDK包含了多个重要的jar文件,如rt.jar、tools.jar和dt.jar,它们各自承担着不同的职责,对于理解和使用Java平台至关重要。下面将详细解释这三个jar文件的作用。 1. **rt.jar** rt.jar是...
然而,在某些特殊情况下,例如进行JAR文件打包或者部署到特定环境时,可能需要确保`rt.jar`在正确的路径下,或者理解其内容来避免命名冲突或重复引入。 关于`rt.jar`的使用和分析,有以下几点需要注意: 1. **安全...
1. Official statement is ...2. since JDK7 is based on OpenJDK, and almost every class in JDK7 is identical to the one shipped with or generated by OpenJDK, why not take the classes from OpenJDK instead?
4. **类加载与初始化**:可以动态地完成类的加载和初始化,这在某些框架设计中很有用。 然而,`Unsafe`类的使用也存在一定的风险。由于它可以绕过Java的内存管理和安全机制,如果不恰当使用,可能导致内存泄漏、...
在实际使用中,通常不需要直接解压和操作rt.jar,因为Java的类加载器会自动加载这个库。但如果需要对其中的类进行修改或替换,可能需要对JAR文件进行反编译和重新打包,这通常需要用到如JAD、Procyon等工具。 总之...
Java基础类库,也就是Java doc里面看到的所有的类的class文件。