17Java進階——反射、程序、Java11新特性
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其它特性