【17-類加載與反射】

 

類加載與反射java


 

Java程序與JVMmysql

 

 

•無論Java程序有多麼複雜、該程序啓動了多少個線程,它們都處於該Java虛擬機進程裏。正如前面sql

介紹的,同一個JVM的全部線程、全部變量都處於同一個進程裏,它們都使用該JVM進程的內存區。數據庫

當系統出現如下幾種狀況時,JVM進程將被終止:編程

 

 

–程序運行到最後正常結束。數組

 

–程序運行到使用System.exit()或Runtime.getRuntime().exit()代碼結束程序。緩存

 

–程序執行過程當中遇到未捕獲的異常或錯誤而結束。網絡

 

–程序所在平臺強制結束了JVM進程。 ide


類加載測試

 

 

•當程序主動使用某個類時,若是該類還未被加載到內存中,系統會經過加載、鏈接、初始化三個步驟

來對該類進行初始化,若是沒有意外,JVM將會連續完成這三個步驟,因此有時也把這三個步驟統稱

爲類加載或類初始化。

 

•類加載指的是將類的class文件讀入內存,併爲之建立一個java.lang.Class對象,也就是說當程序

使用任何類時,系統都會爲之創建一個java.lang.Class對象。 


 

 類數據的來源

 

 

•經過使用不一樣的類加載器,能夠從不一樣來源加載類的二進制數據,一般有以下幾種來源:

–從本地文件系統來加載class文件,這是前面絕大部分示例程序的類加載方式。

–從JAR包中加載class文件,這種方式也是很常見的,前面介紹JDBC編程時用到的數據庫驅動類就是放在JAR文件中,JVM能夠從JAR文件中直接加載該class文件。

–經過網絡在加載class文件。

–把一個Java源文件動態編譯、並執行加載。 


 

 類的鏈接

 

 

•當類被加載以後,系統爲之生成一個對應的Class對象,接着將會進入鏈接階段,鏈接階段將會負責把類的二進制數據合併到JRE中。類鏈接又可分爲以下三個階段:

驗證:驗證階段用於檢驗被加載的類是否有正確的內部結構,並和其餘類協調一致。

準備:類準備階段則負責爲類的靜態屬性分配內存,並設置默認初始值。

解析:將類的二進制數據中的符號引用替換成直接引用。


 

 類的初始化 

 

 

•在類的初始化階段,虛擬機負責對類進行初始化,主要就是對靜態屬性進行初始化。在Java類中對靜態屬性指定初始值有兩種方式:

–(1)聲明靜態屬性時指定初始值;

–(2)使用靜態初始化塊爲靜態屬性指定初始值。 


 

 JVM初始化類的步驟

 

 

•(1)假如這個類尚未被加載和鏈接,程序先加載並鏈接該類。

•(2)假如該類的直接父類尚未被初始化,則先初始化其直接父類。

•(3)假如類中有初始化語句,則系統依次執行這些初始化語句。 


類的初始化時機

 

 

•建立類的實例。爲某個類建立實例的方式包括使用new操做符來建立實例,經過反射來建立實例,經過反序列化的方式來建立實例。

•調用某個類的靜態方法。

•訪問某個類或接口的靜態屬性,或爲該靜態屬性賦值。

•使用反射方式來強制建立某個類或接口對應的java.lang.Class對象。例如代碼:Class.forName("Person")。

•初始化某個類的子類,當初始化某個類的子類時,該子類的全部父類都會被初始化。

•直接使用java.exe命令來運行某個主類,當運行某個主類時,程序會先初始化該主類。

•final型的靜態屬性,若是該屬性能夠在編譯時就獲得屬性值,則可認爲該屬性可被當成編譯時常量。當程序使用編譯時常量時,系統會認爲這是對該類的被動使用,因此不會致使該類的初始化。 


類加載器

 

 

•類加載器負責將.class文件(可能在磁盤上,也可能在網絡上)加載到內存中,併爲之生成對應的java.lang.Class對象。

•當JVM啓動時,會造成由三個類加載器組成的初始類加載器層次結構:

–Bootstrap ClassLoader:根類加載器。

–Extension ClassLoader:擴展類加載器。

–System ClassLoader:系統類加載器。


 

 類加載機制 

 

 

•JVM的類加載機制主要有以下三種機制:

全盤負責:所謂全盤負責,就是說當一個類加載器負責加載某個Class的時候,該Class所依賴的

和引用的其餘Class也將由該類加載器負責載入,除非顯式使用另一個類加載器來載入。

 

父類委託:所謂父類委託則是先讓parent(父)類加載器試圖加載該Class,只有在父類加載器

沒法加載該類時才嘗試從本身的類路徑中加載該類。

 

緩存機制:緩存機制將會保證全部被加載過的Class都會被緩存,當程序中須要使用某個Class

