「面試複習」「Java」一、Java基礎

目錄

(一)Java基礎知識點

1)面向對象的特性有哪些?

2)面向對象和麪向過程的區別?

3)Java 中覆蓋和重載是什麼意思?

4)抽象類和接口的區別有哪些?

5)“static” 關鍵字是什麼意思?

6)Integer 的緩存機制

7)下述兩種方法分別創建了幾個 Sring 對象?

8)String、StringBuffer、StringBuilder的區別?

9)equals()方法和 “==” 運算符和hashCode()方法區別?

10)Java 對象初始化順序?

11)exception 和 error 有什麼區別?

12)throw 和 throws 有什麼區別?

13)單例模式?

(二)Java反射

1)什麼是反射?

2)反射的理解?

3)反射的用途?

4)反射的好處?

5)反射的使用?

參考:


(一)Java基礎知識點

1)面向對象的特性有哪些?

封裝、繼承和多態(應要多算一個那就是抽象)

  • 封裝:指的是將對象的狀態信息隱藏在對象內部,不允許外部程序直接訪問對象內部信息,而是通過該類所提供的方法來實現對內部信息的操作和訪問。
    但封裝不僅僅是 private + getter/setter ,使用封裝可以對 setter 進行更深層次的定製,例如你可以對執行方法的對象做規定,也可以對數據做一定的要求,還可以做類型轉換等等。使用封裝不僅僅安全,更可以簡化操作。(封裝擴展閱讀:oc面向對象三大特性之一 <封裝>

    訪問控制級別表:
     
     
    private
    default
    protected
    public
    同一個類中
    ☑️
    ☑️
    ☑️
    ☑️
    同一個包中
     
    ☑️
    ☑️
    ☑️
    子類中
     
     
    ☑️
    ☑️
    全局範圍內
     
     
     
    ☑️
  • 繼承:實現軟件複用的重要手段。子類是對父類的拓展,子類是特殊的父類。
    繼承的缺點:1)繼承是一種強耦合關係,父類變子類也必須變;2)繼承破壞了封裝,對於父類而言,它的實現細節對子類來說都是透明的。

  • 多態:Java引用變量有兩個類型:一個是編譯時類型,一個是運行時類型。編譯時類型由聲明該變量時使用的類型來決定,運行時類型由實際賦給該變量的對象決定。如果編譯時類型和運行時類型不一致,就有可能出現多態。簡而言之就是,相同類型的變量,調用同一個方法時呈現出不同的行爲特徵。

    (比如說,有一杯水,我不知道它是溫的、冰的還是燙的,但是我一摸我就知道了,我摸水杯的這個動作,對於不同溫度的水,就會得到不同的結果,這就是多態。)
    多態的條件1)繼承;2)重寫;3)向上轉型。

    多態的好處:當把不同的子類對象都當作父類類型來看,可以屏蔽不同子類對象之間的實現差異,從而寫出通用的代碼達到通用編程,以適應需求的不斷變化。(多態擴展閱讀:重新認識java(五) ---- 面向對象之多態(向上轉型與向下轉型)

    Father ins = new Son();
    ins.function();
    Ins只能調用Father(編譯時類型)的方法,但運行時實際執行的是Son(運行時類型)的方法。
  • 抽象是指從特定的角度出發,從已經存在的一些事物中抽取我們所關注的特性、行爲,從而形成一個新的事物的思維過程,是一種從複雜到簡潔的思維方式。

2)面向對象和麪向過程的區別?

面向過程是一種站在過程的角度思考問題的思想,強調的是功能行爲,功能的執行過程,即先幹啥,後幹啥。

  • 面向過程的設計,是採用置頂而下的設計方式,在設計階段就需要考慮每一個模塊應該分解成哪些子模塊,每一個子模塊有細分爲更小的子模塊,如此類推,直到將模塊細化爲一個個函數。
  • 問題:1)設計不夠直觀,與人類的習慣思維不一致;2)系統軟件適應性差,可擴展性差,維護性低。

