反射

反射   重要的底層技術  開發工具和框架 1.2時就出現了
一、基本概念
(1)java類 用於描述一類事物的共性,只負責告訴我們這個類有什麼屬性,沒有什麼屬性,至於屬性的值是由實例對象來決定的。
(2)類對象和類的對象:類對象:類加載的產物,記錄了類的信息。這個類是Class.
    1、補充:
         這就能過解釋爲什麼強轉的時候,編譯器會知道,一個類的父類和子類是什麼,因爲信息被一個類記錄了,根據信息,編譯器就能過限制很多寫法。
         接口在強轉中比較特殊,是因爲如果是一個接口的話,編譯器可能不會去找它的繼承關係,都認爲有類繼承於它或者它實現別的類。
         例子: class Student{}
                interface snior extends Student{}//編譯不通過 因爲是接口 所以接口只能繼承接口 不能繼承普通類
          這個波重要:這就是可以從技術上解釋這個規範,剩下的就是從生活中解釋規範
    2、語法:
        Class cls = 字節碼;
        可以解釋編譯的情況,編譯的時候是會掃描字節碼文件,如果不存在會報錯。而負責這個的是系統組件ClassLoader,即當遇到一個未知的類時(系統沒有,之前也沒加載的)會生成字節碼,然後後面的使用,才能拿到類的信息。
        所以字節碼文件存的是一個類的信息。 Class會創建一個引用指向它。
(3)獲得類對象的方式:
1)  類名.class   直接獲得類對象   還可以獲得基本類型的類對象  double.class
2)  類的對象.getClass()  獲得對應的類對象
3)  Class.forName("類的全名")  通過類名獲得類對象 兩個意思:沒有加載的要加載 加載的我要拿到
 
(4)常見方法
newInstance(): 通過類對象 創建類的對象 (調用類的無參構造方法)
    代替了構造方法中的newInstance 簡化了步驟
    源代碼也揭示了反射比較耗時,影響效率。
invoke():來自Method方法  對某對象調用該方法
Class.isPrimitive int.class = Integer.TYPE;這個對象是否是基本類型(原始類型)
int[].Class.isPrimitive 是對數組的類型判斷 不是對數組的中的元素類型判斷 所以這個方法的結果不是原始類型 因爲數組是對象類型
int[].Class.isArray 判定原類型是否是數組
(5)9個預定義的的Class文件 8種基本類型和void類型
只要程序中出現的類型,都有各自的Class實例對象。例如int[],void
(6)反射
1、定義:將java類中的各種成分映射成相應的java類
2、應用:
    (1)得到一個類的構造方法
            String className = "java.lang.String";
            Constructor[] constructors = Class.forName(className).getConstructors();
            Constructor constructor = Class.forName(className).getConstructor(StringBuffer.class);
            System.out.println(constructors.length);
            System.out.println(constructor.toString());
            Constructor constructor = Class.forName(className).getConstructor(2);//這句代碼執行不通過 由於構造方法是並列的,不能按照順序取出構造方法。
            getConstructor()方法的參數列表形式:Class<?> parameterType
            getConstructor(StringBuffer.class,int.class);//編譯不通過,要求可變的參數的類型都是相同的
            //構造的方法的newInstance()
            String className = "java.lang.String";
            Constructor constructor = Class.forName(className)
            .getConstructor(StringBuffer.class);//選擇StringBuffer
            //構造方法
            String s = (String) constructor.newInstance(
                    new StringBuffer("a"));//用這個對象的時候要
            //傳一個這個StringBuffer參數
            //不好的地方 程序猿可能不知道constructor的所屬是Data還是String
            //的構造方法
    (2)得到成員變量
    class ReflectPoint{
    private int x;
    public int y;
    public ReflectPoint(int x, int y) {
        super();
        this.x = x;
        this.y = y;
    }
    
}
    public static void main(String[] args) throws Exception{
        /*ReflectPoint rflctPoint = new ReflectPoint(1,2);
        //得到字節碼,拿到成員變量的信息
        Class cls = rflctPoint.getClass();
        //拿到要求的、特定的成員變量的信息
        Field fld = cls.getField("y");
        //根據拿到的信息,實例化一個信息
        System.out.println(fld.get(rflctPoint));*/
        //暴力反射訪問私有
        /*ReflectPoint r = new ReflectPoint(4,5);
        Class cls = r.getClass();
        Field fld = cls.getDeclaredField("x");//能夠看到了 但拿不到
        fld.setAccessible(true);//我要拿到它
        System.out.println(fld.get(r));*///拿到了
        
    }
    //例子
    public class practice {
    public static void main(String[] args) throws Exception{        
        ReflectPoint f = new ReflectPoint(1,2);
        changeValue(f);
        System.out.println(f);
    }
    public static void changeValue (Object obj)throws Exception{
        Field[] flds = obj.getClass().getDeclaredFields();
        //System.out.println(flds.length);
        for(Field fld:flds){
            //System.out.println(fld.getType()==String.class);
            if(fld.getType()==String.class){
                String oldValue =(String)fld.get(obj);
                String newValue = oldValue.replace('b', '2');
                System.out.println(newValue);
                fld.set(obj, newValue);
            }
        }
    }
}

