【230天】黑馬程序員27天視頻學習筆記【Day27-下】

叨叨兩句

  1. 今天學習內容好多,忙暈了,明天填坑
  2. 今天學習時間沒安排好,雖然總體學習效果不錯,可是今天的任務完成的很差,不加分,算作小小的懲罰
  3. 坑沒填完,繼續填(2017.9.24)

27-04: 反射Class.forName()讀取配置文件

package test;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;

public class Demo_reflect {
    public static void main(String[] args) throws Exception {
        Juicer j = new Juicer();
        BufferedReader br = new BufferedReader(new FileReader("config.properties")); 
        Class clazz = Class.forName(br.readLine());
        Fruit f = (Fruit)clazz.newInstance();
        j.run(f);
    }
    
}

interface Fruit {
    public void squeeze();
}

class Juicer {
    public void run(Fruit f) {
        f.squeeze();
    }
}

class Apple implements Fruit {
    public void squeeze() {
        System.out.println("蘋果汁好了");
    }
}

class Orange implements Fruit {
    public void squeeze() {
        System.out.println("橘子汁好了");
    }
}

27-05: 經過過反射獲取帶參構造方法並使用

關注點

  1. Class類的newInstance方法是使用該類的無參構造函數建立對象,若是一個類沒有無參構造函數,就不能這樣建立了,須要使用Constructor類的newInstance方法。

思路

  1. 拿到Person類的字節碼文件
  2. 使用getConstructor方法獲取有參構造方法【該方法也能夠獲取無參構造方法,參數列表不傳參便可】
  3. 使用Constructor類的newInstance方法建立對象【注意,不是Class類的方法】
package com.test;

import java.io.BufferedReader;
import java.io.FileReader;
import java.lang.reflect.Constructor;

public class Demo_reflect_1 {
    //拿到Person類的有參構造函數並建立對象
    public static void main(String[] args) throws Exception {
        //拿到Person的字節碼文件
        BufferedReader br = new BufferedReader(new FileReader("config.properties"));
        Class clazz = Class.forName(br.readLine());
        //獲取Person的有參構造函數
        Constructor c = clazz.getConstructor(String.class,int.class);
        //建立Person對象【有參】
        Person p = (Person)c.newInstance("張三",23);
        //打印
        System.out.println(p);
        
    }

}

27-06:經過反射獲取成員變量並使用

關注點

  1. 針對非私有的成員變量java

    1. 使用Class類中的getField方法便可獲取指定字段【返回Field對象】
    2. 使用已傳入特定字段的Field對象中的set方法能夠將傳入的Person對象的指定字段修改成指定的值。
  2. 針對私有的成員變量算法

    1. 使用Class類中的getDeclaredField方法便可獲取指定字段【返回Field對象】
    2. 使用已傳入特定字段的Field對象中的setAccessible(true)方法能夠去除私有權限
    3. 使用已傳入特定字段的Field對象中的set方法能夠將傳入的Person對象的指定字段修改成指定的值。
package com.test;

import java.io.BufferedReader;
import java.io.FileReader;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;

public class Demo_reflect_2 {
    /**
     * @param args
     * 經過反射的方式得到成員變量並修改
     * @throws Exception 
     * @throws ClassNotFoundException 
     */
    public static void main(String[] args) throws ClassNotFoundException, Exception {
        //經過IO流讀取配置文件
        BufferedReader br = new BufferedReader(new FileReader("config.properties"));
        //獲取字節碼文件
        Class clazz = Class.forName(br.readLine());
        //經過獲取的字節碼文件獲取有參構造函數
        Constructor c = clazz.getConstructor(String.class,int.class);
        //經過獲取的有參構造新建一個完成初始化的Person對象
        Person p = (Person)c.newInstance("張三",23);

        //1.屬性非私有的狀況
        
//            //獲取字節碼文件中的指定字段name
//            Field f = clazz.getField("name");
//            //經過獲取的指定字段修改Person對象的name屬性
//            f.set(p,"李四");
//            
        
        //2.私有的狀況【使用暴力反射】
        
            //獲取字節碼文件中的指定字段name
            Field f = clazz.getDeclaredField("name"); 
            //去除私有權限
            f.setAccessible(true);
            //經過獲取的指定字段修改Person對象的name屬性
            f.set(p,"李四");
            
        //打印測試
        System.out.println(p);
    }
}

27-07:經過反射獲取方法並使用

主要內容

  1. 獲取無參的方法設計模式

    1. 使用Class類的getMethod(方法名)方法獲取字節碼文件中的方【返回Method對象】
    2. 使用Method類的方法invoke(指定對象)運行獲取的方法。
  2. 獲取有參的方法ide

    1. 使用Class類的getMethod(方法,參數類型的字節碼文件)方法獲取字節碼文件中的方【返回Method對象】
    2. 使用Method類的方法invoke(指定對象,獲取的方法的參數)運行獲取的方法。

其它內容

  1. 對於私有方法,獲取並使用的方式和獲取私有成員變量的方式差很少。
package com.test;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

/**
 * @author XPS
 * 經過反射獲取方法並使用
 */
