Java基礎(chǔ)學(xué)習(xí)第二十七天——類(lèi)加載器和反射

文檔版本 開(kāi)發(fā)工具 測(cè)試平臺(tái) 工程名字 日期 作者 備注
V1.0 2016.04.05 lutianfei none

[TOC]


第十三章 類(lèi)加載器和反射

類(lèi)的加載

  • 當(dāng)程序要使用某個(gè)類(lèi)時(shí),如果該類(lèi)還未被加載到內(nèi)存中并鸵,則系統(tǒng)會(huì)通過(guò)加載苇倡,連接初始化三步來(lái)實(shí)現(xiàn)對(duì)這個(gè)類(lèi)進(jìn)行初始化审姓。

  • 加載

    • 就是指將class文件讀入內(nèi)存珍特,并為之創(chuàng)建一個(gè)Class對(duì)象。
    • 任何類(lèi)被使用時(shí)系統(tǒng)都會(huì)建立一個(gè)Class對(duì)象魔吐。
  • 連接

    • 驗(yàn)證 是否有正確的內(nèi)部結(jié)構(gòu)扎筒,并和其他類(lèi)協(xié)調(diào)一致
    • 準(zhǔn)備 負(fù)責(zé)為類(lèi)的靜態(tài)成員分配內(nèi)存,并設(shè)置默認(rèn)初始化值
    • 解析 將類(lèi)的二進(jìn)制數(shù)據(jù)中的符號(hào)引用替換為直接引用
  • 初始化 就是我們以前講過(guò)的初始化步驟

類(lèi)初始化時(shí)機(jī)

  • 創(chuàng)建類(lèi)的實(shí)例
  • 訪(fǎng)問(wèn)類(lèi)的靜態(tài)變量酬姆,或者為靜態(tài)變量賦值
  • 調(diào)用類(lèi)的靜態(tài)方法
  • 使用反射方式來(lái)強(qiáng)制創(chuàng)建某個(gè)類(lèi)或接口對(duì)應(yīng)的java.lang.Class對(duì)象
  • 初始化某個(gè)類(lèi)的子類(lèi)
  • 直接使用java.exe命令來(lái)運(yùn)行某個(gè)主類(lèi)

類(lèi)加載器

  • 負(fù)責(zé)將.class文件加載到內(nèi)存中嗜桌,并為之生成對(duì)應(yīng)的Class對(duì)象辞色。
  • 雖然我們不需要關(guān)心類(lèi)加載機(jī)制,但是了解這個(gè)機(jī)制我們就能更好的理解程序的運(yùn)行相满。
  • 類(lèi)加載器的組成
    • Bootstrap ClassLoader 根類(lèi)加載器
    • Extension ClassLoader 擴(kuò)展類(lèi)加載器
    • Sysetm ClassLoader 系統(tǒng)類(lèi)加載器

類(lèi)加載器的作用

  • Bootstrap ClassLoader 根類(lèi)加載器
    • 也被稱(chēng)為引導(dǎo)類(lèi)加載器层亿,負(fù)責(zé)Java核心類(lèi)的加載
      • 比如System,String等悯辙。在JDK中JRE的lib目錄下rt.jar文件中
  • Extension ClassLoader 擴(kuò)展類(lèi)加載器
    • 負(fù)責(zé)JRE的擴(kuò)展目錄jar包的加載。
      • 在JDK中JRE的lib目錄ext目錄
  • Sysetm ClassLoader 系統(tǒng)類(lèi)加載器
    • 負(fù)責(zé)在JVM啟動(dòng)時(shí)加載來(lái)自java命令的class文件脉幢,以及classpath環(huán)境變量所指定的jar包和類(lèi)路徑


