反射知識在我近期的開發(fā)中用到的不過掩缓,所以知識點也不是很清楚叹阔。今天補習了一下反射部分內(nèi)容,在這里做一個小結。
Java反射的概念
反射含義:可以獲取正在運行的Java對象弥锄。Java反射的功能
1)可以判斷運行時對象所屬的類
2)可以判斷運行時對象所具有的成員變量和方法
3)通過反射甚至可以調(diào)用到private的方法
4)生成動態(tài)代理-
Java反射機制
- 在運行狀態(tài)中朵夏,對于任意一個類锌唾,都能夠知道這個類的所有屬性和方法篓像;
對于任意一個對象,都能夠調(diào)用它的任意一個方法涩僻;
這種動態(tài)獲取的信息以及動態(tài)調(diào)用對象的方法的功能稱為java語言的反射機制欣范。 - Java反射機制主要提供了以下功能:
在運行時判斷任意一個對象所屬的類变泄;
在運行時構造任意一個類的對象;
在運行時判斷任意一個類所具有的成員變量和方法恼琼;
在運行時調(diào)用任意一個對象的方法妨蛹;
生成動態(tài)代理。
- 在運行狀態(tài)中朵夏,對于任意一個類锌唾,都能夠知道這個類的所有屬性和方法篓像;
實現(xiàn)Java反射的類
1) Class:它表示正在運行的Java應用程序中的類和接口
2) Field:提供有關類或接口的屬性信息晴竞,以及對它的動態(tài)訪問權限
3) Constructor:提供關于類的單個構造方法的信息以及對它的訪問權限
4) Method:提供關于類或接口中某個方法信息
注意:Class類是Java反射中最重要的一個功能類蛙卤,所有獲取對象的信息(包括:方法/ 屬性/構造方法/訪問權限)都需要它來實現(xiàn)。編寫Java反射程序的步驟:
1) 必須首先獲取一個類的Class對象
例如(推薦第一種):
Class c1 = Test.class;
Class c2 = Class.forName(“com.reflection.Test”);
Class c3 = new Test().getClass();
2) 然后分別調(diào)用Class對象中的方法來獲取一個類的屬性/方法/構造方法的結構
注意:如果要能夠正常的獲取類中方法/屬性/構造方法應該重點掌握如下的反射類
Field
Constructor
Method
常用方法
//首先要獲取一個類的Class對象
Class c1 = TestReflection.class;
或:Class<Bean> c1 = (Class<Bean>) Class.forName(className);
或:Class<Bean> c1 = (Class<Bean>) new Bean().getClass();
//生成一個實例
Bean b = (Bean)c1.newInstance();
//獲取指定的包名
String package01 = c1.getPackage().getName();
//獲取類的修飾符
int mod = c1.getModifiers();
//獲取指定類的完全限定名
String className = c1.getName();
//獲取指定類的父類
Class superClazz = c1.getSuperclass();
//獲取實現(xiàn)的接口
Class[] interfaces = c1.getInterfaces();
//獲取指定類的所有成員變量:(類或接口所聲明的所有字段噩死,public, private, protected 颤难,但不包括從基類繼承的字段)
Field[] fields = c1.getDeclaredFields();
for (Field field : fields) {
//獲取每個字段的訪問修飾符
modifier = Modifier.toString(field.getModifiers());
//獲取字段的數(shù)據(jù)類型所對應的Class對象
Class type = field.getType();
//獲取字段名
String name = field.getName();
//如果是數(shù)組類型則需要特別處理
if (type.isArray()) {
String arrType = type.getComponentType().getName() +"[]";
System.out.println("" + modifier + " " + arrType + " "+ name + ";");
} else {
System.out.println("" + modifier + " " + type + " " + name + ";");
}
}
//獲取指定類的指定成員變量(前者為全部,后者僅為公有已维,但包含基類)
Field field = c1.getDeclaredField("mScroller");
Field field = c1.getField("mScroller");
實例(獲取指定類的指定成員變量):
初始化ViewPager時行嗤,利用獲得指定成員變量,來反射修改滑動速度垛耳。
public class ViewPagerScroller extends Scroller {
// 設置滑動速度
private int mScrollDuration = 2000;
public void setScrollDuration(int duration){
this.mScrollDuration = duration;
}
public ViewPagerScroller(Context context) {
super(context);
}
public ViewPagerScroller(Context context, Interpolator interpolator) {
super(context, interpolator);
}
public ViewPagerScroller(Context context, Interpolator interpolator, boolean flywheel) {
super(context, interpolator, flywheel);
}
@Override
public void startScroll(int startX, int startY, int dx, int dy, int duration) {
super.startScroll(startX, startY, dx, dy, mScrollDuration);
}
@Override
public void startScroll(int startX, int startY, int dx, int dy) {
super.startScroll(startX, startY, dx, dy, mScrollDuration);
}
public void initViewPagerScroll(ViewPager viewPager) {
try {
//在這里使用了反射栅屏,獲得ViewPager類的指定成員變量
Field mScroller = ViewPager.class.getDeclaredField("mScroller");
mScroller.setAccessible(true);
//將ViewPager的實例,即傳入作為形參的viewPager對象堂鲜,也就是主界面程序中的mViewPager對象栈雳,中的成員變量mScroller設置為this
mScroller.set(viewPager, this);
} catch(Exception e) {
e.printStackTrace();
}
}
}
//在主界面程序中使用ViewPager的時候,這樣初始化:
mViewPager = (ShowViewPager) getActivity().findViewById(R.id.viewpager);
ViewPagerScroller viewPagerScroller = new ViewPagerScroller(getActivity());
viewPagerScroller.initViewPagerScroll(mViewPager);
獲取指定類的所有方法的兩種方式:
public Method[] getMethods():返回某個類的所有public方法缔莲,包括從基類繼承的哥纫、從接口實現(xiàn)的所有public方法。
public Method[] getDeclaredMethods():返回某個類自身聲明的所有方法(public, private, protected)痴奏,包括從所實現(xiàn)接口的方法蛀骇,但不包括繼承的方法。
getMethod獲取指定方法的用法舉例:
- 執(zhí)行某對象的方法
public Object invokeMethod(Object owner, String methodName, Object[] args) throws Exception {
//首先得到這個對象的Class
Class ownerClass = owner.getClass();
//配置參數(shù)的Class數(shù)組读拆,作為尋找Method的條件
Class[] argsClass = new Class[args.length];
for (int i = 0, j = args.length; i < j; i++) {
argsClass[i] = args[i].getClass();
}
//得到要執(zhí)行的Method
Method method = ownerClass.getMethod(methodName,argsClass);
//執(zhí)行該Method.invoke方法的參數(shù)是執(zhí)行這個方法的對象owner松靡,和參數(shù)數(shù)組args〗ㄒ可以這么理解:owner對象中帶有參數(shù)args的method方法。返回值是Object岛马,也既是該方法的返回值棉姐。
return method.invoke(owner, args);
}
- 執(zhí)行某個類的靜態(tài)方法
public Object invokeStaticMethod(String className, String methodName,
Object[] args) throws Exception {
Class ownerClass = Class.forName(className);
Class[] argsClass = new Class[args.length];
for (int i = 0, j = args.length; i < j; i++) {
argsClass[i] = args[i].getClass();
}
Method method = ownerClass.getMethod(methodName,argsClass);
//invoke的一個參數(shù)是null,因為這是靜態(tài)方法啦逆,不需要借助實例運行
return method.invoke(null, args);
}
解釋一下getMethod(String name, Class<?>... parameterTypes)方法中的兩個參數(shù):
- 第一個參數(shù)是方法名伞矩,第二個參數(shù)是該方法的參數(shù)類型數(shù)組
- 因為存在同方法名不同參數(shù)這種情況,所以只有同時指定方法名和參數(shù)類型才能唯一確定一個方法夏志。
如一個函數(shù): int test(int a, String str);
對應的getMethod方法:
getMethod("test",int.class, String.class);
或:getMethod("test",new Class[]{ int.class, String.class } );
method.invoke(Object receiver, Object... args)
就是最后一步:執(zhí)行改類的指定方法了乃坤。
需要注意的是其第二個參數(shù),不同于getMethod的第二個參數(shù)。
- 前者是該方法參數(shù)的實際的值湿诊。
- 后者是該方法參數(shù)的實際的值的參數(shù)類型狱杰。
invoke方法的返回值即為該方法實際的返回值類型,包裝成Object厅须,可以向下強轉(zhuǎn)仿畸。
已上面的例子為例引出一個疑問: