黑馬程序員——java反射

---------------------- android培訓java培訓、期待與您交流! ----------------------
反射就是把Java類中各種成分,映射成相應的java類。

關鍵字:Class 代表一類事物。點擊打開鏈接 點擊打開鏈接 點擊打開鏈接 點擊打開鏈接 點擊打開鏈接

getName();getPackage();  getMethod()   getInterfaces() .....

 

語法:Class cls1 = 字節碼;

三種方式得到字節碼:

(1)類名.class  例如 System.class

(2)對象.getClass 例如 new Date().getClass

(3)Class.forName("類名") ;  例子 Class.forName(" java.util.Date");

九個預定義對象: 八個基本類型+ void

 

方法:isPrimitive()來判斷是否是基本類型。

 

int.class ==Integer.TYPE   true

 

數組類型Class實例對象 isArray()判斷是否是數組。

 

在源程序中出現的類型都有各自的Class實例對象,例如 int[ ] ...

 

Filed, Method,constructor  package

constructor 代表某個類中的一個構造方法

getConstructors 得到所有的構造方法

getConstructor 得到一個構造方法  

例子:

Constructor  constructors[  ]  = ClassforName("java.lang.String").getConstructors();

Constructor constructor = ClassforName("java.lang.String").getConstructor(StringBuffer.class);

 

 

 

簡單的描述來區分new關鍵字和newInstance()方法的區別: 

newInstance: 弱類型。低效率。只能調用無參構造。     

new: 強類型。相對高效。能調用任何public構造。 

創建實例對象:

通常方式:

String str = new String (new StringBuffer("abc"));

反射方式:

String str = (String)constructor.newInstance(new StringBuffer("abc"));

(1) //先獲得構造方法

 Constructor constructor1 =  String.class.getConstructor(StringBuffer.class);
  
  //注意類型的強轉
 (2) String str2 =(String) constructor1.newInstance(new StringBuffer("abc"));

調用獲得的方法時,要用到上面相同類型的實例對象。

 

Class.newInstance()方法

例子:

String  obj = (String) Class.forName("java.lang.String").newInstance();

該方法內部先得到默認的構造函數,然後用該構造方法創建實例對象。

package cn.itcast.day1;

 

publicclass ReflectPoint {

 

    privateintx;

    publicinty;

    public ReflectPoint(int x,int y) {

       super();

       this.x = x;

       this.y = y;

    }

   

}

 

 

Filed  代表某個類中的成員變量,

字節碼.getField("str");

打印成員變量具體的值,getField("str").get("對象");

獲取聲明的變量

getDeclaredField

暴利反射

fieldx.setAccessible(true);

 

 //得到所有的成員變量

 Field[] fields =   obj.getClass().getFields();

 

字節碼的比較用“==”

 

    ReflectPoint rp1 = new ReflectPoint(3,5);

       //獲得成員變量對應的類

       Field fieldy = rp1.getClass().getField("y");

       //打印具體對象的值

       System.out.println(fieldy.get(rp1));

       //x是私有的方法變爲getDeclaredField();

       Field fieldx = rp1.getClass().getDeclaredField("x");

       //暴力反射

       fieldx.setAccessible(true);

      

       System.out.println(fieldx.get(rp1));

      

           privatestaticvoid changeStringValue(Object obj)throws Exception{

       //得到所有的成員變量

       Field[] fields =   obj.getClass().getFields();

       //遍歷找到

       for(Field field :fields){

          //如果類型是String類型

          if(field.getType()==String.class){

             //得到值,

             String oldValue = (String)field.get(obj);

             //進行替換

             String newValue = oldValue.replace('b','a');

             //設置新的值

             field.set(obj, newValue);

          }

       }  

    }

Method類:

Method類代表某個類的方法成員。

得到類中的某一個方法:

Method chaAt = Class.forName("java.lang.String").getMethod("charAt", int.class);

 

字節碼.getMethod(name, parameterTypes)

  Method mainMethod = Class.forName(startingClassName).getMethod("main", String[].class);

 

invoke();

public Object  invoke (Object obj,  Object . . . args)

obj 調用底層方法的對象,

args用於方法調用的參數。

返回使用參數args 在obj上使用該對象所表示方法的結果

 

 

調用方式:

通常方式:System.out.println(str.charAt(1));

反射方式:System.out.println(charAt.invoke( str,  1 ));

如果傳遞給Method對象的invoke()方法一個參數爲null,這說明該Method對象對應一個靜態方法。

 mainMethod().invoke(null ,  new Object [ ] { new String [ ] { " "," ". . . } });

 mainMethod( ).invoke(null , (Object) new String [  ] { " "," ". . . });

 

