­

17Java進階——反射、進程、Java11新特性

1.Java反射機制

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.4Stream流

4.5其它特性