程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 實例講授Java編程中數組反射的應用辦法

實例講授Java編程中數組反射的應用辦法

編輯:關於JAVA

實例講授Java編程中數組反射的應用辦法。本站提示廣大學習愛好者:(實例講授Java編程中數組反射的應用辦法)文章只能為提供參考,不一定能成為您想要的結果。以下是實例講授Java編程中數組反射的應用辦法正文


甚麼是反射
“反射(Reflection)可以或許讓運轉於JVM中的法式檢測和修正運轉時的行動。”這個概念經常會和內省(Introspection)混雜,以下是這兩個術語在Wikipedia中的說明:

  • 內省用於在運轉時檢測某個對象的類型和其包括的屬性;
  • 反射用於在運轉時檢測和修正某個對象的構造及其行動。
  • 從它們的界說可以看出,內省是反射的一個子集。有些說話支撐內省,但其實不支撐反射,如C++。

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

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

反射示例:Class.forName()辦法可以經由過程類或接口的稱號(一個字符串或完整限制名)來獲得對應的Class對象。forName辦法會觸發類的初始化。

// 應用反射
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.經由過程慣例方法遍歷數組對數組停止打印--"); 
    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.經由過程慣例方法遍歷數組對數組停止打印-- 
58 55 93 61 61 29 68 0 22 7  
--2.經由過程數組反射的方法遍歷數組對數組停止打印-- 
obj isArray:true 
58 55 93 61 61 29 68 0 22 7 

下面的例子起首創立了一個int的一維數組,然後隨機的像外面填充0~100的整數,接著經由過程System.out.println()辦法直接對數組輸入或許用Arrays.asList辦法(假如不是根本類型的一維數組此辦法能依照希冀轉成List,假如是二維數組也不克不及依照我們希冀轉成List)將數組轉成List再輸入,經由過程都不是我們希冀的輸入成果。接上去以慣例的數組的遍歷方法來輸入數組內的內容,然後將int[]算作是一個Object,應用反射來遍歷其內容。Class.isArray()可以用來斷定是對象能否為一個數組,假設是一個數組,那末在經由過程java.lang.reflect.Array這個對數組反射的對象類來獲得數組的相干信息,這個類經由過程了一些get辦法,可以用來獲得數組的長度,各個版本的用來獲得根本類型的一維數組的對應索引的值,通用獲得值的辦法get(Object array, int index),設置值的辦法,還有2個用來創立數組實例的辦法。經由過程數組反射對象類,可以很便利的應用數組反射寫出通用的代碼,而不消再去斷定給定的數組究竟是那種根本類型的數組。

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個辦法來創立數組
Object newInstance(Class<?> componentType, int length),依據供給的class來創立一個指定長度的數組,假如像下面那樣供給int.class,長度為10,相當於new int[10];
Object newInstance(Class<?> componentType, int... dimensions),依據供給的class和維度來創立數組,可變參數dimensions用來指定命組的每維的長度,像下面的例子那樣相當於創立了一個new int[10][8]的二維數組,然則不克不及創立每維長度都分歧的多維數組。經由過程第一種創立數組的辦法,可以像如許創立數組Object o = Array.newInstance(int[].class, 20)可以用來創立二維數組,這裡相當於Object o = new int[20][];
固然經由過程下面例子那樣來創立數組的用法是很少見的,其實也是過剩的,為何不直接經由過程new來創立數組呢?反射創立數組不只速度沒有new快,並且寫的法式也不容易讀,還不如new來的直接。現實上經由過程反射創立數組確切很少見,是有何種失常的需求須要用反射來創立數組呢!
因為後面對根本類型的數組停止輸入時碰到一些妨礙,上面將應用數組反射來完成一個對象類來完成希冀的輸入:

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對象類供給了一些適用的停止輸入的靜態辦法,而且供給了一些重載版本,可以依據小我的愛好本身編寫一些重載的版本,支撐根本類型的一維數組的打印和多維數組的打印,看下上面的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]] 

輸入文件:

可見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()辦法創立一個List。CollectionUtils還供給了一些其他的辦法來停止轉換,可以依據須要添加本身須要的辦法。

總結:數組的反射關於那些能夠湧現數組的設計中供給更便利、更靈巧的辦法,以避免寫那些比擬費事的斷定語句,這類靈巧性支付的就是機能的價值,關於那些基本不須要數組反射的情形下用數組的反射其實是不該該。能否應用數組的反射,在現實的開辟中仁者見仁智者見智,依據須要來選擇能否應用數組的反射,最好的方法就是用理論來探路,先依照本身想到的方法去寫,在理論中赓續的完美。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved