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





 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM