Java反射學習
反射其實是一個很重要的概念。
引用百度百科的概念:
JAVA反射機制是在執行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個物件,都能夠呼叫它的任意一個方法和屬性;這種動態獲取的資訊以及動態呼叫物件的方法的功能稱為java語言的反射機制。
說白了就是在哪都能呼叫起來任何一個類物件
反射相關類介紹
- Class
它表示正在執行的Java應用程式中的類和介面 - Field
提供有關類或介面的屬性資訊,以及對它的動態訪問許可權 - Constructor
提供關於類的單個構造方法的資訊以及對它的訪問許可權 - Method
提供關於類或介面中某個方法的資訊
實現步驟
反射實現起來跟一般的類例項化物件然後呼叫方法、屬性流程是一樣的,具體我們還是跟著範例來學習
首先先上需要反射操作的類
public interface SkinColor {
public static int age=20;
void color(int color);
}
public class Person implements SkinColor {
public int sex=-1;
private String name;
private Person(int sex, String name) {
this.sex = sex;
this.name = name;
}
public Person() {
new Person(0, "default");
}
public int getSex() {
return sex;
}
public void setSex(int sex) {
this.sex = sex;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public void color(int color) {}
private class Family {
String familyName="default family";
public Family(String familyName) {
this.familyName = familyName;
}
public Family() {
}
public String getFamilyName() {
return familyName;
}
public void setFamilyName(String familyName) {
this.familyName = familyName;
}
}
}
- 物件初始化
Class class_1=Class.forName("com.renyu.demo.Person");
Class class_2=Person.class;
Class class_3=new Person().getClass();
Constructor constructor_1=class_1.getConstructor(null);
Person person= (Person) constructor_1.newInstance();
雖然看上去我們有三種例項化物件的方法,但是我個人建議大家記住第一種就行了,因為第二種跟第三種情況不適用於私有類的例項化
來看看私有內部類的例項化
Class class_family=Class.forName("com.renyu.demo.Person$Family");
內部類的訪問需要用$來獲取,這個熟悉java的同學應該很清楚
下面建構函式的獲取方式跟之前相比就有很大的不同了,我們來看一下
for (Constructor constructor1 : class_family.getDeclaredConstructors()) {
System.out.println(constructor1.toString());
}
看看列印出來的是什麼玩意
public com.renyu.demo.Person$Family(com.renyu.demo.Person,java.lang.String)
public com.renyu.demo.Person$Family(com.renyu.demo.Person)
看到沒有,外部類也進去了。一開始我沒有注意這個地方,然後一直報錯
Constructor constructor1=class_family.getConstructor(Person.class, String.class);
Object family=constructor1.newInstance(person, "123");
這樣我們就完美的例項化內部類了
如果你存在父類,那麼你可以這樣獲取class物件
class_.getSuperclass()
總結一下
- 當你構造方法有引數的話,那麼把它的型別放到getConstructor裡面,如果沒有的話,就直接傳null。同樣在newInstance一樣,無參構造方法就不傳東西了,有參構造方法就把相應初始化的值給放進去即可。當然你可以直接繞過構造方法,因為預設是呼叫無參構造方法的,所以直接class.newInstance()也是可以的
- 如果你沒有寫無參構造方法,直接寫了有參構造方法的話,那麼之前的邏輯就有問題,會丟擲一系列異常出來,所以在使用Class例項化其他類的物件的時候,一定要定義無參構造方法
屬性呼叫
目前有2種獲取屬性的方法
Field[] fields=class_1.getFields();
Field[] fields=class_1.getDeclaredFields();
看下這兩種結果的區別
for (Field field : fields) {
System.out.println(field.getName()+" "+field.getType());
}
第一種情況
sex int
age int
第二種情況
sex int
name class java.lang.String
顯而易見了,getDeclaredFields是獲取當前類所有的屬性(public或者private全都算),getFields是獲取所有(包括父類、介面)public屬性
這樣你應該知道可以通過何種方法去修改相應屬性的值
比如我要改name屬性的初始化值並驗證是否成功,就得用getDeclaredField去獲得這個屬性
Field name=class_1.getDeclaredField("name");
name.setAccessible(true);
name.set(person, "Hello");
String value1=name.get(person).toString();
System.out.println(value1);
列印出來就是一個hello
方法呼叫
同屬性類似,一樣有2種方式獲取當前類所有的方法
class_1.getMethods();
class_1.getDeclaredMethods();
看下這兩種結果的區別
for (Method method : methods) {
System.out.print(method.getName()+" "+method.getReturnType()+" ");
int i=0;
for (Class<?> aClass : method.getParameterTypes()) {
i++;
System.out.print("params"+i+" "+aClass.toString()+" ");
}
System.out.println("");
System.out.println("*********");
}
第一種情況
getName class java.lang.String
*********
setName void params1 class java.lang.String
*********
color void params1 int
*********
getSex int
*********
setSex void params1 int
*********
Disconnected from the target VM, address: '127.0.0.1:52500', transport: 'socket'
wait void
*********
wait void params1 long params2 int
*********
wait void params1 long
*********
equals boolean params1 class java.lang.Object
*********
toString class java.lang.String
*********
hashCode int
*********
getClass class java.lang.Class
*********
notify void
*********
notifyAll void
*********
第二種情況
getName class java.lang.String
*********
setName void params1 class java.lang.String
*********
color void params1 int
*********
setSex void params1 int
*********
getSex int
*********
我將所有方法名、返回值、引數型別一起列印出來了,這樣大家看的比較直觀
我一樣先setName 再 getName 加以驗證
Method method1=class_1.getDeclaredMethod("setName", String.class);
method1.invoke(person, "World");
Method method2=class_1.getDeclaredMethod("getName");
String value3=method2.invoke(person).toString();
列印出來就是一個World
簡單解釋一下getMethod(String name, Class<?>... parameterTypes)方法中的兩個引數:
name:方法名
parameterTypes:該方法的所有引數型別陣列
建立method方法的時候getDeclaredMethod("setName", String.class);可以寫成getDeclaredMethod("setName", new Class[] {String.class});
使用的時候同樣method1.invoke(person, "World");可以寫成method1.invoke(person, new Object[]{"World"});
如果是私有方法,需要加上method1.setAccessible(true);
如果是靜態方法,那麼我們無需傳類物件就可以使用
public static void showValue() {
System.out.println("aaaa");
}
Method method3=class_1.getDeclaredMethod("showValue");
method3.invoke(null);
相關文章
- 【Java 反射學習】Java 反射基礎Java反射
- [Java 反射學習] Java 反射基礎Java反射
- Java學習:反射Java反射
- Java學習_反射Java反射
- java反射學習(一)Java反射
- Java學習之反射篇Java反射
- Java學習筆記--反射Java筆記反射
- Java學習筆記系列-反射Java筆記反射
- java反射機制的學習心得Java反射
- JAVA基礎學習篇之反射Java反射
- Java 反射機制學習資料Java反射
- JAVA核心技術學習筆記--反射Java筆記反射
- Java註解與反射學習筆記Java反射筆記
- .Net 反射學習反射
- java反射之動態代理學習筆記Java反射筆記
- Java高階特性之反射學習總結Java反射
- Java之反射--練習Java反射
- Java學習:反射的應用,依賴載入Java反射
- JAVA之反射學習3-反射獲取成員變數並賦值Java反射變數賦值
- JAVA之反射學習1-如何獲取Class物件Java反射物件
- Java學習之反射機制及應用場景Java反射
- Go 反射 學習筆記Go反射筆記
- java反射——反射AnnotationJava反射
- C# 反射/對映學習C#反射
- JAVA之反射學習2-獲取構造方法並使用Java反射構造方法
- 菜鳥學Java(十四)——Java反射機制(一)Java反射
- 菜鳥學Java(十五)——Java反射機制(二)Java反射
- Java學習十七—反射機制:解鎖程式碼的無限可能Java反射
- 註解和反射學習筆記反射筆記
- Java 反射Java反射
- Java——反射Java反射
- Java反射Java反射
- Java反射—初探反射基礎Java反射
- Java反射與反射優化Java反射優化
- java 學習筆記--利用反射實現自定義toString()的工具類Java筆記反射
- C#反射機制學習總結C#反射
- java學習之道 --- 如何學習java?Java
- Java 反射原理Java反射