反射的概念 和基本使用(一)
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);// 設置無障礙