Class初始化过程
-
加载
jvm将.class文件以二进制的形式读取到内存(.class文件本身是2进制的,但其文件内容是16进制的字节码),存放在方法区(类的元信息),并在堆区创建Class对象(类的实例,用于封装方法区的数据结构)。
-
- 双亲委派模型
约定类加载器的加载机制:根加载器 > 扩展加载器 > 系统加载器 > 自定义加载器,当类加载器收到类加载请求时,总是先委派父类加载器去完成,只有当父类加载器无法加载时,才会尝试自己加载。
目的:保证了类的全局唯一性。
-
- 如何打破jdk默认的双亲委派机制?
继承ClassLoader,并重写loadClass
public class MyClassLoader extends ClassLoader { private String path; public MyClassLoader(String classLoaderName) { super(); } public MyClassLoader(ClassLoader parent, String classLoaderName) { super(parent); } /** * 寻找加载类 * @param name * @return */ @Override protected Class<?> findClass(String name) { byte[] data = this.loadClassData(name); return super.defineClass(name, data, 0, data.length); } /** * 根据地址加载class文件。 * * @param name * @return byte数组 */ private byte[] loadClassData(String name) { InputStream is = null; byte[] data = null; ByteArrayOutputStream baos = null; try { name = name.replace(".", "\\"); JarFile jar = new JarFile(this.path); is = jar.getInputStream(jar.getEntry(name.replace("\\", "/") + ".class")); baos = new ByteArrayOutputStream(); int ch; while (-1 != (ch = is.read())) { baos.write(ch); } data = baos.toByteArray(); } catch (Exception ex) { ex.printStackTrace(); } finally { try { is.close(); baos.close(); } catch (Exception ex) { ex.printStackTrace(); } } return data; } public void setPath(String path) { this.path = path; } }
public class MyTest { public static void main(String[] args) throws Exception{ ClassLoader classloader = Thread.currentThread().getContextClassLoader(); Enumeration<URL> urls = classloader.getResources("com/DataManager.class"); while (urls.hasMoreElements()) { String[] jarPath = urls.nextElement().getPath().split("!"); // 获取文件的路径以及文件名 String filePath = jarPath[0].replace("file:/",""); String classPath = jarPath[1].substring(1).replace(".class", "").replace("/", "."); MyClassLoader loader = new MyClassLoader(null, "myClassLoader"); loader.setPath(filePath); // 加载类 Class<?> clazz = loader.loadClass(classPath); // 反射创建实体 Object obj = clazz.getDeclaredConstructor().newInstance(); Method method = clazz.getMethod("go", String.class); System.out.println(method.invoke(obj, "text")); } } }
- 连接
- 验证:保证.class文件符合jvm要求
- 准备:为静态变量设置默认值(静态变量存储在方法区,实例变量随对象一起被分配到堆区;若静态变量被final修饰,则直接显示赋值)
- 解析:将符号引用(仅仅是个临时的常量符号来表示引用)转为直接引用(即指针,如指向Class对象、类变量、类方法的指针)
标签:name,day2,public,Jvm,加载,data,class,String From: https://www.cnblogs.com/dork-h/p/16729440.html