時,類加載器先從緩存中搜尋該Class,只有當緩存中不存在該Class對象時,系統纔會讀取該類

對應的二進制數據,並將其轉換成Class對象,並存入cache。這就是爲何咱們修改了Class

後,程序必須從新啓動JVM,程序所做的修改纔會生效的緣由。 


 

 實現自定義類加載器

 

 

•ClassLoader類有以下三個關鍵方法:

–loadClass(String name, boolean resolve):該方法爲ClassLoader的入口點,根據指定的二進制名稱來加載類,系統就是調用ClassLoader的該方法來獲取指定類對應的Class對象。

–findClass(String name):根據二進制名稱來查找類。

•若是須要實現自定義的ClassLoader,能夠經過重寫以上兩個方法來實現,固然咱們推薦重寫findClass()方法,而不是重寫loadClass()方法。 


 

 自定義的類加載器的常見功能

 

 

•執行代碼前自動驗證數字簽名。

•根據用戶提供的密碼解密代碼,從而能夠實現代碼混淆器來避免反編譯class文件。

•根據用戶需求來動態地加載類。

•根據應用需求把其餘數據以字節碼的形式加載到應用中。


URLClassLoader

 

 

•Java爲ClassLoader提供了一個URLClassLoader實現類,該類也是系統類加載器和擴展類加載器

的父類(此處是父類,而不是父類加載器,這裏是類與類之間的繼承關係),URLClassLoader功能

比較強大,它既能夠從本地文件系統獲取二進制文件來加載類,也能夠從遠程主機獲取二進制文件來加

載類。

 

•實際上應用程序中能夠直接使用URLClassLoader來加載類,URLClassLoader類提供了以下兩個

構造器:

 

–URLClassLoader(URL[] urls):使用默認的父類加載器建立一個ClassLoader對象,該對象

將從urls所指定的系列路徑來查詢、並加載類。

 

–URLClassLoader(URL[] urls, ClassLoader parent):使用指定的父類加載器建立一個ClassLoader對象,其餘功能前一個構造器相同。 


 

 經過反射獲取Class對象

 

 

•Java程序中得到Class對象一般有以下三種方式:

–使用Class類的forName()靜態方法。該方法須要傳入字符串參數,該字符串參數的值是某個類的全限定類名(必須添加完整包名)。

–調用某個類的class屬性來獲取該類對應的Class對象。例如Person.class將會返回Person類對應的Class對象。

–調用某個對象的getClass()方法,該方法是java.lang.Object類中的一個方法,因此全部Java對象均可以調用該方法,該方法將會返回該對象所屬類對應的Class對象。


 

 從Class中獲取信息 

 

 

•獲取構造器

•訪問Class對應的類所包含的方法

•訪問Class對應的類所包含的屬性(Field)

•訪問Class對應的類上所包含的註釋。

•訪問該Class對象對應類包含的內部類。

•訪問該Class對象對應類所在的外部類。

•訪問該Class對象所對應類所繼承的父類、所實現的接口等。


Java 8新增的方法參數反射

 

 

•Java 8在java.lang.reflect包下新增了一個Executable抽象基類,該對象表明可執行的類成員,該類派生了Constructor、Method兩個子類。

•Executable基類提供了大量方法來獲取修飾該方法或構造器的註解信息;還提供了isVarArgs()方法用於判斷該方法或構造器是否包含數量可變的形參,以及經過getModifiers()方法來獲取該方法或構造器的修飾符。除此以外,Executable提供了以下兩個方法來獲取該方法或參數的形參個數及形參名。

–int getParameterCount():獲取該構造器或方法的形參個數。

–Parameter[] getParameters():獲取該構造器或方法的全部形參。

•上面第二個方法返回了一個Parameter[]數組,Parameter也是Java 8新增的API,每一個Parameter對象表明方法或構造器的一個參數。Parameter也提供了大量方法來獲取聲明該參數的泛型信息。


 

 經過反射執行代碼

 

 

•經過反射調用構造器建立對象。

•經過反射調用方法

•經過反射來訪問Field值

•經過反射操做數組


動態代理

 

•java.lang.reflect包下提供了一個Proxy類和一個InvocationHandler接口,經過使用這個類和

接口能夠生成JDK動態代理類或動態代理對象。

 

•Proxy 提供用於建立動態代理類和代理對象的靜態方法,它也是全部動態代理類的父類。若是咱們在

程序中爲一個或多個接口動態地生成實現類,就可使用Proxy來建立的動態代理類;若是須要爲一個

或多個接口動態地建立實例,也可使用Proxy來建立動態代理實例。


 

 Proxy

 

 

•Proxy提供了以下兩個方法來建立動態代理類和動態代理實例:

–static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces):創

建一個動態代理類所對應的Class對象,該代理類將實現interfaces所指定的多個接口。第一個

