ClassLoader那事儿

ClassLoader是什么

ClassLoader中文类加载器,java编写出来的是.java文件,然后编译成.class文件,而ClassLoader就是把class文件加载到jvm内存中;但jvm启动时,通过不同的类加载器,动态的加载class文件;java比较重要的三类加载器Bootstrap ClassLoader、 Extention ClassLoader、Appclass Loader。

Java中的类加载器

Bootstrap ClassLoader、 Extention ClassLoader、Appclass Loader这三个类加载器分别负责加载不同路径下的文件

Bootstrap CLassloder 

它是最顶级的类加载,主要加载载核心类库,其路径为%JRE_HOME%\lib下的rt.jar、resources.jar、charsets.jar和class等,而这个路径是可以通过jvm启动参数-Xbootclasspath来设置

Extention ClassLoader 

扩展的类加载器,加载目录%JRE_HOME%\lib\ext目录下的jar包和class文件。

AppClassLoader

当前应用的classpath的所有类

 

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package sun.misc;

import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLStreamHandler;
import java.net.URLStreamHandlerFactory;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.CodeSource;
import java.security.PermissionCollection;
import java.security.PrivilegedAction;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.security.ProtectionDomain;
import java.security.cert.Certificate;
import java.util.HashSet;
import java.util.StringTokenizer;
import java.util.Vector;
import sun.net.www.ParseUtil;

public class Launcher {
    private static URLStreamHandlerFactory factory = new Launcher.Factory();
    private static Launcher launcher = new Launcher();
  
private static String bootClassPath = System.getProperty("sun.boot.class.path");

  private ClassLoader loader; private static URLStreamHandler fileHandler; public static Launcher getLauncher() { return launcher; } public Launcher() { Launcher.ExtClassLoader var1; try { var1 = Launcher.ExtClassLoader.getExtClassLoader(); } catch (IOException var10) { throw new InternalError("Could not create extension class loader"); } try { this.loader = Launcher.AppClassLoader.getAppClassLoader(var1); } catch (IOException var9) { throw new InternalError("Could not create application class loader"); } Thread.currentThread().setContextClassLoader(this.loader); String var2 = System.getProperty("java.security.manager"); if (var2 != null) { SecurityManager var3 = null; if (!"".equals(var2) && !"default".equals(var2)) { try { var3 = (SecurityManager)this.loader.loadClass(var2).newInstance(); } catch (IllegalAccessException var5) { ; } catch (InstantiationException var6) { ; } catch (ClassNotFoundException var7) { ; } catch (ClassCastException var8) { ; } } else { var3 = new SecurityManager(); } if (var3 == null) { throw new InternalError("Could not create SecurityManager: " + var2); } System.setSecurityManager(var3); } } public ClassLoader getClassLoader() { return this.loader; } public static URLClassPath getBootstrapClassPath() { return Launcher.BootClassPathHolder.bcp; }
  ………………………………
}

 

从以上源码可以看到

1. 没有看到 Bootstrap ClassLoader,只有bootClassPath,这个应该就是顶级类加载器的加载路径;

2.Launcher 先初始化了Extention ClassLoader ,然后把传入它实例再初始化AppClassLoader。

static class ExtClassLoader extends URLClassLoader {
        public static Launcher.ExtClassLoader getExtClassLoader() throws IOException {
        
       //获取加载的文件,进入getExtDirs可以看到加载的文件路径
String var0 = System.getProperty("java.ext.dirs")
final File[] var0 = getExtDirs();

            try {
                return (Launcher.ExtClassLoader)AccessController.doPrivileged(new PrivilegedExceptionAction<Launcher.ExtClassLoader>() {
                    public Launcher.ExtClassLoader run() throws IOException {
                        int var1 = var0.length;

                        for(int var2 = 0; var2 < var1; ++var2) {
                            MetaIndex.registerDirectory(var0[var2]);
                        }
              //创建类加载
                        return new Launcher.ExtClassLoader(var0);
                    }
                });
            } catch (PrivilegedActionException var2) {
                throw (IOException)var2.getException();
            }
        }

        void addExtURL(URL var1) {
            super.addURL(var1);
        }
      
        public ExtClassLoader(File[] var1) throws IOException {
       
        //调用父类方法创建,留意到第二个参数为null,这个参数是父加载器,预测ExtClassLoader是没有父加载器的
        super(getExtURLs(var1), (ClassLoader)null, Launcher.factory);
        }

