数组浅析

一、声明数组

数组是一种复合数据类型,它是一系列有序数据的集合,它当中的每一个数据都具有相同的数据类型。通过数组名加上一个不会越界的下标值来唯一确定数组中的元素(数组的大小)。一般情况下通过new关键字来声明,通过索引来访问,它的大小是固定的。

声明数组的方式:

 int[] arr1 = new int[5]
 String arr2 = new String[]{"a","b","c","d","e"}
 byte[] b = {1,2,3,4,5} 

数组的使用分为4个步骤:
声明数组 -> 分配空间 -> 赋值 -> 处理
数组对象是存放在堆内存的,数组的引用存放在栈内存,指向堆中的数组数据。
当声明一个数组时必须进行初始化大小,初始化之后他的大小固定,在内存中所占空间也固定。所以在声明数组时明确需求,声明的数组类型选择尽量优化。
对于数组的内存这块比较详细的分析,请参考:java知识之数组内存管理

二、数组是一个对象(特殊的对象)

public static void main(String[] args) {
        int[] array = new int[10];
        System.out.println("array的父类是:" + array.getClass().getSuperclass());
        System.out.println("array的类名是:" + array.getClass().getName());
}

outrPrint:
    array的父类是:class java.lang.Object
    array的类名是:[I

从上面的代码中可以看出,数组的直接父类是Object.它与普通对象存在着很大的不同。这一点可以从他的类名看出来 -> “[I”,在Java中就没有这个类,所以应该是在底层堆数组做了特殊的处理。

 public static void main(String[] args) {
        int[] array_00 = new int[10];
        System.out.println("一维数组:" + array_00.getClass().getName());
        int[][] array_01 = new int[10][10];
        System.out.println("二维数组:" + array_01.getClass().getName());

        int[][][] array_02 = new int[10][10][10];
        System.out.println("三维数组:" + array_02.getClass().getName());
}

outPrint:
    一维数组:[I
    二维数组:[[I
    三维数组:[[[I

从这里看出”[“代表的数组的维度。

public static void main(String[] args) {
        System.out.println("Object[]:" + Object[].class);
        System.out.println("Object[][]:" + Object[][].class);
        System.err.println("Object[][][]:" + Object[][][].class);
        System.out.println("Object:" + Object.class);
}

outPrint:
    Object[]:class [Ljava.lang.Object;
    Object[][]:class [[Ljava.lang.Object;
    Object:class java.lang.Object
    Object[][][]:class [[[Ljava.lang.Object;

可以看出数组和普通的Java类是不同的,普通的java类是以全限定路径名+类名来作为自己的唯一标示的,而数组则是以若干个[+L+数组元素类全限定路径+类来最为唯一标示的。这个不同也许在某种程度上说明了数组也普通java类在实现上存在很大的区别,也许可以利用这个区别来使得JVM在处理数组和普通java类时作出区分。

从网上看,看到有牛人说,”[“这个在Java中是没有声明的,它是在运行时生成的,并且用代码说明了一大堆,在这里先暂且放下不做深究,相信他们即可。并且数组声明中名没有任何成员变量、成员方法、构造函数、Annotation甚至连length成员变量这个都没有,它就是一个彻彻底底的空类。
这些都是JVM对数组作了特殊的处理。

三、数组的性能

现在一般在项目中,有人很少用到数组,一般也不想三七二十一,就直接使用集合。就是因为集合在操作上要比数组方便的多。但是数组还是有他自己的优势的。数组和其他存储数据的容器相比有三个方面的区别:效率、类型、保存基本数据类型的能力。

某些情况下数组效率相比于集合高是因为,集合某些方法的底层实际上是通过数组来实现的。
比如:ArrayList的add()

public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;  //将添加的元素通过下标存在数组
        return true;
}

比如说:求和int[]数组中的元素和List中的int类型的元素。(两者元素一样),这样数组的效率就比集合效率高,因为,集合实际上通过list.get(index)先获取元素的时候是需要进行拆箱操作的。(List中存储的是引用类型)

四、变长数组

数组是定长的,一旦声明初始化后是不可改变长度的,这在实际开发中是不方便的,我们可以对数组变长操作。

public class ArrayUtils {
    /**
     * @desc 对数组进行扩容
     * @author chenssy
     * @data 2013-12-8
     * @param <T>
     * @param datas 原始数组
     * @param newLen 扩容大小
     * @return T[]
     */
    public static <T> T[] expandCapacity(T[] datas,int newLen){
        newLen = newLen < 0 ? datas.length :datas.length + newLen;   
        //生成一个新的数组
        return Arrays.copyOf(datas, newLen);
    }

    /**
     * @desc 对数组进行扩容处理,1.5倍
     * @author chenssy
     * @data 2013-12-8
     * @param <T>
     * @param datas  原始数组
     * @return T[]
     */
    public static <T> T[] expandCapacity(T[] datas){
        int newLen = (datas.length * 3) / 2;      //扩容原始数组的1.5倍
        //生成一个新的数组
        return Arrays.copyOf(datas, newLen);
    }

    /**
     * @desc 对数组进行扩容处理,
     * @author chenssy
     * @data 2013-12-8
     * @param <T>
     * @param datas 原始数组
     * @param mulitiple 扩容的倍数
     * @return T[]
     */
    public static <T> T[] expandCapacityMul(T[] datas,int mulitiple){
        mulitiple = mulitiple < 0 ? 1 : mulitiple;
        int newLen = datas.length * mulitiple;
        return Arrays.copyOf(datas,newLen );
    }
}

五、数组转换为List

在现实中经常需要使用Array.asList()将数组转为List,这样的话操作起来就方便了好多。只是有时候会出现莫名其妙的东西。比如:

public static void main(String[] args) {
        int[] datas = new int[]{1,2,3,4,5};
        List list = Arrays.asList(datas);
        System.out.println(list.size());
}
------------Output:
        1

这输出是1,为什么?

下面给出asList()的源码:

 public static <T> List<T> asList(T... a) {
    return new ArrayList<>(a);
 }

可以看出参数是一个变长的泛型,对于int[]来说他是将这个数组当做一个整个的对象转换成集合,实际上集合中就保存了一个元素,就是int[]对象。但是,将int[]改为Integer[]就可以正常转换。

另外:通过这种方式转换过来的集合是定长的,不可改变

因为返回的ArrayList<>()是Arrays工具的一个对象,不是List的实现,在才ArrayList下并没有提供add()、remove()等方法。只是提供了下面的方法:

  • size():元素数量
  • toArray():转换为数组
  • get():获得指定元素
  • contains():是否包含某元素
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值