面向對象是一種基於面向過程的新的編程思想,是一種站在對象的角度思考問題的思想,我們把多個功能合理的放到不同對象裏。

  • 面向對象更加符合我們常規的思維方式,穩定性好,可重用性強,易於開發大型軟件產品,有良好的可維護性。在軟件工程上,面向對象可以使工程更加模塊化,實現更低的耦合和更高的內聚。
  • 注意: 不要粗淺的認爲面向對象一定就優於面向過程的設計

擴展閱讀:面向過程 VS 面向對象

3)Java 中覆蓋和重載是什麼意思?

覆蓋(Override)是指子類對父類方法的一種重寫,只能比父類拋出更少的異常,訪問權限不能比父類的小,被覆蓋的方法不能是 private 的,否則只是在子類中重新定義了一個新方法。

重載(Overload)表示同一個類中可以有多個名稱相同的方法,但這些方法的參數列表各不相同。

構成重載的條件有哪些?

答:參數類型不同、參數個數不同、參數順序不同。

函數的返回值不同可以構成重載嗎?爲什麼?

答:不可以,因爲 Java 中調用函數並不需要強制賦值。

4)抽象類和接口的區別有哪些?

接口:接口作爲系統與外界交互的窗口,體現的是一種規範。

對於接口的實現者而言,接口規定了實現者必須向外提供哪些服務(以方法的方式提供);對於接口的調用者而言,接口規定了調用者可以調用哪些服務,以及如何調用這些服務(就是如何來調用方法)。

當在一個程序中使用接口時,接口是多個模塊間的耦合標準;當在多個應用程序之間使用接口時,接口是多個程序之間的通信標準。

接口類似於整個系統的“總綱”,制定了系統各個模塊應該遵循的標準。

抽象類:抽象類作爲系統中多個子類的共同父類,它所體現的是一種模版式設計。

抽象類作爲多個子類的抽象父類,可以被當作是系統實現過程中的中間產品,這個中間產品已經實現了系統的部分功能(那些已經提供實現的方法),但這個產品依然不能當成最終產品,必須有更進一步的完善,這種完善可能有幾種不同的形式。

都不能被實例化,都位於繼承樹的頂端,用於被其他類實現和繼承。

都包含抽象方法,實現接口或繼承抽象類的普通子類都必須實現這些抽象方法。

 
接口
抽象類
方法
只能包含抽象方法、靜態方法、默認方法,不能爲普通方法提供方法實現
完全可以包含普通方法
變量
只能定義靜態常量,不能定義普通成員變量
既可以定義普通成員變量,也可以定義靜態常量
構造器
不能包含構造器
可以包含構造器,抽象類中的構造器並不是用於創建對象,而是讓其子類調用這些構造器來完成屬於抽象類的初始化操作
初始化塊
不能包含初始化塊
完全可以包含初始化塊
繼承與實現
一個類可以直接實現多個接口
一個類只能有一個父類,包括抽象類

抽象類和接口如何選擇

答:

  1. 考慮你需要設計的是一種規範,還是一種模板。

  2. 如果要創建不帶任何方法定義和成員變量的基類,那麼就應該選擇接口而不是抽象類。

  3. 如果知道某個類應該是基類,那麼只有在必須要有方法定義和成員變量的時候,才應該選擇抽象類。因爲抽象類中允許存在一個或多個被具體實現的方法,只要方法沒有被全部實現該類就仍是抽象類。

5)“static” 關鍵字是什麼意思?

static” 關鍵字表明一個成員變量或者是成員方法是屬於類而非屬於對象的,可以在沒有所屬的類的實例變量的情況下被訪問。

Java中是否可以覆蓋(override)一個 private 或者是 static 的方法?

答:Java 中 static 方法不能被覆蓋,因爲方法覆蓋是基於運行時動態綁定的,而 static 方法編譯時靜態綁定的。static 方法跟類的任何實例都不相關,所以概念上不適用。

Java 中也不可以覆蓋 private 的方法,因爲 private 修飾的變量和方法只能在當前類中使用,如果是其他的類繼承當前類是不能訪問到 private 變量或方法的,當然也不能覆蓋。