public class Demo_reflect_3 {
    public static void main(String[] args) throws Exception, Exception {
        //獲取字節碼文件
        BufferedReader br = new BufferedReader(new FileReader("config.properties"));
        Class clazz = Class.forName(br.readLine());
        //經過獲取的字節碼文件獲取有參構造函數
        Constructor c = clazz.getConstructor(String.class,int.class);
        //新建一個初始化的Person對象p
        Person p = (Person)c.newInstance("張三",23);
        
//        //1. 獲取無參方法
//            //經過反射得到這個字節碼中的方法eat
//            Method m = clazz.getMethod("eat");
//            //運行p的eat方法
//            m.invoke(p);
        //2. 獲取有參方法
            //經過反射得到這個字節碼中的方法eat(int num)
            Method m = clazz.getMethod("eat",int.class);
            //運行p的eat方法
            m.invoke(p,2);
    }
    
    
    
}

27-08:經過反射越過泛型檢查

原理

泛型只在編譯期有效,運行期將被擦除,而反射是在運行期獲取字節碼文件來調用方法添加咱們想要添加的字符串函數

package com.test;

import java.lang.reflect.Method;
import java.util.ArrayList;

/**
 * @author XPS
 * 使用反射技術繞過泛型檢查,實現往ArrayList<Integer>中添加字符串"abc"
 * 
 * 原理: 泛型只在編譯期有效,運行期將被擦除,而反射是在運行期獲取字節碼文件來調用方法添加咱們想要添加的字符串
 * 
 */
public class Demo_reflect_4 {

    public static void main(String[] args) throws Exception {
        ArrayList<Integer> list = new ArrayList<>();
        list.add(111);
        list.add(222);
        //list.add("abc");  //這個地方填加字符串會報錯
        
        Class clazz = Class.forName("java.util.ArrayList");
        Method m = clazz.getMethod("add",Object.class);
        m.invoke(list, "abc");
        
        System.out.println(list);
        
    }

}

27-09:使用反射改變指定對象特定屬性爲特定值

package com.test;

public class Demo_reflect_5 {
    public static void main(String[] args) throws Exception {
        Student stu = new Student("張三",23);
        Tool.setProperty(stu, "name", "李四");
        System.out.println(stu);
    }
}


class Student {
    private String name;
    private int age;
    
    public Student() {
        super();
        // TODO Auto-generated constructor stub
    }
    
    public Student(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Student [name=" + name + ", age=" + age + "]";
    }
    
    
}
package com.test;

import java.lang.reflect.Field;

public class Tool {
    public static void setProperty(Object obj, String propertyName, Object value) throws Exception, SecurityException {
        Class clazz = obj.getClass();
        Field f = clazz.getDeclaredField(propertyName);
        f.setAccessible(true);
        f.set(obj, value);
    }
}

27-10:反射練習

package com.test;

import java.io.BufferedReader;
import java.io.FileReader;

import cn.itcast.heima.DemoClass;

public class Demo_reflect_6 {

    /**
     * @param args
     * 
     * 已知一個類,定義以下:
     * package cn.itcast.heima;
        public class DemoClass { public void run() { System.out.println("welcome to heima!"); } }
        (1) 寫一個Properties格式的配置文件,配置類的完整名稱。
        (2) 寫一個程序,讀取這個Properties配置文件,得到類的完整名稱並加載這個類,用反射的方式運行run方法。
     * @throws Exception 
     * @throws ClassNotFoundException 
     * 
     */
    
    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new FileReader("XXX.properties"));
        Class clazz = Class.forName(br.readLine());
        DemoClass d = (DemoClass)clazz.newInstance();
        d.run();
    }

}
package cn.itcast.heima;

public class DemoClass {
    public void run() {
        System.out.println("Welcome to heima!");
    }
}

27-11:動態代理的概述和實現

留坑待填

27-12:設計模式(模板(Template)設計模式概述和使用)

模板設計模式

定義一個算法的骨架,而將具體的算法延遲到子類中實現學習

優勢

使用模板方法模式在定義算法骨架的同時,能夠靈活的實現具體算法,知足用戶靈活多變的需求。測試

缺點

若是算法骨架有修改,須要修改抽象類ui

使用模板設計模式前

package com.test;

public class Demo_reflect_9 {

    public static void main(String[] args) {
        long start = System.currentTimeMillis();
        for(int i = 0; i < 100000; i++) {
            System.out.println("x");
        }
        long end = System.currentTimeMillis();
        System.out.println(end - start);
    }

}

使用模板設計模式後

package com.test;

public class Demo_reflect_9 {
    public static void main(String[] args) {
        Demo d = new Demo();
        System.out.println(d.getTime());
    }
}

abstract class GetTime {
    public final long getTime() {
        long start = System.currentTimeMillis();
        code();
        long end = System.currentTimeMillis();
        return end - start;
    }
    
    public abstract void code();
}


class Demo extends GetTime {

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

個人理解

  1. 一個抽象類中,寫一個final修飾的必需要執行的方法,再寫一個可以讓子類隨便定義的抽象方法。

27-(13-16):JDK5新特性

本身實現枚舉類

經過enum實現枚舉類

枚舉注意事項

枚舉類常見方法

27-17:JDK7的六個新特性回顧和講解

27-18:JDK8新特性

相關文章
相關標籤/搜索