ClassLoader指定生成動態代理類的類加載器。

 

–static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,

InvocationHandler  h):直接建立一個動態代理對象,該代理對象的實現類實現了interfaces

指定的系列接口,執行代理對象的每一個方法時都會被替換執行InvocationHandler對象的invoke

方法。


 

 動態代理和AOP 

 

 

•動態代理在AOP(Aspect Orient Program,即面向切面編程)裏被稱爲AOP代理,AOP代理可

代替目標對象,AOP代理包含了目標對象的所有方法。但AOP代理中的方法與目標對象的方法存在差

異:AOP代理裏的方法能夠在執行目標方法以前、以後插入一些通用處理。 


 

 反射的泛型 

 

 

•動態代理在AOP(Aspect Orient Program,即面向切面編程)裏被稱爲AOP代理,AOP代理可

代替目標對象,AOP代理包含了目標對象的所有方法。但AOP代理中的方法與目標對象的方法存在差

異:AOP代理裏的方法能夠在執行目標方法以前、以後插入一些通用處理。 


 

 動態代理和AOP 

 

 

•從JDK1.5以後,Java的Class類增長了泛型功能,從而容許使用泛型來限制Class類,例如,

String.class 的類型其實是Class<String>。 使用Class<T>泛型能夠避免強制類型轉換。


 

 使用反射獲取泛型 

 

 

•得到了Field對象後,就能夠很容易地得到該Field的數據類型,即便用以下代碼便可得到指定Field的類型:

–//獲取Field對象f的類型

–Class<?> a = f.getType();

 

•經過這種方式只對普通類型的Field有效。但若是該Field的類型是有泛型限制的類型,如Map<String , Integer>類型,則不能準確的獲得該Field的泛型參數。

 

•爲了得到指定Field的泛型類型,應先使用以下方法來獲取指定Field的泛型類型:

–//得到Field實例f的泛型類型

–Type gType = f.getGenericType();

 

•而後將Type對象強制類型轉換爲ParameterizedType對象,ParameterizedType表明被參數化的類型,也就是增長了泛型限制的類型。ParameterizedType類提供了兩個方法:

–getRawType():返回被泛型限制的類型。

–getActualTypeArguments():返回泛型參數類型。


 

 

public class A {
    // 定義該類的類變量
    public static int a = 6;
}
View Code
public class ATest1 {
    public static void main(String[] args) {
        // 建立A類的實例
        A a = new A();
        // 讓a實例的類變量a的值自加
        a.a++;
        System.out.println(a.a);
    }
}
View Code
public class ATest2 {
    public static void main(String[] args) {
        // 建立A類的實例
        A b = new A();
        // 輸出b實例的類變量a的值
        System.out.println(b.a);
    }
}
View Code
class Tester {
    static {
        System.out.println("Tester類的靜態初始化塊...");
    }
}

public class ClassLoaderTest {
    public static void main(String[] args) throws ClassNotFoundException {
        ClassLoader cl = ClassLoader.getSystemClassLoader();
        // 下面語句僅僅是加載Tester類
        cl.loadClass("Tester");
        System.out.println("系統加載Tester類");
        // 下面語句纔會初始化Tester類
        Class.forName("Tester");
    }
}
View Code
class MyTest {
    static {
        System.out.println("靜態初始化塊...");
    }
    // 使用一個字符串直接量爲static final的類變量賦值
    static final String compileConstant = "瘋狂Java講義";
}

public class CompileConstantTest {
    public static void main(String[] args) {
        // 訪問、輸出MyTest中的compileConstant類變量
        System.out.println(MyTest.compileConstant); //
    }
}
View Code
public class Test {
    static {
        // 使用靜態初始化塊爲變量b指定出初始值
        b = 6;
        System.out.println("----------");
    }
    // 聲明變量a時指定初始值
    static int a = 5;
    static int b = 9; //
    static int c;

    public static void main(String[] args) {
        System.out.println(Test.b);
    }
}
View Code

public class BootstrapTest {
    public static void main(String[] args) {
        // 獲取根類加載器所加載的所有URL數組
        URL[] urls = sun.misc.Launcher.getBootstrapClassPath().getURLs();
        // 遍歷、輸出根類加載器加載的所有URL
        for (int i = 0; i < urls.length; i++) {
            System.out.println(urls[i].toExternalForm());
        }
    }
}
View Code
public class ClassLoaderPropTest {
    public static void main(String[] args) throws IOException {
        // 獲取系統類加載器
        ClassLoader systemLoader = ClassLoader.getSystemClassLoader();
        System.out.println("系統類加載器:" + systemLoader);
        /*
         * 獲取系統類加載器的加載路徑——一般由CLASSPATH環境變量指定 若是操做系統沒有指定CLASSPATH環境變量,默認以當前路徑做爲
         * 系統類加載器的加載路徑
         */
        Enumeration<URL> em1 = systemLoader.getResources("");
        while (em1.hasMoreElements()) {
            System.out.println(em1.nextElement());
        }
        // 獲取系統類加載器的父類加載器:獲得擴展類加載器
        ClassLoader extensionLader = systemLoader.getParent();
        System.out.println("擴展類加載器:" + extensionLader);
        System.out
                .println("擴展類加載器的加載路徑:" + System.getProperty("java.ext.dirs"));
        System.out.println("擴展類加載器的parent: " + extensionLader.getParent());
    }
}
View Code
public class CompileClassLoader extends ClassLoader {
    // 讀取一個文件的內容
    private byte[] getBytes(String filename) throws IOException {
        File file = new File(filename);
        long len = file.length();
        byte[] raw = new byte[(int) len];
        try (FileInputStream fin = new FileInputStream(file)) {
            // 一次讀取class文件的所有二進制數據
            int r = fin.read(raw);
            if (r != len)
                throw new IOException("沒法讀取所有文件:" + r + " != " + len);
            return raw;
        }
    }

    // 定義編譯指定Java文件的方法
    private boolean compile(String javaFile) throws IOException {
        System.out.println("CompileClassLoader:正在編譯 " + javaFile + "...");
        // 調用系統的javac命令
        Process p = Runtime.getRuntime().exec("javac " + javaFile);
        try {
            // 其餘線程都等待這個線程完成
            p.waitFor();
        } catch (InterruptedException ie) {
            System.out.println(ie);
        }
        // 獲取javac線程的退出值
        int ret = p.exitValue();
        // 返回編譯是否成功
        return ret == 0;
    }

    // 重寫ClassLoader的findClass方法
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        Class clazz = null;
        // 將包路徑中的點(.)替換成斜線(/)。
        String fileStub = name.replace(".", "/");
        String javaFilename = fileStub + ".java";
        String classFilename = fileStub + ".class";
        File javaFile = new File(javaFilename);
        File classFile = new File(classFilename);
        // 當指定Java源文件存在,且class文件不存在、或者Java源文件
        // 的修改時間比class文件修改時間更晚,從新編譯
        if (javaFile.exists()
                && (!classFile.exists() || javaFile.lastModified() > classFile
                        .lastModified())) {
            try {
                // 若是編譯失敗,或者該Class文件不存在
                if (!compile(javaFilename) || !classFile.exists()) {
                    throw new ClassNotFoundException("ClassNotFoundExcetpion:"
                            + javaFilename);
                }
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
        // 若是class文件存在,系統負責將該文件轉換成Class對象
        if (classFile.exists()) {
            try {
                // 將class文件的二進制數據讀入數組
                byte[] raw = getBytes(classFilename);
                // 調用ClassLoader的defineClass方法將二進制數據轉換成Class對象
                clazz = defineClass(name, raw, 0, raw.length);
            } catch (IOException ie) {
                ie.printStackTrace();
            }
        }
        // 若是clazz爲null,代表加載失敗,則拋出異常
        if (clazz == null) {
            throw new ClassNotFoundException(name);
        }
        return clazz;
    }

    // 定義一個主方法
    public static void main(String[] args) throws Exception {
        // 若是運行該程序時沒有參數,即沒有目標類
        if (args.length < 1) {
            System.out.println("缺乏目標類,請按以下格式運行Java源文件:");
            System.out.println("java CompileClassLoader ClassName");
        }
        // 第一個參數是須要運行的類
        String progClass = args[0];
        // 剩下的參數將做爲運行目標類時的參數,
        // 將這些參數複製到一個新數組中
        String[] progArgs = new String[args.length - 1];
        System.arraycopy(args, 1, progArgs, 0, progArgs.length);
        CompileClassLoader ccl = new CompileClassLoader();
        // 加載須要運行的類
        Class<?> clazz = ccl.loadClass(progClass);
        // 獲取須要運行的類的主方法
        Method main = clazz.getMethod("main", (new String[0]).getClass());
        Object[] argsArray = { progArgs };
        main.invoke(null, argsArray);
    }
}
View Code
public class Hello {
    public static void main(String[] args) {
        for (String arg : args) {
            System.out.println("運行Hello的參數:" + arg);
        }
    }
}
View Code
public class URLClassLoaderTest {
    private static Connection conn;

    // 定義一個獲取數據庫鏈接方法
    public static Connection getConn(String url, String user, String pass)
            throws Exception {
        if (conn == null) {
            // 建立一個URL數組
            URL[] urls = { new URL("file:mysql-connector-java-5.1.30-bin.jar") };
            // 以默認的ClassLoader做爲父ClassLoader,建立URLClassLoader
            URLClassLoader myClassLoader = new URLClassLoader(urls);
            // 加載MySQL的JDBC驅動,並建立默認實例
            Driver driver = (Driver) myClassLoader.loadClass(
                    "com.mysql.jdbc.Driver").newInstance();
            // 建立一個設置JDBC鏈接屬性的Properties對象
            Properties props = new Properties();
            // 至少須要爲該對象傳入user和password兩個屬性
            props.setProperty("user", user);
            props.setProperty("password", pass);
            // 調用Driver對象的connect方法來取得數據庫鏈接
            conn = driver.connect(url, props);
        }
        return conn;
    }

    public static void main(String[] args) throws Exception {
        System.out.println(getConn("jdbc:mysql://localhost:3306/mysql", "root",
                "32147"));
    }
}
View Code

 

 

 

// 定義可重複註解
@Repeatable(Annos.class)
@interface Anno {
}

@Retention(value = RetentionPolicy.RUNTIME)
@interface Annos {
    Anno[] value();
}

// 使用4個註解修飾該類
@SuppressWarnings(value = "unchecked")
@Deprecated
// 使用重複註解修飾該類
@Anno
@Anno
public class ClassTest {
    // 爲該類定義一個私有的構造器
    private ClassTest() {
    }

    // 定義一個有參數的構造器
    public ClassTest(String name) {
        System.out.println("執行有參數的構造器");
    }

    // 定義一個無參數的info方法
    public void info() {
        System.out.println("執行無參數的info方法");
    }

    // 定義一個有參數的info方法
    public void info(String str) {
        System.out.println("執行有參數的info方法" + ",其str參數值:" + str);
    }

    // 定義一個測試用的內部類
    class Inner {
    }

    public static void main(String[] args) throws Exception {
        // 下面代碼能夠獲取ClassTest對應的Class
        Class<ClassTest> clazz = ClassTest.class;
        // 獲取該Class對象所對應類的所有構造器
        Constructor[] ctors = clazz.getDeclaredConstructors();
        System.out.println("ClassTest的所有構造器以下:");
        for (Constructor c : ctors) {
            System.out.println(c);
        }
        // 獲取該Class對象所對應類的所有public構造器
        Constructor[] publicCtors = clazz.getConstructors();
        System.out.println("ClassTest的所有public構造器以下:");
        for (Constructor c : publicCtors) {
            System.out.println(c);
        }
        // 獲取該Class對象所對應類的所有public方法
        Method[] mtds = clazz.getMethods();
        System.out.println("ClassTest的所有public方法以下:");
        for (Method md : mtds) {
            System.out.println(md);
        }
        // 獲取該Class對象所對應類的指定方法
        System.out.println("ClassTest裏帶一個字符串參數的info()方法爲:"
                + clazz.getMethod("info", String.class));
        // 獲取該Class對象所對應類的上的所有註解
        Annotation[] anns = clazz.getAnnotations();
        System.out.println("ClassTest的所有Annotation以下:");
        for (Annotation an : anns) {
            System.out.println(an);
        }
        System.out.println("該Class元素上的@SuppressWarnings註解爲:"
                + Arrays.toString(clazz
                        .getAnnotationsByType(SuppressWarnings.class)));
        System.out.println("該Class元素上的@Anno註解爲:"
                + Arrays.toString(clazz.getAnnotationsByType(Anno.class)));
        // 獲取該Class對象所對應類的所有內部類
        Class<?>[] inners = clazz.getDeclaredClasses();
        System.out.println("ClassTest的所有內部類以下:");
        for (Class c : inners) {
            System.out.println(c);
        }
        // 使用Class.forName方法加載ClassTest的Inner內部類
        Class inClazz = Class.forName("ClassTest$Inner");
        // 經過getDeclaringClass()訪問該類所在的外部類
        System.out.println("inClazz對應類的外部類爲:" + inClazz.getDeclaringClass());
        System.out.println("ClassTest的包爲:" + clazz.getPackage());
        System.out.println("ClassTest的父類爲:" + clazz.getSuperclass());
    }
}
View Code
class Test {
    public void replace(String str, List<String> list) {
    }
}

public class MethodParameterTest {
    public static void main(String[] args) throws Exception {
        // 獲取String的類
        Class<Test> clazz = Test.class;
        // 獲取String類的帶兩個參數的replace()方法
        Method replace = clazz.getMethod("replace", String.class, List.class);
        // 獲取指定方法的參數個數
        System.out.println("replace方法參數個數:" + replace.getParameterCount());
        // 獲取replace的全部參數信息
        Parameter[] parameters = replace.getParameters();
        int index = 1;
        // 遍歷全部參數
        for (Parameter p : parameters) {
            if (p.isNamePresent()) {
                System.out.println("---第" + index++ + "個參數信息---");
                System.out.println("參數名:" + p.getName());
                System.out.println("形參類型:" + p.getType());
                System.out.println("泛型類型:" + p.getParameterizedType());
            }
        }
    }
}
View Code

public class ArrayTest1 {
    public static void main(String args[]) {
        try {
            // 建立一個元素類型爲String ,長度爲10的數組
            Object arr = Array.newInstance(String.class, 10);
            // 依次爲arr數組中index爲五、6的元素賦值
            Array.set(arr, 5, "瘋狂Java講義");
            Array.set(arr, 6, "輕量級Java EE企業應用實戰");
            // 依次取出arr數組中index爲五、6的元素的值
            Object book1 = Array.get(arr, 5);
            Object book2 = Array.get(arr, 6);
            // 輸出arr數組中index爲五、6的元素
            System.out.println(book1);
            System.out.println(book2);
        } catch (Throwable e) {
            System.err.println(e);
        }
    }
}
View Code
public class ArrayTest2 {
    public static void main(String args[]) {
        /*
         * 建立一個三維數組。 根據前面介紹數組時講的:三維數組也是一維數組, 是數組元素是二維數組的一維數組,
         * 所以能夠認爲arr是長度爲3的一維數組
         */
        Object arr = Array.newInstance(String.class, 3, 4, 10);
        // 獲取arr數組中index爲2的元素,該元素應該是二維數組
        Object arrObj = Array.get(arr, 2);
        // 使用Array爲二維數組的數組元素賦值。二維數組的數組元素是一維數組,
        // 因此傳入Array的set()方法的第三個參數是一維數組。
        Array.set(arrObj, 2, new String[] { "瘋狂Java講義", "輕量級Java EE企業應用實戰" });
        // 獲取arrObj數組中index爲3的元素,該元素應該是一維數組。
        Object anArr = Array.get(arrObj, 3);
        Array.set(anArr, 8, "瘋狂Android講義");
        // 將arr強制類型轉換爲三維數組
        String[][][] cast = (String[][][]) arr;
        // 獲取cast三維數組中指定元素的值
        System.out.println(cast[2][3][8]);
        System.out.println(cast[2][2][0]);
        System.out.println(cast[2][2][1]);
    }
}
View Code
public class CreateJFrame {
    public static void main(String[] args) throws Exception {
        // 獲取JFrame對應的Class對象
        Class<?> jframeClazz = Class.forName("javax.swing.JFrame");
        // 獲取JFrame中帶一個字符串參數的構造器
        Constructor ctor = jframeClazz.getConstructor(String.class);
        // 調用Constructor的newInstance方法建立對象
        Object obj = ctor.newInstance("測試窗口");
        // 輸出JFrame對象
        System.out.println(obj);
    }
}
View Code
public class ExtendedObjectPoolFactory {
    // 定義一個對象池,前面是對象名,後面是實際對象
    private Map<String, Object> objectPool = new HashMap<>();
    private Properties config = new Properties();