擴展閱讀:重新認識java(六) ---- java中的另類:static關鍵字(附代碼塊知識)

6)Integer 的緩存機制

Integer 有緩存機制,在 JVM 啓動初期就緩存了 -128 到 127 這個區間內的所有數字。

7)下述兩種方法分別創建了幾個 Sring 對象?

// 第一種:直接賦一個字面量
String str1 = "ABCD";
// 第二種:通過構造器創建
String str2 = new String("ABCD");

String str1 = "ABCD";最多創建一個String對象,最少不創建String對象。如果常量池中,存在”ABCD”,那麼str1直接引用,此時不創建String對象。否則,先在常量池先創建”ABCD”內存空間,再引用。

String str2 = new String("ABCD");最多創建兩個String對象,至少創建一個String對象。new關鍵字絕對會在堆空間創建一塊新的內存區域,所以至少創建一個String對象。

  • 當執行第一句話的時候,會在常量池中添加一個新的ABCD字符,str1指向常量池的ABCD
  • 當執行第二句話的時候,因爲有new操作符,所以會在堆空間新開闢一塊空間用來存儲新的String對象,因爲此時常量池中已經有了ABCD字符,所以堆中的String對象指向常量池中的ABCD,而str2則指向堆空間中的String對象。

String 對象是一個特殊的存在,需要注意的知識點也比較多,這裏給一個之前寫的 String 詳解的文章鏈接:傳送門 其中包含的問題大概有:1)“+” 怎麼連接字符串;2)字符串的比較;3)StringBuilder/StringBuffer/String 的區別;

8)String、StringBuffer、StringBuilder的區別?

1. 可變不可變

String中使用字符數組保存字符串,如下就是,因爲有“final”修飾符,所以可以知道string對象是不可變的。

private final char value[];

StringBuilderStringBuffer都繼承自AbstractStringBuilder類,在AbstractStringBuilder中也是使用字符數組保存字符串,如下就是,可知這兩種對象都是可變的。

char[] value;

2. 是否線程安全

String中的對象是不可變的,也就可以理解爲常量,顯然線程安全

AbstractStringBuilder是StringBuilder與StringBuffer的公共父類,定義了一些字符串的基本操作,如expandCapacity、append、insert、indexOf等公共方法。

StringBuffer對方法加了同步鎖或者對調用的方法加了同步鎖,所以是線程安全的。看如下源碼:

public synchronized StringBuffer reverse() {
    super.reverse();
    return this;
}

StringBuilder並沒有對方法進行加同步鎖,所以是非線程安全的。

3. StringBuilderStringBuffer共同點

StringBuilder與StringBuffer有公共父類AbstractStringBuilder(抽象類)

抽象類與接口的其中一個區別是:抽象類中可以定義一些子類的公共方法,子類只需要增加新的功能,不需要重複寫已經存在的方法;而接口中只是對方法的申明和常量的定義。

StringBuilder、StringBuffer的方法都會調用AbstractStringBuilder中的公共方法,如super.append(...)。只是StringBuffer會在方法上加synchronized關鍵字,進行同步。

最後,如果程序不是多線程的,那麼使用StringBuilder效率高於StringBuffer。

9)equals()方法和 “==” 運算符和hashCode()方法區別?

equals()方法,該方法主要用於比較兩個對象是否相等。以下爲源碼:

public boolean equals(Object obj) {
    return (this == obj);
}

所有的對象都擁有標識(內存地址)狀態(數據)。“==”比較兩個對象的的內存地址,所以說Object的equals()方法就是比較兩個對象的內存地址是否相等。實際上,String、Math等封裝類都對equals()方法進行了重寫

1. 對於字符串變量來說,使用“==”“equals()”方法比較字符串時,其比較方法不同

  • “==”比較兩個變量本身的值,即兩個對象在內存中的首地址
  • “equals()”比較字符串中所包含的內容是否相同。

