参考链接: Java中的反射数组类reflect.Array

数组的反射有什么用呢?何时需要使用数组的反射呢?先来看下下面的代码:

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还提供了一些其他的方法来进行转换,可以根据需要添加自己需要的方法。

总结:数组的反射对于那些可能出现数组的设计中提供更方便、更灵活的方法,以免写那些比较麻烦的判断语句,这种灵活性付出的就是性能的代价,对于那些根本不需要数组反射的情况下用数组的反射实在是不应该。是否使用数组的反射,在实际的开发中仁者见仁智者见智,根据需要来选择是否使用数组的反射,最好的方式就是用实践来探路,先按照自己想到的方式去写,在实践中不断的完善。

[转载] java中数组的反射的探究相关推荐

  1. java中数组的复制

    数组复制使我们在编程过程中经常要使用到的,在java中数组复制我们大概能够分为两种,一种是引用复制,还有一种就是深度复制(复制后两个数组互不相干). 以下我们就通过測试的方法来具体看看什么是引用复制和 ...

  2. Java中数组以及集合

    2019独角兽企业重金招聘Python工程师标准>>> java中数组: 数组在Java里是一种特殊类型,有别于普通的"类的实例"的对象.但实际数组也是一种对象类 ...

  3. Java中数组在内存中的存放原理?

    版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/yangyong0717/article/details/79165685 Java中数组被实现为对象 ...

  4. Java语言程序设计 上机实验2 掌握Java的基本语言成分和流程控制语句。 掌握Java中数组的使用,理解引用数据类型。 掌握String类的使用。...

      Java语言程序设计 上机实验2 实验目的: 掌握Java的基本语言成分和流程控制语句. 掌握Java中数组的使用,理解引用数据类型. 掌握String类的使用. 实验内容: 注:标(*)为选做内 ...

  5. 将java中数组转换为ArrayList的方法实例(包括ArrayList转数组)

    方法一:使用Arrays.asList()方法 1 2 String[] asset = {"equity", "stocks", "gold&quo ...

  6. Java中数组转集合总结

    一.使用Arrays.asList() 方法 package com.joshua317;import java.util.*;public class Main {public static voi ...

  7. Java中为什么需要反射?反射要解决什么问题?

    Java中为什么需要反射?反射要解决什么问题? 参考文章: (1)Java中为什么需要反射?反射要解决什么问题? (2)https://www.cnblogs.com/buoge/p/9285142. ...

  8. Java中数组的地址问题(hashCode解析):

    Java中数组的地址问题(hashCode解析): import java.util.Arrays;public class Action1 {public static void main(Stri ...

  9. [转载] java中的经典问题:传值与传引用

    参考链接: 有关Java中数组分配的有趣事实 参数传递的秘密 知道方法参数如何传递吗? 记得刚开始学编程那会儿,老师教导,所谓参数,有形式参数和实际参数之分,参数列表中写的那些东西都叫形式参数,在实际 ...

最新文章

  1. document.forms用法
  2. 常见的正则表达式验证(更新中)
  3. kali kda安装 linux_全昭妍미연Bea MillerWolftylaKDA-THE BADDEST
  4. Pytorch 词嵌入word_embedding1初识
  5. linux扩容后显示管理,linux之lvm管理及扩容
  6. JavaScript:继承
  7. SQL 查询速度慢原因及优化方法(转载)
  8. java输入身高体重计算体脂率_追求健康的体脂率,比追求体重数更有意义:一个公式教你计算...
  9. 【理论】基于模型控制和基于数据驱动控制
  10. 在校园网中进行无线路由器设置
  11. 手机测试设计测试用例——(1)
  12. 基于Web的电子商务解决方案(1)(转)
  13. 费马小定理在ACM中的应用
  14. matplotlib 多子图图例显示
  15. 51自学网java壁虎_我要自学网JAVA基础4-26日历补充壁虎老师的完整代码
  16. 不能打印机与计算机,电脑打印机无法打印
  17. python解析pdf中文乱码_使用Python第三方库pdfminer提取PDF内容,并解决中文编码不支持的问题...
  18. C#pingpong输出
  19. 三菱plc pwm指令_三菱PLC常用指令汇总,速存!
  20. pytorch mnist vgg16 错误记录

热门文章

  1. Spark之scala学习(基础篇)待更新
  2. java五星好评点评器_亲,麻烦给个五星好评!—RatingBar
  3. python编写递归函数和非递归函数、输出斐波那契数列_分别用非递归和递归的方法编写函数求斐波那契数列第n项。斐波那契数列1,1,2,3,5,8,13,…...
  4. esxi挂载Linux的nfs盘,ESXi安装centos7挂载群晖NFS
  5. 高性能MySQL(3)——创建高性能索引
  6. 广度优先搜索练习之神奇的电梯
  7. windows下jenkins常见问题填坑
  8. Spring文件上传
  9. 面向对象、继承、抽象方法重载知识点整理
  10. hbase 学习(十三)集群间备份原理