    // 從指定屬性文件中初始化Properties對象
    public void init(String fileName) {
        try (FileInputStream fis = new FileInputStream(fileName)) {
            config.load(fis);
        } catch (IOException ex) {
            System.out.println("讀取" + fileName + "異常");
        }
    }

    // 定義一個建立對象的方法,
    // 該方法只要傳入一個字符串類名,程序能夠根據該類名生成Java對象
    private Object createObject(String clazzName)
            throws InstantiationException, IllegalAccessException,
            ClassNotFoundException {
        // 根據字符串來獲取對應的Class對象
        Class<?> clazz = Class.forName(clazzName);
        // 使用clazz對應類的默認構造器建立實例
        return clazz.newInstance();
    }

    // 該方法根據指定文件來初始化對象池,
    // 它會根據配置文件來建立對象
    public void initPool() throws InstantiationException,
            IllegalAccessException, ClassNotFoundException {
        for (String name : config.stringPropertyNames()) {
            // 每取出一對key-value對,若是key中不包含百分號(%)
            // 這就標明是根據value來建立一個對象
            // 調用createObject建立對象,並將對象添加到對象池中
            if (!name.contains("%")) {
                objectPool.put(name, createObject(config.getProperty(name)));
            }
        }
    }

    // 該方法將會根據屬性文件來調用指定對象的setter方法
    public void initProperty() throws InvocationTargetException,
            IllegalAccessException, NoSuchMethodException {
        for (String name : config.stringPropertyNames()) {
            // 每取出一對key-value對,若是key中包含百分號(%)
            // 便可認爲該key用於控制調用對象的setter方法設置值,
            // %前半爲對象名字,後半控制setter方法名
            if (name.contains("%")) {
                // 將配置文件中key按%分割
                String[] objAndProp = name.split("%");
                // 取出調用setter方法的參數值
                Object target = getObject(objAndProp[0]);
                // 獲取setter方法名:set + "首字母大寫" + 剩下部分
                String mtdName = "set"
                        + objAndProp[1].substring(0, 1).toUpperCase()
                        + objAndProp[1].substring(1);
                // 經過target的getClass()獲取它實現類所對應的Class對象
                Class<?> targetClass = target.getClass();
                // 獲取但願調用的setter方法
                Method mtd = targetClass.getMethod(mtdName, String.class);
                // 經過Method的invoke方法執行setter方法,
                // 將config.getProperty(name)的值做爲調用setter的方法的參數
                mtd.invoke(target, config.getProperty(name));
            }
        }
    }