反射

  • JAVA反射機(jī)制是在運(yùn)行狀態(tài)中沪曙,對(duì)于任意一個(gè)類(lèi),都能夠知道這個(gè)類(lèi)的所有屬性和方法儿子;對(duì)于任意一個(gè)對(duì)象,都能夠調(diào)用它的任意一個(gè)方法和屬性;這種動(dòng)態(tài)獲取的信息以及動(dòng)態(tài)調(diào)用對(duì)象的方法的功能稱(chēng)為java語(yǔ)言的反射機(jī)制瞬哼。
  • 要想解剖一個(gè)類(lèi),必須先要獲取到該類(lèi)的字節(jié)碼文件對(duì)象结胀。而解剖使用的就是Class類(lèi)中的方法沼死。所以先要獲取到每一個(gè)字節(jié)碼文件對(duì)應(yīng)的Class類(lèi)型的對(duì)象秀姐。

通過(guò)反射獲取構(gòu)造方法并使用

  • 獲取構(gòu)造方法
    • getConstructors
    • getDeclaredConstructors
  • 創(chuàng)建對(duì)象
    • newInstance()
    • con.newInstance(“zhangsan", 20);
  • 獲取所有成員
    • getFields,getDeclaredFields
  • 獲取單個(gè)成員
    • getField,getDeclaredField
  • 修改成員的值
    • set(Object obj,Object value)
      • 將指定對(duì)象變量上此 Field 對(duì)象表示的字段設(shè)置為指定的新值恤磷。
  • 獲取所有方法
    • getMethods
    • getDeclaredMethods
  • 獲取單個(gè)方法
    • getMethod
    • getDeclaredMethod
  • 暴力訪(fǎng)問(wèn)
    • method.setAccessible(true);
  • 獲取class文件對(duì)象的方式:

    • A:Object類(lèi)的getClass()方法
    • B:數(shù)據(jù)類(lèi)型的靜態(tài)屬性class
    • C:Class類(lèi)中的靜態(tài)方法
      • public static Class forName(String className)
  • 一般我們使用誰(shuí)呢?

    • A:自己玩 任選一種虎敦,第二種比較方便
    • B:開(kāi)發(fā) 第三種
    • 為什么呢?因?yàn)榈谌N是一個(gè)字符串吭历,而不是一個(gè)具體的類(lèi)名。這樣我們就可以把這樣的字符串配置到配置文件中遣总。
  • 通過(guò)反射獲取無(wú)參構(gòu)造方法并使用

/*
 * 反射:就是通過(guò)class文件對(duì)象垂券,去使用該文件中的成員變量熙揍,構(gòu)造方法,成員方法。
 * Class類(lèi):
 *      成員變量    Field
 *      構(gòu)造方法    Constructor
 *      成員方法    Method
 * 
 */
public class ReflectDemo {
    public static void main(String[] args) throws ClassNotFoundException {
        // 方式1
        Person p = new Person();
        Class c = p.getClass();

        Person p2 = new Person();
        Class c2 = p2.getClass();

        System.out.println(p == p2);// false
        System.out.println(c == c2);// true

        // 方式2
        Class c3 = Person.class;
        // int.class;
        // String.class;
        System.out.println(c == c3);

        // 方式3
        // ClassNotFoundException
        Class c4 = Class.forName("cn.itcast_01.Person");
        System.out.println(c == c4);
    }
}




public class Person {
    private String name;
    int age;
    public String address;

    public Person() {
    }

    private Person(String name) {
        this.name = name;
    }

    Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public Person(String name, int age, String address) {
        this.name = name;
        this.age = age;
        this.address = address;
    }

    public void show() {
        System.out.println("show");
    }

    public void method(String s) {
        System.out.println("method " + s);
    }

    public String getString(String s, int i) {
        return s + "---" + i;
    }

    private void function() {
        System.out.println("function");
    }

    @Override
    public String toString() {
        return "Person [name=" + name + ", age=" + age + ", address=" + address
                + "]";
    }

}


  • 通過(guò)反射獲取無(wú)參構(gòu)造方法的使用
/*
 * 通過(guò)反射獲取構(gòu)造方法并使用。
 */
