JVM处理java数组ITeye - 凯时娱乐

JVM处理java数组ITeye

2019年02月24日12时08分04秒 | 作者: 鸿飞 | 标签: 数组,成员,元素 | 浏览: 1162

记住vamcily 曾问我:“为什么获取数组的长度用.length(成员变量的方式),而获取String的长度用.length()(成员方法的方式)?”

我其时一听,觉得问得很有道理。做相同一件工作,为什么选用两种风格悬殊的风格呢?何况,Java中的数组其实是齐备(full-fledged)的目标,直接露出成员变量,或许不是一种很OO的风格。那么,规划Java的那帮天才为什么这么做呢?

带着这个疑问,我查阅了一些材料,主要是关于“JVM是怎样处理数组”的。

数组目标的类是什么?

已然数组都是目标,那么数组的类终究是什么呢?当然不是java.util.Arrays啦!咱们以int一维数组为例,看看终究。

public class Main { 
public static void main(String args[]){ 
int a[] = new int[10]; Class clazz = a.getClass(); 
System.out.println(clazz.getName()); 



在SUN JDK 1.6上运转上述代码,输出为:

[I

看起来数组的类很古怪,非但不归于任何包,并且称号还不是合法的标识符(identifier)。详细的命名规矩[1]能够拜见java.lang.Class.getName()的javadoc。简略的说,数组的类名由若干个[和数组元素类型的内部称号组成,[的数目代表了数组的维度。

具有相同类型元素和相同维度的数组,归于同一个类。假如两个数组的元素类型相同,但维度不同,那么它们也归于不同的类。假如两个数组的元素类型和维度均相同,但长度不同,那么它们仍是归于同一个类。

数组的类有哪些成员呢?

已然咱们知道了数组的类名是什么,那么就去看看数组的类终究是什么样的吧?有哪些成员变量?有哪些成员方法?length这个成员变量在哪?是不是没有length()这个成员方法?

找来找去,在JDK的代码中没有找打[I这个类。想想也对,[I都不是一个合法的标识符,必定不会呈现public class [I {...}这样的Java代码。咱们暂时不论[I类是谁声明的,怎样声明的,先用反射机制一探终究吧。

public class Main { 
public static void main(String[] args) { 
int a[] = new int[10];
Class clazz = a.getClass(); 
System.out.println(clazz.getDeclaredFields().length); 
System.out.println(clazz.getDeclaredMethods().length); 
System.out.println(clazz.getDeclaredConstructors().length); 
System.out.println(clazz.getDeclaredAnnotations().length); 
System.out.println(clazz.getDeclaredClasses().length); 
System.out.println(clazz.getSuperclass()); 



在SUN JDK 1.6上运转上述代码,输出为:

0
0
0
0
0
class java.lang.Object 

可见,[I这个类是java.lang.Object的直接子类,自身没有声明任何成员变量、成员方法、结构函数和Annotation,能够说,[I就是个空类。咱们立马能够想到一个问题:怎样连length这个成员变量都没有呢?假如真的没有,编译器怎样不报语法错呢?想必编译器对Array.length进行了特别处理哇!

数组的类在哪里声明的?

先不论为什么没有length成员变量,咱们先搞清楚[I这个类是哪里声明的吧。已然[I都不是合法的标识符,那么这个类必定在Java代码中显式声明的。想来想去,只能是JVM自己在运转时生成的了。JVM生成类仍是一件很简略的工作,乃至无需生成字节码,直接在方法区中创立类型数据,就差不多竣工了。

还没有实力去看JVM的源代码,所以翻了翻The JavaTM Virtual Machine Specification  Second Edition,公然得到了验证,相关内容参阅5.3.3 Creating Array Classes。

标准的描绘很谨慎,还掺杂了界说类加载器和初始化类加载器的内容。先不论这些,简略归纳一下:

类加载器先看看数组类是否现已被创立了。假如没有,那就阐明需求创立数组类;假如有,那就无需创立了。

假如数组元素是引证类型,那么类加载器首先去加载数组元素的类。

JVM依据元素类型和维度,创立相应的数组类。

呵呵,公然是JVM这家伙自个悄悄创立了[I类。JVM不把数组类放到任何包中,也不给他们起个合法的标识符称号,估量是为了防止和JDK、第三方及用户自界说的类发生冲突吧。

再想想,JVM也有必要动态生成数组类,由于Java数组类的数量与元素类型、维度(最多255)有关,适当适当多了,是无法预先声明好的。

竟然没有length这个成员变量!

咱们现已发现,偷闲的JVM没有为数组类生成length这个成员变量,那么Array.length这样的语法怎样经过编译,怎样履行的呢?

让咱们看看字节码吧!编写一段最简略的代码,运用jclasslib检查字节码。

public class Main { 
public static void main(String[] args) 
{ int a[] = new int[2]; int i = a.length; 



运用SUN JDK 1.6编译上述代码,并运用jclasslib翻开Main.class文件,得到main方法的字节码:

0 iconst_2  //将int型常量2压入操作数栈 
1 newarray 10 (int)  //将2弹出操作数栈,作为长度,创立一个元素类型为int, 维度为1的数组,并将数组的引证压入操作数栈 
3 astore_1  //将数组的引证从操作数栈中弹出,保存在索引为1的局部变量(即a)中 
4 aload_1  //将索引为1的局部变量(即a)压入操作数栈 
5 arraylength  //从操作数栈弹出数组引证(即a),并获取其长度(JVM担任完成怎样获取),并将长度压入操作数栈 
6 istore_2  //将数组长度从操作数栈弹出,保存在索引为2的局部变量(即i)中 
7 return  //main方法回来 

可见,在这段字节码中,根本就没有看见length这个成员变量,获取数组长度是由一条特定的指令arraylength完成(怎样完成就不论了,JVM总有方法)。编译器对Array.length这样的语法做了特别处理,直接编译成了arraylength指令。别的,JVM创立数组类,应该就是由newarray这条指令触发的了。

很自然地想到,编译器也能够对Array.length()这样的语法做特别处理,直接编译成arraylength指令。这样的话,咱们就能够运用方法调用的风格获取数组的长度了,这样看起来形似也愈加OO一点。那为什么不运用Array.length()的语法呢?也许是开发Java的那帮天才对.length有所偏心,或许抛硬币拍脑袋随意决议的吧。 方式不重要,重要的是咱们理解了背面的机理。

Array in Java

最终,对Java中纯目标的数组宣布点感触吧。



JVM概念之Java目标的巨细与引证类型
闲谈Java理念的改变与JVM的五大优势
闲谈JVM的根本废物收回算法
JVM废物收回面对的问题
JVM分代废物收回战略的根底概念
比较C/C++中的数组,Java数组在安全性要好许多。C/C++常遇到的缓存区溢出或数组拜访越界的问题,在Java中不再存在。由于Java运用特定的指令拜访数组的元素,这些指令都会对数组的长度进行检查。假如发现越界,就会抛出java.lang.ArrayIndexOutOfBoundsException。


Java数组元素的灵活性比较大。一个数组的元素自身也能够是数组,只需一切元素的数组类型相同即可。咱们知道数组的类型和长度无关,因而元素能够是长度不同的数组。这样,Java的多维数组就不一定是规规矩矩的矩阵了,能够千变万化。
版权声明
本文来源于网络,版权归原作者所有,其内容与观点不代表凯时娱乐立场。转载文章仅为传播更有价值的信息,如采编人员采编有误或者版权原因,请与我们联系,我们核实后立即修改或删除。

猜您喜欢的文章