JVM1

虛擬機是有規範的,HotSpotsun公司也就是如今的oracle公司提供的,虛擬機並非只有oracle有,IBM也有虛擬機,虛擬機是有規範的, 只要遵循這個規範就能夠本身造虛擬機。虛擬機也有商用的,收費很高。Oracle是免費的虛擬機。Openjdk是基於jdk的開源實現,open是開源的意思。html

HotSpotoracle的,是使用的很普遍的。java

 

Java代碼中,類型的加載,連接,初始化都是在程序運行期間runtime完成的(其餘的一些語言是編譯期間完成的)。類型是定義的一個類、接口、枚舉,不是對象。數據庫

 

動態代理是類型在運行期間動態的生成出來,在編譯期間沒有的。windows

 

Java是靜態語言,可是也有不少動態的特性。數組

 

 

 

加載:class文件從磁盤到內存安全

 

鏈接:類與類的關係肯定好,字節碼的驗證校驗。字節碼有問題虛擬機就不會去執行。字節碼文件是能夠人爲操縱的。網絡

 

初始化:類的靜態變量賦值。都是在運行期間完成的,不是編譯期間。數據結構

 

 

 

類加載器:每個類型(類)會被歸入jvm管轄範圍中。加載類的工具。oracle

 

虛擬機就是一個進程,進程在某些狀況下就會停掉:dom

 

  1. 程序執行了System.exit()
  2. 程序正常結束
  3. 執行過程當中遇到了異常
  4. 操做系統層面出現錯誤致使虛擬機進程結束

 

符號引用就是字符串,寫的時候,直接引用就是去找相應的地址

 

 

 

類的卸載:類的信息從內存移除。

加載:類加載到內存,.class文件二進制數據讀入到內存,放入到方法區中,而後在內存建立一個Class對象,虛擬機規範並無規定Class對象放在哪裏,OracleHotSpot虛擬機將其放在了方法區中(沒有放到堆區),Class對象封裝類在方法區的數據結構。全部的實例都會對應一份Class對象。因此反射要使用Class對象。

驗證:驗證類的正確性

準備:靜態變量賦予初始值,分配相應的空間大小。

解析:符號引用轉換爲直接引用

初始化:賦予正確的初始值

加載連接初始化加載到內存、校驗,賦予默認值、正確值,符號引用轉換

加載class文件的方式:

  1. 磁盤直接加載,位於classpath類路徑下
  2. 網絡下載.class文件
  3. Zip,jar文件加載.class文件
  4. 數據庫提取.class文件(使用的少)
  5. Java源文件動態編譯爲.class文件(動態代理)。運行期生成,編譯時沒有。jsp文件轉換成class文件。

 

Java對類的使用方式:

 

  1. 主動使用
  2. 被動使用

 

類或接口必須首次主動使用初始化(初始化就會執行裏面的static代碼塊)。不首次主動使用也會加載,只是不初始化

 

JVM規範容許加載器預料某個類將要使用時候預先加載它,若是預先加載中遇到了class文件錯誤,類加載器要在首次主動使用這個類時候報告錯誤。入股這個類一直沒有首次使用,就一直不報錯

 

主動使用7種:

 

  1. 建立實例
  2. 訪問(讀寫)類的靜態變量。調用類的靜態方法
  3. 反射
  4. 初始化類的子類(初始化之類時候父類也是主動使用,也會初始化,爺爺類也會初始化)
  5. 被標記爲啓動類的類(main函數了類,入口類)

 

其餘使用類的方式都是被動使用,都不會致使類的初始化。有可能致使類的加載和連接

調用ClassLoader類的loadClass方法加載一個類,並非對類的主動使用,不會致使類的初始化。

 

先讓父類加載器加載,加載不了在本身加載,是爲了安全

表面看是一種繼承關係,其實是一種包含關係。

public class 額鵝鵝鵝 {
    public static void main(String[] args) {
        System.out.println(Child.p);
    }
}

class Parent{
    static String p = "parent";
    static {
        System.out.println("parent static");
    }
}

class Child extends Parent{
    static String c = "Child";
    static {
        System.out.println("Child static");
    }
}
/*
 System.out.println(Child.c)
     parent static
    Child static
    Child
    使用子類的靜態屬性,是對子類的主動使用,父類的靜態代碼塊執行,子類的靜態代碼塊會執行。
 
 System.out.println(Child.p)
     parent static
    parent
     使用父類的靜態屬性,不是對子類的主動使用,父類的靜態代碼塊執行,子類的靜態代碼塊不會執行。
 */

 -XX:+TraceClassLoading,追蹤類的加載信息

 -XX:+TraceClassUnloading,追蹤類的卸載信息

