Java 数组

目录

声明数组变量

创建数组

数组的初始化

1、动态初始化

2、静态初始化

数组的四个基本特点:

数组小结

数组内存分析

处理数组

基本循环

For-Each 循环

数组作为函数的参数

数组作为函数的返回值


你可以声明一个数组变量,如 numbers[100] 来代替直接声明 100 个独立变量 number0,number1,....,number99。

数组对于每一门编程语言来说都是重要的数据结构之一

1、数组是相同类型数据的有序集合;

2、其中,每一个数据称作一个数组元素,每个数组元素可以通过一个下标来访问它们。

声明数组变量

首先必须声明数组变量,才能在程序中使用数组。下面是声明数组变量的语法:

 dataType[] arrayRefVar;   // 首选的方法   
 或
 dataType arrayRefVar[];  // 效果相同,但不是首选方法

创建数组

Java语言使用new操作符来创建数组,语法如下:

 arrayRefVar = new dataType[arraySize];

数据类型可以是8种基本的数据类型,也可以是引用数据类型

上面的语法语句做了两件事:

  • 1、使用 dataType[arraySize] 创建了一个数组。

  • 2、把新创建的数组的引用赋值给变量 arrayRefVar。

数组的初始化

1、动态初始化

创建了一个dataType类型,大小为arraySize的数组。数组元素并未被赋值,此时有默认值

 dataType[] arrayRefVar = new dataType[arraySize];
 数据类型     数组名      = new  数据类型[数组大小]

注意:

1.数组的元素是通过索引访问的。数组索引从 0 开始,索引值从 0 到 arrayRefVar.length-1。

2.数组边界:下标的合法区间: [0, length-1],如果越界就会报错; ArrayIndexOutOfBoundsException :数组下标越界异常!

3.数组名称.length:取得数组长度(数组长度可以由属性length获得)。

4.数组属于引用数据类型,在使用之前一定要开辟空间(实例化),否则就会产生"NullPoninterException"。Java使用new操作符来创建数组

当数组采用动态初始化开辟空间之后,数组之中的每个元素都是该数据类型的默认值。

数据类型默认初始化
byte、short、int、long0
foat、double0.0
char一个空字符,即 ‘\u0000’
booleanfalse
引用数据类型null,表示变量不引用任何对象

实例:

下面的语句首先声明了一个数组变量 nums,接着创建了一个包含 10 个 int 类型元素的数组,并且把它的引用赋值给 nums 变量。

 public class ArrayDemo01 {
     public static void main(String[] args) {
         //变量的类型 变量的名称 = 变量的值
         //声明数组
         int[] nums;
         //创建数组:给数组分配空间
         nums = new int[10];
         //int[] nums = new int[10];声明创建数组
         //给数组元素赋值:数组元素通过下标(索引)访问,索引从0开始,
         //没有赋值的元素有默认值   int类型默认值是0,String类型默认是null
         nums[0] = 1;
         nums[1] = 2;
         nums[2] = 3;
         nums[3] = 4;
         nums[4] = 5;
         nums[5] = 6;
         nums[6] = 7;
         nums[7] = 8;
         nums[8] = 9;
         nums[9] = 10;
         //计算所有元素的和:for循环遍历数组
         int sum = 0;
         //数组长度:array.length   length是数组的属性
         for (int i = 0; i < nums.length; i++) {
             sum = sum + nums[i];
         }
         System.out.println("数组元素的和为:" + sum);
         //System.out.println(nums[10]);  数组下标越界
         //java.lang.ArrayIndexOutOfBoundsException
     }
 }

2、静态初始化

创建了一个dataType类型的数组,数组元素被赋值。

 dataType[] arrayRefVar = {value0, value1, ..., valuek};
 数据类型 []  数组名      ={数组元素值};

例如:int[] arrays = {1,2,3,4,5};