用反射的方式執行某個類中的main方法。     

        String startingClassName = args[0];

        Method mainMethod = Class.forName(startingClassName).getMethod("main", String[].class);

        //main接收一個字符串數組,一個參數。需要進行處理。兩種方式:

        mainMethod.invoke(new TestArguments(),new Object[] {new String[  ]{"111","222","333"}});

        //強轉成一個對象

       mainMethod.invoke(null, (Object)new String[  ] {"1","2","3"});

 

Arrays工具類用於完成對數組的反射操作。

具有相同的維數和元素類型的數組屬於同一個類型,即具有相同的Class實例對象。

代表數組的Class實例對象的getSuperClass( )方法返回的父類爲Object類對應的Class

基本類型的以爲數組可以被當做Object類型使用,不能當做Object [  ]使用

非基本類型的一維數組,既可以當做Object類型使用,又可以當做Object[  ]類型使用。

Arrays.asList( )方法處理 int[ ]和String [ ]時的差異。

 

 

先將數組轉成List對象

       String [   ] a4 = new String[ ]{"a","b","c"};  
      System.out.println(Arrays.asList(a4));

       printObject(a4); a  b  c 

       printObject("xyz");  xyz

構造方法printObject打印數組。 

    private static voidprintObject(Object obj) {

       Class cla1 = obj.getClass();

       if(cla1.isArray()){

          int len =  Array.getLength(obj);

          for(int i =0;i<len;i++){

             System.out.println(Array.get(obj, i));

          }             

       }else{

          System.out.println(obj);

       }     

    }

hashCode()是用來產生哈希碼的,而哈希碼是用來在散列存儲結構中確定對象的存儲地址的,

hashCode()方法使用來提高Map裏面的搜索效率的,Map會根據不同的hashCode()來放在不同的

區域段裏面,Map在搜索一個對象的時候先通過hashCode()找到相應的區域段,然手再根據

equals()方法找到相應的對象。

兩個相等對象的equals方法一定爲true,但兩個hashcode相等的對象不一定是相等的對象。

所以hashcode相等只能保證兩個對象在一個Hash表裏的同一條hash鏈上,繼而通過equals方法才能確定

是不是同一個對象,如果結果爲true,則認爲是同一對象不再插入,否則認爲是不同對象

繼續插入。

 

只有類的實例對象要被採用哈希算法進行存儲和檢索是,這個類才需要按要求覆蓋hashCode

方法。即使程序可能暫時不會用到當前類的hashCode方法,但是爲它提供一個hashCode

方法也不會有什麼不好,只是未雨綢繆。所以,通常要求hashCode方法和equals方法一併被

同時覆蓋。

提示

(1)通常來說,一個類的兩個實例對象用equals( )方法比較的結果相等時,他們的哈希碼也

必須相等,但反之則不成立,即equals方法比較不相等的對象可以有相同的哈希碼,或者說哈希

碼相同的兩個對象的equals方法比較的結果可以不等,例如,“BB”和“AA”的equals

方法比較結果肯定不相等,但他們的hashCode方法返回值卻相等。

(2)當一個對象被存儲進HashSet集合以後,就不能修改這個對象中那些參與計算哈希值的字段了

,否則,對象修改後的哈希值與最初存儲進HashSet集合中時的哈希值就不同了,在這種情況下

即使在contains方法使用該對象的當前引用作爲的參數去HashSet集合中檢索對象,也將返回

找不到對象的結果,這也會導致無法從HashSet集合中單獨刪除當前對象,從而造成內存泄露。

 

反射的作用:實現框架功能。

房子                             門                                   鎖

(框架)                   (客戶)                       (工具類)

工具類被用戶的類調用,

框架則是調用用戶提供的類。

 

例子:

(1)設置一個 . properties文件

(2)讀取配置文件中類的名字

(3)利用上一步結果,創建新的實例,這樣整個程序中不會有new()

 

//讀取配置文件
  //InputStream is = new FileInputStream("config.properties");

 

類加載器,加載資源


  //InputStream is  = ReflectTest2.class.getClassLoader().getResourceAsStream("cn\\itcast\\day1\\config.properties");
  //InputStream is  = ReflectTest2.class.getResourceAsStream("Resourse\\config.properties");
  InputStream is  = ReflectTest2.class.getResourceAsStream("/cn/itcast/day1/Resourse/config.properties");
       //問:" \ "  和 " / " 在路徑表示的時候有什麼區別
  
  //創建Properties對象
  Properties prop = new Properties();
  //加載配置文件
  prop.load(is);
  is.close();
  //指定字符串classname爲類名
  String classname = prop.getProperty("classname");
  //創建實例對象。無參構造方法,創建實例對象。
  Collection collections =(Collection) Class.forName(classname).newInstance();

在MyEclipse中如果源文件目錄中有非. java文件 那麼會自動複製到classpath下

 

未來學習的框架:配置文件都是放在classpath路徑下

 

 

 

config.properties

name                                     value

classname                            java.util.HashSet         

 

 ---------------------- android培訓java培訓、期待與您交流! ----------------------詳細請查看:http://edu.csdn.net/heima

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