        private static File[] getExtDirs() {
            String var0 = System.getProperty("java.ext.dirs");
            File[] var1;
            if (var0 != null) {
                StringTokenizer var2 = new StringTokenizer(var0, File.pathSeparator);
                int var3 = var2.countTokens();
                var1 = new File[var3];

                for(int var4 = 0; var4 < var3; ++var4) {
                    var1[var4] = new File(var2.nextToken());
                }
            } else {
                var1 = new File[0];
            }

            return var1;
        }

        private static URL[] getExtURLs(File[] var0) throws IOException {
            Vector var1 = new Vector();

            for(int var2 = 0; var2 < var0.length; ++var2) {
                String[] var3 = var0[var2].list();
                if (var3 != null) {
                    for(int var4 = 0; var4 < var3.length; ++var4) {
                        if (!var3[var4].equals("meta-index")) {
                            File var5 = new File(var0[var2], var3[var4]);
                            var1.add(Launcher.getFileURL(var5));
                        }
                    }
                }
            }

            URL[] var6 = new URL[var1.size()];
            var1.copyInto(var6);
            return var6;
        }

        public String findLibrary(String var1) {
            var1 = System.mapLibraryName(var1);
            URL[] var2 = super.getURLs();
            File var3 = null;

            for(int var4 = 0; var4 < var2.length; ++var4) {
                File var5 = (new File(var2[var4].getPath())).getParentFile();
                if (var5 != null && !var5.equals(var3)) {
                    String var6 = VM.getSavedProperty("os.arch");
                    File var7;
                    if (var6 != null) {
                        var7 = new File(new File(var5, var6), var1);
                        if (var7.exists()) {
                            return var7.getAbsolutePath();
                        }
                    }

                    var7 = new File(var5, var1);
                    if (var7.exists()) {
                        return var7.getAbsolutePath();
                    }
                }

                var3 = var5;
            }

            return null;
        }

        private static AccessControlContext getContext(File[] var0) throws IOException {
            PathPermissions var1 = new PathPermissions(var0);
            ProtectionDomain var2 = new ProtectionDomain(new CodeSource(var1.getCodeBase(), (Certificate[])null), var1);
            AccessControlContext var3 = new AccessControlContext(new ProtectionDomain[]{var2});
            return var3;
        }

        static {
            ClassLoader.registerAsParallelCapable();
        }
    }




看看ExtenTionClassLoader初始化做了什么 

从上面可以看到ExtClassLoader extends URLClassLoader,初始化ExtClassLoader先读取java.ext.dirs路径(D:\java7\jre\lib\ext;C:\Windows\Sun\Java\lib\ext)下的文件,然后调用URLClassLoader.supper()-->

SecureClassLoader.supper()-->ClassLoader.supper()-->方法创建,因为传入的parent是null,可以看到ExtClassLoader 没有父加载器的;简单说就是加载java.ext.dirs的文件创建了个无父加载器的类加载器。

 

public static void main(String[] args) {
        System.out.println(System.getProperty("java.ext.dirs"));
    }

/*
D:\java7\jre\lib\ext;C:\Windows\Sun\Java\lib\ext
*/

/*
URLClassLoader extends SecureClassLoader implements Closeable
*/
public URLClassLoader(URL[] urls, ClassLoader parent,
URLStreamHandlerFactory factory) {
super(parent);
// this is to make the stack depth consistent with 1.1
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkCreateClassLoader();
}
ucp = new URLClassPath(urls, factory);
acc = AccessController.getContext();
}

 /******************************************************************************/


  /*

  SecureClassLoader extends ClassLoader

  */

protected SecureClassLoader(ClassLoader parent) {
super(parent);
// this is to make the stack depth consistent with 1.1
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkCreateClassLoader();
}
initialized = true;
}

  /******************************************************************************/

/*
ClassLoader类
*/
protected ClassLoader(ClassLoader parent) {
this(checkCreateClassLoader(), parent);
}
private ClassLoader(Void unused, ClassLoader parent) {
this.parent = parent;
if (ParallelLoaders.isRegistered(this.getClass())) {
parallelLockMap = new ConcurrentHashMap<>();
package2certs = new ConcurrentHashMap<>();
domains =
Collections.synchronizedSet(new HashSet<ProtectionDomain>());
assertionLock = new Object();
} else {
// no finer-grained lock; lock on the classloader instance
parallelLockMap = null;
package2certs = new Hashtable<>();
domains = new HashSet<>();
assertionLock = this;
}
}

 

看看APPClassLoader初始化做了什么

static class AppClassLoader extends URLClassLoader {
        public static ClassLoader getAppClassLoader(final ClassLoader var0) throws IOException {
            final String var1 = System.getProperty("java.class.path");
            final File[] var2 = var1 == null ? new File[0] : Launcher.getClassPath(var1);
            return (ClassLoader)AccessController.doPrivileged(new PrivilegedAction<Launcher.AppClassLoader>() {
                public Launcher.AppClassLoader run() {
                    URL[] var1x = var1 == null ? new URL[0] : Launcher.pathToURLs(var2);
                    return new Launcher.AppClassLoader(var1x, var0);
                }
            });
        }

        AppClassLoader(URL[] var1, ClassLoader var2) {
            super(var1, var2, Launcher.factory);
        }

        public Class loadClass(String var1, boolean var2) throws ClassNotFoundException {
            int var3 = var1.lastIndexOf(46);
            if (var3 != -1) {
                SecurityManager var4 = System.getSecurityManager();
                if (var4 != null) {
                    var4.checkPackageAccess(var1.substring(0, var3));
                }
            }

            return super.loadClass(var1, var2);
        }

        protected PermissionCollection getPermissions(CodeSource var1) {
            PermissionCollection var2 = super.getPermissions(var1);
            var2.add(new RuntimePermission("exitVM"));
            return var2;
        }

        private void appendToClassPathForInstrumentation(String var1) {
            assert Thread.holdsLock(this);

            super.addURL(Launcher.getFileURL(new File(var1)));
        }

        private static AccessControlContext getContext(File[] var0) throws MalformedURLException {
            PathPermissions var1 = new PathPermissions(var0);
            ProtectionDomain var2 = new ProtectionDomain(new CodeSource(var1.getCodeBase(), (Certificate[])null), var1);
            AccessControlContext var3 = new AccessControlContext(new ProtectionDomain[]{var2});
            return var3;
        }

        static {
            ClassLoader.registerAsParallelCapable();
        }
    }

 

从上面看APPClassLoader也是继承URLClassLoader,与ExtClassLoader不同的是,

1.读取的路径是java.class.path

2.把ExtClassLoader的实例作为APPClassLoader的父加载器,也就是说APPClassLoader的父类加载器是ExtClassLoader

3.加载顺序Bootstrap ClassLoader 到 ExtClassLoader 到 APPClassLoader

父加载器

首先我们先要明确一点是父加载器并不是父类,我们可以通过下面的代码看到

public class MyClassLoader extends URLClassLoader {

    public MyClassLoader(URL[] repositories) {
        super(repositories);
    }

    public MyClassLoader(URL[] repositories, ClassLoader parent) {
        super(repositories, parent);
    }

}

  public static void main(String[] args) {
        ClassLoader cl = MyClassLoader.class.getClassLoader();
        System.out.println("ClassLoader is:"+cl.toString());
        System.out.println("ClassLoader\'s parent is:"+cl.getParent().toString());
//        System.out.println("ClassLoader\'s grand father is:"+cl.getParent().getParent().toString());
    }


ClassLoader is:sun.misc.Launcher$AppClassLoader@31fc6b2
ClassLoader's parent is:sun.misc.Launcher$ExtClassLoader@1b2dd1b8

 

1.MyClassLoader 继承URLClassLoader,但是可以到店MyClassLoader的父加载器是AppClassLoader

2.AppClassLoader 的父加载器是ExtClassLoader,这个在上面分析初始化的APPClassLoader的时候,就可以看到传入ExtClassLoader的实例作为它的加载器,那么ExtClassLoader的父加载器上面初始时是null,我们可以验证一下

    public static void main(String[] args) {
        ClassLoader cl = MyClassLoader.class.getClassLoader();
//        System.out.println("ClassLoader is:"+cl.toString());
//        System.out.println("ClassLoader\'s parent is:"+cl.getParent().toString());
        System.out.println("ClassLoader\'s grand father is:"+cl.getParent().getParent().toString());
    }


Exception in thread "main" java.lang.NullPointerException
    at com.suntek.vdm.gw.util.NotifyHandler.main(NotifyHandler.java:373)

 

从上面的代码可以看到,我们的上面是对的ExtClassLoader的父加载器的确是null.

3.那么其他的没有指定父加载器的ClassLoader的父加载器是什么呢?从上面的代码我们可以看到MyClassLoader的的是APPClassLoader,那么这是为什么呢?难道没有指定父加载器的ClassLoader的默认是APP

        
    /*
这ClassLoader是没有指定父加载器创建方法
*/
    protected ClassLoader() {
        this(checkCreateClassLoader(), getSystemClassLoader());
    }

//这里我们可以看到getSytemClassLoader()这个方法获取父加载器
private ClassLoader(Void unused, ClassLoader parent) {
        this.parent = parent;
        if (ParallelLoaders.isRegistered(this.getClass())) {
            parallelLockMap = new ConcurrentHashMap<>();
            package2certs = new ConcurrentHashMap<>();
            domains =
                Collections.synchronizedSet(new HashSet<ProtectionDomain>());
            assertionLock = new Object();
        } else {
            // no finer-grained lock; lock on the classloader instance
            parallelLockMap = null;
            package2certs = new Hashtable<>();
            domains = new HashSet<>();
            assertionLock = this;
        }
    }

  //看到return的是scl,而scl赋值是initSystemClassLoader()方法
    public static ClassLoader getSystemClassLoader() {
        initSystemClassLoader();
        if (scl == null) {
            return null;
        }
        SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            checkClassLoaderPermission(scl, Reflection.getCallerClass());
        }
        return scl;
    }

  //真相就在这里了,就是Launcher的getClassLoader(),而Luancher初始化的前面有看过了,也可以往下看
    private static synchronized void initSystemClassLoader() {
        if (!sclSet) {
            if (scl != null)
                throw new IllegalStateException("recursive invocation");
            sun.misc.Launcher l = sun.misc.Launcher.getLauncher();
            if (l != null) {
                Throwable oops = null;
                scl = l.getClassLoader();
                try {
                    scl = AccessController.doPrivileged(
                        new SystemClassLoaderAction(scl));
                } catch (PrivilegedActionException pae) {
                    oops = pae.getCause();
                    if (oops instanceof InvocationTargetException) {
                        oops = oops.getCause();
                    }
                }
                if (oops != null) {
                    if (oops instanceof Error) {
                        throw (Error) oops;
                    } else {
                        // wrap the exception
                        throw new Error(oops);
                    }
                }
            }
            sclSet = true;
        }
    }


//这个是Launcher对的getClassLoader,然后在看看下面的图,明白了,就是APPClassLoader
 public ClassLoader getClassLoader() {
        return this.loader;
    }

一层层往下最终APPClassLoader作为默认的ClassLoader;

也就是没有指定的父加载器的默认为是APPClassLoader;

双亲委托

有了父加载器的概念之后,我们就可以开始双亲委托这个玩意了!这部分,发现个哥们写得不错 https://blog.csdn.net/briblue/article/details/54973413,于是就复制了!

 

一个类加载器查找class和resource时,是通过“委托模式”进行的,它首先判断这个class是不是已经加载成功,如果没有的话它并不是自己进行查找,而是先通过父加载器,然后递归下去,直到Bootstrap ClassLoader,如果Bootstrap classloader找到了,直接返回,如果没有找到,则一级一级返回,最后到达自身去查找这些对象。这种机制就叫做双亲委托。 
整个流程可以如下图所示: 

大家可以看到2根箭头,蓝色的代表类加载器向上委托的方向,如果当前的类加载器没有查询到这个class对象已经加载就请求父加载器(不一定是父类)进行操作,然后以此类推。直到Bootstrap ClassLoader。如果Bootstrap ClassLoader也没有加载过此class实例,那么它就会从它指定的路径中去查找,如果查找成功则返回,如果没有查找成功则交给子类加载器,也就是ExtClassLoader,这样类似操作直到终点,也就是我上图中的红色箭头示例。 
用序列描述一下: 
1. 一个AppClassLoader查找资源时,先看看缓存是否有,缓存有从缓存中获取,否则委托给父加载器。 
2. 递归,重复第1部的操作。 
3. 如果ExtClassLoader也没有加载过,则由Bootstrap ClassLoader出面,它首先查找缓存,如果没有找到的话,就去找自己的规定的路径下,也就是sun.mic.boot.class下面的路径。找到就返回,没有找到,让子加载器自己去找。 
4. Bootstrap ClassLoader如果没有查找成功,则ExtClassLoader自己在java.ext.dirs路径中去查找,查找成功就返回,查找不成功,再向下让子加载器找。 
5. ExtClassLoader查找不成功,AppClassLoader就自己查找,在java.class.path路径下查找。找到就返回。如果没有找到就让子类找,如果没有子类会怎么样?抛出各种异常。

