1. 程式人生 > 實用技巧 >面試官:如何在Integer型別的ArrayList中同時新增String、Character、Boolean等型別的資料? | Java反射高階應用

面試官:如何在Integer型別的ArrayList中同時新增String、Character、Boolean等型別的資料? | Java反射高階應用

原文連結:原文來自公眾號:C you again,歡迎關注!

1、問題描述

    “如何在Integer型別的ArrayList中同時新增String、Character、Boolean等型別的資料?”

    你是不是想到下面的程式碼?

package com.cya.test;

import java.util.ArrayList;
import java.util.List;

public class Test{

    public static void main(String []args){

        List<Integer> list=new ArrayList<>();
        Integer in=1;
        Character ch='c';
        Boolean bo=true;
        list.add(in);
        list.add(ch);
        list.add(bo);
        System.out.println(list);

    }

}

    有點Java基礎的人都知道上面的程式碼執行會報錯,如果使用Eclipse等開發工具的話在沒執行之前就會提示有錯了,如下圖:


    強制執行一波,看下錯誤提示:

Exception in thread "main" java.lang.Error: Unresolved compilation problems: 
    The method add(Integer) in the type List<Integer> is not applicable for the arguments (Character)
    The method add(Integer) in the type List<Integer> is not applicable for the arguments (Boolean)

    at com.cya.test.Test.main(Test.java:15)

    聽說英語差的都去當程式設計師了!!

    不過沒關係,能get到大體意思就好了,上面的錯誤大體意思如下:

程式在編譯時遇到了無法解析的錯誤,
add方法的引數是Integer型別,無法接收Character型別的引數,
add方法的引數是Integer型別,無法接收Boolean型別的引數

    上面程式碼錯誤的原因是程式無法通過編譯,在編譯期出現異常,這和Java是編譯性語言(如:C、C++、Delphi、Pascal、Java)有關。與解釋性語言(如:Basic、javascript、Python)不同,Java先將字尾名為.java的原始碼檔案編譯成字尾名為.class的位元組碼檔案,編譯期間會進行詞法、語法、資料型別、語義分析。上面的錯誤就是在編譯期間進行資料型別分析時型別不匹配造成的。

    談到這裡,我們不得不提下Java的異常體系,異常體系結構圖如下:

2、什麼是異常

    程式在執行過程中發生由於硬體裝置問題、軟體設計錯誤等導致的程式異常事件。(在Java等面向物件的程式語言中)異常本身是一個物件,產生異常就是產生了一個異常物件。

3、異常體系分類

    如上面的Java異常體系結構圖所示,Throwable有兩個重要的子類:Exception(異常)和Error(錯誤),兩者都包含了大量的異常處理類。

    (一)Error(錯誤)
    程式中無法處理的錯誤,表示執行應用程式中出現了嚴重的錯誤。此類錯誤一般表示程式碼執行時JVM出現問題。通常有Virtual MachineError(虛擬機器執行錯誤)、NoClassDefFoundError(類定義錯誤)等。比如說當JVM耗完可用記憶體時,將出現OutOfMemoryError。此類錯誤發生時,JVM將終止執行緒。

    這些錯誤是不可查的,非程式碼性錯誤。因此,當此類錯誤發生時,應用不應該去處理此類錯誤。

    (二)Exception(異常)
    程式本身可以捕獲並且可以處理的異常。

    Exception這種異常又分為兩類:執行時異常和編譯異常。

  1. 執行時異常(不受檢異常):RuntimeException類及其子類表示JVM在執行期間可能出現的錯誤。比如說試圖使用空值物件的引用(NullPointerException)、陣列下標越界(ArrayIndexOutBoundException)。此類異常屬於不可查異常,一般是由程式邏輯錯誤引起的,在程式中可以選擇捕獲處理,也可以不處理。

  2. 編譯異常(受檢異常):Exception中除RuntimeException及其子類之外的異常。如果程式中出現此類異常,比如說IOException,必須對該異常進行處理,否則編譯不通過。在程式中,通常不會自定義該類異常,而是直接使用系統提供的異常類。

    看完了Java的異常體系,我們知道上面程式碼出現的異常為編譯時異常,是必須要處理的,否則無法通過編譯階段,更不要談運行了。

    既然上面程式碼不可用,那就請出本期的主角---Java的反射機制。

4、反射的概述

    JAVA反射機制是在執行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個物件,都能夠呼叫它的任意一個方法和屬性;這種動態獲取資訊以及動態呼叫物件方法的功能稱為Java語言的反射機制。

5、反射機制的作用

