刚刚开始接触java数组的人都会听到一句类似的话:java是纯面向对象的语言,他的数组也是一个对象。于是乎,笔者就按照一个对象的方式来使用数组,心安理得。直到我接触到C的数组后,才发现将数组作为一个类来使用在实现上是多么的“不自然”。
首先我们看一下表面现象,数组创建的时候采用的是如下语句:
MyClass[] arr = new MyClass[9];
而普通类采用的是如下语句:
MyClass obj = new MyClass();
就是说,创建数组的时候不使用小括号传参。使得数组和普通类看起来就有很多不同,因为小括号里的参数是传递给构造方法的,进而让人感觉数组类是没有构造方法的。
再往深了想,还有很多让人感觉不自然的东西。可以肯定的是,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虚拟机指令来处理数组。
既然我们可以得到数组的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类来处理”说起来容易,用起来自然,但是细细想来,还是有很多不简单的地方。
分享到:
相关推荐
### Java数组深度解析 在Java编程语言中,数组是一种非常基础且重要的数据结构,它能够存储固定数量的同类型元素。对于初学者来说,经常会听到这样一句话:“Java是一门纯粹的面向对象的语言,其数组也是一种对象。...
2.2.3 Java中的数组 2.3 绝对不要清除对象 2.3.1 作用域 2.3.2 对象的作用域 2.4 新建数据类型:类 2.4.1 字段和方法 2.5 方法、自变量和返回值 2.5.1 自变量列表 2.6 构建Java程序 2.6.1 名字的可见性 2.6.2 使用...
《Thinking in Java》是一本深度剖析Java编程语言的著作,旨在帮助读者深入理解Java的核心概念和技术。本书通过对比Java和C++,使读者能够更好地理解Java的独特之处,并为初学者提供了一个逐步学习Java的框架。 第1...
在Java版的五子棋实现中,首先我们需要创建一个棋盘模型,通常使用二维数组来模拟棋盘,每个元素代表棋盘上的一个位置。数组的值可以表示棋子的颜色(例如,0表示空位,1表示黑棋,2表示白棋)。棋盘大小通常是15x15...
在Java中,数组可以是一维、二维或多维的。学习如何声明、初始化和操作数组是编程的基础,同时也涉及到数组遍历、查找和排序等操作。 2. **链表**:链表是一种动态数据结构,每个元素(节点)包含数据和指向下一个...
可能使用二维数组或者特定的数据结构(如矩阵、链表)来表示棋盘,并用特定的方式(如位运算)记录棋子位置和棋局状态。 7. **游戏规则的实现**:实现五子棋的规则,包括判断胜负条件(横、竖、斜方向连续五个同色...
- 棋局评估:可能会使用某种搜索算法(如深度优先搜索、Alpha-Beta剪枝)来评估当前棋局的优劣,辅助AI决策。 5. **多线程**: - 为了实现游戏的并发性,可能使用了Java的线程机制。例如,用户操作和AI思考可以在...
这款游戏中,玩家可以体验到经典的拼图玩法,通过逻辑思考和空间感知能力将打乱的图像重新组合成完整的图片。以下是对这个项目及其相关知识点的详细说明: 1. **Java编程语言**:Java是一种广泛使用的面向对象的...
- **空间复杂度**:递归栈的最大深度为树的高度,即O(log n),此外还需要存储左右子数组的空间,因此总的空间复杂度为O(n)。 #### 进阶思考 1. **非递归实现**:虽然递归方式简洁明了,但在实际应用中,为了避免...
4. **数据结构**:为了存储拼图的状态,通常会使用二维数组或链表来表示拼图的每个部分。每个单元格包含图像块的信息,如位置、旋转状态等。 5. **算法**:拼图游戏的核心算法是解决拼图的逻辑。这可能包括: - **...
本文将结合高职教育的特点,探讨在慕课环境下Java程序设计教学的实践与思考。 Java程序设计教学的目标和内容 Java程序设计课程的开设旨在使学生掌握Java语言的基本使用方法,包括语法和特性,同时理解和掌握API的...
3. **数据结构**:棋盘状态通常用二维数组或自定义棋盘类来存储,每格代表一个棋盘位置,存储着当前棋子的颜色或者为空。 4. **游戏逻辑**:五子棋的核心逻辑包括检查落子合法性、判断胜负条件(横向、纵向、斜向...
这需要用到数据结构如二维数组或链表来存储游戏盘面,以及算法(如深度优先搜索或广度优先搜索)来查找和消除匹配的元素。 3. 事件处理:当玩家点击某个图标时,程序需要捕获并处理这个事件。Java提供了事件监听器...
在实现连连看的核心算法——寻找可匹配的图案对时,可以运用深度优先搜索(DFS)或广度优先搜索(BFS)策略,结合二维数组或链表数据结构进行高效操作。 此外,事件驱动编程是Java GUI开发的关键。利用...
Java竞赛题目通常涵盖了广泛的编程概念和技术,旨在测试参赛者对Java语言的理解深度、编程技巧以及问题解决能力。这类竞赛往往包含设计模式、数据结构、算法、多线程、网络编程、异常处理、集合框架、IO流、反射等...
在实际学习过程中,应该结合教材内容,先独立思考,然后对照答案理解思路,尝试自己修改和优化代码,这样可以更好地吸收知识。同时,遇到不理解的部分,可以通过网络资源、论坛讨论或者向教师请教来解决,以达到深度...
综上所述,"Java小游戏-记忆测试"项目涵盖了Java编程语言的多个核心方面,不仅锻炼了开发者的技术能力,也展现了其在软件设计和用户体验方面的思考。通过参与这样的项目,开发者可以提升自己的编程技巧,并对Java ...
5. **算法**:AI部分可能使用了搜索算法,如深度优先搜索(DFS)或Minimax算法,配合α-β剪枝来优化搜索效率,使得计算机能够作出合理的决策。 6. **递归**:Minimax算法是基于递归的,它通过模拟所有可能的走法来...
6. 面试技巧与问题分析:在每道题目的分析中,都涉及了如何针对该问题展开思考,以及如何向面试官展示自己的解题思路,这对于提升面试表现非常有帮助。 由于内容繁多,以下对部分题目进行知识点的详细说明: - ...