[转载] java中数组的反射的探究

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

 

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/540183.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

防火墙iptables之常用脚本

防火墙iptables之常用脚本 转自&#xff1a;http://zhujiangtao.blog.51cto.com/6387416/1286490 标签&#xff1a;防火墙 主机 1。不允许别人ping我的主机&#xff0c;但是我可以ping别人的主机 #!/bin/bash iptables -F iptables -X iptables -Z modprobe ip_tables modprobe…

[转载] java中50个关键字以及各自用法大全

参考链接&#xff1a; Java中的默认数组值 关键字和保留字的区别 正确识别java语言的关键字&#xff08;keyword&#xff09;和保留字&#xff08;reserved word&#xff09;是十分重要的。Java的关键字对java的编译器有特殊的意义&#xff0c;他们用来表示一种数据类型&…

NFS 共享存储

服务器客户端yum -y install rpcbind nfs-utils 服务器 vim /etc/exports /data 192.168.10.0/24(rw,sync,no_root_squash) * ro # 只读权限 * rw # 读写权限 * sync # 同步&#xff0c;数据更安全&#xff0c;速度慢 * async #异步&#xff0c;速度快&#xff0c;效率高&a…

[转载] Java中的final变量、final方法和final类

参考链接&#xff1a; Java中的final数组 &#xff5c; Final arrays 1、final变量 final关键字可用于变量声明&#xff0c;一旦该变量被设定&#xff0c;就不可以再改变该变量的值。通常&#xff0c;由final定义的变量为常量。例如&#xff0c;在类中定义PI值&#xff0c;可…

Linux基础篇_01_计算机概论

学习资料&#xff1a;《鸟哥的Linux私房菜&#xff08;基础篇&#xff09;》部分&#xff1a;Linux的规划与安装 时间&#xff1a;20130225 学习笔记&#xff1a;计算机定义&#xff1a;接受使用者输入指令与数据&#xff0c; 经由中央处理器的数学与逻辑单元运算处理后&#x…

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

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

[3/21]Windows Server 2008时钟方面的改进展示

在Windows Server 2008中的时钟显示和以往Windows Server 2003及以前的版本显示有很大的差别。如果要显示并进行简单的时间修改可以在时钟上双击&#xff0c;会出现如下图所示的界面。在上图中可以调整但无法进行真正的修改&#xff0c;彻底修改需要点击&#xff02;更改日期和…

[转载] 黑马程序员_学习笔记8_C#基础归纳之数组

参考链接&#xff1a; Java中的锯齿数组Jagged array ---------------------- Windows Phone 7手机开发、.Net培训、期待与您交流&#xff01; ---------------------- 什么是数组&#xff1f; 数组是一组数据结构&#xff0c;它可以包含同一类型的多个元素。C#用特殊记号还…

2Python全栈之路系列之MysQl基本数据类型

Python全栈之路系列之MySQL基本数据类型 MySQL中定义数据字段的类型对你数据库的优化是非常重要的。 MySQL支持多种类型&#xff0c;大致可以分为三类&#xff1a; 数字类型 日期和时间类型 字符串类型 数字类型 类型大小用途BIT-二进制TINYINT1字节小整数值INT or INTEGER4字…

[转载] JAVA笔记_(Day04,Day05)函数数组

参考链接&#xff1a; 了解Java中的数组IndexOutofbounds异常 文章目录 函数定义练习误区重载&#xff08;overload&#xff09;重载选择题练习函数的内存调用问题 数组定义数组的内存图解数组的常见问题应用求和最大值将数组转成字符串查表法转十六进制查表版&#xff08;十六…

VDI序曲二 RemotoAPP部署

首先&#xff0c;我们需要准备如下角色&#xff1a;沿用VDI序曲一的2台物理服务器以及角色我们在物理服务器1的hyper-v上&#xff0c;我们利用之前我介绍的“服务器虚拟化之准备母盘VHD”的方法再创建如下虚拟机&#xff1a;WIN-RDAPP&#xff1b;WIN-RDWA&#xff1b;WIN-RDCB…

[转载] Java ArrayList toArray(T[] a) 解惑

参考链接&#xff1a; Java中的Array vs ArrayList 先看一个小的代码片段 ArrayList<Integer> arrayList new ArrayList<>(); Collections.addAll(arrayList, 11, 21, 31, 41, 51); Integer[] a new Integer[0]; Integer[] b new Integer[arrayList.size()]; …

CentOS7使用firewalld打开关闭防火墙与端口(转载)

1、firewalld的基本使用 启动&#xff1a; systemctl start firewalld 查看状态&#xff1a; systemctl status firewalld 停止&#xff1a; systemctl disable firewalld 禁用&#xff1a; systemctl stop firewalld 2.systemctl是CentOS7的服务管理工具中主要的工具&#xff…

多任务管理类 MutilTaskManager

计算和计算所需的数据能被较为平均的非配到若干task的时候&#xff0c;下面的任务管理类可以提供在大数据大计算量的情况下非精确的控制task的执行数量来限制计算量和内存占用量.下面是代码&#xff08;非线程安全版本&#xff09;&#xff1a; public class MutilTaskManager{…

[转载] Scanner和bufferreader读取控制台字符的区别

参考链接&#xff1a; Java中Scanner和BufferReader类之间的区别 从开始学习Java就用了scanner&#xff0c;因为比较简单每当遇到空格键或者换行键则读取下一个字符&#xff0c;一般用法 while(input.hasNextInt()){ int n input.nextInt(); int t input.nextInt(); int c …

Node.js meitulu图片批量下载爬虫1.051

原有1.05版程序没有断点续传模式&#xff0c;现在在最近程序基础上改写一版1.051. // // meitulu图片批量下载爬虫1.051 // 用最近的断点续传框架改写原有1.05版程序 // 2017年11月21日 //// 内置https模块 var httpsrequire("https");// 内置http模块 var httprequi…

[转载] Java实现归并排序(超详细,新手请进)

参考链接&#xff1a; Java中将数组合并为的新数组 归并排序 大家好&#xff0c;这是我第一次在CSDN上写东西&#xff0c;因为我一直觉得有需要就去找别人的blog看看就好&#xff0c;但我发现自己写出来的东西确实能加深记忆。我半路出家&#xff0c;属实是个菜鸟&#xff0…

centos6设置静态IP

#编辑配置文件,添加修改以下内容 vim /etc/sysconfig/network-scripts/ifcfg-eth0 BOOTPROTOstatic #启用静态IP地址 ONBOOTyes #开启开机自动启用网络连接 IPADDR192.168.21.129 #设置IP地址 NETMASK255.255.255.0 #设置子网掩码 GATEWAY192.168…

[转载] 1022 D进制的A+B (20分)【java题解】【80ms】

参考链接&#xff1a; Java流Stream 题解 使用 toUnsignedString&#xff08;&#xff09;即可 我有仔细读过toUnsignedString&#xff08;&#xff09;&#xff0c;有兴趣可以看看 第3章 java的基本程序设计结构【补缺学习】【注释与数据类型】【核心技术卷I】 impor…