class ReflectPoint{
    private int x;
    public int y;
    public String s1 = "abc";
    public String s2 = "bcd";
    public String s3 = "cde";
    public ReflectPoint(int x, int y) {
        //super();
        this.x = x;
        this.y = y;
    }
    @Override
    public String toString() {
        return "ReflectPoint [s1=" + s1 + ", s2=" + s2 + ", s3=" + s3 + ", x="
                + x + ", y=" + y + "]";
    }
    
}
    (3)方法
        //得到String中CahrAt的方法
        Method mthd = String.class.getMethod("charAt", int.class);
        String s = "abc";
        //再得到特定對象的CharAt的方法
        System.out.println(mthd.invoke(s,1));//s如果是一個null表示調用的是靜態方法
    (4)對接收數組參數的成員方法進行反射
    public class practice {
    public static void main(String[] args) throws Exception{        
        //根據用戶給我的類,我來調用它裏面的main方法
        //找到用戶給我類的Class信息
        String className = "test.Test";
        Class cls = Class.forName(className);
        //根據給的信息,找到需要的方法
        Method mtd = cls.getMethod("main", String[].class);        
        //調用該方法
        mtd.invoke(null, (Object)new String[]{"aaa","bbb","ccc"});
        //mtd.invoke(null, new Object[]{new String[]{"aaa","bbb","ccc"}});
        //mtd.invoke(null, new String[]{"aaa","bbb","ccc"});//這個方法不會出結果,因爲爲了兼容5.0一下版本,會將這個數組打散成三個元素,而main中的參數要求是一個對象類型 的單個元素。前兩種方法是解決辦法。
    }

}
class Test{
    public static void main(String[] args){
        for(String arg:args){
            System.out.println(arg);
        }
    }
}