    public Object getObject(String name) {
        // 從objectPool中取出指定name對應的對象。
        return objectPool.get(name);
    }

    public static void main(String[] args) throws Exception {
        ExtendedObjectPoolFactory epf = new ExtendedObjectPoolFactory();
        epf.init("extObj.txt");
        epf.initPool();
        epf.initProperty();
        System.out.println(epf.getObject("a"));
    }
}
View Code
class Person {
    private String name;
    private int age;

    public String toString() {
        return "Person[name:" + name + " , age:" + age + " ]";
    }
}

public class FieldTest {
    public static void main(String[] args) throws Exception {
        // 建立一個Person對象
        Person p = new Person();
        // 獲取Person類對應的Class對象
        Class<Person> personClazz = Person.class;
        // 獲取Person的名爲name的成員變量
        // 使用getDeclaredField()方法代表可獲取各類訪問控制符的成員變量
        Field nameField = personClazz.getDeclaredField("name");
        // 設置經過反射訪問該成員變量時取消訪問權限檢查
        nameField.setAccessible(true);
        // 調用set()方法爲p對象的name成員變量設置值
        nameField.set(p, "Yeeku.H.Lee");
        // 獲取Person類名爲age的成員變量
        Field ageField = personClazz.getDeclaredField("age");
        // 設置經過反射訪問該成員變量時取消訪問權限檢查
        ageField.setAccessible(true);
        // 調用setInt()方法爲p對象的age成員變量設置值
        ageField.setInt(p, 30);
        System.out.println(p);
    }
}
View Code
public class ObjectPoolFactory {
    // 定義一個對象池,前面是對象名,後面是實際對象
    private Map<String, Object> objectPool = new HashMap<>();

    // 定義一個建立對象的方法,
    // 該方法只要傳入一個字符串類名,程序能夠根據該類名生成Java對象
    private Object createObject(String clazzName)
            throws InstantiationException, IllegalAccessException,
            ClassNotFoundException {
        // 根據字符串來獲取對應的Class對象
        Class<?> clazz = Class.forName(clazzName);
        // 使用clazz對應類的默認構造器建立實例
        return clazz.newInstance();
    }

    // 該方法根據指定文件來初始化對象池,
    // 它會根據配置文件來建立對象
    public void initPool(String fileName) throws InstantiationException,
            IllegalAccessException, ClassNotFoundException {
        try (FileInputStream fis = new FileInputStream(fileName)) {
            Properties props = new Properties();
            props.load(fis);
            for (String name : props.stringPropertyNames()) {
                // 每取出一對key-value對,就根據value建立一個對象
                // 調用createObject()建立對象,並將對象添加到對象池中
                objectPool.put(name, createObject(props.getProperty(name)));
            }
        } catch (IOException ex) {
            System.out.println("讀取" + fileName + "異常");
        }

    }

    public Object getObject(String name) {
        // 從objectPool中取出指定name對應的對象。
        return objectPool.get(name);
    }

    public static void main(String[] args) throws Exception {
        ObjectPoolFactory pf = new ObjectPoolFactory();
        pf.initPool("obj.txt");
        System.out.println(pf.getObject("a")); //
        System.out.println(pf.getObject("b")); //
    }
}
View Code

 

 

 

public interface Dog {
    // info方法聲明
    void info();

    // run方法聲明
    void run();
}
View Code
public class DogUtil {
    // 第一個攔截器方法
    public void method1() {
        System.out.println("=====模擬第一個通用方法=====");
    }

    // 第二個攔截器方法
    public void method2() {
        System.out.println("=====模擬通用方法二=====");
    }
}
View Code
public class GunDog implements Dog {
    // 實現info()方法,僅僅打印一個字符串
    public void info() {
        System.out.println("我是一隻獵狗");
    }

    // 實現run()方法,僅僅打印一個字符串
    public void run() {
        System.out.println("我奔跑迅速");
    }
}
View Code
public class MyInvokationHandler implements InvocationHandler {
    // 須要被代理的對象
    private Object target;

    public void setTarget(Object target) {
        this.target = target;
    }

