反射的概念:
反射就是把java類中的各種成份映射成相應的java類。例如,一個java類中的用一個Class類的對象來表示,一個類中的組成部分,成員變量、方法、構造函數、包等等信息也用一個個java類來表示。表示java類的Class類顯然要提供一系列的方法,來獲得其中的變量、方法、構造函數、修飾 符、包等信息,這些類就是用相應的類的實例對象來表示,他們是Filed、Method、Constructor、Package等。
一個類中的每個成員都可以用相應的反射API類的一個實例對象來表示,通過調用Class類的方法可以得到這些實例對象
反射的用途:
反射的主要作用是:用來擴展系統和動態調用程序集。
擴展系統:就是先把系統寫好,系統裏面定義接口,後面開發的人去寫接口的代碼。
此時該系統就要用反射了,系統用反射調用接口,當接口沒寫,系統利用反射就不會不會出錯,此時就等於沒實現此功能而已,當接口被人寫好了,系統就會自動調用接口的功能展現在系統上。即反射實現即插即用功能。
動態調用程序集就是利用反射去調用編譯好的程序,反射具有一定靈活性,不需改變你所建的工程。
反射最主要的用戶適用於做框架的
反射的基石-Class類:
如何得到各個字節碼對應的實例對象
類名:class,例如System.class
對象.getClass(),例如,new Date().getClass();
Class.forName(“類名”),例如Class.forName(“java.util.Date”);
publicclassReflectDemo1 {
publicstaticvoid main(String[] args) throwsException {
Stringstr1 = "abc";
//得到字節碼的三種方式
Classcls1 =str1.getClass();
Classcls2 = String.class;
Classcls3 = Class.forName("java.lang.String");
System.out.println(cls1 == cls2);//true
System.out.println(cls1 == cls3);//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
}
}
總之,只要在源程序中出現的類型,都有各自的Class實例對象,例如int[],void
得到字節碼的三種方式:
publicclassReflectDemo1 {
publicstaticvoidmain(String[] args) throws Exception {
Stringstr1 = "abc";
//得到字節碼的三種方式
Classcls1 =str1.getClass();
Classcls2 = String.class;
Classcls3 = Class.forName("java.lang.String");
System.out.println(cls1 == cls2);//true
System.out.println(cls1 == cls3);//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
}
成員構造函數的反射:
使用到的ReflectPoint類
publicclassReflectPoint {
privateintx;
publicinty;
public ReflectPoint(int x, int y) {
super();
this.x = x;
this.y = y;
}
}
publicclassReflectDemo2 {
publicstaticvoidmain(String[] args) throws Exception {
//new String(new StringBuilder("abc"));
//得到類型
Constructorconstructor1= String.class.getConstructor(StringBuilder.class);
//得到方法的對象
Stringstr2 = (String) constructor1.newInstance(new StringBuilder("c"));
System.out.println(str2);
}
}
字段的反射:
使用到的ReflectPoint類
publicclassReflectPoint {
privateintx;
publicinty;
public ReflectPoint(int x, int y) {
super();
this.x = x;
this.y = y;
}
}
publicclassReflectDemo2 {
publicstaticvoidmain(String[] args) throws Exception {
ReflectPoint rp = newReflectPoint(3,5);
FieldfieldY = rp.getClass().getField("y");
System.out.println(fieldY.get(rp));
Fieldfieldx = rp.getClass().getDeclaredField("x");
fieldx.setAccessible(true);
System.out.println(fieldx.get(rp));
}
}
反射成員變量的綜合案例:
publicclassReflectPoint {
privateintx;
publicinty;
public String str1 = "ball";
public String str2 = "basketball";
public String str3 = "itcast";
public ReflectPoint(int x, int y) {
super();
this.x = x;
this.y = y;
}
//@Override可以判斷重載的方法是否寫正確
@Override
public String toString(){
return"ReflectPoint [x="+ x + ", y=" + y + ", str1="+ str1
+", str2="+ str2+ ", str3="+ str3+ "]";
}
}
publicclassReflectDemo2 {
publicstaticvoidmain(String[] args) throws Exception {
//操作field字段
changeStringValue(rp);
System.out.println(rp);
}
privatestaticvoidchangeStringValue(Object obj) throwsException {
Field[]fields = obj.getClass().getFields();
for(Field field : fields) {
//比較同一份字節碼使用==而不是使用equals
if(field.getType() ==String.class){
Stringvalue = (String) field.get(obj);
StringnewValue = value.replace('b', 'a');
field.set(obj,newValue);
}
}
}
}
反射得到類的方法:
methodCharAt.invoke(null, 1)當第一個參數爲null時,意味着調用的是靜態的方法
//jdk1.4的語法來調用
System.out.println(methodCharAt.invoke(str1,newObject[] {2}));
//jdk1.5的語法來調用
System.out.println(methodCharAt.invoke(str1, 1));
publicclassReflectDemo1 {
publicstaticvoidmain(String[] args) throws Exception {
Stringstr1 = "abc";
//得到類的方法,String.charAt方法
MethodmethodCharAt = String.class.getMethod("charAt", int.class);
//methodCharAt.invoke(null,1)當第一個參數爲null時,意味着調用的是靜態的方法
System.out.println(methodCharAt.invoke(str1,1));//jdk1.5的語法來調用
System.out.println(methodCharAt.invoke(str1,newObject[] {2}));//jdk1.4的語法來調用
}
}
反射執行某個類中的main方法:
對接收數組參數的成員方法進行反射
方法一: mainMethod.invoke(null, new Object[]{new String[] {"111","222","333"}});
方法二: mainMethod.invoke(null, (Object)newString[]{"111","222","333"});
publicclassReflectDemo1 {
publicstaticvoidmain(String[] args) throws Exception {
//反射執行某個類中的main方法
StringstartingClassName = args[0];
MethodmainMethod =Class.forName(startingClassName).getMethod("main", String[].class);
mainMethod.invoke(null, new Object[]{new String[] {"111","222","333"}});
mainMethod.invoke(null, (Object)new String[] {"111","222","333"});
}
}
classTestArguments {
publicstaticvoidmain(String[] args) {
for(String s : args) {
System.out.println(s);
}
}
}
注意在運行的時候要傳遞TestArguments類的包給ReflectDemo1
數組的反射:
publicclassReflectDemo1 {
publicstaticvoidmain(String[] args) throws Exception {
int[]a1 =newint[3];
int[] a2 = newint[4];
int[][] a3 = newint[2][3];
String[] a4 = new String[] {"abc","bcd","cde"};
System.out.println(a1.getClass()== a2.getClass());
// System.out.println(a1.getClass()== a4.getClass());
// System.out.println(a1.getClass()== a3.getClass());
System.out.println(a1.getClass().getName());
System.out.println(a1.getClass().getSuperclass().getName());
System.out.println(a4.getClass().getSuperclass().getName());
Object aObj1 = a1;
Object aObj2 = a4;
// Object[] aObj3= a1;
Object[] aObj4 = a3;
Object[] aObj5 = a4;
System.out.println(a1);
System.out.println(a4);
System.out.println(Arrays.asList(a1));
System.out.println(Arrays.asList(a4));
}
}
數組的反射應用:
publicclassReflectDemo1 {
publicstaticvoidmain(String[] args) throws Exception {
String[] a4 = newString[]{"abc","bcd","cde"};
printObject(a4);
printObject("xyz");
}
privatestaticvoidprintObject(Object obj) {
Classclazz = obj.getClass();
if(clazz.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);
}
}
}
反射的綜合案例:
ArrayList_HashSet的比較以及HashCode的分析
ArrayList是線性的存放,有多少放多少,按照先後的順序
HashSet是存放不重複的,存放之前先判斷集合中是否存在,不存在才放入
HashCode是一種編碼方式,在Java中,每個對象都會有一個hashcode,Java可以通過這個hashcode來識別一個對象
publicclassReflectDemo2 {
publicstaticvoidmain(String[] args) {
Collectioncollection= newHashSet();
ReflectPointpt1 = newReflectPoint(3, 3);
ReflectPointpt2 = newReflectPoint(5, 5);
ReflectPointpt3 = newReflectPoint(3, 3);
collection.add(pt1);
collection.add(pt2);
collection.add(pt3);
collection.add(pt1);
/*
*此處並不能移走pt1,因爲將數據加入hashset中以後不能再去更改他,
這樣會導致內存泄露
內存泄露的作用,此處是一個例子,java中有內存泄露嗎?爲什麼?
pt1.y= 7;
collection.remove(pt1);
*/
System.out.println(collection.size());
}
}
packagecom.wj.reflect;
publicclassReflectPoint {
privateintx;
publicinty;
public ReflectPoint(int x, int y) {
super();
this.x = x;
this.y = y;
}
@Override
publicint hashCode() {
finalint prime = 31;
int result = 1;
result= prime * result + x;
result= prime * result + y;
return result;
}
@Override
publicbooleanequals(Object obj) {
if (this == obj)
returntrue;
if (obj == null)
returnfalse;
if (getClass() !=obj.getClass())
returnfalse;
ReflectPointother = (ReflectPoint) obj;
if (x != other.x)
returnfalse;
if (y != other.y)
returnfalse;
returntrue;
}
@Override
public String toString(){
return"ReflectPoint [x="+ x + ", y=" + y + ", str1="+ str1
+", str2="+ str2+ ", str3="+ str3+ "]";
}
}
用類加載器管理資源和配置文件,也會使用到反射。詳見另一篇博客