其中的main方法不是static
public static void main(String[] args) throws Exception{        
        //對接收數組參數的成員方法進行反射
        //根據用戶給我的類,我來調用它裏面的main方法
        //找到用戶給我類的Class信息
        String className = "test.Test";
        Class cls = Class.forName(className);
        //根據給的信息,找到需要的方法
        Object obj = cls.newInstance();
        Method mtd = cls.getMethod("main", String[].class);        
        //調用該方法
        mtd.invoke(obj, (Object)new String[]{"aaa","bbb","ccc"});
        //mtd.invoke(null, new Object[]{new String[]{"aaa","bbb","ccc"}});
        //mtd.invoke(null, new String[]{"aaa","bbb","ccc"});//這個方法不會出結果,因爲爲了兼容5.0一下版本,會將這個數組打散成三個元素,而main中的參數要求是一個對象類型 的單個元素。前兩種方法是解決辦法。
    
    class Test{
    public  void main(String[] args){
        for(String arg:args){
            System.out.println(arg);
        }
    }
}
    (5)數組與Object的關係及反射類型
        數組的元素類型和緯度相同,那麼這些數組的Class也相同
        例子:int[] a1 = new int[3];
        int[] a2 = new int[2];
        int[][] a3 = new int[3][4];
        String[] a4 = new String[3];
        System.out.println(a1.getClass() == a2.getClass());
        //System.out.println(a1.getClass() == a3.getClass());
        //System.out.println(a1.getClass() == a4.getClass());
        System.out.println(a1.getClass().getName());
        System.out.println(a3.getClass().getName());
        System.out.println(a4.getClass().getName());
        System.out.println(a1.getClass().getSuperclass().getName());
        System.out.println(a1.getClass().getSuperclass().getName());
        Object o1 = a1;
        Object o2 = a3;
        Object o3 = a4;
        //Object[] o3 = a1;//報錯
        Object[] o5 = a3;
        Object[] o6 = a4;
        //這個地方是比較奇特的。。。。用數組對象的引用指向一個數組對象 而不是用一個對象引用指向數組對象
        看這個問題的應用:
            //這個地方的應用可以解釋這個下面現象,當a1是int時,不會使用4.0的方式
        //就是參數不是數組。5.0參數可以變化 String就可以打印出來
        System.out.println(Arrays.asList(a1));
        System.out.println(Arrays.asList(a4));
        System.out.println(Arrays.asList(a3));
    (6)數組的反射應用
    用反射的方式操作數組,例如:我們常要遍歷數組,或者更改某一個數組元素的值,或者取出某個特定下標的元素。
    //數組的反射應用
    public void printObject(Object obj){
        Class cls = obj.getClass();
        if(cls.isArray()){//判斷是否數組
            //遍歷數組
            //Array利用反射操作數組的工具類
            int length = Array.getLength(obj);
            for(int i=0;i<length;i++){
                System.out.println(Array.get(obj, i));
            }
        }else{
            System.out.println(obj);
        }
    }
    
    利用反射得到數組的類型的一個問題:
    Object[] objs = new Object[]{"1",1};
    類型是什麼?
        Object[] objs = new Object[]{"1",1};
        Object obj = objs[0].getClass().getName();
        //String
        Object obj = objs[1].getClass().getName();
        //Integer
        System.out.println(obj);
    數組之前所學說,是同類型的元素放到一起,現在看,這個就有問題了。
    (7)框架的概念及用反射技術開發框架的原理
    我們使用的類有兩種:我們使用別人的:工具類。別人使用我們的:框架。
    框架要解決的問題:我們寫的框架,可以調用以後人們寫的類。
    1、加載配置文件
    2、生成實例newInstance()
package test;

import java.util.*;
import java.io.*;
public class TestReflection {
    public void reflectionApp() throws Exception{
        InputStream ips = new FileInputStream("config.propertis");
        Properties props = new Properties();
        props.load(ips);
        ips.close();
        String className = props.getProperty("className");
        
        Collection<ReflectionPoint> collections = (Collection)Class.forName(className).newInstance();
        ReflectionPoint rfctp1 =new ReflectionPoint(3,3);
        ReflectionPoint rfctp2 =new ReflectionPoint(3,4);
        ReflectionPoint rfctp3 =new ReflectionPoint(3,5);
        ReflectionPoint rfctp4 =new ReflectionPoint(3,3);
        collections.add(rfctp1);
        collections.add(rfctp2);
        collections.add(rfctp3);
        collections.add(rfctp4);
        collections.add(rfctp1);
        System.out.println("ArrayList");
        for(ReflectionPoint rfctp:collections){
            System.out.println(rfctp);
        }
        collections = new HashSet<ReflectionPoint>();
        collections.add(rfctp1);
        collections.add(rfctp2);
        collections.add(rfctp3);
        collections.add(rfctp4);
        collections.add(rfctp1);
        System.out.println("HashSet");
        for(ReflectionPoint rfctp:collections){
            System.out.println(rfctp);
        }
    }
}

class ReflectionPoint{
    //屬性
    private double x;
    private double y;
    //構造方法
    public ReflectionPoint(){}
    public ReflectionPoint(double x,double y){
        this.x = x;
        this.y = y;
    }
    //set和get方法
    public double getX(){return x;}
    public double getY(){return y;}
    public void setX(double x){this.x = x;}
    public void getY(double y){this.y = y;}
    
    //toString
    public String toString(){
        return "X = " + x + " Y = " + y;
    }
    
    //equals
    public boolean equals(Object o){
        /*if(this == o) return true;
        if(o == null) return false;
        if(this.getClass()!=o.getClass())return false;
        ReflectionPoint rf = (ReflectionPoint)o;
        if(rf.getX()!=x)return false;
        if(rf.getY()!=y)return false;
        if(rf.getX()!=x)return false;
        if(rf.getY()!=y)return false;*/
        System.out.println(" equals "+x+"+"+y);
        return true;
    }
    
    //hashcode
    public int hashCode(){
        return (int)x;
    }
}
(8)用類加載器的方法管理資源和配置文件
 配置文件存放路徑:當前工作路徑。
 解決配置文件存放路徑遇到的問題:用戶將信息存放在配置文件中,程序是通過get配置文件信息的方式來找到配置文件。簡單來說就是:配置文件管理配置文件。
 例子:得到項目的絕對路徑之後找到項目中的配置文件。即:絕對路徑+相對路徑。
 應用:將配置文件放到統一的目錄中。
 
 類加載器:可以加載類也可以加載類的配置文件信息。
ClassLoader.getResourceAsStream(String ProjectPath);
ProjectPath = "it\cast\day1\config.properties";
Class.getResourceAsStream(String ProjectParh);
ProjectPath = "config.properties";知道是在我的包裏的。
ProjectPath = "it\cast\day1\config.properties";也可以用這個路徑,我會判斷是否是在我的包裏。 框架中都是將配置文件放到ClassPath中,就是因爲內部的機制是使用類加載器加載的配置文件


   
發佈了33 篇原創文章 · 獲贊 1 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章