-XX:+<option>:開啓option選項

-XX:-<option>:關閉option選項

-XX:<option>=value:設置option選項值

 

Jvm的參數有上千個,

 

如何在windows平臺下使用hsdisjitwatch查看JIT後的彙編碼

http://www.javashuo.com/article/p-garuezop-cr.html

package com.ssss;
class A  {
    static final String c = "Child";//final是常量,編譯階段,常量放在調用這個常量的方法所在的類的常量池中。就是TT類的常量池中。
    //TT類並無直接引用A類,所以使用A.c這個常量的時候,不會觸發A類的初始化,所以Child static不會打印。
    //由於是在TT類的常量池中,所以TT類和A類沒有關係了。甚至將A類的class文件刪除均可以。(不能刪源文件,不然就不能編譯了)
    volatile int s = 1;
    static {
        System.out.println("Child static");
    }
    public synchronized int j() {
        return s++;
    }
}/*
 Child
 */
                                // javap 查看java編譯器爲咱們生成的字節碼彙編代碼。
/*
C:\Users\Admin\Desktop\圖片\111>javap -c A.class
class ssss.A {
  static final java.lang.String c;//屬性

  static {};//靜態
    Code:
       0: getstatic     #13    // Field java/lang/System.out:Ljava/io/PrintStream :System.out.println
       3: ldc           #19    // String Child static
       5: invokevirtual #21    // Method java/io/PrintStream.println:(Ljava/lang/String;)V :System.out.println
       8: return

  ssss.A();//方法
    Code:
       0: aload_0
       1: invokespecial #30    // Method java/lang/Object."<init>":()V
       4: return
}

C:\Users\Admin\Desktop\圖片\111>javap -c TT.class
Compiled from "TT.java"
public class ssss.TT {
  public ssss.TT();
    Code:
       0: aload_0
       1: invokespecial #8      // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: getstatic     #16      // Field java/lang/System.out:Ljava/io/PrintStream :System.out.println
       3: ldc           #22      // String Child ,A.c已是Child了,編譯時候就已是Child了。ldc將int,float,String推到棧頂。
       5: invokevirtual #24      // Method java/io/PrintStream.println:(Ljava/lang/String;)V :System.out.println
       8: return
}
*/
public class TT {
    public static void main(String[] args) {
        System.out.println(A.c);
    }
}
class abc {
    //常量final UUID.randomUUID()不是編譯期間能夠肯定值,那麼編譯時候就不會把str的值放入
    //DDD類的常量池中,運行時候,就會主動使用abc類,致使abc類的初始化。不然abc類是不會初始化的(abc的static代碼塊就不會執行)。
    public static final String str = UUID.randomUUID().toString();
    static {
        System.out.println("static");
    }
}

public class DDD{
    public static void main(String[] args) {
        System.out.println(abc.str);
    }
}
class abc {
    static {
        System.out.println("static abc");
    }
}

public class DDD{
    public static void main(String[] args) {
        abc a = new abc();//靜態代碼塊執行
        System.out.println(a.getClass());//class com.ssss.abc
        System.out.println(a.getClass().getSuperclass());//class java.lang.Object
        
        abc[] ss = new abc[1];//不會執行靜態代碼塊,數組不是主動使用,
        System.out.println(ss.getClass());//class [Lcom.ssss.abc;
        System.out.println(ss.getClass().getSuperclass());//class java.lang.Object
        
        int[] i = new int[1];//,不是主動使用,
        System.out.println(i.getClass());//class [I  I是int類型
        System.out.println(i.getClass().getSuperclass());//class java.lang.Object
        
        char[] c = new char[1];//,不是主動使用,
        System.out.println(c.getClass());//class [C  C是char類型
        System.out.println(c.getClass().getSuperclass());//class java.lang.Object
        
        boolean[] b = new boolean[1];//,不是主動使用,
        System.out.println(b.getClass());//class [Z  Z是boolean類型
        System.out.println(b.getClass().getSuperclass());//class java.lang.Object
        
        short[] s = new short[1];//,不是主動使用,
        System.out.println(s.getClass());//class [S  S是short類型
        System.out.println(s.getClass().getSuperclass());//class java.lang.Object
        
        long[] l = new long[1];//,不是主動使用,
        System.out.println(l.getClass());//class [J  J是long類型
        System.out.println(l.getClass().getSuperclass());//class java.lang.Object
        
        byte[] by = new byte[1];//,不是主動使用,
        System.out.println(by.getClass());//class [B  B是byte類型
        System.out.println(by.getClass().getSuperclass());//class java.lang.Object
    }
}
//一個接口初始化,並不要求父接口也初始化。
//真正使用父接口時候(如使用接口中的常量時候)纔不會初始化。類的初始化是會初始化父類的。

//final常量是會放到調用類的常量池中去的,不會引發定義常量的類的初始化,運行期間就放進去了。
//若是常量是隨機數運行期間才能肯定的,那麼就會引發定義常量的類的初始化。
public class sd {
    public static void main(String[] args) {
        System.out.println(Ic.b);
    }
}

interface Ip {
    public static int a = 5;
}

interface Ic extends Ip {
    public static int b = 6;
}
package com.ssss;
public class sd {
    @SuppressWarnings("static-access")
    public static void main(String[] args) {
        Singleton ss = Singleton.get();//先去初始化Singleton類,最後調用get方法。
        System.out.println(ss.i);//1
        System.out.println(ss.j);//0
    }
}
@SuppressWarnings("static-access")
class Singleton {
    public static int i;
    /*static {
        System.out.println("s "+s );//s報錯,找不到定義。
    }*/
    public static Singleton s = new Singleton();//看到new就會去執行構造函數。在執行下面的靜態塊。不然不執行構造函數。
    static {
        System.out.println("s.i2:"+s.i);//1
        System.out.println("s.j2:"+s.j);//1
    }
    private Singleton() {
        System.out.println("i0:"+i);//i:0
        System.out.println("j0:"+j);//j:0,
        i++;
        j++;
        System.out.println("i:"+i);//i:1
        System.out.println("j:"+j);//j:1,j這裏是1,可是後面把j賦值爲了0,因此get時候是0.
        System.out.println("s.i:"+s.i);//1
        System.out.println("s.j:"+s.j);//1
    }
//    public static int j = 0;//就是執行這裏,再去執行get方法,把對象的屬性j賦值成了0
    
    public static Singleton get() {
        System.out.println("i1:"+i);//i1:1
        System.out.println("j1:"+j);//j1:0
        System.out.println("s.i1:"+s.i);//1
        System.out.println("s.j1:"+s.j);//0
        return s;
    }
    static {
        System.out.println("s.i3:"+s.i);//1
        System.out.println("s.j3:"+s.j);//1
    }
    public static int j = 0;//就是執行這裏,再去執行get方法,把對象的屬性j賦值成了0。即便這行代碼放在這裏,j也會是0
    //由於先初始化Singleton類,get方法最後調用。即便get方法是靜態的,也是在main函數中調用的時候再去執行,不會初始化執行,初始化只會執行靜態代碼塊。構造函數也只是有new纔會執行。初始化從上到下執行。
    static {
        System.out.println("s.i4:"+s.i);//1
        System.out.println("s.j4:"+s.j);//0
    }
}
/*i0:0
j0:0
i:1
j:1
s.i:1
s.j:1
s.i2:1
s.j2:1
s.i3:1
s.j3:1
s.i4:1
s.j4:0
i1:1
j1:0
s.i1:1
s.j1:0
1
0*/
package com.ssss;
public class sd {
    @SuppressWarnings("static-access")
    public static void main(String[] args) {
        Singleton ss = Singleton.get();//先去初始化Singleton類,最後調用get方法。
        System.out.println(ss.i);//1
        System.out.println(ss.j);//0
    }
}
@SuppressWarnings("static-access")
class Singleton {
    public static int i;
    public static Singleton s = new Singleton();//看到new就會去執行構造函數。在執行下面的靜態塊。不然不執行構造函數。
    public static int j = 0; 
    static {//不加static,則是最早執行,而後執行構造函數,且每一個對象都會執行一遍
        System.out.println("s.i2:"+s.i);//1
        System.out.println("s.j2:"+s.j);//0
    }
    private Singleton() {
        System.out.println("i0:"+i);//i:0
        System.out.println("j0:"+j);//j:0,
        i++;
        j++;
        System.out.println("i:"+i);//i:1
        System.out.println("j:"+j);//j:1,         System.out.println("s.i:"+s.i);//1
        System.out.println("s.j:"+s.j);//1
    }
    
