关于java数组的深度思考

1html

  刚刚开始接触java数组的人都会听到一句相似的话:java是纯面向对象的语言,他的数组也是一个对象。因而乎,笔者就按照一个对象的方式来使用数组,问心无愧。直到我接触到C的数组后,才发现将数组做为一个类来使用在实现上是多么的“不天然”。java

  
  首先咱们看一下表面现象,数组建立的时候采用的是以下语句:数据库

  MyClass[] arr = new MyClass[9];数组

  而普通类采用的是以下语句:网络

  MyClass obj = new MyClass();spa

  就是说,建立数组的时候不使用小括号传参。使得数组和普通类看起来就有不少不一样,由于小括号里的参数是传递给构造方法的,进而让人感受数组类是没有构造方法的。htm

  
再往深了想,还有不少让人感受不天然的东西。能够确定的是,java确实将数组做为了一个类来处理。仍是用上面的例子说明:对象

  能够经过如下方法获得MyClass[]的Class实例:arr.getClass()或MyClass[].class。这样,我就能够向数组类里面“窥探”了。内存

  
  Class clazz = MyClass[].class;
  System.out.println(clazz.getConstructors().length);字符串

  
  打印出来的结果是0;证实数组类确实没有构造方法。

  
  若是强行执行clazz.newInstance();就会获得下面的错误。

  java.lang.InstantiationException: [Larraytest.MyClass;

  证实数组类不可以经过普通的反射方式来建立一个实例。

  再看看数组类的“庐山真面目”:

  System.out.println(clazz);

  输出是:

  [Larraytest.MyClass

   对Java Class文件结构稍有告终就知道,这个字符串的意思就是一个元素类型为arraytest.MyClass的一维数组。也就是说,数组类型不是和普通类 同样,以一个全限定路径名+类名来做为本身的惟一标示的,而是以[+一个或者多个L+数组元素类全限定路径+类来最为惟一标示的。这个()也是数组和普通 类的区别。而这个区别彷佛在某种程度上说明数组和普通java类在实现上有很大区别。由于java虚拟机(java指令集)在处理数组类和普通类的时候, 确定会作出区分。笔者猜测,可能会有专门的java虚拟机指令来处理数组。

2

   既然咱们能够获得数组的Class类实例,就说明确定须要调用ClassLoader的 defineClass(不必定非要是loadClass方法)方法,来构造一个Class实例。java虚拟机规范规定,任何一个能够被加载的类,若是 其类文件存储在文件系统上,那么一个*.class文件只能存储一个类信息,也就是说,数组类的信息不可能以类文件的形式存储在本地磁盘上(不然任意一个 类都要配有255个数组类了.....),既然这样,那就说明java虚拟机确定内置了一块用来声明数组类的数据(不论是几级数组)。这是符合java虚 拟机规范的,规范规定class类数据能够来自任意介质,包括本地磁盘、网络、数据库、内存等等。

  分析到这里,我基本上能够确定:java对数组对象化的操做的支持是指令级的,也就是说java虚拟机有专门针对数组的指令。数组的Class类实例是java虚拟机动态建立动态加载的,其结构与普通java类的Class实例有一些不一样。

  JDK API中有一个java.lang.reflect.Array类,这个类提供了不少方法(绝大多数是native方法,这在另外一个方面证实了java对数组的支持是专用指令支持的,不然用本地方法干吗^_^),用来弥补咱们对数组操做的局限性。

  下面这句话用来建立一个一维的、长度为10的、类型为arraytest.MyClass的数组:

  arraytest.MyClass[] arr = (arraytest.MyClass[]) Array.newInstance(arraytest.MyClass, 10);

  下面这句话用来建立一个二维的、3乘5的、类型为arraytest.MyClass的数组:

  int[] arrModel = new int[]{3,5};
Object arrObj = Array.newInstance(Sub.class, arrModel);

  固然你能够用一个数组的引用指向上面的二维数组,这里咱们用一个Object的引用指向他。
使用的时候,咱们也是能够利用Array类提供的方法来实现:

  System.out.println(Array.getLength(arrObj);//第一维长度为3
  System.out.println(Array.getLength(Array.get(arrObj, 2)));//第二维长度为5,这里若是写3,就会获得你意想之中的java.lang.ArrayIndexOutOfBoundsException

  打印结果是如咱们所想的:

  3
  5

  对于数组的Class类实例,还有一些奇怪的现象:

   在运行代码 java.lang.reflect.Field fieldarr = clazz.getField("length");的时候,会抛出异常:java.lang.NoSuchFieldException: length,这彷佛在说数组类没有length这个域,而这个域实际上是咱们用的最多的一个(也就是说这个域是确定存在的)。笔者认为关于数组的 Class类实例、数组的实现等,还有不少“猫腻”在里面。   顺便说一句,java数组最多只能是255维的。这个让人看到了C的影子,嘿嘿。“Java把数组看成一个java类来处理”提及来容易,用起来天然,可是细细想来,仍是有不少不简单的地方。

相关文章
相关标签/搜索