public class ReflectDemo {
    public static void main(String[] args) throws Exception {
        // 獲取字節(jié)碼文件對(duì)象
        Class c = Class.forName("cn.itcast_01.Person");

        // 獲取構(gòu)造方法
        // public Constructor[] getConstructors():所有公共構(gòu)造方法
        // public Constructor[] getDeclaredConstructors():所有構(gòu)造方法
        // Constructor[] cons = c.getDeclaredConstructors();
        // for (Constructor con : cons) {
        // System.out.println(con);
        // }

        // 獲取單個(gè)構(gòu)造方法
        // public Constructor<T> getConstructor(Class<?>... parameterTypes)
        // 參數(shù)表示的是:你要獲取的構(gòu)造方法的構(gòu)造參數(shù)個(gè)數(shù)及數(shù)據(jù)類(lèi)型的class字節(jié)碼文件對(duì)象
        Constructor con = c.getConstructor();// 返回的是構(gòu)造方法對(duì)象

        // Person p = new Person();
        // System.out.println(p);
        // public T newInstance(Object... initargs)
        // 使用此 Constructor 對(duì)象表示的構(gòu)造方法來(lái)創(chuàng)建該構(gòu)造方法的聲明類(lèi)的新實(shí)例勇吊,并用指定的初始化參數(shù)初始化該實(shí)例。
        Object obj = con.newInstance();
        System.out.println(obj);
        
        // Person p = (Person)obj;
        // p.show();
    }
}


  • 獲取帶參構(gòu)造方法
/*
 * 需求:通過(guò)反射去獲取該構(gòu)造方法并使用:
 * public Person(String name, int age, String address)
 * 
 * Person p = new Person("林青霞",27,"北京");
 * System.out.println(p);
 */
 
public class ReflectDemo2 {
    public static void main(String[] args) throws Exception {
        // 獲取字節(jié)碼文件對(duì)象
        Class c = Class.forName("cn.itcast_01.Person");

        // 獲取帶參構(gòu)造方法對(duì)象
        // public Constructor<T> getConstructor(Class<?>... parameterTypes)
        Constructor con = c.getConstructor(String.class, int.class,
                String.class);

        // 通過(guò)帶參構(gòu)造方法對(duì)象創(chuàng)建對(duì)象
        // public T newInstance(Object... initargs)
        Object obj = con.newInstance("林青霞", 27, "北京");
        
        System.out.println(obj);
    }
}


  • 獲取私有構(gòu)造方法并使用
/*
 * 需求:通過(guò)反射獲取私有構(gòu)造方法并使用
 * private Person(String name){}
 * 
 * Person p = new Person("風(fēng)清揚(yáng)");
 * System.out.println(p);
 */
public class ReflectDemo3 {
    public static void main(String[] args) throws Exception {
        // 獲取字節(jié)碼文件對(duì)象
        Class c = Class.forName("cn.itcast_01.Person");

        // 獲取私有構(gòu)造方法對(duì)象
        // NoSuchMethodException:每有這個(gè)方法異常
        // 原因是一開(kāi)始我們使用的方法只能獲取公共的碟狞,下面這種方式就可以了啄枕。
        Constructor con = c.getDeclaredConstructor(String.class);

        // 用該私有構(gòu)造方法創(chuàng)建對(duì)象
        // IllegalAccessException:非法的訪(fǎng)問(wèn)異常。
        // 暴力訪(fǎng)問(wèn)
        con.setAccessible(true);// 值為true則指示反射的對(duì)象在使用時(shí)應(yīng)該取消Java語(yǔ)言訪(fǎng)問(wèn)檢查族沃。
        Object obj = con.newInstance("風(fēng)清揚(yáng)");

        System.out.println(obj);
    }
}


  • 獲取成員變量并使用
/*
 * 通過(guò)反射獲取成員變量并使用
 */