2. 對於非字符串變量來說,"==""equals"方法的作用是相同的都是用來比較其對象在堆內存的首地址,即用來比較兩個引用變量是否指向同一個對象
總之:

  • “equals()”方法對於字符串來說是比較內容的,而對於非字符串來說是比較其指向的對象是否相同的。
  • “==”是比較指向的對象是否相同的也就是對象在對內存中的的首地址

Java對象的eqauls方法hashCode方法是這樣規定的:

  • 相等(相同)的對象必須具有相等的哈希碼(或者散列碼)。
  • 如果兩個對象的hashCode相同,它們並不一定相同。

10)Java 對象初始化順序?

不考慮靜態成員的初始化,調用一個對象的構造函數時,程序1)先調用父類的構造函數(可以通過super關鍵字指定父類的構造函數,否則默認調用無參的構造函數,並且需要在子類的構造函數的第一行調用);2)之後靜態成員變量的初始化函數和靜態初始化塊則按照在代碼當中的順序執行,成員變量如果沒有指定值的話則賦予默認值,即基本數據類型爲0或false等,對象則爲null;3)最後調用自身構造函數。

11)exception 和 error 有什麼區別?

Exception 和 Error 都是繼承了 Throwable 類,在 Java 中只有 Throwable 類型的實例纔可以被拋出(throw)或者捕獲(catch),它是異常處理機制的基本組成類型。
Exception 和 Error 體現了 Java 平臺設計者對不同異常情況的分類。
Exception 是程序正常運行中,可以預料的意外情況,可能並且應該被捕獲,進行相應處理。
Error 是指在正常情況下,不大可能出現的情況,絕大部分的Error都會導致程序(比如 JVM 自身)處於非正常的、不可恢復狀態。既然是非正常情況,所以不便於也不需要捕獲,常見的比如OutOfMemoryError之類,都是Error的子類。

Exception 又分爲可檢查(checked)異常不檢查(unchecked)異常
可檢查異常在源代碼裏必須顯式地進行捕獲處理,這是編譯期檢查的一部分。前面我介紹的不可查的 Error,是 Throwable 不是 Exception。
不檢查異常就是所謂的運行時異常,類似 NullPointerException、ArrayIndexOutOfBoundsException 之類,通常是可以編碼避免的邏輯錯誤,具體根據需要來判斷是否需要捕獲,並不會在編譯期強制要求。

有哪些Error、Exception 或者 RuntimeException?

12)throw 和 throws 有什麼區別?

throw 關鍵字用來在程序中明確的拋出異常,相反,throws 語句用來表明方法不能處理的異常。每一個方法都必須要指定哪些異常不能處理,所以方法的調用者才能夠確保處理可能發生的異常,多個異常是用逗號分隔的。

13)單例模式?

 1、懶漢式,線程不安全

描述:這種方式是最基本的實現方式,這種實現最大的問題就是不支持多線程。因爲沒有加鎖 synchronized,所以嚴格意義上它並不算單例模式。

public class Singleton {  
    private static Singleton instance;  
    private Singleton (){}  
  
    public static Singleton getInstance() {  
        if (instance == null) {  
            instance = new Singleton();  
        }  
        return instance;  
     }  
}  

這段代碼簡單明瞭,而且使用了懶加載( lazy loading )模式,但是卻存在致命的問題。當有多個線程並行調用 getInstance() 的時候,就會創建多個實例。也就是說在多線程下不能正常工作。

2、懶漢式,線程安全

爲了解決上面的問題,最簡單的方法是將整個 getInstance() 方法設爲同步(synchronized)。

描述:這種方式具備很好的 lazy loading,能夠在多線程中很好的工作,但是,效率很低,99% 情況下不需要同步。
優點:第一次調用才初始化,避免內存浪費。
缺點:必須加鎖 synchronized 才能保證單例,但加鎖會影響效率。
getInstance() 的性能對應用程序不是很關鍵(該方法使用不太頻繁)。

public class Singleton {  
    private static Singleton instance;  
    private Singleton (){}  
    public static synchronized Singleton getInstance() {  
    if (instance == null) {  
        instance = new Singleton();  
    }  
    return instance;  
    }  
} 

