亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

實例講解Java編程中數組反射的使用方法

 更新時間:2016年04月25日 14:22:53   作者:RiccioZhang  
這篇文章主要介紹了Java編程中數組反射的使用方法,通過編寫數組反射工具類可以重用許多基礎代碼,減少對類型的判斷過程,需要的朋友可以參考下

什么是反射
“反射(Reflection)能夠讓運行于JVM中的程序檢測和修改運行時的行為。”這個概念常常會和內?。↖ntrospection)混淆,以下是這兩個術語在Wikipedia中的解釋:

  • 內省用于在運行時檢測某個對象的類型和其包含的屬性;
  • 反射用于在運行時檢測和修改某個對象的結構及其行為。
  • 從它們的定義可以看出,內省是反射的一個子集。有些語言支持內省,但并不支持反射,如C++。

內省示例:instanceof 運算符用于檢測某個對象是否屬于特定的類。

if (obj instanceof Dog) {
  Dog d = (Dog) obj;
  d.bark();
}

反射示例:Class.forName()方法可以通過類或接口的名稱(一個字符串或完全限定名)來獲取對應的Class對象。forName方法會觸發(fā)類的初始化。

// 使用反射
Class<?> c = Class.forName("classpath.and.classname");
Object dog = c.newInstance();
Method m = c.getDeclaredMethod("bark", new Class<?>[0]);
m.invoke(dog);

在Java中,反射更接近于內省,因為你無法改變一個對象的結構。雖然一些API可以用來修改方法和屬性的可見性,但并不能修改結構。

數組的反射
數組的反射有什么用呢?何時需要使用數組的反射呢?先來看下下面的代碼:

Integer[] nums = {1, 2, 3, 4}; 
Object[] objs = nums; //這里能自動的將Integer[]轉成Object[] 
Object obj = nums; //Integer[]當然是一個Object 
int[] ids = {1, 2, 3, 4}; 
//Object[] objs2 = ids; //這里不能將int[]轉換成Object[] 
Object obj2 = ids; //int[] 是一個Object 

上面的例子表明:基本類型的一維數組只能當做Object,而不能當作Object[]。

int[][] intArray = {{1, 2}, {3, 4}}; 
Object[] oa = intArray; 
Object obj = intArray; 
//Integer[][] integerArray = intArray; int[][] 不是 Integer[][] 
Integer[][] integerArray2 = new Integer[][]{{1, 2}, {3, 4}}; 
Object[][] oa2 = integerArray2; 
Object[] oa3 = integerArray2; 
Object obj2 = integerArray2; 

從上面的例子可以看出java的二位數組是數組的數組。下面來看下對數組進行反射的例子:

package cn.zq.array.reflect; 
 
import java.lang.reflect.Array; 
import java.util.Arrays; 
import java.util.Random; 
 
public class ArrayReflect { 
  public static void main(String[] args) { 
    Random rand = new Random(47); 
    int[] is = new int[10]; 
    for(int i = 0; i < is.length; i++) { 
      is[i] = rand.nextInt(100); 
    } 
    System.out.println(is); 
    System.out.println(Arrays.asList(is)); 
    /*以上的2個輸出都是輸出類似"[[I@14318bb]"的字符串, 
      不能顯示數組內存放的內容,當然我們采用遍歷的方式來輸出數組內的內容*/ 
    System.out.println("--1.通過常規(guī)方式遍歷數組對數組進行打印--"); 
    for(int i = 0; i < is.length; i++) { 
      System.out.print(is[i] + " "); 
    } 
    System.out.println(); 
    System.out.println("--2.通過數組反射的方式遍歷數組對數組進行打印--"); 
    Object obj = is; //將一維的int數組向上轉為Object 
    System.out.println("obj isArray:" + obj.getClass().isArray()); 
    for(int i = 0; i < Array.getLength(obj); i++) { 
      int num = Array.getInt(obj, i); 
      //也能通過這個常用的方法來獲取對應索引位置的值 
      //Object value = Array.get(obj, i); //如果數組存放的是基本類型,那么返回的是基本類型對應的包裝類型 
      System.out.print(num + " "); 
    } 
  } 
} 

輸出:

[I@14318bb 
[[I@14318bb] 
--1.通過常規(guī)方式遍歷數組對數組進行打印-- 
58 55 93 61 61 29 68 0 22 7  
--2.通過數組反射的方式遍歷數組對數組進行打印-- 
obj isArray:true 
58 55 93 61 61 29 68 0 22 7 

上面的例子首先創(chuàng)建了一個int的一維數組,然后隨機的像里面填充0~100的整數,接著通過System.out.println()方法直接對數組輸出或者用Arrays.asList方法(如果不是基本類型的一維數組此方法能按照期望轉成List,如果是二維數組也不能按照我們期望轉成List)將數組轉成List再輸出,通過都不是我們期望的輸出結果。接下來以常規(guī)的數組的遍歷方式來輸出數組內的內容,然后將int[]看成是一個Object,利用反射來遍歷其內容。Class.isArray()可以用來判斷是對象是否為一個數組,假如是一個數組,那么在通過java.lang.reflect.Array這個對數組反射的工具類來獲取數組的相關信息,這個類通過了一些get方法,可以用來獲取數組的長度,各個版本的用來獲取基本類型的一維數組的對應索引的值,通用獲取值的方法get(Object array, int index),設置值的方法,還有2個用來創(chuàng)建數組實例的方法。通過數組反射工具類,可以很方便的利用數組反射寫出通用的代碼,而不用再去判斷給定的數組到底是那種基本類型的數組。

package cn.zq.array.reflect; 
 
import java.lang.reflect.Array; 
 
public class NewArrayInstance { 
  public static void main(String[] args) { 
    Object o = Array.newInstance(int.class, 20); 
    int[] is = (int[]) o; 
    System.out.println("is.length = " + is.length); 
    Object o2 = Array.newInstance(int.class, 10, 8); 
    int[][] iss = (int[][]) o2; 
    System.out.println("iss.length = " + iss.length  
        + ", iss[0].lenght = " + iss[0].length); 
  } 
} 

is.length = 20 
iss.length = 10, iss[0].lenght = 8 

Array總共通過了2個方法來創(chuàng)建數組
Object newInstance(Class<?> componentType, int length),根據提供的class來創(chuàng)建一個指定長度的數組,如果像上面那樣提供int.class,長度為10,相當于new int[10];
Object newInstance(Class<?> componentType, int... dimensions),根據提供的class和維度來創(chuàng)建數組,可變參數dimensions用來指定數組的每一維的長度,像上面的例子那樣相當于創(chuàng)建了一個new int[10][8]的二維數組,但是不能創(chuàng)建每一維長度都不同的多維數組。通過第一種創(chuàng)建數組的方法,可以像這樣創(chuàng)建數組Object o = Array.newInstance(int[].class, 20)可以用來創(chuàng)建二維數組,這里相當于Object o = new int[20][];
當然通過上面例子那樣來創(chuàng)建數組的用法是很少見的,其實也是多余的,為什么不直接通過new來創(chuàng)建數組呢?反射創(chuàng)建數組不僅速度沒有new快,而且寫的程序也不易讀,還不如new來的直接。事實上通過反射創(chuàng)建數組確實很少見,是有何種變態(tài)的需求需要用反射來創(chuàng)建數組呢!
由于前面對基本類型的數組進行輸出時遇到一些障礙,下面將利用數組反射來實現一個工具類來實現期望的輸出:

package cn.zq.util; 
 
import java.io.ByteArrayOutputStream; 
import java.io.PrintStream; 
import java.lang.reflect.Array; 
 
public class Print { 
  public static void print(Object obj) { 
    print(obj, System.out); 
  } 
  public static void print(Object obj, PrintStream out) { 
    out.println(getPrintString(obj)); 
  } 
  public static void println() { 
    print(System.out); 
  } 
  public static void println(PrintStream out) { 
    out.println(); 
  } 
  public static void printnb(Object obj) { 
    printnb(obj, System.out); 
  } 
  public static void printnb(Object obj, PrintStream out) { 
    out.print(getPrintString(obj)); 
  } 
  public static PrintStream format(String format, Object ... objects) { 
    return format(System.out, format, objects); 
  } 
  public static PrintStream format(PrintStream out, String format, Object ... objects) { 
    Object[] handleObjects = new Object[objects.length]; 
    for(int i = 0; i < objects.length; i++) { 
      Object object = objects[i]; 
      if(object == null || isPrimitiveWrapper(object)) { 
        handleObjects[i] = object; 
      } else { 
        ByteArrayOutputStream bos = new ByteArrayOutputStream(); 
        PrintStream ps = new PrintStream(bos); 
        printnb(object, ps); 
        ps.close(); 
        handleObjects[i] = new String(bos.toByteArray()); 
      } 
    } 
    out.format(format, handleObjects); 
    return out; 
  } 
  /** 
   * 判斷給定對象是否為基本類型的包裝類。 
   * @param o 給定的Object對象 
   * @return 如果是基本類型的包裝類,則返回是,否則返回否。 
   */ 
  private static boolean isPrimitiveWrapper(Object o) { 
    return o instanceof Void || o instanceof Boolean 
        || o instanceof Character || o instanceof Byte  
        || o instanceof Short || o instanceof Integer  
        || o instanceof Long || o instanceof Float 
        || o instanceof Double; 
  } 
  public static String getPrintString(Object obj) { 
    StringBuilder result = new StringBuilder(); 
    if(obj != null && obj.getClass().isArray()) { 
      result.append("["); 
      int len = Array.getLength(obj); 
      for(int i = 0; i < len; i++) { 
        Object value = Array.get(obj, i); 
        result.append(getPrintString(value)); 
        if(i != len - 1) { 
          result.append(", "); 
        } 
      } 
      result.append("]"); 
    } else { 
      result.append(String.valueOf(obj)); 
    } 
    return result.toString(); 
  } 
} 

上面的Print工具類提供了一些實用的進行輸出的靜態(tài)方法,并且提供了一些重載版本,可以根據個人的喜歡自己編寫一些重載的版本,支持基本類型的一維數組的打印以及多維數組的打印,看下下面的Print工具進行測試的示例:

package cn.zq.array.reflect; 
 
import static cn.zq.util.Print.print; 
 
import java.io.PrintStream; 
 
import static cn.zq.util.Print.*; 
 
public class PrintTest { 
  static class Person { 
    private static int counter; 
    private final int id = counter ++; 
    public String toString() { 
      return getClass().getSimpleName() + id; 
    } 
  } 
   
  public static void main(String[] args) throws Exception { 
    print("--打印非數組--"); 
    print(new Object()); 
    print("--打印基本類型的一維數組--"); 
    int[] is = new int[]{1, 22, 31, 44, 21, 33, 65}; 
    print(is); 
    print("--打印基本類型的二維數組--"); 
    int[][] iss = new int[][]{ 
        {11, 12, 13, 14}, 
        {21, 22,}, 
        {31, 32, 33} 
    }; 
    print(iss); 
    print("--打印非基本類型的一維數組--"); 
    Person[] persons = new Person[10]; 
    for(int i = 0; i < persons.length; i++) { 
      persons[i] = new Person(); 
    } 
    print(persons); 
    print("--打印非基本類型的二維數組--"); 
    Person[][] persons2 = new Person[][]{ 
        {new Person()}, 
        {new Person(), new Person()}, 
        {new Person(), new Person(), new Person(),}, 
    }; 
    print(persons2); 
    print("--打印empty數組--"); 
    print(new int[]{}); 
    print("--打印含有null值的數組--"); 
    Object[] objects = new Object[]{ 
        new Person(), null, new Object(), new Integer(100) 
    }; 
    print(objects); 
    print("--打印特殊情況的二維數組--"); 
    Object[][] objects2 = new Object[3][]; 
    objects2[0] = new Object[]{}; 
    objects2[2] = objects; 
    print(objects2); 
    print("--將一維數組的結果輸出到文件--"); 
    PrintStream out = new PrintStream("out.c"); 
    try { 
      print(iss, out); 
    } finally { 
      out.close(); 
    } 
    print("--格式化輸出--"); 
    format("%-6d%s %B %s", 10086, "is", true, iss); 
    /** 
     * 上面列出了一些Print工具類的一些常用的方法, 
     * 還有一些未列出的方法,請自行查看。 
     */ 
  } 
} 

輸出:

--打印非數組-- 
java.lang.Object@61de33 
--打印基本類型的一維數組-- 
[1, 22, 31, 44, 21, 33, 65] 
--打印基本類型的二維數組-- 
[[11, 12, 13, 14], [21, 22], [31, 32, 33]] 
--打印非基本類型的一維數組-- 
[Person0, Person1, Person2, Person3, Person4, Person5, Person6, Person7, Person8, Person9] 
--打印非基本類型的二維數組-- 
[[Person10], [Person11, Person12], [Person13, Person14, Person15]] 
--打印empty數組-- 
[] 
--打印含有null值的數組-- 
[Person16, null, java.lang.Object@ca0b6, 100] 
--打印特殊情況的二維數組-- 
[[], null, [Person16, null, java.lang.Object@ca0b6, 100]] 
--將一維數組的結果輸出到文件-- 
--格式化輸出-- 
10086 is TRUE [[11, 12, 13, 14], [21, 22], [31, 32, 33]] 

輸出文件:

2016425142151040.png (1111×352)

可見Print工具類已經具備打印基本類型的一維數組以及多維數組的能力了,總體來說上面的工具類還是挺實用的,免得每次想要看數組里面的內容都有手動的去編寫代碼,那樣是在是太麻煩了,以后直接把Print工具類拿過去用就行了,多么的方便啊。
上面的工具類確實能很好的工作,但是假如有這樣一個需求:給你一個數組(也有可能是其他的容器),你給我整出一個List。那么我們應該怎樣做呢?事實上Arrays.asList不總是能得到我們所期望的結果,java5雖然添加了泛型,但是是有限制的,并不能像c++的模板那樣通用,正是因為java中存在基本類型,即使有自動包裝的機制,與泛型一起并不能使用,參數類型必須是某種類型,而不能是基本類型。下面給出一種自己的解決辦法:

package cn.zq.util; 
 
import java.lang.reflect.Array; 
import java.util.ArrayList; 
import java.util.Arrays; 
import java.util.Enumeration; 
import java.util.Iterator; 
import java.util.List; 
import java.util.Map; 
 
public class CollectionUtils { 
   
  public static List<?> asList(Object obj) { 
    return convertToList( 
        makeIterator(obj)); 
  } 
  public static <T>List<T> convertToList(Iterator<T> iterator) { 
    if(iterator == null) { 
      return null; 
    } 
    List<T> list = new ArrayList<T>(); 
    while(iterator.hasNext()) { 
      list.add(iterator.next()); 
    } 
    return list; 
  } 
  @SuppressWarnings({ "rawtypes", "unchecked" }) 
  public static Iterator<?> makeIterator(Object obj) { 
    if(obj instanceof Iterator) { 
      return (Iterator<?>) obj; 
    } 
    if(obj == null) { 
      return null; 
    } 
    if(obj instanceof Map) { 
      obj = ((Map<?, ?>)obj).entrySet(); 
    } 
     
    Iterator<?> iterator = null; 
    if(obj instanceof Iterable) { 
      iterator = ((Iterable<?>)obj).iterator(); 
    } else if(obj.getClass().isArray()) { 
      //Object[] objs = (Object[]) obj; //原始類型的一位數組不能這樣轉換 
      ArrayList list = new ArrayList(Array.getLength(obj)); 
      for(int i = 0; i < Array.getLength(obj); i++) { 
        list.add(Array.get(obj, i)); 
      } 
      iterator = list.iterator(); 
    } else if(obj instanceof Enumeration) { 
      iterator = new EnumerationIterator((Enumeration) obj); 
    } else { 
      iterator = Arrays.asList(obj).iterator(); 
    } 
    return iterator; 
  } 
   
  public static class EnumerationIterator<T> implements Iterator<T> { 
    private Enumeration<T> enumeration; 
    public EnumerationIterator(Enumeration<T> enumeration) { 
      this.enumeration = enumeration; 
    } 
    public boolean hasNext() { 
      return enumeration.hasMoreElements(); 
    } 
    public T next() { 
      return enumeration.nextElement(); 
    } 
    public void remove() { 
      throw new UnsupportedOperationException(); 
    } 
  } 
} 

測試代碼:

package cn.zq.array.reflect; 
 
import java.util.Iterator; 
import java.util.List; 
 
import cn.zq.array.reflect.PrintTest.Person; 
import cn.zq.util.CollectionUtils; 
 
public class CollectionUtilsTest { 
  public static void main(String[] args) { 
    System.out.println("--基本類型一維數組--"); 
    int[] nums = {1, 3, 5, 7, 9}; 
    List<?> list = CollectionUtils.asList(nums); 
    System.out.println(list); 
    System.out.println("--非基本類型一維數組--"); 
    Person[] persons = new Person[]{ 
        new Person(), 
        new Person(), 
        new Person(), 
    }; 
    List<Person> personList = (List<Person>) CollectionUtils.asList(persons); 
    System.out.println(personList); 
    System.out.println("--Iterator--"); 
    Iterator<Person> iterator = personList.iterator(); 
    List<Person> personList2 = (List<Person>) CollectionUtils.asList(iterator); 
    System.out.println(personList2); 
 
  } 
} 

輸出:

--基本類型一維數組-- 
[1, 3, 5, 7, 9] 
--非基本類型一維數組-- 
[Person0, Person1, Person2] 
--Iterator-- 
[Person0, Person1, Person2] 

在java的容器類庫中可以分為Collection,Map,數組,由于Iterator(以及早期的遺留接口Enumeration)是所有容器的通用接口并且Collection接口從Iterable(該接口的iterator將返回一個Iterator),所以在makeIterator方法中對這些情形進行了一一的處理,對Map類型,只需要調用其entrySet()方法,對于實現了Iterable接口的類(Collection包含在內),調用iterator()直接得到Iterator對象,對于Enumeration類型,利用適配器EnumerationIterator進行適配,對于數組,利用數組反射遍歷數組放入ArrayList中,對于其他的類型調用Arrays.asList()方法創(chuàng)建一個List。CollectionUtils還提供了一些其他的方法來進行轉換,可以根據需要添加自己需要的方法。

總結:數組的反射對于那些可能出現數組的設計中提供更方便、更靈活的方法,以免寫那些比較麻煩的判斷語句,這種靈活性付出的就是性能的代價,對于那些根本不需要數組反射的情況下用數組的反射實在是不應該。是否使用數組的反射,在實際的開發(fā)中仁者見仁智者見智,根據需要來選擇是否使用數組的反射,最好的方式就是用實踐來探路,先按照自己想到的方式去寫,在實踐中不斷的完善。

相關文章

  • 圖解Java排序算法之希爾排序

    圖解Java排序算法之希爾排序

    這篇文章主要為大家詳細介紹了Java排序算法之希爾排序,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-11-11
  • Java Set集合去重的原理及實現

    Java Set集合去重的原理及實現

    這篇文章主要介紹了Java Set集合去重的原理及實現,幫助大家更好的理解和學習Java,感興趣的朋友可以了解下
    2020-09-09
  • Java匿名內部類的寫法示例

    Java匿名內部類的寫法示例

    這篇文章主要給大家介紹了關于Java匿名內部類的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-08-08
  • String StringBuilder StringBuffer區(qū)別以及源碼分析

    String StringBuilder StringBuffer區(qū)別以及源碼分析

    string是C++標準庫的一個重要的部分,主要用于字符串處理??梢允褂幂斎胼敵隽鞣绞街苯舆M行string操作,同時,C++的算法庫對string類也有著很好的支持,并且string類還和c語言的字符串之間有著良好的接口
    2021-06-06
  • Mybatis動態(tài)SQL的示例代碼

    Mybatis動態(tài)SQL的示例代碼

    本文主要介紹了Mybatis動態(tài)SQL的示例代碼,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-10-10
  • Java?8函數式接口之Consumer用法示例詳解

    Java?8函數式接口之Consumer用法示例詳解

    這篇文章主要為大家介紹了Java?8函數式接口之Consumer用法示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-07-07
  • Java注解處理器學習之編譯時處理的注解詳析

    Java注解處理器學習之編譯時處理的注解詳析

    編譯時注解相信對每一個java開發(fā)者來說都不陌生,下面這篇文章主要給大家介紹了關于Java注解處理器學習之編譯時處理的注解的相關資料,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考借鑒,下面來一起看看吧
    2018-05-05
  • springboot中@RequestMapping的用法

    springboot中@RequestMapping的用法

    這篇文章主要介紹了springboot中@RequestMapping的用法,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-02-02
  • SpringBoot基于HttpMessageConverter實現全局日期格式化

    SpringBoot基于HttpMessageConverter實現全局日期格式化

    這篇文章主要介紹了SpringBoot基于HttpMessageConverter實現全局日期格式化,使用Jackson消息轉換器,非常具有實用價值,需要的朋友可以參考下
    2018-12-12
  • 熟練掌握Java8新特性之Stream API的全面應用

    熟練掌握Java8新特性之Stream API的全面應用

    Stream是Java8的一大亮點,是對容器對象功能的增強,它專注于對容器對象進行各種非常便利、高效的 聚合操作(aggregate operation)或者大批量數據操作。Stream API借助于同樣新出現的Lambda表達式,極大的提高編程效率和程序可讀性,感興趣的朋友快來看看吧
    2021-11-11

最新評論