public class ReflectDemo {
    public static void main(String[] args) throws Exception {
        // 獲取字節(jié)碼文件對(duì)象
        Class c = Class.forName("cn.itcast_01.Person");

        // 獲取所有的成員變量
        // Field[] fields = c.getFields();
        // Field[] fields = c.getDeclaredFields();
        // for (Field field : fields) {
        // System.out.println(field);
        // }

        /*
         * Person p = new Person(); p.address = "北京"; System.out.println(p);
         */

        // 通過(guò)無(wú)參構(gòu)造方法創(chuàng)建對(duì)象
        Constructor con = c.getConstructor();
        Object obj = con.newInstance();
        System.out.println(obj);

        // 獲取單個(gè)的成員變量
        // 獲取address并對(duì)其賦值
        Field addressField = c.getField("address");
        // public void set(Object obj,Object value)
        // 將指定對(duì)象變量上此 Field 對(duì)象表示的字段設(shè)置為指定的新值频祝。
        addressField.set(obj, "北京"); // 給obj對(duì)象的addressField字段設(shè)置值為"北京"
        System.out.println(obj);

        // 獲取name并對(duì)其賦值
        // NoSuchFieldException
        Field nameField = c.getDeclaredField("name");
        // IllegalAccessException
        nameField.setAccessible(true);
        nameField.set(obj, "林青霞");
        System.out.println(obj);

        // 獲取age并對(duì)其賦值
        Field ageField = c.getDeclaredField("age");
        ageField.setAccessible(true);
        ageField.set(obj, 27);
        System.out.println(obj);
    }
}


  • 獲取無(wú)參無(wú)返回值成員方法并使用
  • 獲取帶參數(shù)返回值成員方法并使用
public class ReflectDemo {
    public static void main(String[] args) throws Exception {
        // 獲取字節(jié)碼文件對(duì)象
        Class c = Class.forName("cn.itcast_01.Person");

        // 獲取所有的方法
        // Method[] methods = c.getMethods(); // 獲取自己的包括父親的公共方法
        // Method[] methods = c.getDeclaredMethods(); // 獲取自己的所有的方法
        // for (Method method : methods) {
        // System.out.println(method);
        // }

        Constructor con = c.getConstructor();
        Object obj = con.newInstance();

        /*
         * Person p = new Person(); p.show();
         */

        // 獲取單個(gè)方法并使用
        // public void show()
        // public Method getMethod(String name,Class<?>... parameterTypes)
        // 第一個(gè)參數(shù)表示的方法名,第二個(gè)參數(shù)表示的是方法的參數(shù)的class類(lèi)型
        Method m1 = c.getMethod("show");
        // obj.m1(); // 錯(cuò)誤
        // public Object invoke(Object obj,Object... args)
        // 返回值是Object接收,第一個(gè)參數(shù)表示對(duì)象是誰(shuí)脆淹,第二參數(shù)表示調(diào)用該方法的實(shí)際參數(shù)
        m1.invoke(obj); // 調(diào)用obj對(duì)象的m1方法

        System.out.println("----------");
        // public void method(String s)
        Method m2 = c.getMethod("method", String.class);
        m2.invoke(obj, "hello");
        System.out.println("----------");

        // public String getString(String s, int i)
        Method m3 = c.getMethod("getString", String.class, int.class);
        Object objString = m3.invoke(obj, "hello", 100);
        System.out.println(objString);
        // String s = (String)m3.invoke(obj, "hello",100);
        // System.out.println(s);
        System.out.println("----------");

        // private void function()
        Method m4 = c.getDeclaredMethod("function");
        m4.setAccessible(true);
        m4.invoke(obj);
    }
}


反射應(yīng)用舉例

  • 通過(guò)配置文件運(yùn)行類(lèi)中的方法
public class Student {
    public void love() {
        System.out.println("愛(ài)生活,愛(ài)Java");
    }
}



public class Teacher {
    public void love() {
        System.out.println("愛(ài)生活,愛(ài)青霞");
    }
}



public class Worker {
    public void love() {
        System.out.println("愛(ài)生活,愛(ài)老婆");
    }
}




/*
 * 通過(guò)配置文件運(yùn)行類(lèi)中的方法
 * 
 * 反射:
 *      需要有配置文件配合使用智润。
 *      用class.txt代替。
 *      并且你知道有兩個(gè)鍵未辆。
 *          className
 *          methodName
 */
public class Test {
    public static void main(String[] args) throws Exception {
        // 反射前的做法
        // Student s = new Student();
        // s.love();
        // Teacher t = new Teacher();
        // t.love();
        // Worker w = new Worker();
        // w.love();
        // 反射后的做法

        // 加載鍵值對(duì)數(shù)據(jù)
        Properties prop = new Properties();
        FileReader fr = new FileReader("class.txt");
        prop.load(fr);
        fr.close();

        // 獲取數(shù)據(jù)
        String className = prop.getProperty("className");
        String methodName = prop.getProperty("methodName");

        // 反射
        Class c = Class.forName(className);

        Constructor con = c.getConstructor();
        Object obj = con.newInstance();

        // 調(diào)用方法
        Method m = c.getMethod(methodName);
        m.invoke(obj);
    }
}


  • 我給你ArrayList<Integer>的一個(gè)對(duì)象窟绷,我想在這個(gè)集合中添加一個(gè)字符串?dāng)?shù)據(jù),如何實(shí)現(xiàn)呢咐柜?
public class ArrayListDemo {
    public static void main(String[] args) throws NoSuchMethodException,
            SecurityException, IllegalAccessException,
            IllegalArgumentException, InvocationTargetException {
        // 創(chuàng)建集合對(duì)象
        ArrayList<Integer> array = new ArrayList<Integer>();

        // array.add("hello");
        // array.add(10);

        Class c = array.getClass(); // 集合ArrayList的class文件對(duì)象
        Method m = c.getMethod("add", Object.class);

        m.invoke(array, "hello"); // 調(diào)用array的add方法兼蜈,傳入的值是hello
        m.invoke(array, "world");
        m.invoke(array, "java");

        System.out.println(array);
    }
}


  • 寫(xiě)一個(gè)方法攘残,
    • public void setProperty(Object obj, String propertyName, Object value){},
    • 此方法可將obj對(duì)象中名為propertyName的屬性的值設(shè)置為value为狸。
public class Tool {
    public void setProperty(Object obj, String propertyName, Object value)
            throws NoSuchFieldException, SecurityException,
            IllegalArgumentException, IllegalAccessException {
        // 根據(jù)對(duì)象獲取字節(jié)碼文件對(duì)象
        Class c = obj.getClass();
        // 獲取該對(duì)象的propertyName成員變量
        Field field = c.getDeclaredField(propertyName);
        // 取消訪(fǎng)問(wèn)檢查
        field.setAccessible(true);
        // 給對(duì)象的成員變量賦值為指定的值
        field.set(obj, value);
    }
}




public class ToolDemo {
    public static void main(String[] args) throws NoSuchFieldException,
            SecurityException, IllegalArgumentException, IllegalAccessException {
        Person p = new Person();
        Tool t = new Tool();
        t.setProperty(p, "name", "林青霞");
        t.setProperty(p, "age", 27);
        System.out.println(p);
        System.out.println("-----------");

        Dog d = new Dog();

        t.setProperty(d, "sex", '男');
        t.setProperty(d, "price", 12.34f);

        System.out.println(d);
    }
}

class Dog {
    char sex;
    float price;

    @Override
    public String toString() {
        return sex + "---" + price;
    }
}

class Person {
    private String name;
    public int age;

    @Override
    public String toString() {
        return name + "---" + age;
    }
}


