——- android培訓、java培訓、期待與您交流! ———-
問題1: Class類是什麼?有什麼作用?
Class類是所有類的基類,是每一個類放在內存中的字節碼。
通過Class類可以知道,每一個類中的所有組成部分。包括類中屬性,該類的構造函數,該類所擁有的方法等內容。
問題2:如何獲得一個類的Class類的字節碼實例對象,三種方法(以Person類爲例):
1)Class cls1 = Person.class
2)Class cls2 = person.getClass()
3)Class cls3 = Class.forName(“java.lang.String”)
forName加載有兩種,一種是已經存在了,直接加載,另一種是不存在,先加載到虛擬機中在應用。
問題3:Class類有幾種基本字節碼?
基本字節碼共九種,包括8種基本數據類型和Void.class,是否是基本自己碼可以用isPrimitive()來判斷。用isArray()判斷是否是數組。
具體看下面代碼實例:
class ReflectTest
{
public static void main(String args[])
{
String str = "abc";
Class cls1 = String.class;
Class cls2 = str.getClass();
Class cls3 = Class.forName("java.lang.String");
System.out.println("cls1==cls2");//true
System.out.println("cls1==cls2");//true
System.out.println("cls1.isPrimitive()");//false
System.out.println("int.class.isPrimitive()");//true
System.out.println("int.class==Integer.class");//false
System.out.println("int.class==Integer.Type");//true
System.out.println("int[].class.isPrimitive()");//false
System.out.println("int[].class.isArray()");//true
}
}
(一)利用反射得到構造方法,並實例化對象
1)正常情況:String str = new String(new StringBuffer(“abc”));
2)利用反射:Constructor con=Class.forName(“java.lang.String”).getConstructor(StringBuffer.class);
String str = con.newInstance(new StringBuffer(“abc”));
3)String.class類中有一個方法newInstance()是獲得無參構造。
示例1如下:
首先定義已知類:ReflectPoint
class ReflectPoint
{
private int x;//私有屬性
public int y;//公共屬性
public RefletctPoint(int x,int y)//含有兩個整型參數的構造方法
{
super();
this.x = x;
this.y = y;
}
}
1)獲取公共屬性y
ReflectPoint rp = new ReflectPoint(3,5);//獲得該類的實例對象
Field fiedlY = rp.getClass().getField("y");//通過該類的實例對象獲得該類的公共屬性y
System.out.println(fieldY.get(rp));//取得該類對應的此實例對象的公共屬性y對應的值,結果爲5。
2)私有屬性獲得方式
Field fieldX = rp.getClass().getDeclaredField("x");//通過該類的實例對象獲得該類的私有屬性x
fieldX.setAccessible(true);//設置該私有屬性可以被訪問。
System.out.println(fieldX.get(rp));//取得該類對應的此實例對象的私有屬性x對應的值,結果爲3。
示例2:
利用反射:將任意一個對象中的所有String 類型的成員變量所對應的字符內容中的‘b’改爲 ‘a’。
首先定義已知類
class ReflectPoint
{
public String str1 = "ball";
public String str2 = "basketball";
public String str3 = "all";
public String toString()
{
return str1+"......"+str2+"......"+str3+"......";
}
}
封裝一個函數進行改寫操作
public static void changeStringValue(Object obj) throws Exception
{
Field[] fields = obj.getClass().getFields();
for(Field field:fields)
{
if(field.getType()==String.class)
{
String oldValue = (String)field.get(obj);
String newValue = oldValue.replace('b','a');
field.set(obj,newValue);
}
}
}
在主函數中調用並驗證
{
ReflectPoint rp = new ReflectPoint();
changeStringValue(rp);
System.out.println(rp);
}
運行結果如下:
改寫成功!
(三)利用反射:調用方法
以java.lang.String類爲例,獲取它的CharAt()方法
String str = "abc";
Method methodCharAt = String.class.getMethod("charAt",int.class);
System.out.println(methodCharAt.invoke(str1,1));//結果爲b
此處invoke()爲調用的意思,其中第一個參數爲調用的對象,第二個爲該方法的參數。如果是靜態函數,則第一個參數爲null,應書寫如下:
System.out.println(methodCharAt.invoke(null,1));
示例3: 用反射提供一個程序,根據用戶提供的類名,調用該類的main方法
首先寫出已知類ReflectTest:
package com.test;
public class ReflectTest
{
public static void main(String args[])
{
for(String arg:args)
{
System.out.println(arg);
}
}
}
在另一個程序中調用:
public class ReflectDemo
{
public static void main(String args[])
{
String startingClassName = args[0];
Method mainMethod = Class.forName(startingClassName).getMethod("main",String[].class);
mainMethod.invoke(null,(Object)new String[]{"123","345","234"});
mainMethod.invoke(null,new Object[]{new String[]{"123","345","234"}});
}
}
程序運行結果如下:
[“123”,”345”,”234”]
“123”
“345”
“234”
此處invoke()方法的第二參數,作爲被調用方法的參數傳入,其形式爲Object數組形成,也可以爲Object對象。
附帶:分析一下數組與Object類的關係
看如下示例4:
public class ArrayObjectDemo
{
public static void main(String args[])
{
int[] a1 = new int[3];
int[] a2 = new int[4];
int[][] a3 = new int[2][3];
String[] a4 = new String[3];
System.out.println(a1.getClass()==a2.getClass());//true
System.out.println(a1.getClass()==a3.getClass());//false
System.out.println(a1.getClass()==a4.getClass());//false
System.out.println(a1.getClass.getName());//I
System.out.println(a1.getClass.getSuperclass().getName());//
System.out.println(a4.getClass.getSuperclass().getName());
Object obj1 = a1;
Object obj2 = a4;
Object[] obj3 = a3;
Object[] obj4 = a4;
Object[] obj5 = a1;//此處編譯不通過。
System.out.println(a1);//
System.out.println(a4);//
System.out.println(Arrays.asList(a1));//
System.out.println(Arrays.asList(a4));//
}
}
備註:Arrays.asList()這個方法的作用是把數組轉化爲List集合。
綜上例子可以發現:
1)具有相同維數和元素類型的數組屬於同一個類型,即具有相同的Class實例對象。
2)基本類型的一維數組可以被當作Object類型使用,不能當作Object[]類型使用。
3)非基本數據類型的一維數組既可以被當作Object類使用,也可以當作Object[]類型使用
利用反射機制和Array工具類完成對數組的操作:
示例5:打印數組。
封裝打印數組的方法如下:
public void printObj(Object obj)
{
Class cla = obj.getClass();
if(cla.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);
}
}
主方法調用並獲得結果如下:
String[] a4 = new String[]{"a","b","c"};
printObj(a4);//結果爲a,b,c
printObj("abdc");//結果爲abcd
綜上是說明Class類的基本作用;
作爲反射機制,最大的作用在於:
實現框架功能
在許多框架中,在寫框架時,還不知道要被調用的類名,所以,在程序中無法直接new某個類的實例對象,而要用反射方式來做。
用例子說明如下:
示例6:新建一個Properties類,新建config.properties文件。
className=java.util.HashSet
該主方法(模擬爲框架代碼)
public class ReflectTest3
{
public static void main(String args[])
{
InputStream is = new FileInputStream("config.properties");
Properties props = new Properties();
props.load(is);
is.close();
String className = props.getProperties("className");
Collection collections = Class.forName(className);
ReflectPoint pt1 = new ReflectPoint(3,3);
ReflectPoint pt2 = new ReflectPoint(5,5);
ReflectPoint pt3 = new ReflectPoint(3,3);
collections.add(pt1);
collections.add(pt2);
collections.add(pt3);
collections.add(pt1);
System.out.println(collections.size()); //打印結果爲2
}
}
定義被框架調用的類
class ReflectPoint
{
public String str1 = "ball";
public String str2 = "basketball";
public String str3 = "all";
public String toString()
{
return str1+"......"+str2+"......"+str3+"......";
}
}
以上內容是對反射內容的全部概括,但是也是最基本的內容,多做練習,加深理解。