雖然做到了線程安全,並且解決了多實例的問題,但是它並不高效。因爲在任何時候只能有一個線程調用 getInstance() 方法。但是同步操作只需要在第一次調用時才被需要(即if語句中判斷 instance 爲null時才調用,不爲null時是直接返回instance的),即第一次創建單例實例對象時。這就引出了雙重檢驗鎖。

3、雙檢鎖/雙重校驗鎖(DCL,即 double-checked locking)

雙重檢驗鎖模式(double checked locking pattern),是一種使用同步塊加鎖的方法。程序員稱其爲雙重檢查鎖,因爲會有兩次檢查 instance == null,一次是在同步塊外,一次是在同步塊內。爲什麼在同步塊內還要再檢驗一次?因爲可能會有多個線程一起進入同步塊外的 if,如果在同步塊內不進行二次檢驗的話就會生成多個實例了。

描述:這種方式採用雙鎖機制,安全且在多線程情況下能保持高性能。
getInstance() 的性能對應用程序很關鍵。

public class Singleton {
    private volatile static Singleton singleton;//聲明成 volatile
    private Singleton() {}

    public static Singleton getSingleton() {
        if (instance == null) {              // Single Checked
            synchronized (Singleton.class) {
                if (instance == null) {      // Double Checked
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}  

注意上面使用了volatile 關鍵字。

如果去掉volatile 關鍵字,它是有問題。主要在於instance = new Singleton()這句,這並非是一個原子操作,事實上在 JVM 中這句話大概做了下面 3 件事情。

  • 給 instance 分配內存
  • 調用 Singleton 的構造函數來初始化成員變量
  • 將instance對象指向分配的內存空間(執行完這步 instance 就爲非 null 了)

但是在 JVM 的即時編譯器中存在指令重排序的優化。也就是說上面的第二步和第三步的順序是不能保證的,最終的執行順序可能是 1-2-3 也可能是 1-3-2。如果是後者,則在 3 執行完畢、2 未執行之前,被線程二搶佔了,這時 instance 已經是非 null 了(但卻沒有初始化),所以線程二會直接返回 instance,然後使用,然後順理成章地報錯。

所以我們只需要將 instance 變量聲明成 volatile 就可以了。

4、餓漢式

餓漢法就是在第一次引用該類的時候就創建對象實例,而不管實際是否需要創建。

描述:這種方式比較常用,但容易產生垃圾對象。
優點:沒有加鎖,執行效率會提高。
缺點:類加載時就初始化,浪費內存。

它基於 classloder 機制避免了多線程的同步問題,不過,instance 在類裝載時就實例化,雖然導致類裝載的原因有很多種,在單例模式中大多數都是調用 getInstance 方法, 但是也不能確定有其他的方式(或者其他的靜態方法)導致類裝載,這時候初始化 instance 顯然沒有達到 lazy loading 的效果。

public class Singleton {  
    private static Singleton instance = new Singleton();  
    private Singleton (){}  
    public static Singleton getInstance() {  
        return instance;  
    }  
}

這種寫法如果完美的話,就沒必要在囉嗦那麼多雙檢鎖的問題了。缺點是它不是一種懶加載模式(lazy initialization),單例會在加載類後一開始就被初始化,即使客戶端沒有調用 getInstance()方法。餓漢式的創建方式在一些場景中將無法使用:譬如 Singleton 實例的創建是依賴參數或者配置文件的,在 getInstance() 之前必須調用某個方法設置參數給它,那樣這種單例寫法就無法使用了。

5、登記式/靜態內部類

描述:這種方式能達到雙檢鎖方式一樣的功效,但實現更簡單。對靜態域使用延遲初始化,應使用這種方式而不是雙檢鎖方式。這種方式只適用於靜態域的情況,雙檢鎖方式可在實例域需要延遲初始化時使用。

這種方式同樣利用了 classloder 機制來保證初始化 instance 時只有一個線程,它跟第 4 種方式不同的是:第 4 種方式只要 Singleton 類被裝載了,那麼 instance 就會被實例化(沒有達到 lazy loading 效果),而這種方式是 Singleton 類被裝載了,instance 不一定被初始化。因爲 SingletonHolder 類沒有被主動使用,只有顯示通過調用 getInstance 方法時,纔會顯示裝載 SingletonHolder 類,從而實例化 instance。想象一下,如果實例化 instance 很消耗資源,所以想讓它延遲加載,另外一方面,又不希望在 Singleton 類加載時就實例化,因爲不能確保 Singleton 類還可能在其他的地方被主動使用從而被加載,那麼這個時候實例化 instance 顯然是不合適的。這個時候,這種方式相比第 4 種方式就顯得很合理。

public class Singleton {  
    private static class SingletonHolder {  
        private static final Singleton INSTANCE = new Singleton();  
    }  
    private Singleton (){}  
    public static final Singleton getInstance() {  
        return SingletonHolder.INSTANCE;  
    }  
}  

這種寫法仍然使用JVM本身機制保證了線程安全問題;由於 SingletonHolder 是私有的,除了 getInstance() 之外沒有辦法訪問它,因此它是懶漢式的;同時讀取實例的時候不會進行同步,沒有性能缺陷;也不依賴 JDK 版本。

(二)Java反射

1)什麼是反射?

通過反射,我們可以在運行時獲得程序或程序集中每一個類型的成員和成員的信息。程序中一般的對象的類型都是在編譯期就確定下來的,而 Java 反射機制可以動態地創建對象並調用其屬性,這樣的對象的類型在編譯期是未知的。所以我們可以通過反射機制直接創建對象,即使這個對象的類型在編譯期是未知的。

反射的核心是 JVM 在運行時才動態加載類或調用方法/訪問屬性,它不需要事先(寫代碼的時候或編譯期)知道運行對象是誰。

Java 反射主要提供以下功能:

  • 在運行時判斷任意一個對象所屬的類;
  • 在運行時構造任意一個類的對象;
  • 在運行時判斷任意一個類所具有的成員變量和方法(通過反射甚至可以調用private方法);
  • 在運行時調用任意一個對象的方法

重點:是運行時而不是編譯時

2)反射的理解?

3)反射的用途?