在執行時判斷任意一個物件所屬的類;
在執行時構造任意一個類的物件;
在執行時判斷任意一個類所具有的成員變數和方法;
在執行時呼叫任意一個物件的方法;

6、反射的三種實現方式

  1. 通過物件的getClass()方法。getClass()方法是Object類的方法,因為所有類都繼承自Object類,所以可以直接使用getClass()方法。
  2. 通過類名.class屬性。如果知道類的名稱,可以直接獲取一個類的Class。
  3. 通過Class類的forName(parameter)方法(常用)。這種方式是最常用的,在各類框架的配置檔案中可以看到,如:Spring、SpringMVC、Mybatis等等。其中,引數parameter為全限定類名(即:包名+類名),如:com.cya.test.Test。

7、通過反射獲取類中的方法

方法名稱 返回值 引數 說明
getMethods() Method [] 獲取包括自身和繼承過來的所有的public方法
getDeclaredMethods() Method [] 獲取自身類中所有的方法(不包括繼承的,和訪問許可權無關)
getMethod(String methodName,Class<?>... parameterTypes) Method methodName:表示被獲取方法的名字parameterTypes:表示被獲取方法的引數的Class型別,如String.class 表示獲取指定的一個公共的方法(包括繼承的)
getDeclaredMethod(String methodName,Class<?>... parameterTypes) Method methodName:表示被獲取方法的名字parameterTypes:表示被獲取方法的引數的Class型別,如 String.class 表示獲取指定的一個本類中的方法(不包括繼承的)

8、通過反射建立物件

    java中,除了使用new關鍵字建立物件外,也可以用newInstance()方法建立物件,例如:

Class class1 = Class.forName("java.util.ArrayList");
List list=(List)class1.newInstance();

9、Method類的invoke()方法

public Object invoke(Object obj,Object args[])
作用:動態呼叫Method類代表的方法
obj:從中呼叫底層方法的物件,必須是例項化的物件
args:用於方法呼叫的引數,是個Object陣列,因為引數有可能有多個
obj可以為空,但必填null,表示同類中的公用方法
args引數可以為空,就是對應方法沒有引數

    有關Java反射的詳細內容我將會專門出一期來講解,這裡只對本期用到的幾個重要的知識點做概述。

    看完了上面的內容,你是不是對面試官的問題有解答思路了呢?下面給出小編自己的想法,如果你有更好的方法,記得跟大家分享哦。

10、思路分享

1、建立Integer型別的List集合,用於存放資料。
2、使用物件名.getClass()方法獲取Class物件。
3、呼叫getMethod()方法獲取指定的Method。
4、呼叫invoke()方法將不同資料型別的資料新增到list集合中。

11、程式碼實現

package com.cya.test;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

public class Test{

    public static void main(String []args) throws Exception{

        List<Integer> list=new ArrayList<>();
        Object o;

        //向list中新增Integer型別的資料
        Integer integer=1;
        o=integer;
        Test.addObjectToList(list, o);

        //向list中新增String型別的資料
        String string="Hello World";
        o=string;
        Test.addObjectToList(list, o);

        //向list中新增Character型別的資料
        Character character='c';
        o=character;
        Test.addObjectToList(list, o);

        //向list中新增Boolean型別的資料
        Boolean boolean1=true;
        o=boolean1;
        Test.addObjectToList(list, o);

        System.out.println(list);

    }

public static List<Integer> addObjectToList(List<Integer> list, Object o) throws Exception{

        Class class1=list.getClass();
        Method method=class1.getMethod("add", Object.class);
        method.invoke(list, o);
        return list;
    }

}

12、公眾號推薦(資源加油站)

瞭解更多資源請關注個人公眾號:C you again,你將收穫以下資源

1、PPT模板免費下載,簡歷模板免費下載
2、基於web的機票預訂系統基於web的圖書管理系統
3、貪吃蛇小遊戲原始碼
4、各類IT技術分享

13、文章推薦

推薦一:計算機網路中這些高頻考題,你還在死記硬背嗎?(一),講述內容:IP地址及其分類,子網掩碼的概念,網路號、主機號、直接廣播地址計算方法等。

推薦二:計算機網路中這些高頻考題,你還在死記硬背嗎?(二),講述內容:區域網介面配置、路由器的靜態路由配置、OSPF動態路由協議配置和DHCP伺服器配置。

推薦三:用x種方式求第n項斐波那契數,99%的人只會第一種,講述內容:七種方式求解第N項斐波那契數。

    以上就是本期的所有內容了,是否對你有幫助呢?瞭解更多演算法請關注公眾號“C you again”。

演示地址:點選檢視演示