数组(一):Java数组基础

一、定义数组

数组的定义有三种方式

方式1:推荐
type[] a = new type[元素个数];

方式2:c语言方式
type a[] = new type[元素个数];

方式3:直接初始化
type[] a = new type[]{逗号分隔的初始化值};
例如:int[] a = new int[]{1,2,3,4,5};

当数组存放的元素不是基本数据类型时,数组内存放的是对象的引用

二、数组是什么?

数组肯定不是基本数据类型,按照我们自己的说法:
数组是一种复合数据类型,它含有一系列相同类型的元素,并且元素的数量是定长的,元素的排列是有序的。

我们可以通过代码来了解一下数组:

int[] a = new int[10];
System.out.println(a.getClass().getSuperclass());
System.out.println(a.getClass().getName());

int[][] b = new int[10][10];
System.out.println(b.getClass().getSuperclass());
System.out.println(b.getClass().getName());

Integer[] c = new Integer[10];
System.out.println(c.getClass().getSuperclass());
System.out.println(c.getClass().getName());

Integer a = new Integer(1);
System.out.println(a.getClass().getSuperclass());
System.out.println(a.getClass().getName());

//output:
class java.lang.Object
[I
class java.lang.Object
[[I
class java.lang.Object
[Ljava.lang.Integer
class java.lang.Object
[C
class java.lang.Number
java.lang.Integer

可见,数组也是一个对象,但是数组的类名却有点奇怪,但是从规律上来看,可以知道:
1. [ 代表数组的维度
2. 最后的大写字母是一种特殊的标识,标识数组的类型,例如int数组的是I,char数组的C,同理double的就是D,如果是对象则是L + 全限定名

在jvm中,这被叫做描述符,描述符的作用是用来描述字段的数据结构、方法的参数列表和返回值,它的规则是:基本数据类型和void用它们的第一个大写字母表示,而对象类型则用字符L加对象的全限定名来表示,例如:
int[][]的描述符是:[[I
方法void inc(int i)的的描述符是:(I)V

从上面可以看出,数组的元素时用描述符来表示的,而普通的对象则是用类的全限定名表示,这也侧面的暗示了jvm处理数组和普通对象的方式是不同的!

对于数组,jvm不通过类加载器加载(类加载器会从源码包中读取类的class文件),而是由jvm直接创建的,而对于普通对象,则是由类加载器加载,因此会到类路径下加载。但是,数组类的元素类型最终还是靠类加载器去创建

有一个问题值得思考,为什么数组通过.length来获取长度,而String通过.length()来获取长度?

从面向对象的角度来说,直接暴露成员变量是不合理的,我们可以通过反射看看数组的内部结构:

Object[] obj = new Object[10];
Class clazz  = obj.getClass();
System.out.println(clazz.getDeclaredConstructors().length);
System.out.println(clazz.getDeclaredFields().length);
System.out.println(clazz.getDeclaredMethods().length);
try {
    System.out.println(clazz.getDeclaredField("length"));
    } catch (NoSuchFieldException e) {
        System.out.println("没有该域");
    } catch (SecurityException e) {
}

//output:
0
0
0
没有该域

可以看到,数组内部,没有任何的 构造方法、方法、变量,并且连length这个域都没有,而我们就是通过length这个域来获取长度的,这不是很矛盾吗?
这就是JVM做的处理:

使用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处理Java数组方法的思考

三、二维数组的定义

基本的定义方式有两种形式,如:

方式一:(推荐)
type[][] i = new type[2][3];

方式二:
type i[][] = new type[2][3];

声明二维数组的时候可以只指定第一维大小,空缺出第二维大小,之后再指定不同长度的数组。但是注意,第一维大小不能空缺(不能只指定列数不指定行数)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值