動(dòng)態(tài)代理

  • 代理:本來(lái)應(yīng)該自己做的事情歼郭,卻請(qǐng)了別人來(lái)做,被請(qǐng)的人就是代理對(duì)象辐棒。

    • 舉例:春季回家買(mǎi)票讓人代買(mǎi)
  • 動(dòng)態(tài)代理:在程序運(yùn)行過(guò)程中產(chǎn)生的這個(gè)對(duì)象

    • 而程序運(yùn)行過(guò)程中產(chǎn)生對(duì)象其實(shí)就是我們剛才反射講解的內(nèi)容病曾,所以,動(dòng)態(tài)代理其實(shí)就是通過(guò)反射來(lái)生成一個(gè)代理漾根。
  • 在Java中java.lang.reflect包下提供了一個(gè)Proxy類(lèi)和一個(gè)InvocationHandler接口泰涂,通過(guò)使用這個(gè)類(lèi)和接口就可以生成動(dòng)態(tài)代理對(duì)象。JDK提供的代理只能針對(duì)接口做代理辐怕。我們有更強(qiáng)大的代理cglib逼蒙。

  • Proxy類(lèi)中的方法創(chuàng)建動(dòng)態(tài)代理類(lèi)對(duì)象

    • public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
      • 最終會(huì)調(diào)用InvocationHandler的方法
        • Object invoke(Object proxy,Method method,Object[] args)
  • Proxy類(lèi)中創(chuàng)建動(dòng)態(tài)代理對(duì)象的方法的三個(gè)參數(shù):

    • ClassLoader對(duì)象,定義了由哪個(gè)ClassLoader對(duì)象 來(lái)對(duì) 生成的 代理對(duì)象進(jìn)行加載寄疏。
    • Interface對(duì)象的數(shù)組是牢,表示的是 我將要 給 我需要代理的對(duì)象 提供一組什么接口,如果我提供了一組接口給它陕截,那么這個(gè)代理對(duì)象就宣稱(chēng)實(shí)現(xiàn)了該接口(多態(tài))驳棱,這樣我就能調(diào)用這組接口中的方法了。
    • InvocationHandler對(duì)象农曲,表示的是 當(dāng)我這個(gè)動(dòng)態(tài)代理對(duì)象 在調(diào)用方法的時(shí)候蹈胡,會(huì)關(guān)聯(lián)到哪一個(gè)InvocationHandler對(duì)象上。
  • 每一個(gè)動(dòng)態(tài)代理類(lèi)都必須要實(shí)現(xiàn)InvocationHandler這個(gè)接口朋蔫,并且每個(gè)代理類(lèi)的實(shí)例都關(guān)聯(lián)到了一個(gè)handler,當(dāng)我們通過(guò)代理對(duì)象調(diào)用一個(gè)方法的時(shí)候却汉,這個(gè)方法的調(diào)用就會(huì)被轉(zhuǎn)發(fā)為由InvocationHandler這個(gè)接口的invoke方法來(lái)進(jìn)行調(diào)用驯妄。

  • InvocationHandler接口中invoke方法的三個(gè)參數(shù):

    • proxy:代表動(dòng)態(tài)代理對(duì)象
    • method:代表正在執(zhí)行的方法
    • args:代表調(diào)用目標(biāo)方法時(shí)傳入的實(shí)參
  • Proxy.newProxyInstance

    • 創(chuàng)建的代理對(duì)象是在jvm運(yùn)行時(shí)動(dòng)態(tài)生成的一個(gè)對(duì)象,它并不是我們的InvocationHandler類(lèi)型合砂,也不是我們定義的那組接口的類(lèi)型青扔,而是在運(yùn)行是動(dòng)態(tài)生成的一個(gè)對(duì)象,并且命名方式都是這樣的形式翩伪,以$開(kāi)頭微猖,proxy為中,最后一個(gè)數(shù)字表示對(duì)象的標(biāo)號(hào)缘屹。
public class MyInvocationHandler implements InvocationHandler {
    private Object target; // 目標(biāo)對(duì)象

    public MyInvocationHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        System.out.println("權(quán)限校驗(yàn)");
        Object result = method.invoke(target, args);
        System.out.println("日志記錄");
        return result; // 返回的是代理對(duì)象
    }
}


public interface StudentDao {
    public abstract void login();

    public abstract void regist();
}



public class StudentDaoImpl implements StudentDao {

    @Override
    public void login() {
        System.out.println("登錄功能");
    }

    @Override
    public void regist() {
        System.out.println("注冊(cè)功能");
    }

}



/*
 * 用戶(hù)操作接口
 */
public interface UserDao {
    public abstract void add();

    public abstract void delete();

    public abstract void update();

    public abstract void find();
}



public class UserDaoImpl implements UserDao {

    @Override
    public void add() {
        System.out.println("添加功能");
    }

    @Override
    public void delete() {
        System.out.println("刪除功能");
    }

    @Override
    public void update() {
        System.out.println("修改功能");
    }

    @Override
    public void find() {
        System.out.println("查找功能");
    }

}