    // 執行動態代理對象的全部方法時,都會被替換成執行以下的invoke方法
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Exception {
        DogUtil du = new DogUtil();
        // 執行DogUtil對象中的method1。
        du.method1();
        // 以target做爲主調來執行method方法
        Object result = method.invoke(target, args);
        // 執行DogUtil對象中的method2。
        du.method2();
        return result;
    }
}
View Code
public class MyProxyFactory {
    // 爲指定target生成動態代理對象
    public static Object getProxy(Object target) throws Exception {
        // 建立一個MyInvokationHandler對象
        MyInvokationHandler handler = new MyInvokationHandler();
        // 爲MyInvokationHandler設置target對象
        handler.setTarget(target);
        // 建立、並返回一個動態代理
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),
                target.getClass().getInterfaces(), handler);
    }
}
View Code
public class Test {
    public static void main(String[] args) throws Exception {
        // 建立一個原始的GunDog對象,做爲target
        Dog target = new GunDog();
        // 以指定的target來建立動態代理
        Dog dog = (Dog) MyProxyFactory.getProxy(target);
        dog.info();
        dog.run();
    }
}
View Code

interface Person {
    void walk();

    void sayHello(String name);
}

class MyInvokationHandler implements InvocationHandler {
    /*
     * 執行動態代理對象的全部方法時,都會被替換成執行以下的invoke方法 其中: proxy:表明動態代理對象 method:表明正在執行的方法
     * args:表明調用目標方法時傳入的實參。
     */
    public Object invoke(Object proxy, Method method, Object[] args) {
        System.out.println("----正在執行的方法:" + method);
        if (args != null) {
            System.out.println("下面是執行該方法時傳入的實參爲:");
            for (Object val : args) {
                System.out.println(val);
            }
        } else {
            System.out.println("調用該方法沒有實參!");
        }
        return null;
    }
}

public class ProxyTest {
    public static void main(String[] args) throws Exception {
        // 建立一個InvocationHandler對象
        InvocationHandler handler = new MyInvokationHandler();
        // 使用指定的InvocationHandler來生成一個動態代理對象
        Person p = (Person) Proxy.newProxyInstance(
                Person.class.getClassLoader(), new Class[] { Person.class },
                handler);
        // 調用動態代理對象的walk()和sayHello()方法
        p.walk();
        p.sayHello("孫悟空");
    }
}
View Code

public class CrazyitArray {
    // 對Array的newInstance方法進行包裝
    @SuppressWarnings("unchecked")
    public static <T> T[] newInstance(Class<T> componentType, int length) {
        return (T[]) Array.newInstance(componentType, length); //
    }

    public static void main(String[] args) {
        // 使用CrazyitArray的newInstance()建立一維數組
        String[] arr = CrazyitArray.newInstance(String.class, 10);
        // 使用CrazyitArray的newInstance()建立二維數組
        // 在這種狀況下,只要設置數組元素的類型是int[]便可。
        int[][] intArr = CrazyitArray.newInstance(int[].class, 5);
        arr[5] = "瘋狂Java講義";
        // intArr是二維數組,初始化該數組的第二個數組元素
        // 二維數組的元素必須是一維數組
        intArr[1] = new int[] { 23, 12 };
        System.out.println(arr[5]);
        System.out.println(intArr[1][1]);
    }
}
View Code
public class CrazyitObjectFactory {
    public static Object getInstance(String clsName) {
        try {
            // 建立指定類對應的Class對象
            Class cls = Class.forName(clsName);
            // 返回使用該Class對象所建立的實例
            return cls.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}
View Code
public class CrazyitObjectFactory2 {
    public static <T> T getInstance(Class<T> cls) {
        try {
            return cls.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static void main(String[] args) {
        // 獲取實例後無須類型轉換
        Date d = CrazyitObjectFactory2.getInstance(Date.class);
        JFrame f = CrazyitObjectFactory2.getInstance(JFrame.class);
    }
}
View Code
public class GenericTest {
    private Map<String, Integer> score;

    public static void main(String[] args) throws Exception {
        Class<GenericTest> clazz = GenericTest.class;
        Field f = clazz.getDeclaredField("score");
        // 直接使用getType()取出的類型只對普通類型的成員變量有效
        Class<?> a = f.getType();
        // 下面將看到僅輸出java.util.Map
        System.out.println("score的類型是:" + a);
        // 得到成員變量f的泛型類型
        Type gType = f.getGenericType();
        // 若是gType類型是ParameterizedType對象
        if (gType instanceof ParameterizedType) {
            // 強制類型轉換
            ParameterizedType pType = (ParameterizedType) gType;
            // 獲取原始類型
            Type rType = pType.getRawType();
            System.out.println("原始類型是:" + rType);
            // 取得泛型類型的泛型參數
            Type[] tArgs = pType.getActualTypeArguments();
            System.out.println("泛型信息是:");
            for (int i = 0; i < tArgs.length; i++) {
                System.out.println("第" + i + "個泛型類型是:" + tArgs[i]);
            }
        } else {
            System.out.println("獲取泛型類型出錯!");
        }
    }
}
View Code
相關文章
相關標籤/搜索