Java筆記-反射
反射:
通過java語言的反射機制可以操作位元組碼檔案。
在java.lang.reflect.*;的包下。
反射機制重要的類:
java.lang.Class; //代表整個位元組碼檔案
java.lang.reflect.Method; //代表位元組碼中的方法位元組碼
java.lang.reflect.Constructor; //代表位元組碼中的構造方法位元組碼
java.lang.Field; //代表位元組碼中的屬性位元組碼。類中的成員變數,包括靜態變數、例項變數。
java.lang.Class:
獲取java.lang.Class的方式:
1.用Class.forName()來獲取:1.靜態方法。2.方法的引數是一個字串。3.字串需要是一個完整類名。4.完整類名帶有包名。
2.用getClass()方法來獲取:任何一個物件都有getClass()方法。返回當前物件方法區的位元組碼檔案。
3.用class屬性來獲取:java語言中任何一種型別,包括基本資料型別,都有class屬性。
- 可以通過獲得當前的Class檔案(c),使用c.newInstance()來建立物件。通過反射機制建立物件。此時,只需要修改
配置檔案中的資訊,就可以實現建立不同物件的功能。 - 使用Class.forName(“完整類名”); 會導致類載入,這樣可以只執行這個類的靜態程式碼塊。
java.lang.Field:
通過 類名.getFields() 可以得到field陣列,陣列中是類中所有public修飾的屬性。
通過得到的field.getName(),方法可以得到屬性名。
類名.getDeclaredFields(),可以獲得類中所有屬性。
field.getType(),可以得到當前屬性的型別,返回一個class,可以通過field.getType().getName()獲得型別名字。
getModifiers(),class中的方法,可以返回此類或介面的修飾符,返回的是int型別,
可以通過Modifiers中的toString(int mod) 方法,將返回的int型別資料轉換為對應的修飾符。
使用反射機制去訪問一個物件的屬性:
Class studentClass = Class.forName("reflesh.student");
Object obj = studentClass.newInstance();//obj是student物件,底層呼叫無參構造方法。
//獲取名字為no的屬性
Field noField = studentClass.getField("no");
//給obj物件的no屬性賦值222.
noField.set(obj,222);
//讀取obj物件的no屬性的值。
noField.get(obj);
注意:以上訪問只能訪問public型別的,private型別的需要用Field類中的方法**setAccessible(true)**來打破封裝,才可以獲取。
java.lang.reflect.Method:
通過 類名.getDeclaredMethods() 返回一個Methods陣列,陣列中存放物件的所有方法。
Method.getName();//返回方法的名字
Method.getModifiers();//返回修飾符列表,返回的是數值
Method.toString();//通常將Method.getModifiers()返回的數值傳進去,返回修飾符列表。
Method.getReturnType();//可以獲得方法的返回值型別。可配合.getSimpleName()使用。
Method.getParameterTypes();//可以獲得引數型別陣列,通過getSimpleName()方法可以看到屬性。
使用反射機制去呼叫一個物件的方法(重點):
例如:
public static void main(String[] args) throws Exception {
Class student = Class.forName("reflesh.student");//獲取類
Object obj = student.newInstance();//用類來new物件
Method method = student.getDeclaredMethod("login",String.class,String.class);//獲取物件的方法
Object result = method.invoke(obj,"admin","123");//將方法和這個物件繫結,傳參。
}
反射機制讓程式碼具有通用性,可變化的內容寫到配置檔案中。修改配置檔案可以建立不同的物件和方法,java程式碼不需要修改。
java.lang.reflect.Constructor:
通過類名.getDeclaredConstructors();獲得一個Constructor陣列,裡面存放物件的所有構造方法。
通過constructor.getModifiers();獲得構造方法的修飾符
通過constructors.getParameterTypes();可以獲得當前構造方法的引數型別陣列
用反射調構造方法:
無引數構造方法:
Class student = Class.forName("reflesh.student");
Object obj = student.newInstance();
有引數構造方法:
Class student = Class.forName("reflesh.student");
Constructor con = student.getDeclaredConstructor(String.class,String.class);
con.newInstance("sun","6225");
路徑問題:
解決通常情況下,程式碼交換位置出現的路徑問題,前提條件:檔案必須在類路徑(在src下的都是類路徑)下。
String path = Thread.currentThread().getContextClassLoader().getResource("test.properties").getPath();
Thread.currentThread() | 當前執行緒物件。 |
getContextClassLoader | 執行緒物件的方法,可以獲得當前執行緒的類載入器物件。 |
getResource() | 獲得資源,類載入器的方法,當前執行緒的類載入器預設從根路徑下載入資源。 |
也可以在類載入器中使用getResourceAsStream()方法得到流。
例如:
InputStream reader = Thread.currentThread().getContextClassLoader().getResourceAsStream("test.properties");
資源繫結器:
使用這種方式時,配置屬性檔案必須放在類路徑下。並且只能繫結xx.properties檔案。
在寫路徑的時候,路徑後面的副檔名不能寫。
ResourceBundle bundle = ResourceBundle.getBundle("test");
String className = bundle.getString("ClassName");
類載入器:
專門負責載入類的命令/工具。ClassLoader
JDK自帶的3個類載入器:
1.啟動類載入器:
程式碼在開始執行前,會將所需要的類全部載入到JVM中。首先通過啟動類載入器載入.class檔案,專門載入核心類庫(rt.jar)。
2.擴充套件類載入器:
如果通過啟動類載入器載入不到時,會通過擴充套件類載入器載入。擴充套件類載入器專門載入ext目錄中的檔案。
3.應用類載入器:
如果擴充套件類載入器也沒有找到,會通過應用類載入器載入,應用類載入器專門載入classpath中的jar包。
雙親委派機制:
為了保證類載入的安全,優先從啟動類載入器中載入(父),再從擴充套件類載入器中載入(母),如果都載入不到
才會考慮從應用類載入器中載入。
可變長度引數:
在方法的引數中,型別的後面加…可以實現。
例如:public static void add(int… args)
可以將可變長度引數當作一個陣列來看。
例如:
public static void main(String[] args) {
reflesh3.printString("abc","efg","ghj");//這裡也可以直接傳一個陣列
}
public static void printString(String...args){
for (int i = 0; i < args.length; i++) {
System.out.println(args[i]);
}
}
注意:可變長引數只能有1個,且必須在引數列表的最後。
如何獲得一個類的父類:
通過getSuperclass()來獲取父類。
例如:
public static void main(String[] args) throws Exception{
Class stringClass = Class.forName("java.lang.String");
Class superClass = stringClass.getSuperclass();
System.out.println(superClass.getSimpleName());
}
如何獲得一個類的所有介面:
通過getInterfaces()方法來獲得一個陣列,陣列中存放物件的所有介面。
例如:
public static void main(String[] args) throws Exception{
Class stringClass = Class.forName("java.lang.String");
Class[] interfaces = stringClass.getInterfaces();
for(Class in : interfaces){
System.out.println(in.getSimpleName());
}
}
相關文章
- Java筆記-Java反射(二)Java筆記反射
- java基礎 -反射筆記Java反射筆記
- Java筆記-反射機制(一)Java筆記反射
- Java學習筆記系列-反射Java筆記反射
- JAVA核心技術學習筆記--反射Java筆記反射
- Java註解與反射學習筆記Java反射筆記
- java反射之動態代理學習筆記Java反射筆記
- Java基礎加強筆記——測試、反射、註解Java筆記反射
- 筆記-go反射操作私有變數筆記Go反射變數
- 註解和反射學習筆記反射筆記
- 【Java 反射學習】Java 反射基礎Java反射
- [Java 反射學習] Java 反射基礎Java反射
- Java 反射Java反射
- Java——反射Java反射
- Java反射Java反射
- java 筆記Java筆記
- Java反射—初探反射基礎Java反射
- 【Java筆記】Java JDKJava筆記JDK
- Java 反射 APIJava反射API
- Java 反射原理Java反射
- Java的反射Java反射
- 20201209——java反射Java反射
- java 筆記(草稿)Java筆記
- Java安全筆記Java筆記
- Java筆記1Java筆記
- Java筆記——【Map】Java筆記
- Java筆記02Java筆記
- 淺析Java反射--JavaJava反射
- java筆記-one(簡記)Java筆記
- 《Go 語言程式設計》讀書筆記(十)反射Go程式設計筆記反射
- 我的 golang 學習筆記系列四:反射初識Golang筆記反射
- Java基礎系列—Java反射Java反射
- Java 反射基礎Java反射
- Java反射-註解Java反射
- Java學習:反射Java反射
- Java反射-屬性Java反射
- Java反射-模組Java反射
- Java 反射詳解Java反射