范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

一JVM类加载机制

  类加载运行全过程
  当我们用java命令运行某个类的main函数启动程序时,首先需要通过类加载器把主类加载到JVM。public class Math {     public static final int initData = 666;     public static User user = new User();      public int compute() {  //一个方法对应一块栈帧内存区域         int a = 1;         int b = 2;         int c = (a + b) * 10;         return c;     }      public static void main(String[] args) {         Math math = new Math();         math.compute();     } }
  通过Java命令执行代码的大体流程如下:
  其中loadClass的类加载过程有如下几步:
  加载 >> 验证 >> 准备 >> 解析 >> 初始化 >> 使用 >> 卸载
  加载:在硬盘上查找并通过IO读入字节码文件,使用到类时才会加载,例如调用类的main()方法,new对象等等,在加载阶段会在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口
  验证:校验字节码文件的正确性
  准备:给类的静态变量分配内存,并赋予默认值
  解析:将符号引用替换为直接引用,该阶段会把一些静态方法(符号引用,比如main()方法)替换为指向数据所存内存的指针或句柄等(直接引用),这是所谓的静态链接过程(类加载期间完成),动态链接是在程序运行期间完成的将符号引用替换为直接引用,下节课会讲到动态链接
  初始化:对类的静态变量初始化为指定的值,执行静态代码块
  类被加载到方法区中后主要包含 运行时常量池、类型信息、字段信息、方法信息、类加载器的引用、对应class实例的引用等信息。
  类加载器的引用:这个类到类加载器实例的引用
  对应class实例的引用:类加载器在加载类信息放到方法区中后,会创建一个对应的Class 类型的对象实例放到堆(Heap)中, 作为开发人员访问方法区中类定义的入口和切入点。
  注意: 主类在运行过程中如果使用到其它类,会逐步加载这些类。jar包或war包里的类不是一次性全部加载的,是使用到时才加载。public class TestDynamicLoad {      static {         System.out.println("*************load TestDynamicLoad************");     }      public static void main(String[] args) {         new A();         System.out.println("*************load test************");         B b = null;  //B不会加载,除非这里执行 new B()     } }  class A {     static {         System.out.println("*************load A************");     }      public A() {         System.out.println("*************initial A************");     } }  class B {     static {         System.out.println("*************load B************");     }      public B() {         System.out.println("*************initial B************");     } }  运行结果: *************load TestDynamicLoad************ *************load A************ *************initial A************ *************load test************类加载器和双亲委派机制
  上面的类加载过程主要是通过类加载器来实现的,Java里有如下几种类加载器
  引导类加载器:负责加载支撑JVM运行的位于JRE的lib目录下的核心类库,比如rt.jar、charsets.jar等
  扩展类加载器:负责加载支撑JVM运行的位于JRE的lib目录下的ext扩展目录中的JAR类包
  应用程序类加载器:负责加载ClassPath路径下的类包,主要就是加载你自己写的那些类
  自定义加载器:负责加载用户自定义路径下的类包
  看一个类加载器示例:public class TestJDKClassLoader {      public static void main(String[] args) {         System.out.println(String.class.getClassLoader());         System.out.println(com.sun.crypto.provider.DESKeyFactory.class.getClassLoader().getClass().getName());         System.out.println(TestJDKClassLoader.class.getClassLoader().getClass().getName());          System.out.println();         ClassLoader appClassLoader = ClassLoader.getSystemClassLoader();         ClassLoader extClassloader = appClassLoader.getParent();         ClassLoader bootstrapLoader = extClassloader.getParent();         System.out.println("the bootstrapLoader : " + bootstrapLoader);         System.out.println("the extClassloader : " + extClassloader);         System.out.println("the appClassLoader : " + appClassLoader);          System.out.println();         System.out.println("bootstrapLoader加载以下文件:");         URL[] urls = Launcher.getBootstrapClassPath().getURLs();         for (int i = 0; i < urls.length; i++) {             System.out.println(urls[i]);         }          System.out.println();         System.out.println("extClassloader加载以下文件:");         System.out.println(System.getProperty("java.ext.dirs"));          System.out.println();         System.out.println("appClassLoader加载以下文件:");         System.out.println(System.getProperty("java.class.path"));      } }  运行结果: null sun.misc.Launcher$ExtClassLoader sun.misc.Launcher$AppClassLoader  the bootstrapLoader : null the extClassloader : sun.misc.Launcher$ExtClassLoader@3764951d the appClassLoader : sun.misc.Launcher$AppClassLoader@14dad5dc  bootstrapLoader加载以下文件: file:/D:/dev/Java/jdk1.8.0_45/jre/lib/resources.jar file:/D:/dev/Java/jdk1.8.0_45/jre/lib/rt.jar file:/D:/dev/Java/jdk1.8.0_45/jre/lib/sunrsasign.jar file:/D:/dev/Java/jdk1.8.0_45/jre/lib/jsse.jar file:/D:/dev/Java/jdk1.8.0_45/jre/lib/jce.jar file:/D:/dev/Java/jdk1.8.0_45/jre/lib/charsets.jar file:/D:/dev/Java/jdk1.8.0_45/jre/lib/jfr.jar file:/D:/dev/Java/jdk1.8.0_45/jre/classes  extClassloader加载以下文件: D:devJavajdk1.8.0_45jrelibext;C:WindowsSunJavalibext  appClassLoader加载以下文件: D:devJavajdk1.8.0_45jrelibcharsets.jar;D:devJavajdk1.8.0_45jrelibdeploy.jar;D:devJavajdk1.8.0_45jrelibextaccess-bridge-64.jar;D:devJavajdk1.8.0_45jrelibextcldrdata.jar;D:devJavajdk1.8.0_45jrelibextdnsns.jar;D:devJavajdk1.8.0_45jrelibextjaccess.jar;D:devJavajdk1.8.0_45jrelibextjfxrt.jar;D:devJavajdk1.8.0_45jrelibextlocaledata.jar;D:devJavajdk1.8.0_45jrelibext ashorn.jar;D:devJavajdk1.8.0_45jrelibextsunec.jar;D:devJavajdk1.8.0_45jrelibextsunjce_provider.jar;D:devJavajdk1.8.0_45jrelibextsunmscapi.jar;D:devJavajdk1.8.0_45jrelibextsunpkcs11.jar;D:devJavajdk1.8.0_45jrelibextzipfs.jar;D:devJavajdk1.8.0_45jrelibjavaws.jar;D:devJavajdk1.8.0_45jrelibjce.jar;D:devJavajdk1.8.0_45jrelibjfr.jar;D:devJavajdk1.8.0_45jrelibjfxswt.jar;D:devJavajdk1.8.0_45jrelibjsse.jar;D:devJavajdk1.8.0_45jrelibmanagement-agent.jar;D:devJavajdk1.8.0_45jrelibplugin.jar;D:devJavajdk1.8.0_45jrelibresources.jar;D:devJavajdk1.8.0_45jrelibrt.jar;D:ideaProjectsproject-all	argetclasses;C:Userszhuge.m2repositoryorgapachezookeeperzookeeper3.4.12zookeeper-3.4.12.jar;C:Userszhuge.m2repositoryorgslf4jslf4j-api1.7.25slf4j-api-1.7.25.jar;C:Userszhuge.m2repositoryorgslf4jslf4j-log4j121.7.25slf4j-log4j12-1.7.25.jar;C:Userszhuge.m2repositorylog4jlog4j1.2.17log4j-1.2.17.jar;C:Userszhuge.m2repositoryjlinejline.9.94jline-0.9.94.jar;C:Userszhuge.m2repositoryorgapacheyetusaudience-annotations.5.0audience-annotations-0.5.0.jar;C:Userszhuge.m2repositoryio etty etty3.10.6.Final etty-3.10.6.Final.jar;C:Userszhuge.m2repositorycomgoogleguavaguava22.0guava-22.0.jar;C:Userszhuge.m2repositorycomgooglecodefindbugsjsr3051.3.9jsr305-1.3.9.jar;C:Userszhuge.m2repositorycomgoogleerrorproneerror_prone_annotations2.0.18error_prone_annotations-2.0.18.jar;C:Userszhuge.m2repositorycomgooglej2objcj2objc-annotations1.1j2objc-annotations-1.1.jar;C:Userszhuge.m2repositoryorgcodehausmojoanimal-sniffer-annotations1.14animal-sniffer-annotations-1.14.jar;D:devIntelliJ IDEA 2018.3.2libidea_rt.jar
  类加载器初始化过程:
  参见类运行加载全过程图可知其中会创建JVM启动器实例sun.misc.Launcher。sun.misc.Launcher初始化使用了单例模式设计,保证一个JVM虚拟机内只有一个sun.misc.Launcher实例。
  在Launcher构造方法内部,其创建了两个类加载器,分别是sun.misc.Launcher.ExtClassLoader(扩展类加载器)和sun.misc.Launcher.AppClassLoader(应用类加载器)。
  JVM默认使用Launcher的getClassLoader()方法返回的类加载器 AppClassLoader的实例加载我们的应用程序。//Launcher的构造方法 public Launcher() {     Launcher.ExtClassLoader var1;     try {         //构造扩展类加载器,在构造的过程中将其父加载器设置为null         var1 = Launcher.ExtClassLoader.getExtClassLoader();     } catch (IOException var10) {         throw new InternalError("Could not create extension class loader", var10);     }      try {         //构造应用类加载器,在构造的过程中将其父加载器设置为ExtClassLoader,         //Launcher的loader属性值是AppClassLoader,我们一般都是用这个类加载器来加载我们自己写的应用程序         this.loader = Launcher.AppClassLoader.getAppClassLoader(var1);     } catch (IOException var9) {         throw new InternalError("Could not create application class loader", var9);     }      Thread.currentThread().setContextClassLoader(this.loader);     String var2 = System.getProperty("java.security.manager");     … … //省略一些不需关注代码  }双亲委派机制
  JVM类加载器是有亲子层级结构的,如下图
  这里类加载其实就有一个双亲委派机制,加载某个类时会先委托父加载器寻找目标类,找不到再委托上层父加载器加载,如果所有父加载器在自己的加载类路径下都找不到目标类,则在自己的类加载路径中查找并载入目标类。
  比如我们的Math类,最先会找应用程序类加载器加载,应用程序类加载器会先委托扩展类加载器加载,扩展类加载器再委托引导类加载器,顶层引导类加载器在自己的类加载路径里找了半天没找到Math类,则向下退回加载Math类的请求,扩展类加载器收到回复就自己加载,在自己的类加载路径里找了半天也没找到Math类,又向下退回Math类的加载请求给应用程序类加载器, 应用程序类加载器于是在自己的类加载路径里找Math类,结果找到了就自己加载了…
  双亲委派机制说简单点就是,先找父亲加载,不行再由儿子自己加载
  我们来看下应用程序类加载器AppClassLoader加载类的双亲委派机制源码,AppClassLoader 的loadClass方法最终会调用其父类ClassLoader的loadClass方法,该方法的大体逻辑如下:
  1. 首先,检查一下指定名称的类是否已经加载过,如果加载过了,就不需要再加载,直接返回。
  2. 如果此类没有加载过,那么,再判断一下是否有父加载器;如果有父加载器,则由父加载器加载(即调用parent.loadClass(name, false);).或者是调用bootstrap类加载器来加载。
  3.如果父加载器及bootstrap类加载器都没有找到指定的类,那么调用当前类加载器的findClass方法来完成类加载。//ClassLoader的loadClass方法,里面实现了双亲委派机制 protected Class<?> loadClass(String name, boolean resolve)     throws ClassNotFoundException {     synchronized (getClassLoadingLock(name)) {         // 检查当前类加载器是否已经加载了该类         Class<?> c = findLoadedClass(name);         if (c == null) {             long t0 = System.nanoTime();             try {                 if (parent != null) {  //如果当前加载器父加载器不为空则委托父加载器加载该类                     c = parent.loadClass(name, false);                 } else {  //如果当前加载器父加载器为空则委托引导类加载器加载该类                     c = findBootstrapClassOrNull(name);                 }             } catch (ClassNotFoundException e) {                 // ClassNotFoundException thrown if class not found                 // from the non-null parent class loader             }              if (c == null) {                 // If still not found, then invoke findClass in order                 // to find the class.                 long t1 = System.nanoTime();                 //都会调用URLClassLoader的findClass方法在加载器的类路径里查找并加载该类                 c = findClass(name);                  // this is the defining class loader; record the stats                 sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);                 sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);                 sun.misc.PerfCounter.getFindClasses().increment();             }         }         if (resolve) {  //不会执行             resolveClass(c);         }         return c;     } }为什么要设计双亲委派机制?
  沙箱安全机制:自己写的java.lang.String.class类不会被加载,这样便可以防止核心API库被随意篡改
  避免类的重复加载:当父亲已经加载了该类时,就没有必要子ClassLoader再加载一次,保证被加载类的唯一性
  看一个类加载示例:package java.lang;  public class String {     public static void main(String[] args) {         System.out.println("**************My String Class**************");     } }  运行结果: 错误: 在类 java.lang.String 中找不到 main 方法, 请将 main 方法定义为:    public static void main(String[] args) 否则 JavaFX 应用程序类必须扩展javafx.application.Application全盘负责委托机制
  " 全盘负责 "是指当一个ClassLoder装载一个类时,除非显示的使用另外一个ClassLoder,该类 所依赖及引用的类也由这个ClassLoder载入。 自定义类加载器示例:
  自定义类加载器只需要继承 java.lang.ClassLoader 类,该类有两个核心方法,一个是loadClass(String, boolean),实现了双亲委派机制,还有一个方法是findClass,默认实现是空方法,所以我们自定义类加载器主要是重写findClass方法。public class MyClassLoaderTest {     static class MyClassLoader extends ClassLoader {         private String classPath;          public MyClassLoader(String classPath) {             this.classPath = classPath;         }          private byte[] loadByte(String name) throws Exception {             name = name.replaceAll(".", "/");             FileInputStream fis = new FileInputStream(classPath + "/" + name                     + ".class");             int len = fis.available();             byte[] data = new byte[len];             fis.read(data);             fis.close();             return data;         }          protected Class<?> findClass(String name) throws ClassNotFoundException {             try {                 byte[] data = loadByte(name);                 //defineClass将一个字节数组转为Class对象,这个字节数组是class文件读取后最终的字节数组。                 return defineClass(name, data, 0, data.length);             } catch (Exception e) {                 e.printStackTrace();                 throw new ClassNotFoundException();             }         }      }      public static void main(String args[]) throws Exception {         //初始化自定义类加载器,会先初始化父类ClassLoader,其中会把自定义类加载器的父加载器设置为应用程序类加载器AppClassLoader         MyClassLoader classLoader = new MyClassLoader("D:/test");         //D盘创建 test/com/tuling/jvm 几级目录,将User类的复制类User1.class丢入该目录         Class clazz = classLoader.loadClass("com.tuling.jvm.User1");         Object obj = clazz.newInstance();         Method method = clazz.getDeclaredMethod("sout", null);         method.invoke(obj, null);         System.out.println(clazz.getClassLoader().getClass().getName());     } }  运行结果: =======自己的加载器加载类调用方法======= com.tuling.jvm.MyClassLoaderTest$MyClassLoader打破双亲委派机制
  再来一个沙箱安全机制示例,尝试打破双亲委派机制,用自定义类加载器加载我们自己实现的java.lang.String.classpublic class MyClassLoaderTest {     static class MyClassLoader extends ClassLoader {         private String classPath;          public MyClassLoader(String classPath) {             this.classPath = classPath;         }          private byte[] loadByte(String name) throws Exception {             name = name.replaceAll(".", "/");             FileInputStream fis = new FileInputStream(classPath + "/" + name                     + ".class");             int len = fis.available();             byte[] data = new byte[len];             fis.read(data);             fis.close();             return data;          }          protected Class<?> findClass(String name) throws ClassNotFoundException {             try {                 byte[] data = loadByte(name);                 return defineClass(name, data, 0, data.length);             } catch (Exception e) {                 e.printStackTrace();                 throw new ClassNotFoundException();             }         }          /**          * 重写类加载方法,实现自己的加载逻辑,不委派给双亲加载          * @param name          * @param resolve          * @return          * @throws ClassNotFoundException          */         protected Class<?> loadClass(String name, boolean resolve)                 throws ClassNotFoundException {             synchronized (getClassLoadingLock(name)) {                 // First, check if the class has already been loaded                 Class<?> c = findLoadedClass(name);                  if (c == null) {                     // If still not found, then invoke findClass in order                     // to find the class.                     long t1 = System.nanoTime();                     c = findClass(name);                      // this is the defining class loader; record the stats                     sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);                     sun.misc.PerfCounter.getFindClasses().increment();                 }                 if (resolve) {                     resolveClass(c);                 }                 return c;             }         }     }      public static void main(String args[]) throws Exception {         MyClassLoader classLoader = new MyClassLoader("D:/test");         //尝试用自己改写类加载机制去加载自己写的java.lang.String.class         Class clazz = classLoader.loadClass("java.lang.String");         Object obj = clazz.newInstance();         Method method= clazz.getDeclaredMethod("sout", null);         method.invoke(obj, null);         System.out.println(clazz.getClassLoader().getClass().getName());     } }  运行结果: java.lang.SecurityException: Prohibited package name: java.lang 	at java.lang.ClassLoader.preDefineClass(ClassLoader.java:659) 	at java.lang.ClassLoader.defineClass(ClassLoader.java:758)Tomcat打破双亲委派机制
  以Tomcat类加载为例,Tomcat 如果使用默认的双亲委派类加载机制行不行? 我们思考一下:Tomcat是个web容器, 那么它要解决什么问题:
  1. 一个web容器可能需要部署两个应用程序,不同的应用程序可能会依赖同一个第三方类库的不同版本,不能要求同一个类库在同一个服务器只有一份,因此要保证每个应用程序的类库都是独立的,保证相互隔离。
  2. 部署在同一个web容器中相同的类库相同的版本可以共享。否则,如果服务器有10个应用程序,那么要有10份相同的类库加载进虚拟机。
  3. web容器也有自己依赖的类库,不能与应用程序的类库混淆。基于安全考虑,应该让容器的类库和程序的类库隔离开来。
  4. web容器要支持jsp的修改,我们知道,jsp 文件最终也是要编译成class文件才能在虚拟机中运行,但程序运行后修改jsp已经是司空见惯的事情, web容器需要支持 jsp 修改后不用重启。
  再看看我们的问题:Tomcat 如果使用默认的双亲委派类加载机制行不行?
  答案是不行的。为什么?
  第一个问题,如果使用默认的类加载器机制,那么是无法加载两个相同类库的不同版本的,默认的类加器是不管你是什么版本的,只在乎你的全限定类名,并且只有一份。
  第二个问题,默认的类加载器是能够实现的,因为他的职责就是保证唯一性。第三个问题和第一个问题一样。
  我们再看第四个问题,我们想我们要怎么实现jsp文件的热加载,jsp 文件其实也就是class文件,那么如果修改了,但类名还是一样,类加载器会直接取方法区中已经存在的,修改后的jsp 是不会重新加载的。那么怎么办呢?我们可以直接卸载掉这jsp文件的类加载器,所以你应该想
  到了,每个jsp文件对应一个唯一的类加载器,当一个jsp文件修改了,就直接卸载这个jsp类加载器。重新创建类加载器,重新加载jsp文件。
  Tomcat自定义加载器详解
  tomcat的几个主要类加载器:
  commonLoader:Tomcat最基本的类加载器,加载路径中的class可以被Tomcat容器本身以及各个Webapp访问;
  catalinaLoader:Tomcat容器私有的类加载器,加载路径中的class对于Webapp不可见;
  sharedLoader:各个Webapp共享的类加载器,加载路径中的class对于所有Webapp可见,但是对于Tomcat容器不可见;
  WebappClassLoader:各个Webapp私有的类加载器,加载路径中的class只对当前Webapp可见,比如加载war包里相关的类,每个war包应用都有自己的
  WebappClassLoader,实现相互隔离,比如不同war包应用引入了不同的spring版本, 这样实现就能加载各自的spring版本;
  从图中的委派关系中可以看出:
  CommonClassLoader能加载的类都可以被CatalinaClassLoader和SharedClassLoader使用, 从而实现了公有类库的共用,而CatalinaClassLoader和SharedClassLoader自己能加载的类则与对方相互隔离。
  WebAppClassLoader可以使用SharedClassLoader加载到的类,但各个WebAppClassLoader 实例之间相互隔离。
  而JasperLoader的加载范围仅仅是这个JSP文件所编译出来的那一个.Class文件,它出现的目的就是为了被丢弃:当Web容器检测到JSP文件被修改时,会替换掉目前的JasperLoader的实例, 并通过再建立一个新的Jsp类加载器来实现JSP文件的热加载功能。
  tomcat 这种类加载机制违背了java 推荐的双亲委派模型了吗?
  答案是:违背了。
  很显然,tomcat 不是这样实现,tomcat 为了实现隔离性,没有遵守这个约定,每个webappClassLoader加载自己的目录下的class文件,不会传递给父类加载器,打破了双亲委派机制。模拟实现Tomcat的webappClassLoader加载自己war包应用内不同版本类实现相互共存与隔离public class MyClassLoaderTest {     static class MyClassLoader extends ClassLoader {         private String classPath;          public MyClassLoader(String classPath) {             this.classPath = classPath;         }          private byte[] loadByte(String name) throws Exception {             name = name.replaceAll(".", "/");             FileInputStream fis = new FileInputStream(classPath + "/" + name + ".class");             int len = fis.available();             byte[] data = new byte[len];             fis.read(data);             fis.close();             return data;         }          protected Class<?> findClass(String name) throws ClassNotFoundException {             try {                 byte[] data = loadByte(name);                 return defineClass(name, data, 0, data.length);             } catch (Exception e) {                 e.printStackTrace();                 throw new ClassNotFoundException();             }         }          /**          * 重写类加载方法,实现自己的加载逻辑,不委派给双亲加载          * @param name          * @param resolve          * @return          * @throws ClassNotFoundException          */         protected Class<?> loadClass(String name, boolean resolve)                 throws ClassNotFoundException {             synchronized (getClassLoadingLock(name)) {                 // First, check if the class has already been loaded                 Class<?> c = findLoadedClass(name);                  if (c == null) {                     // If still not found, then invoke findClass in order                     // to find the class.                     long t1 = System.nanoTime();                     //非自定义的类还是走双亲委派加载                     if (!name.startsWith("com.tuling.jvm")){                         c = this.getParent().loadClass(name);                     }else{                         c = findClass(name);                     }                      // this is the defining class loader; record the stats                     sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);                     sun.misc.PerfCounter.getFindClasses().increment();                 }                 if (resolve) {                     resolveClass(c);                 }                 return c;             }         }     }      public static void main(String args[]) throws Exception {         MyClassLoader classLoader = new MyClassLoader("D:/test");         Class clazz = classLoader.loadClass("com.tuling.jvm.User1");         Object obj = clazz.newInstance();         Method method= clazz.getDeclaredMethod("sout", null);         method.invoke(obj, null);         System.out.println(clazz.getClassLoader());                  System.out.println();         MyClassLoader classLoader1 = new MyClassLoader("D:/test1");         Class clazz1 = classLoader1.loadClass("com.tuling.jvm.User1");         Object obj1 = clazz1.newInstance();         Method method1= clazz1.getDeclaredMethod("sout", null);         method1.invoke(obj1, null);         System.out.println(clazz1.getClassLoader());     } }  运行结果: =======自己的加载器加载类调用方法======= com.tuling.jvm.MyClassLoaderTest$MyClassLoader@266474c2  =======另外一个User1版本:自己的加载器加载类调用方法======= com.tuling.jvm.MyClassLoaderTest$MyClassLoader@66d3c617
  注意: 同一个JVM内,两个相同包名和类名的类对象可以共存,因为他们的类加载器可以不一样,所以看两个类对象是否是同一个,除了看类的包名和类名是否都相同之外,还需要他们的类加载器也是同一个才能认为他们是同一个。
  附下User类的代码:public class User {      private int id;     private String name;          public User() {     }      public User(int id, String name) {         super();         this.id = id;         this.name = name;     }      public int getId() {         return id;     }      public void setId(int id) {         this.id = id;     }      public String getName() {         return name;     }      public void setName(String name) {         this.name = name;     }      public void sout() {         System.out.println("=======自己的加载器加载类调用方法=======");     } }
  补充:Hotspot源码JVM启动执行main方法流程

电动车所谓的终身质保其实就是个营销噱头,争议到底在哪里电动车所谓的终身质保其实就是个噱头,对于消费者来讲没什么用。今天我们就以比亚迪新能源的终身质保为例,给大家做一个深度的解析。首先比亚迪为他的车型提供了六年15万公里的整车质保,先到修间茶室,不附风雅,只为己欢修间茶室,不附风雅,只为己欢。邀两三知己,畅所欲言。或一人独抿,静心参禅。没了茶馆的喧闹嘈杂,少了伺奉的人情负担。一件薄板即成茶案,几把木椅围于跟前。竹木茶盘摆中间,喜欢的茶具,适中国从不是一个国家,而是伪装成国家的文明,为何西方教授这么说中国不是一个国家,而是伪装成一个国家的文明,西方学者亨廷顿在文明的冲突一书中这样写道,他为什么会得出这样的结论呢?细数一下世界历史,身为中国人的我自豪感油然而生,在历史的长河之中,债主申请清盘!恒大,只剩最后2个月?恒大来到了最关键的时刻。1hr突如其来的清盘申请风雨飘摇的恒大,再次引起了大家的关注。就在昨天(6月27日),香港高等法院网站更新法庭日志显示,一家位于太平洋萨摩亚岛的公司提出对中童星被13名同学欺凌选择跳楼解脱,霸凌者真幸运,居然没毁容那些经历过校园霸凌的人,始终生活在痛苦和恐惧之中。有时,他们被折磨得陷入绝望,甚至会做出极端的选择。6月20日,童星邵一卜的妈妈发文,表示女儿经历了校园霸凌,只想通过跳楼来获得解脱缺什么维生素会长白发?导致白发的原因有哪些?医生告诉您答案最近,50岁出头的张先生犯了愁,他总感觉自己还年轻,却长了满头白发,就连眉毛,也有逐渐变白的趋势。跟张先生同龄的很多朋友,头发都是乌黑茂密,只有自己满头白发,看起来好像比他们大个十仗北约身份硬刚中俄的立陶宛,今天带你看看真实的立陶宛现状立陶宛国土面积65300平方公里,和我国宁夏回族自治区大小相当。总人口数量约279。5万,与宁夏回族自治区首府银川市差不多。维尔纽斯是立陶宛首都和最大城市,也是该国政治经济文化交通明星娱乐张娜拉娱乐聚焦丰功伟绩疯丫头7667202206282149娱乐聚焦聚聚焦娱乐张娜拉韩国首尔人她是因为一首歌进入演艺圈她演了明郎少女成功记红豆女之恋淘气少女求爱记叼蛮公主叼蛮俏御医201斗破苍穹迦南学院比中州的一流势力还要强?迦南学院虽然身处于黑角域,但是如果你知道他的底蕴和雄厚的实力后就会发现其实他要强于一些中州的一流势力,下面我们来细细数下迦南学院到底有多少底蕴。首先,迦南学院分为内院和外院,而外院OPPO智行OPPOcar车联是真有其事还是PPT画饼?OPPO智行OPPOcar车联是真有其事还是PPT画饼?先说结论在车机互联上,OPPO何时能用还遥遥无期,无视存量车主,而VIVO一年前早已用上,友好存量车主。论点1OPPOcar河南95岁老人逝世,送行路上警车开道行人驻立默哀,他到底干了啥2021年6月17日,雨下得很大,河南省信阳市里充满了悲伤,一排排静立在路旁的行人,正在抒发着他们的哀思,警车一路护送,而这一切只是为了送一位95岁的老人最后一程。那这位老人到底是
iPhone15消息泄露!灵动岛成全系标配,售价又得翻一番?iphone14系列手机上市以来,就一直被各种嫌弃,其口碑也不如以往那么好。甚至是坑苦了一众黄牛,被戏称为黄牛克星。但是,即便如此iphone14系列手机的销量依然是高歌猛进。毕竟同样是赵本山的女儿,赵玉芳和球球却活成了完全相反的样子前言赵本山有过两段婚姻,生下了4个子女。没成名以前和葛淑珍结婚,生下了大女儿赵玉芳和多病早逝的儿子赵铁蛋,12岁就夭折了。成名后和葛淑珍离婚,女儿跟着前妻他净身出户。一年之后他又娶中军摩派到中天摩派,骗局还是那个骗局,换了个名字前不久,防骗小视野转发报道过一篇名为换部手机就能躺赚?中军通信的启屏广告手机推广模式遭质疑!的文章。文章曝光后收到了来自全国各地粉丝的点赞和转发,聚集了大量的关注。原本曝光的目的就为生男孩,她喂孕妇吃转胎丸,孩子却惨成畸形双性人农村的一处小院子里,一个小腹微微隆起的女人正看着眼前盛着不明液体的碗有些为难。孕妇看了看丈夫,他对母亲的决定似乎非常支持,并没有拦着的意思。妈,我听人说这东西对孩子不一定好,万一造珠海航展今日开幕!大男孩的圆梦之地第十四届中国国际航空航天博览会将于2022年11月8日至13日在广东珠海国际航展中心举行,集中展示我国航空航天和国防科技领域的尖端技术及创新突破。精彩内容一睹为快展览亮点陆空一体演乡村振兴看安徽丨安徽霍山筑巢引得凤凰栖,南庄老茶发新芽央广网霍山5月16日消息(记者徐鹏通讯员陈波)春生夏长,万物繁茂。时过立夏,霍山县漫水河镇南庄村一处高山茶园里,喝饱了初夏雨水的茶叶翠绿茁壮。黄大茶是立夏前后黄芽采摘结束,茶叶长到北京加强快递外卖农贸市场等重点行业重点人群核酸筛查北京市卫健委提醒要坚持动态清零总方针不动摇,坚定必胜信心,压实四方责任,认真落实各项防控措施,做好风险人员排查,加强员工管理,建立人员台账,掌握员工动态,严格落实测温验码健康监测核2020年,福建女子丧夫后用胚胎做试管婴儿被拒,医院须丈夫同意前言常言道不孝有三,无后为大,娶妻生子,延续香火,是我们中国人的传统认知。特别是作为一个女人来说,更是渴望做妈妈的,但是世事无常,现实生活中有很多夫妻却被不孕不育所困扰。不过随着医张亮14岁儿子被曝早恋,和漂亮女友亲吻互动,张亮发长文回应2013年,一档亲子真人秀爸爸去哪儿热播,而节目中,张亮厨艺精湛情商高,儿子天天可爱懂事,父子俩以抢眼的表现,受到了无数观众的喜欢。当年张亮儿子天天(张悦轩)才6岁,一转眼如今已经美丽风景线是做梦!佩洛西再发涉港错误言论,赵立坚犀利回应近日,美国众议院议长佩洛西在华盛顿邮报发表涉港错误言论,无理攻击中国的涉港政策,大言不惭地抹黑中国有关香港高度自治的承诺,对此中方也给出了犀利回应。5月16日,中国外交部发言人赵立酸汤鱼片比酸菜鱼好吃多了,酸甜开胃,鲜香可口,连汤汁都好喝酸汤鱼片比酸菜鱼好吃多了,酸甜开胃,鲜香可口,连汤汁都好喝!酸汤鱼片,鱼肉鲜嫩,汤汁酸甜鲜香,比酸菜鱼好吃多了,很适合广东人。作为广东人,我不太喜欢吃辣椒,但是喜欢吃酸,酸菜鱼就是