数组的初始化实例:

 /*数组三种初始化
   1.静态初始化
   2.动态初始化
   3.数组的默认初始化:数组是引用类型,它的元素相当于类的实例变量,因此数组一经分配空间,其中的每个元素也被按照实例变量同样的方式被隐式初始化。
 */
 public class ArrayDemo02 {
     public static void main(String[] args) {
         //基本类型 静态初始化:创建数组并赋值
         int[] a = {1, 2, 3};
         System.out.println(a[0]);
         //引用类型 静态初始化
         Man[] mans = {new Man(), new Man()};
 ​
         //动态初始化:包含默认初始化
         int[] b = new int[5];
         b[0] = 1;
         b[1] = 2;
         b[2] = 3;
         b[3] = 4;
         b[4] = 5;
         System.out.println(b[0]);
     }
 ​
 }

数组的四个基本特点:

1.长度是确定的。数组一旦被创建,它的大小就是不可以改变的。

2.元素必须是相同类型,不允许出现混合类型。

3.数组变量属引用类型,数组也可以看成是对象,数组中的每个元素相当于该对象的成员变量。

4.数组本身就是对象,Java中对象是在堆中的,因此数组无论保存原始类型还是其他对象类型,数组对象本身是在堆中的。

数组小结

1.数组是相同数据类型(数据类型可以为任意类型)的有序集合

2.数组也是对象。数组元素相当于对象的成员变量

3.数组长度的确定的,不可变的。如果越界,则报: ArrayIndexOutOfBounds

数组内存分析

数组是一种引用数据类型,数组引用变量只是一个引用,数组元素和数组变量在内存里是分开存放的。下面将深入介绍数组在内存中的运行机制。

数组在内存中的运行机制

  1. 数组引用变量只是一个引用,这个引用变量可以指向任何有效的内存,只有当该引用指向有效内存后,才可通过该数组变量来访问数组元素。

  2. 与所有引用变量相同的是,引用变量是访问真实对象的根本方式。也就是说,如果我们希望在程序中访问数组,则只能通过这个数组的引用变量来访问它。

  3. 实际的数组元素被存储在堆(heap)内存中;数组引用变量是一个引用类型的变量,被存储在栈(stack)内存中。数组在内存中的存储示意图如图所示:

为什么有栈内存和堆内存之分?

  1. 当一个方法执行时,每个方法都会建立自己的内存栈,在这个方法内定义的变量将会逐个放入这块栈内存里,随着方法的执行结束,这个方法的内存栈也将自然销毁了。因此,所有在方法中定义的变量都是放在栈内存中的;

  2. 当我们在程序中创建一个对象时,这个对象将被保存到运行时数据区中,以便反复利用(因为对象的创建成本通常较大),这个运行时数据区就是堆内存。堆内存中的对象不会随方法的结束而销毁,即使方法结束后,这个对象还可能被另一个引用变量所引用(方法的参数传递时很常见),则这个对象依然不会被销毁。只有当一个对象没有任何引用变量引用它时,系统的垃圾回收机制才会在合适的时候回收它。

  3. 如果堆内存中数组不再有任何引用变量指向自己,则这个数组将成为垃圾,该数组所占的内存将会被系统的垃圾回收机制回收。因此,为了让垃圾回收机制回收一个数组所占的内存空间,则可以将该数组变量赋为null,也就切断了数组引用变量和实际数组之间的引用关系,实际数组也就成了垃圾。

把数组a的值赋给数组b

只要类型相互兼容,可以让一个数组变量指向另一个实际的数组,这种操作会产生数组的长度可变的错觉。如下代码所示:

 public class ArrayInRam
  {
    public static void main(String[] args){
      //定义并初始化数组,使用静态初始化
      int[] a = {5, 7 , 20};
      //定义并初始化数组,使用动态初始化
      int[] b = new int[4];
      //输出b数组的长度
      System.out.println("b数组的长度为:" + b.length);
      //循环输出a数组的元素
      for (int i = 0 ; i < a.length ; i++ ){
        System.out.println(a[i]);
     }
    //循环输出b数组的元素
      for (int i = 0 ; i < b.length ; i++ ){
         System.out.println(b[i]);
     }
    //因为a是int[]类型,b也是int[]类型,所以可以将a的值赋给b。
    //也就是让b引用指向a引用指向的数组
     b = a;
     //再次输出b数组的长度
    System.out.println("b数组的长度为:" + b.length);
    }
 }

