Class Literal(Java)

前言

上一節咱們討論過經過關鍵字synchronized實現線程同步,同時最主要了解到在Java中className.class所表明的具體含義,在博客寫完後,感受仍是有點迷糊,而後再次深刻了解後,原來關於className.class在Java語言規範中定義爲(Class Literal),咱們翻譯爲類文字好像比較生硬,仍是以英文做爲說明最好,本節咱們再來詳細討論下Class Literal。html

Class Literal

在java語言規範中有對Class Literals的定義《https://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.8.2》:它是由類,接口,數組或原始類型的名稱或僞類型void組成的表達式,後面緊跟【.】和【class】。好比C.class,那麼它的類型則爲Class <C>,其中C是類,接口或數組類型的名稱。好比p.class的類型(其中p是基本類型的名稱)是Class <B>,其中B是裝箱轉換後的類型p的表達式的類型,也就說例如int.class,它的Class Literal其實是Class<Integer>。而void.class,它的Class Literal是Class<Void>。最後對於類型的變量固然也就沒有Class Literal。好比咱們要想獲取包裝類Integer的Class Literal,能夠經過以下兩種方式來獲取:java

System.out.println(Class.forName("java.lang.Integer"));
System.out.println(Integer.class);

接下來咱們經過定義一個類來更加深刻了解,以下:數組

class Test {
}

咱們再來經過上述方法獲取其Class Literal,此時forName中參數則是類所在包空間,以下:安全

Class cls = Class.forName("com.company.Test");
System.out.println(cls.toString());
        
System.out.println(Test.class);

還記得上一節咱們重點講解的就是經過關鍵字synchronized,在其方法或同步塊中的監視器或鎖定對象是className.class即Class Literal,咱們也知道在類加載時機的第一階段中的第三件事情則是在JVM中生成對於對應類且只存在一次的java.lang.class的對象,該對象包含有關該類的元數據等等,也就是說該鎖定對象就是對該類生成的java.lang.class對象的引用。例如,以下例子:併發

class Test {
    public void lockMethod1() {
        synchronized (Test.class) {
            System.out.println("1");
        }
    }

    public void lockMethod2() {
        synchronized (Test.class) {
            System.out.println("2");
        }
    }
}

當發生併發分別執行如上方法一和方法二,若此時執行到方法二時,可是方法一併未執行完成,經過上述對鎖定對象的詳細分析,此時必將致使方法二會被阻塞,直到方法一執行完畢,釋放線程同步鎖。到此咱們講解了Class Literal在線程同步中的使用,其實在反射中使用的機會也比較多,好比建立命令行將程序進行重啓的命令,咱們經過ProcessImpl類中的createCommandLine方法,建立命令行,這裏咱們嘗試使用反射來實現,C#中經過反射調用方法,其參數是Object數組(記得是這樣),在java中經過反射調用方法,其參數就是ClassLiteral泛型數組,因此咱們必須顯式指定參數類型,這就應用到了Class Literal,以下:oracle

public static void main(String[] args) throws
            InvocationTargetException,
            IllegalAccessException,
            NoSuchMethodException,
            ClassNotFoundException {

        final String[] cmd = {
                "shutdown.exe",
                "/r",
                "/t 0",
        };

        final String executablePath = new File(cmd[0]).getPath();

        final Class<?> impl = ClassLoader.getSystemClassLoader().loadClass("java.lang.ProcessImpl");

        final Method myMethod = impl.getDeclaredMethod(
                "createCommandLine",
                new Class[] {
                        int.class,
                        String.class,
                        String[].class });
        myMethod.setAccessible(true);

        final Object result = myMethod.invoke(
                null,
                2,
                executablePath,
                cmd);
        System.out.println(result);

    }

總結 

本節咱們再一次深刻並瞭解className.class,在java語言規範中其專有名詞爲Class Literal,並對其在線程同步中的使用以及爲什麼就保證了線程安全又進行了囉嗦式的分析,最後也經過一個反射例子做爲Class Literal的使用練習而結束本文,至此關於Class Literal的學習算告一段落。下一節咱們進入學習hibernate。學習

相關文章
相關標籤/搜索