上面的序列,详细说明了双亲委托的加载流程。我们可以发现委托是从下向上,然后具体查找过程却是自上至下。

 

这里要说一下ExtClassLoader 这个是没有父加载器,就通过BootStrapClassLoader这个来查找的,下面这个代码的ClassLoader这个类的方法,

    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) { long t0 = System.nanoTime(); try { if (parent != null) {
              //如果父加强是空,往上找 c
= parent.loadClass(name, false); } else {
              //否则就通过BootStrapClassLoader找,也就应该是ExtClassLoader 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(); 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; } }

 自定义类加载器

了解我们可以自己写一个简单的加载类

public class MyClassLoader extends URLClassLoader {

    public MyClassLoader(URL[] repositories) {
        super(repositories);
    }

    public MyClassLoader(URL[] repositories, ClassLoader parent) {
        super(repositories, parent);
    }

}




public final class MyClassLoaderFactory {

    public static ClassLoader createClassLoader(File unpacked[], final ClassLoader parent)
            throws Exception {

        Set<URL> set = new LinkedHashSet<URL>();

        if (unpacked != null) {
            for (int i = 0; i < unpacked.length; i++) {
                File file = unpacked[i];
                if (!file.exists() || !file.canRead()){
                    continue;
                }
                file = new File(file.getCanonicalPath() + File.separator);
                URL url = file.toURI().toURL();
                set.add(url);
            }
        }

        final URL[] array = set.toArray(new URL[set.size()]);
        return AccessController.doPrivileged(new PrivilegedAction<MyClassLoader>() {

            @Override
            public MyClassLoader run() {
                if (parent == null){
                    return new MyClassLoader(array);
                }else {
                    return new MyClassLoader(array, parent);
                }
            }
        });
    }
}





private static void startWithClassloader(String path) throws Exception { String classPath= path; File[] packed = new File[] { new File(path) }; ClassLoader catalinaLoader = MyClassLoaderFactory.createClassLoader(null, packed, null);
Thread.currentThread().setContextClassLoader(catalinaLoader); Class
<?> startupClass = catalinaLoader.loadClass(MAIN_CLASS); Object startupInstance = startupClass.newInstance(); Method method = startupInstance.getClass().getMethod("start"); method.invoke(startupInstance); }

 

一步一步来吧,首先自定义一个MyClassLoader类继承了URlClassLoader,再对比一下AppClassLoader 的创建,可以说基本一样;

a.获取路径的File[] 文件;

b.然后就调用了AccessController 的native <T> T doPrivileged(PrivilegedAction<T> action),而关于这个方法的说法,网友们是这么说的一个调用者在调用doPrivileged方法时,可被标识为 "特权"。在做访问控制决策时,如果checkPermission方法遇到一个通过doPrivileged调用而被表示为 "特权"的调用者,并且没有上下文自变量,checkPermission方法则将终止检查。如果那个调用者的域具有特定的许可,则不做进一步检查,checkPermission安静地返回,表示那个访问请求是被允许的;如果那个域没有特定的许可,则象通常一样,一个异常被抛出

c.调用福利的supper方法创建

 

Thread.currentThread().setContextClassLoader(catalinaLoader) 这个句有什么用??

a.在java的应用中,每个线程都有一个contextClassLoad,而充init()方法可以看到,默认是父线程的上下文类加载器,当月我们也可以通过Thread.currentThread().setContextClassLoader(catalinaLoader)来设置;

b.这个上下文的加载器的作用简单的说,就是当这个线程加载某些类时,通过这加载器进行加载;

c.网友说法:

每个运行中的线程都有一个成员contextClassLoader,用来在运行时动态地载入其它类
系统默认的contextClassLoader是systemClassLoader,所以一般而言java程序在执行时可以使用JVM自带的类、$JAVA_HOME/jre/lib/ext/中的类和$CLASSPATH/中的类
可以使用Thread.currentThread().setContextClassLoader(...);更改当前线程的contextClassLoader,来改变其载入类的行为
ClassLoader被组织成树形,一般的工作原理是:
1) 线程需要用到某个类,于是contextClassLoader被请求来载入该类
2) contextClassLoader请求它的父ClassLoader来完成该载入请求
3) 如果父ClassLoader无法载入类,则contextClassLoader试图自己来载入
注意:WebApp?ClassLoader的工作原理和上述有少许不同:
它先试图自己载入类(在ContextBase?/WEB-INF/...中载入类),如果无法载入,再请求父ClassLoader完成

