1 反射
什麼是反射
java反射 是指在執行狀態中 對於任意一個類 我們都可以知到這個類的所有方法和屬性 也可以呼叫其所有的方法和屬性 這種動態獲取的方式 我們稱為 反射
什麼是class物件
我們通過使用
反射
就是通過Class類來實現的Class
類的例項表示正在執行的 Java 應用程式中的類和介面。也就是jvm中有N多的例項每個類都有該Class物件。(包括基本資料型別)
反射的使用
獲取class物件的三種方式
基本類
/**
*
* @author : look-word
* @date : 2022-04-05 20:49
**/
public class Student {
private String username;
private String gender;
public String getInfo() {
this.setUsername("張三");
this.setGender("男");
return this.username+"="+this.gender;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
}
測試程式碼如下
/**
* @author : look-word
* @date : 2022-04-05 20:54
**/
public class Test {
public static void main(String[] args) {
/*
1 建立物件 獲取其class物件
*/
Student student = new Student();
Class<? extends Student> aClass = student.getClass();
System.out.println(aClass.getSimpleName());
/*
2 任何資料型別(包括基本資料型別)都有一個“靜態”的class屬性
*/
Class<? extends Student> bClass=Student.class;
System.out.println(aClass == bClass?"兩者是同一物件":"兩者不是同一物件");
/*
3 通過Class類的forName方法獲取
*/
try {
// Class.forName(類的相對路徑)
Class<?> cClass = Class.forName("bean.Student");
System.out.println(bClass == cClass?"兩者是同一物件":"兩者不是同一物件");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
結果如下
證明
在執行期間 一個類只有一個class物件的產生
常用的是
第三次
清晰 明瞭 因為 在一個專案中 可能會產生 相同名字的類解決疑惑 為什麼要是用 第三種
第一種物件都有了還要反射干什麼。
第二種需要匯入類的包,依賴太強,不導包就拋編譯錯誤。
第三種
,一個字串可以傳入也可寫在配置檔案中等多種方法。
獲取Class類中的所有構造方法
基本類
public class Student {
//---------------構造方法-------------------
//(預設的構造方法)
Student(String str){
System.out.println("(預設)的構造方法 s = " + str);
}
//無參構造方法
public Student(){
System.out.println("呼叫了公有、無參構造方法執行了。。。");
}
//有一個引數的構造方法
public Student(char name){
System.out.println("姓名:" + name);
}
//有多個引數的構造方法
public Student(String name ,int age){
System.out.println("姓名:"+name+" 年齡:"+ age);//這的執行效率有問題,以後解決。
}
//受保護的構造方法
protected Student(boolean n){
System.out.println("受保護的構造方法 n = " + n);
}
//私有構造方法
private Student(int age){
System.out.println("私有的構造方法 年齡:"+ age);
}
}
測試程式碼
/**
* 測試構造方法
* @author : look-word
* @date : 2022-04-05 21:18
**/
public class TestConstructor {
/**
* 通過Class物件可以獲取某個類中的:構造方法、成員變數、成員方法;並訪問成員;
*
* 1.獲取構造方法:
* 1).批量的方法:
* public Constructor[] getConstructors():所有"公有的"構造方法
public Constructor[] getDeclaredConstructors():獲取所有的構造方法(包括私有、受保護、預設、公有)
* 2).獲取單個的方法,並呼叫:
* public Constructor getConstructor(Class... parameterTypes):獲取單個的"公有的"構造方法:
* public Constructor getDeclaredConstructor(Class... parameterTypes):獲取"某個構造方法"可以是私有的,或受保護、預設、公有;
*
* 呼叫構造方法:
* Constructor-->newInstance(Object... initargs)
*/
public static void main(String[] args) throws Exception {
Class<?> student = Class.forName("bean.Student");
/*
1 獲取所有共有的構造方法
*/
System.out.println("\n1 獲取所有共有的構造方法");
Constructor<?>[] constructors = student.getConstructors();
for (Constructor<?> constructor : constructors) {
System.out.println(constructor);
}
/*
2 獲取共有的無參構造方法 可以寫 null 或者 不填
*/
System.out.println("\n2 獲取共有的無參構造方法 可以寫 null 或者 不填");
Constructor<?> constructor2 = student.getConstructor();
constructor2.newInstance();
/*
3 獲取 給定引數共有的構造方法 public bean.Student(java.lang.String,int)
*/
System.out.println("\n 3 獲取 給定引數共有的構造方法 public bean.Student(java.lang.String,int)");
Constructor<?> constructor3 = student.getConstructor(String.class, int.class);
constructor3.newInstance("張三",19);
/*
4 獲取 私有給定引數的構造方法 私有 不給定引數 不傳引數即可
*/
Constructor<?> constructor4 = student.getDeclaredConstructor(int.class);
/*
獲取私有的屬性 或者構造方法是 需要 設定無障礙 俗稱 暴力訪問
不設定 會出異常 java.lang.IllegalAccessException
*/
constructor4.setAccessible(true);
constructor4.newInstance(19);
}
}
執行結果
注意
獲取私有屬性的時候 一定要設定無障礙
setAccessible(true);
不設定 會出異常 java.lang.IllegalAccessException
newInstance(Object... initargs) 建立一個新例項
使用此Constructor
物件表示的構造方法來建立該構造方法的宣告類的新例項,並用指定的初始化引數初始化該例項。每次是用
newInstance
建立的物件 都是不同的物件 代表不同的例項
操作成員變數
基本類
public class Student {
public Student(){
}
//**********欄位*************//
public String name;
protected int age;
char sex;
private String phoneNum;
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + ", sex=" + sex
+ ", phoneNum=" + phoneNum + "]";
}
}
測試程式碼
/**
* @author : look-word
* @date : 2022-04-05 21:55
**/
public class TestField {
/*
* 獲取成員變數並呼叫:
*
* 1.批量的
* 1).Field[] getFields():獲取所有的"公有欄位"
* 2).Field[] getDeclaredFields():獲取所有欄位,包括:私有、受保護、預設、公有;
* 2.獲取單個的:
* 1).public Field getField(String fieldName):獲取某個"公有的"欄位;
* 2).public Field getDeclaredField(String fieldName):獲取某個欄位(可以是私有的)
*
* 設定欄位的值:
* Field --> public void set(Object obj,Object value):
* 引數說明:
* 1.obj:要設定的欄位所在的物件;
* 2.value:要為欄位設定的值;
*/
public static void main(String[] args) throws Exception{
Class<?> aClass = Class.forName("bean.Student");
Student student = new Student();
/*
獲取所有的共有欄位
*/
System.out.println("-------------------獲取所有的共有欄位--------------------");
Field[] fields = aClass.getFields();
for (Field field : fields) {
/*
filed => public java.lang.String bean.Student.username
filed => 成員變數
*/
/*
我理解為 給某個物件的 成員變數 賦值
當前的filed 為 username 因為這裡只能獲取為 共有屬性的成員變數
* field.set(student,"zhangsan");
*/
field.set(student,"zhangsan");
System.out.println(student);
/*
field.get(student);
獲取某student中的 field 的 內容
*/
Object o = field.get(student);
System.out.println(o);
/*
* 列印filed的內容 => public java.lang.String bean.Student.username
*/
System.out.println(field);
}
System.out.println("-------------------給私有欄位賦值--------------------");
Field phone = aClass.getDeclaredField("phone");
phone.setAccessible(true);// 設定無障礙
phone.set(student,"110");// 賦值給student物件
System.out.println("-------------------獲取私有欄位--------------------");
Field phone1 = aClass.getDeclaredField("phone");
phone1.setAccessible(true);// 設定無障礙
System.out.println(phone1.get(student));//取出student物件中的phone屬性的值
}
}
注意
在操作私有屬性的時候 不管是獲取還是設定值 都需要設定無障礙
setAccessible(true);// 設定無障礙