    public static Singleton get() {
        System.out.println("i1:"+i);//i1:1
        System.out.println("j1:"+j);//j1:0
        System.out.println("s.i1:"+s.i);//1
        System.out.println("s.j1:"+s.j);//0
        return s;
    }
    static {
        System.out.println("s.i3:"+s.i);//1
        System.out.println("s.j3:"+s.j);//0
    }
}
/*i0:0
j0:0
i:1
j:1
s.i:1
s.j:1
s.i2:1
s.j2:0
s.i3:1
s.j3:0
i1:1
j1:0
s.i1:1
s.j1:0
1
0*/
package com.ssss;
public class sd {
    @SuppressWarnings("static-access")
    public static void main(String[] args) {
        Singleton ss = Singleton.get();//先去初始化Singleton類,最後調用get方法。
        System.out.println(ss.i);//1
        System.out.println(ss.j);//1
    }
}
@SuppressWarnings("static-access")
class Singleton {
    public static int i;
    public static int j = 0; 
    public static Singleton s = new Singleton();//看到new就會去執行構造函數。在執行下面的靜態塊。不然不執行構造函數。
    static {
        System.out.println("s.i2:"+s.i);//1
        System.out.println("s.j2:"+s.j);//1
    }
    private Singleton() {
        System.out.println("i0:"+i);//i:0
        System.out.println("j0:"+j);//j:0 
        i++;
        j++;
        System.out.println("i:"+i);//i:1
System.out.println("j:"+j);//j:1         System.out.println("s.i:"+s.i);//1
        System.out.println("s.j:"+s.j);//1
    }
    
    public static Singleton get() {
        System.out.println("i1:"+i);//i1:1
        System.out.println("j1:"+j);//j1:1
        System.out.println("s.i1:"+s.i);//1
        System.out.println("s.j1:"+s.j);//1
        return s;
    }
    static {
        System.out.println("s.i3:"+s.i);//1
        System.out.println("s.j3:"+s.j);//1
    }
}
/*i0:0
j0:0
i:1
j:1
s.i:1
s.j:1
s.i2:1
s.j2:1
s.i3:1
s.j3:1
i1:1
j1:1
s.i1:1
s.j1:1
1
1
*/

類加載器:

  1. 虛擬機自帶類加載器

1.1根類加載器(Bootstrap

1.2擴展類加載器(Extension

1.3系統(應用)類加載器(System,App

  1. ClassLoader的子類

 

Loader1發起加載Sample類,可是根加載器和擴展加載器都是加載特定目錄的類,所以最終是由系統加載器加載成功,並把結果返回給loader1加載器。首先是向上委託到根,加載不了又向下委託,一個雙向循環

 

rt.jar是使用最多的類,平時使用的都是這個裏面的。

定義類加載器:加載這個類成功的類加載器。Sample類是由系統類加載器加載成功的,系統類加載器就是定義類加載器。

 

package com.ssss;
public class TT {
    public static void main(String[] args) throws Exception {
        Class cl = Class.forName("java.lang.String");
        System.out.println(cl.getClassLoader());//null。返回類加載器,若是是null就是bootStrap類加載器加載的。
        
        Class cl1 = Class.forName("com.ssss.C");//反射,主動使用,static會執行
        System.out.println(cl1.getClassLoader());//sun.misc.Launcher$AppClassLoader@73d16e93,,內部類,系統加載器/應用加載器。
        //應用加載器 加載的是  工程環境變量 classpath裏面的類。
        
        System.out.println("-------------------------------");
        ClassLoader l = ClassLoader.getSystemClassLoader();//系統加載器
        Class dd = l.loadClass("com.ssss.C");//只是loadClass,不是對類的主動使用,不是初始化,不執行static代碼塊
        System.out.println(dd);//class com.ssss.C

                                                                                              System.out.println("==============================");
         ClassLoader l1 = l.getParent();
    System.out.println(l1);//sun.misc.Launcher$ExtClassLoader@15db9742
        ClassLoader l2 = l1.getParent();
        System.out.println(l2);//null

    }
}
class C {
    static {
        System.out.println("ccccc");
    }
}

 

public class TT {
    public static void main(String[] args) throws Exception {
        ClassLoader t = Thread.currentThread().getContextClassLoader();
        System.out.println(t);//sun.misc.Launcher$AppClassLoader@73d16e93。加載應用的加載器。
        
        String s = "com\\ssss\\C.class";
        Enumeration<URL> urls = t.getResources(s);
        while(urls.hasMoreElements()) {
            URL u = urls.nextElement();
            System.out.println(u);//"com\\ssss\\C.class"
        }
        
        System.out.println("----=======-------========-----=======");
        Class c = TT.class;
        System.out.println(c.getClassLoader());//sun.misc.Launcher$AppClassLoader@73d16e93
        
        Class c1 = String.class;
        System.out.println(c1.getClassLoader());//null。根加載器。String在rt.jar中
    }
}

類加載器加載的是類,不是對象線程上下文clssloaderAppClassLoader

相關文章
相關標籤/搜索