public class Test {
    public static void main(String[] args) {
        UserDao ud = new UserDaoImpl();
        ud.add();
        ud.delete();
        ud.update();
        ud.find();
        System.out.println("-----------");
        // 我們要?jiǎng)?chuàng)建一個(gè)動(dòng)態(tài)代理對(duì)象
        // 我準(zhǔn)備對(duì)ud對(duì)象做一個(gè)代理對(duì)象
        MyInvocationHandler handler = new MyInvocationHandler(ud);
        UserDao proxy = (UserDao) Proxy.newProxyInstance(ud.getClass()
                .getClassLoader(), ud.getClass().getInterfaces(), handler);
        proxy.add();
        proxy.delete();
        proxy.update();
        proxy.find();
        System.out.println("-----------");

        StudentDao sd = new StudentDaoImpl();
        MyInvocationHandler handler2 = new MyInvocationHandler(sd);
        StudentDao proxy2 = (StudentDao) Proxy.newProxyInstance(sd.getClass()
                .getClassLoader(), sd.getClass().getInterfaces(), handler2);
        proxy2.login();
        proxy2.regist();
    }
}




模版設(shè)計(jì)模式(抽象類(lèi))

  • 模版方法模式就是定義一個(gè)算法的骨架凛剥,而將具體的算法延遲到子類(lèi)中來(lái)實(shí)現(xiàn)
  • 優(yōu)點(diǎn)
    • 使用模版方法模式,在定義算法骨架的同時(shí)轻姿,可以很靈活的實(shí)現(xiàn)具體的算法犁珠,滿(mǎn)足用戶(hù)靈活多變的需求
  • 缺點(diǎn)
    • 如果算法骨架有修改的話(huà)逻炊,則需要修改抽象類(lèi)
public class ForDemo extends GetTime {

    @Override
    public void code() {
        for (int x = 0; x < 100000; x++) {
            System.out.println(x);
        }
    }

}



public abstract class GetTime {
    // 需求:請(qǐng)給我計(jì)算出一段代碼的運(yùn)行時(shí)間
    public long getTime() {
        long start = System.currentTimeMillis();
        code();

        long end = System.currentTimeMillis();

        return end - start;
    }

    public abstract void code();
}



public class GetTimeDemo {
    public static void main(String[] args) {
        // GetTime gt = new GetTime();
        // System.out.println(gt.getTime() + "毫秒");

        GetTime gt = new ForDemo();
        System.out.println(gt.getTime() + "毫秒");

        gt = new IODemo();
        System.out.println(gt.getTime() + "毫秒");
    }
}




public class IODemo extends GetTime{

    @Override
    public void code() {
        try {
            BufferedInputStream bis = new BufferedInputStream(
                    new FileInputStream("a.avi"));
            BufferedOutputStream bos = new BufferedOutputStream(
                    new FileOutputStream("b.avi"));
            byte[] bys = new byte[1024];
            int len = 0;
            while ((len = bis.read(bys)) != -1) {
                bos.write(bys, 0, len);
            }
            bos.close();
            bis.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
}


裝飾設(shè)計(jì)模式

  • 裝飾模式就是使用被裝飾類(lèi)的一個(gè)子類(lèi)的實(shí)例,在客戶(hù)端將這個(gè)子類(lèi)的實(shí)例交給裝飾類(lèi)犁享。是繼承的替代方案
  • 優(yōu)點(diǎn)
    • 使用裝飾模式余素,可以提供比繼承更靈活的擴(kuò)展對(duì)象的功能,它可以動(dòng)態(tài)的添加對(duì)象的功能炊昆,并且可以隨意的組合這些功能
  • 缺點(diǎn)
    • 正因?yàn)榭梢噪S意組合桨吊,所以就可能出現(xiàn)一些不合理的邏輯
public interface Phone {
    public abstract void call();
}



public class IPhone implements Phone {

    @Override
    public void call() {
        System.out.println("手機(jī)可以打電話(huà)了");
    }

}



public class MusicPhoneDecorate extends PhoneDecorate {

    public MusicPhoneDecorate(Phone p) {
        super(p);
    }

    @Override
    public void call() {
        super.call();
        System.out.println("手機(jī)可以聽(tīng)音樂(lè)");
    }
}





public class RingPhoneDecorate extends PhoneDecorate {

    public RingPhoneDecorate(Phone p) {
        super(p);
    }

    @Override
    public void call() {
        System.out.println("手機(jī)可以聽(tīng)彩鈴");
        super.call();
    }
}



public abstract class PhoneDecorate implements Phone {

    private Phone p;

    public PhoneDecorate(Phone p) {
        this.p = p;
    }

    @Override
    public void call() {
        this.p.call();
    }
}




public class PhoneDemo {
    public static void main(String[] args) {
        Phone p = new IPhone();
        p.call();
        System.out.println("------------");

        // 需求:我想在接電話(huà)前,聽(tīng)彩鈴
        PhoneDecorate pd = new RingPhoneDecorate(p);
        pd.call();
        System.out.println("------------");

        // 需求:我想在接電話(huà)后凤巨,聽(tīng)音樂(lè)
        pd = new MusicPhoneDecorate(p);
        pd.call();
        System.out.println("------------");

        // 需求:我要想手機(jī)在接前聽(tīng)彩鈴视乐,接后聽(tīng)音樂(lè)
        // 自己提供裝飾類(lèi),在打電話(huà)前聽(tīng)彩鈴磅甩,打電話(huà)后聽(tīng)音樂(lè)
        pd = new RingPhoneDecorate(new MusicPhoneDecorate(p));
        pd.call();
        System.out.println("----------");
        // 想想我們?cè)贗O流中的使用
        // InputStream is = System.in;
        // InputStreamReader isr = new InputStreamReader(is);
        // BufferedReader br = new BufferedReader(isr);
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter((new OutputStreamWriter(
                System.out)));

        Scanner sc = new Scanner(System.in);
    }
}




最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末炊林,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子卷要,更是在濱河造成了極大的恐慌渣聚,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,324評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件僧叉,死亡現(xiàn)場(chǎng)離奇詭異奕枝,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)瓶堕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,356評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)隘道,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人郎笆,你說(shuō)我怎么就攤上這事谭梗。” “怎么了宛蚓?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,328評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵激捏,是天一觀(guān)的道長(zhǎng)。 經(jīng)常有香客問(wèn)我凄吏,道長(zhǎng)远舅,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,147評(píng)論 1 292
  • 正文 為了忘掉前任痕钢,我火速辦了婚禮图柏,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘任连。我一直安慰自己蚤吹,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,160評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布随抠。 她就那樣靜靜地躺著距辆,像睡著了一般余佃。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上跨算,一...
    開(kāi)封第一講書(shū)人閱讀 51,115評(píng)論 1 296
  • 那天爆土,我揣著相機(jī)與錄音,去河邊找鬼诸蚕。 笑死步势,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的背犯。 我是一名探鬼主播坏瘩,決...
    沈念sama閱讀 40,025評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼漠魏!你這毒婦竟也來(lái)了倔矾?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 38,867評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤柱锹,失蹤者是張志新(化名)和其女友劉穎哪自,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體禁熏,經(jīng)...
    沈念sama閱讀 45,307評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡壤巷,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,528評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了瞧毙。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片胧华。...
    茶點(diǎn)故事閱讀 39,688評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖宙彪,靈堂內(nèi)的尸體忽然破棺而出矩动,到底是詐尸還是另有隱情,我是刑警寧澤释漆,帶...
    沈念sama閱讀 35,409評(píng)論 5 343
  • 正文 年R本政府宣布悲没,位于F島的核電站,受9級(jí)特大地震影響灵汪,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜柑潦,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,001評(píng)論 3 325
  • 文/蒙蒙 一享言、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧渗鬼,春花似錦览露、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,657評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)命锄。三九已至,卻和暖如春偏化,著一層夾襖步出監(jiān)牢的瞬間脐恩,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,811評(píng)論 1 268
  • 我被黑心中介騙來(lái)泰國(guó)打工侦讨, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留驶冒,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,685評(píng)論 2 368
  • 正文 我出身青樓韵卤,卻偏偏與公主長(zhǎng)得像骗污,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子沈条,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,573評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容