------<a href="http://www.itheima.com" target="_blank" rel="external nofollow" target="blank">Java教育訓練、Android教育訓練、iOS教育訓練、.Net教育訓練</a>、期待與您交流! -------
反射
Class 類:反射的基石
反射就是将java類中的各種成分映射成相應的java類。
java程式中的各個java類,可以描述為同一類事物,用Class類來表示。
換句話說:Class類是全部java類的抽象,無論是JDK中的,還是自定義的類。
void,數組,java基本資料類型也都表示為Class對象。
特性:
Class類沒有公共構造方法,Class對象是在加載類時由Java虛拟機以及通過調用類加載器中的defineClass方法自動構造的。
1. Class cls1 = 類名.class;
2. Class cls2 = 對象引用(或對象).getClass();
3. Class cls3 = Class.forName(“類名稱”);
常用方法:
1. Object.getClass():傳回此Object的運作時類。
2. isPrimitive():判定指定的Class對象,是否指定一個基本資料類型。
3. Class.forName(String className)
傳回 字元串指定的類或接口相關連的Class對象。
傳回位元組碼檔案(.class檔案)兩種方式:
1. 已加載過得類,放在java虛拟機中。
2. 沒有加載過,類加載器加載到虛拟機中。
得到各個 位元組碼 對應的 執行個體對象(Class類型)。
1. 類名.class (如:System.class)
2. 對象.getClass() (如:new Data().getClass)
3. Class.forName(“類名”) (如:Class.forName(“java.lang.Thread”) )
forNmae(“類名”),将執行個體化該類
getConstructor()
Constructor strConst = Class.forName("java.lang.String").getConstructor(StringBuffer.class);
獲得具體的構造方法時,要傳遞類型
Constructor類
String str = (String)strConst.newInstance(new StringBuffer("abc"));
調用獲得的方法來構造對象時,要用到相同類型的執行個體對象。
getField()
1. 非private成員
① 通過反射通路成員變量時,通過Class類的getField(“成員變量名稱”)方法,得到Field對象。
② 再将被通路的對象,傳遞給Field對象,即可得到該值了。
2. private成員
① 使用Class類的getDeclaredField(),該方法可以傳回全部聲明過的字段。
② 使用Field類的父類AccessibleObject的setAccessible(boolean flag)方法将私有變量設定成為可通路的變量。
public static void myGetField() throws Exception {
// 1. 使用反射得到單個變量的構造方法的對象,這是傳遞的變量為構造函數的類型
Constructor fieConst = ReflectField.class.getConstructor(int.class,int.class);
// 2. 使用此構造方法類的對象,執行個體化類,傳遞給類型對應的對象
ReflectField rf = (ReflectField)fieConst.newInstance(4,5);
// 3. 傳遞要查詢的字段名,傳回
Field fieldA = ReflectField.class.getField("x");
// 4. 傳遞對象,字段對象根據獲得其相應的值,說明該類通路另一個對象。
System.out.println(fieldA.get(rf));
// y字段為private,需要使用Field的getDeclaredField,傳回所有聲明過的對象。
Field fieldY = ReflectField.class.getDeclaredField("y");
// 私有成員變量,需要暴力反射,設定為可以通路
fieldY.setAccessible(true);
System.out.println(fieldY.get(rf));
getMethod()
public Method getMethod(String name, Class<T>... parameterTypes )
name : 方法名
parameter Types : 參數清單
Method類
invoke()方法:
public Object invoke(Object obj , Object...arg / Object[]...args)
參數:
1. obj : 從這個對象中調用底層方法。
① 如果底層方法是靜态的,則可以忽略obj參數,該參數可以為null。
② 如果底層方法是靜态,并且尚未初始化聲明此方法的類,則會将其初始化
2. args : 參數清單。 * 如果底層方法所需的形參個數為0,則所提供的args長度,可以為0或null。
public static void myGetMethod() throws Exception {
String str = "123";
Method charAtMethod = String.class.getMethod("charAt", int.class);
System.out.println(charAtMethod.invoke(str,1));
System.out.println(charAtMethod.invoke(str, new Object[]{2}));
}
對接收數組方式的成員方法反射
在A類的main方法中,調用B類的main方法,并且傳遞字元串參數給B的main方法:
注意:
1. 需要給A的main的參數清單args[0]複制,B類的名稱。
2. main方法是static的,則可以忽略該對象參數,而隻傳遞null。
public class GetXxx {
public static void main(String[] args) throws Exception {
//myGetConstructor();
//myGetMethod();
/**
* 1. 因為在GetXxx類運作時,其main方法的參數傳遞了TestArguments的完整類名,
* 是以,就能夠根據ClassName來獲得該類的位元組碼,進而可以得到該類的全部内容。
* **/
String mainArgument = args[0];
// 2.根據args[0]就可以獲得TestArguments類的位元組碼檔案,進而得到main方法。
Method mainMethod = Class.forName(mainArgument).getMethod("main", String[].class);
// 3. main()方法是靜态的,靜态的則不用傳遞對象,傳遞null即可。
mainMethod.invoke(null, (Object)new String[]{"111","222","333"});
}
}
class TestArguments {
public static void main(String[] args) {
for(String arg : args) {
System.out.println(arg);
}
}
}
數組:
Class類:
每個數組屬于被映射為Class對象的一個類,所有具有相同類型及次元的數組 都共享該Class類。
getName():
public String getName()
以 String 的形式傳回此 Class 對象所表示的實體(類、接口、數組類、基本類型或 void)名稱。
1. 當類對象表示一個數組類型:
① 其名字為:
表示該數組嵌套的一個或多個”[”字元加元素類型名。
2. 當類對象表示一個非數組類型的引用類型:
3. 當類對象表示一個基本資料類型或void:
① 傳回該類的二進制名稱
getSuperclass()
public Class<? super T> getSuperclass()
傳回表示此 Class 所表示的實體(類、接口、基本類型或 void)的超類的 Class。
System.out.println(a1.getClass().getSuperclass().getName());
System.out.println(s1.getClass().getSuperclass().getName());
System.out.println(a1.getClass().getSuperclass().getName() == s1.getClass().getSuperclass().getName());
結果:
java.lang.Object
java.lang.Object
true
Arrays類
asList方法
public static <T> List<T> asList(T... a)
說明:JDK1.4asList方法,其參數支援Object[]數組。是以傳遞的是Object數組,則其可以直接解析,非Object的參數,則傳回其對應的getName()方法傳回的數組的名稱。
int[][] a4 = new int[][]{{1,2,3,4}};
String[] s2 = new String[]{"a","b","c"};
System.out.println(Arrays.asList(a4));
System.out.println(Arrays.asList(s2));
結果為:
[[[email protected]]
[a, b, c]
需求:
使用反射,周遊類的數組。
Class類 --> isArray()
boolean isArray() 判定此 Class 對象是否表示一個數組類。 |
Array類 --> getLength(Object obj)
static int getLength(Object array) 以 int 形式傳回指定數組對象的長度。 |
Array類 --> get(Object array, int index)
static Object get(Object array, int index) 傳回指定數組對象中索引元件的值。 |
public static void main(String[] args) {
// testArray();
int[][] a = new int[][]{{1,2,3,4}};
int[] a1 = new int[]{11,22,33,44};
int i = 2;
String[] s = new String[]{"a","b","c"};
Object[] objs = {a,a1,i,s};
for(Object obj : objs) {
printArray(obj);
}
}
public static void printArray(Object objs) {
// 1. Class類的isArray()方法,判斷該對象是否為數組
if(objs.getClass().isArray()) {
// 2. Array類的static getLength(Object obj)方法,獲得該數組對象的長度。
for(int i = 0; i < Array.getLength(objs) ; i++) {
// 3. Array類的static get(Object obj , int index)方法,得到數組對應索引上的值。
System.out.println(Array.get(objs, i));
}
} else {
System.out.println(objs);
}
}
架構
架構的思想
架構就是開發商改好的毛坯房,自己寫的類就像後來根據門框大小,木桶标準等等自己安裝的家具門窗。自己寫的類是為架構服務的。
與工具類的差別
工具類是為自己寫的類服務的,而自己寫的類是為架構服務的。
代碼:
config.properties
className=java.util.HashSet
package com.lxh.reflect;
import java.util.*;
import java.io.*;
public class ReflectFrame {
public static void main(String[] args) throws Exception {
InputStream in = new FileInputStream("C:\\Users\\fox\\Workspaces\\MyEclipse 8.5\\reflect\\src\\com\\lxh\\reflect\\config.properties");
Properties prop = new Properties();
prop.load(in);
String className = prop.getProperty("className");
/**
* 反射
* 先寫好這個類,隻需要在開始運作這個類之前,其他類已經寫好了就可以。
* */
Collection collections = (Collection)Class.forName(className).newInstance();
// 建立幾個圓點的對象,其中rf1和rf3的值相同。
ReflectField rf1 = new ReflectField(1,1);
ReflectField rf2 = new ReflectField(2,2);
ReflectField rf3 = new ReflectField(1,1);
collections.add(rf1);
collections.add(rf2);
collections.add(rf3);
collections.add(rf1);
// rf1.x = 5;
// collections.remove(rf3);
System.out.println(collections.size());
}
}