17Java進階——反射、進程、Java11新特性
- 2021 年 8 月 1 日
- 筆記
Java反射(Reflection)概念:在運行時動態獲取類的資訊以及動態調用對象方法的功能。
1.1反射的應用——通過全類名獲取類對象及其方法
package two.reflection; import java.util.Scanner; import java.lang.reflect.Method; public class Test1 { } class TestRef { public static void main(String[] args) { Scanner input = new Scanner(System.in); System.out.print("請輸入一個Java類全名:"); String cName = input.next(); showMethods(cName); } public static void showMethods(String name) { try { //使用Class.forName()獲得Class對象 //Class類存在於java.lang.Class Class c = Class.forName(name); //獲得該類聲明的方法,返回一個Method集合 //Method類位於java.lang.reflect包下 Method m[] = c.getDeclaredMethods(); System.out.print("該Java類的方法有:"); for (int i = 0; i < m.length; i++) { //將方法名、修飾符、參數列表輸出 System.out.println(m[i].toString()); } } catch (Exception e) { e.printStackTrace(); } } }
請輸入一個Java類全名:two.reflection.TestRef 該Java類的方法有:public static void two.reflection.TestRef.main(java.lang.String[]) public static void two.reflection.TestRef.showMethods(java.lang.String)
eclipse等開發環境中,使用對象會顯示其方法和屬性,就利用了java的反射機制。
1.2 java.lang
包中的 Class
類和 java.lang.reflect
包中的 Method
類、Field
類、Constructor
類、Array
類
常用方法:類名:
Class.forName(全類名):獲得類對象
類名.class:獲取Class對象
包裝類.TYPE:獲得Class對象
對象.getClass():獲取Class對象
class.getSuperClass():通過class對象獲取父類對象
class.getName():獲取類的全類名
欄位:
class.getFields():獲取所有public屬性(含繼承來的屬性)
class.getDeclaredFields():獲取所有訪問許可權的屬性(不含繼承來的屬性)
方法:
class.getMethods():獲取所有public修飾的方法,除構造函數(含繼承來的方法)
class.getDeclaredMethods():獲取所有訪問許可權的方法,除構造函數(不含繼承來的方法)
class.getMethods(String name,Class[] args):獲取特定的方法
class.getDeclaredMethods(String name,Class[] args):獲取特定的方法
構造方法:(返回類型是Constructor)
class.getConstructors():獲取公共的構造函數
class.getConstructors(Class[] args):獲取指定參數列表的構造函數
介面:
class.getInterfaces():獲取該類或者介面實現的介面數組
class.newInstance():使用無參構造方法創建該類的一個新實例
方法名、參數列表、返回值:
m.getName():獲取方法名
m.getDeclaringClass():獲取調用方法的類/介面
m.getParameterTypes():獲取形參列表的Class數組
m.getReturnType():獲取返回值類型
m.getModifiers():獲取修飾符
1.3 利用反射構造對象
獲得一個類的Class對象,使用class.newInstance()的方法得到Object對象,再強制轉型獲得實例對象。
就可以調用對象的公開方法,獲得對象的公開屬性。
如果類中沒有默認的無參構造方法,會報InstantiationException異常。
1.4利用反射獲得的構造方法實例化
無參構造:getDeclaredConstructor()獲得無參構造Constructor對象,調用newInstance()方法。得到Object對象後強制類型轉換。
帶參構造:getDeclaredConstructor((Class[] args))獲得帶參構造Constructor對象,調用newInstance(Object[] o)方法,輸入傳入的參數。得到Object對象後強制類型轉換。
1.5使用反射修改屬性訪問許可權
Field f = c.getDeclaredField(name);
f.setAccessible(true); //取消屬性的訪問許可權控制,即使private屬性也可以進行訪問
f.get(sup));獲取欄位值
f.set(sup,20));設置欄位值
1.6使用反射調用特定方法
Method m = c.getDeclaredMethod(name,params);
m.invoke(Object o,Object[] args):調用對象o對應方法,對象o是調用方法的對象
1.7使用反射包下Array類構造動態數組
Array.newInstance(Class componentType, int length):返回一個Object類型的數組
Array.getXxx(Object array, int index):返回下標元素,為xxx類型
Array.setXxx(Object array, int index,xxx val):將下標為index的元素修改為xxx類型的值
int dim[] = {8, 10};
Object arr = Array.newInstance(Integer.TYPE, dim);:創建一個8*10的二維數組
沒有賦值的情況下,和數組沒有賦值的情況是相同的。
2 執行緒補充知識
2.1執行緒的三大優勢
系統開銷小
方便通訊和資源共享
簡化程式結構
2.2執行緒的其他常用方法
void interrupt():中斷執行緒的阻塞狀態(而非中斷執行緒)
boolean isAlive():判定該執行緒是否處於活動狀態,處於就緒、運行和阻塞狀態的都屬於活動狀態。
boolean isDaemon():判斷一個執行緒是否是守護執行緒
3 註解
註解是 Java 程式碼中的特殊標記,這些標記可以在編譯、類載入、運行時被讀取,並執行相應的處理。
註解以@開頭,註解有不帶參數的,一個參數的和多個參數的。
內建註解:@Override @Deprecated @SuppressWarnings
@Override:重寫方法
@Deprecated:已過時
@SuppressWarnings:抑制警告。可以將value設置為以下值
deprecation:使用了過時的程式元素。 unchecked:執行了未檢查的轉換。 unused:有程式元素未被使用。 fallthrough:switch 程式塊直接通往下一種情況而沒有 break。 path:在類路徑中有不存在的路徑。 serial:在可序列化的類上缺少 serialVersionUID 定義。 finally:任何 finally 子句都不能正常完成。 all:所有情況。
元註解:@Target @Retention @Documented @Inherited
@Target:指定被修飾的註解能修飾哪些元素。value可以設置為以下值
ElementType.ANNOTATION_TYPE:註解類型聲明 ElementType.CONSTRUCTOR:構造方法聲明 ElementType.FIELD:欄位聲明(包括枚舉常量) ElementType.LOCAL_VARIABLE:局部變數聲明 ElementType.METHOD:方法聲明 ElementType.PACKAGE:包聲明 ElementType.PARAMETER:參數聲明 ElementType.TYPE:類、介面(包括註解類型)或枚舉聲明
@Retention:指定被修飾的註解可以保留多長時間
RetentionPolicy.CLASS:編譯器將把註解記錄在 class 文件中,當運行 Java 程式時,虛擬機不再保留註解 RetentionPolicy.RUNTIME:編譯器將把註解記錄在 class 文件中,當運行 Java 程式時,虛擬機保留註解,程式可以通過反射獲取該註解 RetentionPolicy.SOURCE:編譯器將直接丟棄被修飾的註解
@Documented:如果添加該註解,那麼所有被該註解修飾的註解出現在使用的類的javadoc中。
@Inherited:修飾的註解是可以被繼承的
3.1 自定義註解並完成賦值
4 Java11新特性
4.1Lambda表達式
lambda表達式用法:簡化函數式介面的實現。
lambda表達式格式:()->語句
()是形參列表,沒有參數為(),一個參數為(s),兩個參數為(s1,s2)。可以省略形參的類型,也可以全部寫上。形參列表的變數需要提前定義好。
語句可以是一條,不需要寫大括弧,可以有返回值也可以沒有。如果寫上return ,必須要有大括弧。如果是多條,需要寫大括弧。
lambda表達式可以作為參數傳入。
A b = (z,x)->z+x; A ccc = (int z,int x)->z+x;//都是正確實現
interface A{ int add(int a,int b); }
函數式介面:介面中只有一個抽象方法。可以用@FunctionalInterface修飾,也可以不修飾
四大函數式介面:
Consumer<T>{void consume(T t);}
Predicate<T>{boolean test(T t);}
Function<T,R>{R apply(T t);}
Supplier<T> {T get();}
Comparable的lambda表達式:Arrays.sort(a,((o1, o2) -> o2-o1));
4.2 方法引用
引用某個對象的實例方法:對象名 :: 非靜態方法
引用類中的實例方法:類名 :: 非靜態方法
引用構造方法:類名:: new
引用數組:元素類型[] :: new
4.2.介面的默認方法
jdk11後允許方法中有默認方法。修飾符是public default,default不能省略。
實現類可以重寫介面中的抽象方法,但是同時實現多個介面且默認方法重名,重寫方法會引起編譯錯誤。
解決方法:實現類重寫重名方法,內部使用介面名.super.方法名(),讓重名方法轉化為一個介面的實現。
4.3重複註解
4.5其它特性