运行上面代码后,将可以看到先输出b数组的长度为4,然后依次输出a数组和b数组的每个数组元素,接着会输出b数组的长度为3。看起来似乎数组的长度是可变的,但这只是一个假象。必须牢记:定义并初始化一个数组后,在内存里分配了两个空间,一个用于存放数组的引用变量,一个用于存放数组本身。下面将结合示意图来说明上面程序的运行过程。

当程序定义并初始化了a、b两个数组后,系统内存中实际上产生了4块内存区,其中栈内存中有两个引用变量:a和b;堆内存中也有两块内存区,分别用于存储a和b引用所指向的数组本身。a引用和b引用所指向数组里数组元素的值

当执行上面粗体字标识代码:b = a代码时,系统将会把a的值赋给b,a和b都是引用类型变量,存储的是地址。因此把a的值赋给b后,就是让b指向a所指向的地址。此时计算机内存的存储示意如图所示:

图4.4 让b引用指向a引用所指向数组

从图4.4中可以看出,当执行了b = a之后,堆内存中第一个数组具有了两个引用:a变量和b变量都指向了第一个数组。此时第二个数组失去了引用,变成垃圾,只有等待垃圾回收来回收它——但它的长度依然不会改变,直到它彻底消失。

程序员进行程序开发时,不要仅仅停留在代码表面,而要深入底层的运行机制,才可以对程序的运行机制有更准确的把握。当我们看一个数组时,一样要把数组看成两个部分:一个是数组引用,也就是在代码中定义的数组引用变量;还有一个是实际数组本身,这个部分是运行在系统内存里的,通常无法直接访问它,只能通过数组引用变量来访问它。

处理数组

数组的元素类型和数组的大小都是确定的,所以当处理数组元素时候,我们通常使用基本循环或者 For-Each 循环。

基本循环

示例

该实例完整地展示了如何创建、初始化和操纵数组:

 public class TestArray {
    public static void main(String[] args) {
       double[] myList = {1.9, 2.9, 3.4, 3.5};
  
       // 打印所有数组元素
       for (int i = 0; i < myList.length; i++) {
          System.out.println(myList[i] + " ");
       }
       // 计算所有元素的总和
       double total = 0;
       for (int i = 0; i < myList.length; i++) {
          total += myList[i];
       }
       System.out.println("Total is " + total);
       // 查找最大元素
       double max = myList[0];
       for (int i = 1; i < myList.length; i++) {
          if (myList[i] > max) max = myList[i];
       }
       System.out.println("Max is " + max);
    }
 }

以上实例编译运行结果如下:

 1.9
 2.9
 3.4
 3.5
 Total is 11.7
 Max is 3.5

For-Each 循环

JDK 1.5 引进了一种新的循环类型,被称为 For-Each 循环或者加强型循环,它能在不使用下标的情况下遍历数组。

语法格式如下:

 for(type element: array)
 {
     System.out.println(element);
 }

实例

该实例用来显示数组 myList 中的所有元素:

 public class TestArray {
    public static void main(String[] args) {
       double[] myList = {1.9, 2.9, 3.4, 3.5};
  
       // 打印所有数组元素
       for (double element: myList) {
          System.out.println(element);
       }
    }
 }

以上实例编译运行结果如下:

 1.9
 2.9
 3.4
 3.5

数组作为函数的参数

数组可以作为参数传递给方法。

例如,下面的例子就是一个打印 int 数组中元素的方法:

 public static void printArray(int[] array) {
   for (int i = 0; i < array.length; i++) {
     System.out.print(array[i] + " ");
   }
 }

下面例子调用 printArray 方法打印出 3,1,2,6,4 和 2:

 printArray(new int[]{3, 1, 2, 6, 4, 2});

数组作为函数的返回值

 public static int[] reverse(int[] list) {
   int[] result = new int[list.length];
  
   for (int i = 0, j = result.length - 1; i < list.length; i++, j--) {
     result[j] = list[i];
   }
   return result;
 }

以上实例中 result 数组作为函数的返回值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值