Class類的使用
- 所有類都是
Class類的對象,這種對象有三種表示方式
// c1/c2/c3是Foo的類類型
// 一個類的類類型只有一個,即 c1==c2==c3
Class c1 = Foo.class;
Class c2 = foo.getClass();
Class c3 = Class.forName("Foo");
- 可以通過類類型創(chuàng)建對象
Foo foo = (Foo)c1.newInstance(); // Foo需要有無參構(gòu)造方法
- 基本數(shù)據(jù)類型、
void關(guān)鍵字都有類類型
方法的反射
-
Method類:一個方法就是一個Method對象。 - 根據(jù)類類型獲取方法
// 獲取public方法,包括父類方法
Method[] methods = c.getMethods();
// 獲取當(dāng)前類聲明的方法,不論訪問權(quán)限
Method[] methods = c.getDeclaredMethods();
- 根據(jù)方法獲取返回值類類型
Class returnClassType = method.getReturnType();
- 獲取方法名稱
String methodName = method.getName();
- 根據(jù)方法獲取方法參數(shù)類類型數(shù)據(jù)
Class[] paramClassTypes = method.getParameterTypes();
- 獲取某一方法
// 獲取帶兩個int類型參數(shù)的,名字為print的方法
Method method = c.getMethod("print",int.class,int.class)
- 方法的操作
格式:method.invoke(obj,params[])
//調(diào)用a對象的print方法,傳入兩個參數(shù)
method.invoke(a,10,20);
//和直接調(diào)用方法效果一樣
a.print(10,20);
成員變量的反射
-
Field類:一個成員變量就是一個Field對象。 - 根據(jù)類類型獲取成員變量
// 獲取public成員變量,包括父類成員變量
Field[] fields = c.getFields();
// 獲取當(dāng)前類聲明的成員變量,不論訪問權(quán)限
Field[] fields = c.getDeclaredFields();
- 例子
// 修改字符串的內(nèi)容而不修改地址
//獲取之前的值
String s = new String("abc");
System.out.println(s);
String s1 = s;
//利用反射屬性修改值
Field field = null;
try {
field = s.getClass().getDeclaredField("value");
field.setAccessible(true);
field.set(s,"abcd".toCharArray());
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
//修改后的值
System.out.println(s);
System.out.println(s1 == s);
- 獲取成員變量的類類型
Class fieldClassType = field.getType();
- 獲取成員變量名稱
String fieldName = field.getName();
構(gòu)造函數(shù)的反射
-
Constructor類:一個構(gòu)造函數(shù)就是一個Constructor對象。 - 根據(jù)類類型獲取構(gòu)造函數(shù)
// 獲取public構(gòu)造函數(shù),包括父類構(gòu)造函數(shù)
Constructor[] constructors = c.getConstructors();
// 獲取當(dāng)前類聲明的構(gòu)造函數(shù),不論訪問權(quán)限
//建議使用,因為構(gòu)造方法都需要自己聲明
Constructor[] constructors = c.getDeclaredConstructors();
- 獲取構(gòu)造函數(shù)名稱
String methodName = constructor.getName();
- 根據(jù)方法獲取構(gòu)造函數(shù)參數(shù)類類型數(shù)據(jù)
Class[] paramClassTypes = constructor.getParameterTypes();
Java類加載機制
- 靜態(tài)加載類:編譯時加載類
new對象是靜態(tài)加載類,在編譯時加載可能用到的類 - 動態(tài)加載類:運行時加載類
Class.forName得到類類型,通過類類型創(chuàng)建對象是動態(tài)加載
需求實例:程序中如果是
World調(diào)用World的啟動方法,如果是Excel調(diào)用Excel的啟動方法,等等。
思路:如果直接在這個類中使用World、Excel等類,當(dāng)某一個可能不會用到的類不存在時會報錯,所以需要動態(tài)加載
1.抽象出公共功能:
public interface OfficeAble {
void start();
}
2.實際類擁有功能:
public class World implements OfficeAble {
@Override
public void start() {
System.out.println("World start...");
}
}
public class Excel implements OfficeAble {
@Override
public void start() {
System.out.println("Excel start...");
}
}
3.實際使用:
public class OfficeTest {
public static void main(String[] args) {
try {
// Class c = Class.forName("com.zp.zptest.reflect.World");
Class c = Class.forName("com.zp.zptest.reflect.Excel");
OfficeAble officeAble = (OfficeAble) c.newInstance();
officeAble.start();
} catch (Exception e) {
e.printStackTrace();
}
}
}
用反射認(rèn)識泛型的本質(zhì)
- 反射是編譯后的操作
- 編譯后的集合是去泛型化的
- Java泛型是為了防止錯誤輸入,只在編譯時生效
- 反射是去泛型化的:
ArrayList list1 = new ArrayList();
ArrayList<String> list2 = new ArrayList<String>();
Class c1 = list1.getClass();
Class c2 = list2.getClass();
System.out.println(c1 == c2); // 結(jié)果為true
- 使用反射給c2添加整型元素:
list2.add("hello");
Method method = c2.getMethod("add",Object.class);
method.invoke(list2,10);
System.out.println(list2); // [hello,10]