Java基本数据类型数组与可变长度参数

Java基本数据类型数组与可变长度参数


概述

在本文中,只讨论基本数据类型的数组定义及其相关的操作,并不涉及引用数据类型的操作,以为引用数据类型的机制和基本数据类型数组的机制是有区别的,在后续的博客中会继续深入的讨论。

基本定义

  • 一维数组
    数组是我们经常用的一种数据结构,非常有必要进行详细的讨论,如果你曾经是C/C++程序员,那么这部分内容应该仔细的阅读,因为在C/C++中的数组和在Java中的数组不一样,在Java中数组的限制更多。一维数组的定义格式有下面的两种:
    静态数组格式:
数据类型[] 变量名 = {元素1,元素2,元素3...};

动态数组格式:

数据类型[] 变量名 = new 数据类型[长度]; //必须要给出数组的长度,其中数组的长度可以根据length得到。
  • 二维数组
    静态数组格式:
数据类型[][] 变量名 = {{元素1,元素2...},{元素1,元素2...}...};

动态数组格式:

数据类型[][] 变量名 = new 数据类型[长度1][长度2];

在Java中关于数组的定义有且仅有这两种格式,存在很大的局限性,对于熟悉C/C++的人来说更是难以接受这种定义格式,sun公司也考虑到了这个问题,所以在后面定义了其他的数据结构去补充数组定义带来的不灵活,我们应该接受这种折中,因为Java在很多方面固定格式是为了保证程序的正确性,避免了更大的自由导致的错误。

内存

在Java中出于安全的考虑,不允许程序员操作内存,但是当我们能明确数组究竟在内存中是怎样存储的,对于我们更好的理解Java程序与相当大的好处,在Java中,内存被分为5个部分,但是在数组的存放过程中,仅仅用到其中的两个部分,分别是:栈区和堆区。栈区存储的仅仅在作用域内有效,一旦出了作用域立马就会销毁,但是堆区的数据却不是根据作用域来释放的,在C/C++中需要程序员手动去释放堆区的内存,否则会导致内存的泄露,而我们在敲代码的过程中经常会忘记去释放内存,同样,sun公司为了弥补这个缺陷,利用了一个垃圾回收器,当堆区中出现没有被引用的对象时,会在合适的时间调用垃圾回收器回收空间,避免了程序员因不能及时回收空间导致堆区空间耗尽,影响后面程序的运行,这是JVM的职责,关于垃圾回收器究竟是什么,会在以后的博客中深入的说明,现在并不适合去说明JVM的机制。http://www.linuxidc.com/Linux/2013-03/81800.htm 参考这篇文章,讲的还是不错的,我不想画图了,所以略去吧,尤其对于熟悉C/C++内存分配的程序员,我想你们应该更能理解这个内存表示的原因,并能看出其本质究竟是什么。

常见的两个问题

  • 数组下标越界

数组下标越界是一个经常会遇到的问题,请自行控制你的程序,通过debug可以跟踪这个bug。

  • 空指针异常
    很多的资料都把空指针异常说的很神奇,但是其实并不是那么玄乎,所谓的空指针异常,实际上就是说一个指针没有引用相应的对象,但是却使用这个指针引用了该对象的属性或者方法,怎么理解这段话呢?看下面的例子:
public class TestPoint{
    public static void main(String[] args){
        int[] arr = {1,3,5};//定义个一个静态数组
        arr = null;//也就是将arr的地址清空
        System.out.print(arr[0]);//这个句子就是所谓的空指针异常,这段代码在编译时会发生错误,arr已经没有指向{1,3,5}这个堆区空间了,但是仍然使用了arr[0]
    }
}
可变长度参数与数组

  • 可变长度参数的定义及其与数组的关系
    可变长度参数在C++中也是存在的,但是在C++中的可变长度参数使用起来比较复杂,还要使用start、end等方法,但是在Java只用及其的简单,它实际上的实现方式是数组的语法糖,并不神秘,而且在可变长度数组内部也是转化成了一个数组,后面会具体讲这个语法糖,现在我们来看下可变长度参数的定义:
public static void fun(int...arr)//定义一个可变长度参数
{
    for(int i = 0 ; i < arr.length; i++){
        System.out.println(arr[i])  //在这里我们实际把它当做了数组使用
    }
}

关于可变长度参数有几点说明:
* 可变长度参数必须是函数的最后一个参数;
* 可变长度参数实际上就是数组的语法糖,在调用有可变长度参数的函数时,完全可以将数组作为实参。

那么sun公司为了要定义可变长度参数呢?我在前面说过,Java中的数组很不自由,从数组的两种定义方式中我们可以看出,在定义数组的时候,必须给出数组的长度,但是很多情况下,我们很难确定数组的长度究竟是多少,所以sun公司为了弥补数组的这个缺陷,同时也为了与C++抗衡(你说不抗衡我不信,毕竟C++也拥有那么大的市场份额),在C++中有可变长度参数,Java也要有这个功能,同时还弥补了Java数组的缺陷,一举两得,何乐而不为?

但是在很多情况下我不建议广大的程序员使用可变长度参数类型,因为这样至少存在一个缺陷是:慢,为什么会慢?因为实际上可变长度参数是数组的语法糖,所以在编译运行的过程中,实际上JVM必须将这个语法糖转换为真正的数组,这用中国人的话来讲是脱裤子放屁,多此一举啊。

for循环语法糖

如果非要使用数组的语法糖,也不是不可以,在这种情况下,Java的程序员会同时使用for循环的语法糖,使这个代码的逻辑更加的简单,for语法糖的例子如下(还是操作上面那哥可变长度参数的例子):

for(int num:arr){
    System.out.println(num);//同样能打印出这个数组的值
}

二维数组的for循环语法糖:

int[][] arr = {{1,2},{3,4},{4,5,6}}
for(int[] level_1:arr){
    for(int num:level_1){
        System.out.println(num); //同样能实现输出的效果
}
sun公司提供的数组工具类

请查阅JDK中:java.util.Arrays,其中关于数组的很多操作,在这个类中都有详细的定义,许多函数都进行了不同数据类型的重载,例如数组的排序、二分查找等。

参考资料
  • java.util.Arrays工具类:https://docs.oracle.com/javase/7/docs/api/java/util/Arrays.html
联系我

Java基本数据类型数组与可变长度参数_第1张图片

你可能感兴趣的:(Java)