  • 使用 IDE(如 Eclipse,IDEA)時,當輸入一個對象或類並想調用它的屬性或方法時,一按點號,編譯器就會自動列出它的屬性或方法,這裏就會用到反射。
  • 反射最重要的用途就是開發各種通用框架。很多框架(比如 Spring)都是配置化的(比如通過 XML 文件配置 Bean),爲了保證框架的通用性,它們可能需要根據配置文件加載不同的對象或類,調用不同的方法,這個時候就必須用到反射,運行時動態加載需要加載的對象。

4)反射的好處?

更加靈活,降低耦合,提高代碼的自適應能力。

不用反射:

public static void main(String[] args) {
    HeroFacrty facrty =new HeroFacrty();
    hero iroman= facrty.CreateHero("IronMan");
    iroman.attach();
}

public hero CreateHero(String name) {
    if ((name).equals("IronMan")) {
        return new IronMan();
    }
    if ((name).equals("Hulk")) {
        return new Hulk();
    }
    return null;
}

interface hero {
    public void attach();
}

class IronMan implements hero {

    @Override
    public void attach() {
        System.out.println("Laser Light");

    }
}

class Hulk implements hero {

    @Override
    public void attach() {
        System.out.println("fist");

    }
}

如果有成千上萬個hero,那麼過多的if判斷就會顯得非常冗餘。

利用反射:

public static void main(String[] args) {
    HeroFacrty facrty = new HeroFacrty();
    Hero hero=facrty.CreateHero("test.IroMan");
    hero.attack();
}

public Hero CreateHero(String name) {
    try {
        Class<?> cls = Class.forName(name);
        Hero hero = (Hero) cls.newInstance();
        return hero;
    } catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}


interface Hero {
    public void attack();
}

class IroMan implements Hero {
    @Override
    public void attack() {
        System.out.println("Laser Light");

    }
}

class Hulk implements Hero {
    @Override
    public void attack() {
        System.out.println("Fist");

    }
}

利用反射機制進行解耦的原理就是利用反射機制“動態”的的創建對象:向CreateHero()方法傳入Hero類的包名.類名,通過加載指定的類,然後再實例化對象。

5)反射的使用?

反射就是把Java類中的各種成分映射成一個個的Java對象。一個類有:構造方法、成員變量、成員方法、包等等信息,利用反射技術可以對一個類進行解剖,把個個組成部分映射成一個個對象。

獲取Class對象的方式:

  1. Object.getClass()
  2. 任何類(包括基本數據類型)都有一個“靜態”的class屬性
  3. 通過Class類的靜態方法:Class.forName(String  className)(常用)
		//第一種方式獲取Class對象  
		Student stu1 = new Student();//這一new 產生一個Student對象,一個Class對象。
		Class stuClass = stu1.getClass();//獲取Class對象

		//第二種方式獲取Class對象
		Class stuClass2 = Student.class;
		
		//第三種方式獲取Class對象
		try {
			Class stuClass3 = Class.forName("fanshe.Student");//注意此字符串必須是真實路徑,就是帶包名的類路徑,包名.類名
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}

獲取對象的構造方法:

批量的:

  • public Constructor[] getConstructors():所有"公有的"構造方法
  • public Constructor[] getDeclaredConstructors():獲取所有的構造方法(包括私有、受保護、默認、公有)

單個的:

  • public Constructor getConstructor(Class... parameterTypes):獲取單個的"公有的"構造方法:
  • public Constructor getDeclaredConstructor(Class... parameterTypes):獲取"某個構造方法"可以是私有的,或受保護、默認、公有

調用構造方法:

  • Constructor-->newInstance(Object... initargs)
//加載Class對象
Class clazz = Class.forName("fanshe.Student");
		
//1
Constructor[] conArray = clazz.getConstructors();
for(Constructor c : conArray){
    System.out.println(c);
}
conArray = clazz.getDeclaredConstructors();
for(Constructor c : conArray){
    System.out.println(c);
}
//2
Constructor con = clazz.getConstructor(null);
//調用構造方法
Object obj = con.newInstance();
		
con = clazz.getDeclaredConstructor(char.class);
//調用構造方法
con.setAccessible(true);//暴力訪問(忽略掉訪問修飾符)
obj = con.newInstance('男');

獲取成員變量:

批量的:

  • Field[] getFields():獲取所有的"公有字段"
  • Field[] getDeclaredFields():獲取所有字段,包括:私有、受保護、默認、公有;

單個的:

  • public Field getField(String fieldName):獲取某個"公有的"字段;
  • public Field getDeclaredField(String fieldName):獲取某個字段(可以是私有的)

設置字段的值:

  • Field --> public void set(Object obj,Object value):

參數:

1. obj:要設置的字段所在的對象;x

2. value:要爲字段設置的值;

獲取成員方法:

批量的:

  • public Method[] getMethods():獲取所有"公有方法";(包含了父類的方法也包含Object類)
  • public Method[] getDeclaredMethods():獲取所有的成員方法,包括私有的(不包括繼承的)

單個的:

  • public Method getMethod(String name,Class<?>... parameterTypes):
  • public Method getDeclaredMethod(String name,Class<?>... parameterTypes)

參數:
name : 方法名;
Class ... : 形參的Class類型對象

調用方法:

  • Method --> public Object invoke(Object obj,Object... args):

參數:
obj : 要調用方法的對象;
args:調用方式時所傳遞的實參;

 

 

 

參考:

https://www.jianshu.com/p/883260941da8

https://www.cnblogs.com/xudong-bupt/p/3961159.html

https://www.cnblogs.com/Qian123/p/5704007.html

https://www.cnblogs.com/Qian123/p/5703507.html

https://www.cnblogs.com/Qian123/p/5729172.html

https://www.sczyh30.com/posts/Java/java-reflection-1/

https://blog.csdn.net/sinat_38259539/article/details/71799078

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章