public
class Thread implements Runnable {
    /* Make sure registerNatives is the first thing <clinit> does. */
    private static native void registerNatives();
    static {
        registerNatives();
    }

    private char        name[];
    private int         priority;
    private Thread      threadQ;
    private long        eetop;

    /* Whether or not to single_step this thread. */
    private boolean     single_step;

    /* Whether or not the thread is a daemon thread. */
    private boolean     daemon = false;

    /* JVM state */
    private boolean     stillborn = false;

    /* What will be run. */
    private Runnable target;

    /* The group of this thread */
    private ThreadGroup group;

    /* The context ClassLoader for this thread */
    private ClassLoader contextClassLoader;




……………… }

 

    private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize, AccessControlContext acc) {
        if (name == null) {
            throw new NullPointerException("name cannot be null");
        }

        this.name = name.toCharArray();

        Thread parent = currentThread();
        SecurityManager security = System.getSecurityManager();
        if (g == null) {
            /* Determine if it's an applet or not */

            /* If there is a security manager, ask the security manager
               what to do. */
            if (security != null) {
                g = security.getThreadGroup();
            }

            /* If the security doesn't have a strong opinion of the matter
               use the parent thread group. */
            if (g == null) {
                g = parent.getThreadGroup();
            }
        }

        /* checkAccess regardless of whether or not threadgroup is
           explicitly passed in. */
        g.checkAccess();

        /*
         * Do we have the required permissions?
         */
        if (security != null) {
            if (isCCLOverridden(getClass())) {
                security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
            }
        }

        g.addUnstarted();

        this.group = g;
        this.daemon = parent.isDaemon();
        this.priority = parent.getPriority();
        if (security == null || isCCLOverridden(parent.getClass()))
            this.contextClassLoader = parent.getContextClassLoader();
        else
            this.contextClassLoader = parent.contextClassLoader;
        this.inheritedAccessControlContext =
                acc != null ? acc : AccessController.getContext();
        this.target = target;
        setPriority(priority);
        if (parent.inheritableThreadLocals != null)
            this.inheritableThreadLocals =
                ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
        /* Stash the specified stack size in case the VM cares */
        this.stackSize = stackSize;

        /* Set thread ID */
        tid = nextThreadID();
    }

 

最后通过反射把程序运行起来

 

 

一个题目

/**
 * a.加载->校验->准备->初始化->使用->卸载(准备和初始化)
 * b.父类静态->本身静态->父类变量和代码块->父类构造器->本身变量和代码块->本身构造器
 * c.静态只会加载一次,静态变量一开始会在准备阶段赋值默认值,如st = null, flag = false;
 * c.而st = new StaticTest()这步骤被镶嵌到static StaticTest st = new StaticTest();
 * d.开始执行new StaticTest(),因为静态变量都已经初始化,因此进入:本身变量和代码块->本身构造器
 * e.结束new StaticTest(),进入下一个静态变量初始化System.out.println("2");再下一个static boolean flag = true;
 * f.执行方法staticFunction();
 */
public class StaticTest {
    public static void main(String[] args) {
        staticFunction();
    }

    {
        System.out.println("1");
    }

    static StaticTest st = new StaticTest();

    static {
        System.out.println("2");
    }


    StaticTest() {
        System.out.println("3");
        double temp = 3*0.1;
        if (temp == a){
            System.out.println(a+","+flag);
        }else {
            System.out.println(a+","+flag);
        }

    }

    private static void staticFunction(){
        if (flag){
            System.out.println("4");
        }else {
            System.out.println("5");

        }
    }
    double a=0.3;
    static boolean flag = true;
}



1
3
0.3,false
2
4





 

posted @ 2018-05-28 21:09  注册邮箱  阅读(1301)  评论(0编辑  收藏  举报