Java的反射機制粗淺學習
阿新 • • 發佈:2020-12-30
Java的反射機制
- JAVA反射機制是在執行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個物件,都能夠呼叫它的任意方法和屬性;
- 這種動態獲取資訊以及動態呼叫物件方法的功能稱為java語言的反射機制。
- 反射機制多用於程式執行後才能確定建立的類的場景
- 首先準備了兩個類,一個介面與一個註解
// 自定義註解 @Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE}) @Retention(RetentionPolicy.RUNTIME) public @interface MyAnnotation { String value(); }
// 自定義介面
public interface MyInterface {
// 自定義介面
void myMethod();
}
// Person類 public class Person implements Serializable { // attribute private int age; public String name; // method private void eat(){ System.out.println("Person--eat"); } public void sleep(){ System.out.println("Person--sleep"); } }
// Student類 @MyAnnotation("hello") public class Student extends Person implements MyInterface { // 屬性 private int sno;//學號 double height;//身高 protected double weight;// 體重 public double score;// 成績 // 方法 public String showInfo(){ return "我是一名三好學生"; } @MyAnnotation("hi method") public String showInfo(int a, int b){ return "我是一名三好學生,過載方法"; } private void work(int a){ System.out.println("好好工作,碼農"); } void happy(){ System.out.println("做人要開心"); } protected int getSno(){ return sno; } // 構造器 public Student(){ } public Student(double weight, double height){ this.weight = weight; this.height = height; } private Student(int sno){ this.sno = sno; } Student(int sno, double height){ this.sno = sno; this.height = height; } protected Student(int sno,double height,double weight){ this.sno = sno; this.height = height; this.weight = weight; } @Override @MyAnnotation("hello mymethod") public void myMethod() throws RuntimeException{ System.out.println("重寫介面方法"); } @Override public String toString() { return "Student{" + "sno=" + sno + ", height=" + height + ", weight=" + weight + ", score=" + score + '}'; } }
獲取類的構造器與建立物件
- 反射機制中,無論是進行什麼操作,首先都需要先獲取位元組碼資訊
xxx.class
,然後才能通過位元組碼資訊完成後續操作
public class Test01 {
// 這是main方法,實現程式主要邏輯
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
// 獲取位元組碼資訊
Class cls = Student.class;
// 通過位元組碼資訊獲取構造器
// getConstructors() 只能獲取當前執行時類被public修飾的構造器
Constructor[] c1 = cls.getConstructors();
for(Constructor c:c1){
System.out.println(c);
}
System.out.println("---------------------------");
// getDeclaredConstructors() 獲取執行時,類的全部修飾符的構造器
Constructor[] c2 = cls.getDeclaredConstructors();
for(Constructor c: c2){
System.out.println(c);
}
System.out.println("---------------------------");
// 獲取指定的構造器
// 什麼都不傳的話,會獲得public修飾的空參構造器
Constructor con1 = cls.getConstructor();
System.out.println(con1);
// 獲取兩個引數的public修飾的有參構造器
Constructor con2 = cls.getConstructor(double.class, double.class);
System.out.println(con2);
// 獲取一個引數的private修飾的有參構造器
Constructor con3 = cls.getDeclaredConstructor(int.class);
System.out.println(con3);
// 使用構造器建立物件
Object o1 = con1.newInstance();
System.out.println(o1);
Object o2 = con2.newInstance(120.5, 180.4);
System.out.println(o2);
}
}
獲取類的屬性並進行賦值
public class Test02 {
// 這是main方法,實現程式主要邏輯
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, InstantiationException {
// 獲取位元組碼資訊
Class cls = Student.class;
// 獲取屬性
// getFields() 獲取執行時類和父類中被public修飾的屬性,包含父類
Field[] fields = cls.getFields();
for(Field f:fields){
System.out.println(f);
}
System.out.println("________________________________");
// getDeclaredFields 獲取執行時類中的所有屬性,不包含父類
Field[] declaredFields = cls.getDeclaredFields();
for(Field f:declaredFields){
System.out.println(f);
}
System.out.println("________________________________");
// 獲取指定屬性
Field score = cls.getField("score");
System.out.println(score);
Field sno = cls.getDeclaredField("sno");
System.out.println(sno);
System.out.println("________________________________");
// 屬性的具體結構
// 獲取修飾符
int modifiers = sno.getModifiers();
System.out.println(modifiers);
System.out.println(Modifier.toString(modifiers));
// 獲取屬性的資料型別
Class type = sno.getType();
System.out.println(type.getName());
// 獲取屬性的名字
System.out.println(sno.getName());
System.out.println("________________________________");
// 給屬性賦值 給屬性賦值,必須要有這個類的物件,首先要建立物件才行
Field sco = cls.getField("score");
Object obj = cls.newInstance();
sco.set(obj, 98);
System.out.println(obj);
}
}
獲取方法並呼叫方法
public class Test03 {
// 這是main方法,實現程式主要邏輯
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
// 首先獲取位元組碼資訊
Class cls = Student.class;
// 獲取public修飾的方法 包含父類
Method[] me1 = cls.getMethods();
for(Method m:me1){
System.out.println(m);
}
System.out.println("________________________");
// 獲取所有的方法,不包含父類
Method[] me2 = cls.getDeclaredMethods();
for(Method m:me2){
System.out.println(m);
}
System.out.println("________________________");
// 獲取指定方法(無參)
Method showInfo = cls.getMethod("showInfo");
System.out.println(showInfo);
// 獲取指定方法(有參)
Method showInfo2 = cls.getMethod("showInfo",int.class,int.class);
System.out.println(showInfo2);
//獲取private修飾的方法
Method work = cls.getDeclaredMethod("work",int.class);
System.out.println(work);
System.out.println("________________________");
// 獲取方法的具體結構
/*
@註解
修飾符 返回值型別 方法名(引數列表) throws XXXX{}
*/
// 方法名
System.out.println(work.getName());
// 修飾符
int modifiers = work.getModifiers();
System.out.println(Modifier.toString(modifiers));
// 返回值
System.out.println(work.getReturnType());
// 引數列表
Class[] parameterTypes = work.getParameterTypes();
for(Class c:parameterTypes){
System.out.println(c);
}
// 註解
Method myMethod = cls.getMethod("myMethod");
Annotation[] annotations = myMethod.getAnnotations();
for(Annotation a:annotations){
System.out.println(a);
}
// 異常
Class[] exceptionTypes = myMethod.getExceptionTypes();
for(Class c:exceptionTypes){
System.out.println(c);
}
System.out.println("________________________");
// 呼叫方法
Object o = cls.newInstance();
myMethod.invoke(o);
System.out.println(showInfo2.invoke(o, 12, 14));
}
}
獲取類的結構相關資訊
public class Test04 {
// 這是main方法,實現程式主要邏輯
public static void main(String[] args) {
// 獲取位元組碼資訊
Class cls = Student.class;
// 獲取執行時類的介面
Class[] interfaces = cls.getInterfaces();
for(Class c:interfaces){
System.out.println(c);
}
System.out.println("____________________________");
// 獲取父類的介面
// 先得到父類的位元組碼資訊
Class superclass = cls.getSuperclass();
// 獲取父類介面
Class[] interfaces1 = superclass.getInterfaces();
for(Class c:interfaces1){
System.out.println(c);
}
System.out.println("____________________________");
// 執行時類所在包
Package aPackage = cls.getPackage();
System.out.println(aPackage);
System.out.println(aPackage.getName());
System.out.println("____________________________");
// 執行時類的註解
Annotation[] annotations = cls.getAnnotations();
for(Annotation a:annotations){
System.out.println(a);
}
}
}