zoukankan      html  css  js  c++  java
  • Java Review (五、数组)

    @


    数组是编程语言中最常见的一种数据结构,可用于存储多个数据,每个数组元素存放一个数据,通 常可通过数组元素的索引来访问数组元素,包括为数组元素赋值和取出数组元素的值。

    数组数据类型

    Java的数组要求所有的数组元素具有相同的数据类型。因此,在一个数组中,数组元素的类型是唯一的,即一个数组里只能存储一种数据类型的数据,而不能存储多种数据类型的数据。
    一旦数组的初始化完成,数组在内存中所占的空间将被固定下来,因此数组的长度将不可改变。即 使把某个数组元素的数据清空,但它所占的空间依然被保留,依然属于该数组,数组的长度依然不变。
    Java的数组既可以存储基本类型的数据,也可以存储引用类型的数据,只要所有的数组元素具有相同的类型即可。
    数组也是一种数据类型,它本身是一种引用类型。例如int是一个基本类型,但int[] 就是一种引用类型了。


    声明数组变量

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

    数组是一种引用类型的变量,因此使用它定义一个变量时,仅仅表示定义了一个引用变量(也就是 定义了一个指针),这个引用变量还未指向任何有效的内存,因此定义数组时不能指定数组的长度。而 且由于定义数组只是定义了一个引用变量,并未指向任何有效的内存空间,所以还没有内存空间来存储 数组元素,因此这个数组也不能使用,只有对数组进行初始化后才可以使用。

    初始化数组

    Java语言中数组必须先初始化,然后才可以使用。所谓初始化,就是为数组的数组元素分配内存空 间,并为每个数组元素赋初始值。
    数组的初始化有如下两种方式。

    • 静态初始化:初始化时由程序员显式指定每个数组元素的初始值,由系统决定数组长度。
    • 动态初始化:初始化时程序员只指定数组长度,由系统为数组元素分配初始值。

    静态初始化

    arrayName = new type[]{elementl, element2 , element3 , element4 ...}
    

    在上面的语法格式中,前面的type就是数组元素的数据类型,此处的type必须与定义数组变量时 所使用的type相同,也可以是定义数组时所指定的type的子类,并使用花括号把所有的数组元素括起 来,多个数组元素之间以英文逗号(,)隔开,定义初始化值的花括号紧跟[]之后。值得指出的是,执行 静态初始化时,显式指定的数组元素值的类型必须与new关键字后的type类型相同,或者是其子类的 实例。下面代码定义了使用这三种形式来进行静态初始化。

    实例
    //定义一个int数组类型的变量,变量名为intArr
    int[] intArr;
    //使用静态初始化,初始化数组时只指定数组元素的初始值,不指定数组长度
    intArr = new int[](5, 6, 8, 20);
    //定义一个Object数组类型的变量,变量名为:bjArr
    Object[] objArr;
    //使用静态初始化,初始化数组时数组元素的类型是
    //定义数组时所指定的数组元素类型的子类
    objArr = new String [ ] ( "Java", "C#" );
    Object[] objArr2;
    //使用静态初始化
    objArr2 = new Object [ ] {"Java” ,"Python"};
    

    动态初始化

    动态初始化只指定数组的长度,由系统为每个数组元素指定初始值。动态初始化的语法格式如下:

    arrayName = new type[length];
    

    在上面语法中,需要指定一个int类型的length参数,这个参数指定了数组的长度,也就是可以容 纳数组元素的个数。与静态初始化相似的是,此处的type必须与定义数组时使用的type类型相同,或 者是定义数组时使用的type类型的子类。下面代码示范了如何进行动态初始化(程序清单同上)。

    //数组的定义和初始化同时完成,使用动态初始化语法
    int[] prices = new int[5];
    //数组的定义和初始化同时完成,初始化数组时元素的类型是定义数组时元素类型的子类 Object[] books = new String[4];
    

    执行动态初始化时,程序员只需指定数组的长度,即为每个数组元素指定所需的内存空间,系统将 负责为这些数组元素分配初始值。指定初始值时,

    数组元素类型 系统分配初始值规则
    整数类型(byte、short、int和long) 0
    浮点类型(float、double) 0.0
    字符类型(char) 'u0000'
    布尔类型(boolean) false
    引用类型(类、接口和数组) null

    数组使用

    Java语言的数组索引是从0开始的,也就是说,第一个数组元素的索引值为0,最后一个数组元素 的索引值为数组长度减1。

    double[] arr = {1.9, 2.9, 3.4, 3.5};
    

    arr[2]表示3.4,数组第三个元素。

    for-each循环

    Java 5之后,Java提供了一种更简单的循环:foreach循环,这种循环遍历数组和集合更加简洁。

    深入数组

    数组是一种引用数据类型,数组引用变量只是一个引用,数组元素和数组变量在内存里是分开存放的。

    内存中的数组

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

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

    实际的数组对象被存储在堆(heap)内存中;如果引用该数组对象的数组引用变量是一个局部变量, 那么它被存储在栈(stack)内存中。

    数组在内存中的存储示意图

    在这里插入图片描述

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

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

    实例
    public class ArrayInRam {
    
    	public static void main(String[] args) {
    		//静态初始化a
    		int []a= {5,7,20};
    		//动态初始化b
    		int []b=new int[4];
    		//输出b的长度
    		System.out.println(b.length);
    		//循环遍历输出a
    		for(int aa:a) {
    			System.out.print(aa+"	");
    		}	
    		//b引用a
    		b=a;
    		//输出b的长度
    		System.out.println("
    "+b.length);
    
    	}
    
    }
    

    输出结果:

    4
    5	7	20	
    3
    

    看起来b数组的长度似乎发生了变化。实际上:

    定义并初始化一个数组后,在内存 中分配了两个空间,一个用于存放 数组的引用变量,另一个用于存放数组本身。

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

    可以非常清楚地看出a引用和b引用各自所引用的数组对象,并可以很清楚地看出a变量所引用的数组长度是3, b变量所引用的数组长度是4。

    定义并初始化a、b两个数组后的内存示意图

    在这里插入图片描述

    • 当执行代码 b = a 时,系统将会把a的值赋给b, a和b都是引用类型变量,存储的是地址。因此把a的值赋给 b后,就是让b指向a所指向的地址。

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

    让b引用指向a引用所指向数组后的存储示意图

    在这里插入图片描述

    基本类型数组的初始化

    对于基本类型数组而言,数组元素的值直接存储在对应的数组元素中,因此,初始化数组时,先为 该数组分配内存空间,然后直接将数组元素的值存入对应数组元素中。

    实例
    public class PrimitiveArrayTest {
    	public static void main(String[] args) {
    	//定义一个int[]类型的数组变量iArr
    	int[] iArr;
    	//动态初始化数组,数组长度为5
    	iArr = new int[5];
    	//采用循环方式为每个数组元素赋值
    	for (int i = 0; i <iArr.length ; i++ ){
    	  iArr[i] = i + 10;
        }
     }
    }
    

    定义iArr数组变量后的存储示意图

    在这里插入图片描述


    动态初始化iArr数组变量后的存储示意图

    在这里插入图片描述

    显式指定每个数组元素值后的存储示意图

    在这里插入图片描述

    引用类型数组的初始化

    引用类型数组的数组元素是引用,因此情况变得更加复杂。每个数组元素里存储的还是引用,它指 向另一块内存,这块内存里存储了有效数据。

    先定义一个Person类:

    public class Person {
    	public int age; // 年龄
    	public double height; // 身高
    	//定义一个info方法
    	public void info(){
    	System.out .println ("我的年龄是:" + age+ "我的身高是:"+ height);
    	}
    
    }
    

    定义一个Person]]数组,接着动态初始化这个Person[]数组,并为这个数组的每个数组元素指定值:

    public class ReferenceArrayTest {
    
    	public static void main(String[] args) {
    		//定义一个students数组变量,其类型是Person[]
    		Person[] students;
    		//执行动态初始化
    		students = new Person[2];
    		//创建一个Person实例,并将这个Person实例赋给zhang变量
    		Person zhang=new Person();
    		//为zhang所引用的Person对象的age、height赋值
    		zhang.age = 15;
    		zhang.height = 158;
    		//创建一个Person实例,并将这个Person实例赋给丄ee变量
    		Person lee = new Person();
    		//为lee所引用的Person对象的age、height赋值
    		lee.age = 16;
    		lee.height = 161;
    		//将zhang变量的值赋给第一个数组元素
    		students[0] = zhang;
    		//将lee变量的值赋给第二个数组元素
    		students[1] = lee;
    		//下面两行代码的结果完全一样,因为lee
    		//和students [1]指向的是同一个Person实例
    		lee.info();
    		students[1].info();
    	}
    
    }
    



    定义students数组变量后的存储示意图

    在这里插入图片描述


    动态初始化students数组变量后的存储示意图

    在这里插入图片描述


    创建两个Person实例后的存储示意图

    在这里插入图片描述


    为数组元素赋值后的存储示意图

    在这里插入图片描述

    多维数组

    Java语言里提供了支持多维数组的语法。

    但从底层运行机制来讲,二维数组实际上仍然是一维数组。

    Java语言里的数组类型是引用类型,因此数组变量其实是一个引用,这个引用指向真实的数组内存。 数组元素的类型也可以是引用,如果数组元素的引用再次指向真实的数组内存,这种情形看上去很像多维数组。
    回到前面定义数组类型的语法:

    type[] arrName;
    

    这是典型的一维数组的定义语法,其中type是数 组元素的类型。如果希望数组元素也是一个引用,而且是指向int数组的引用,则可以把type具体成int[],那么上面定义数组的 语法就是 int[][] arrName

    如果把int这个类型扩大到Java的所有类型(不包括数组类型),则出现了定义二维数组的语法:

    type[][] arrName;
    

    Java语言采用上面的语法格式来定义二维数组,但它的实质还是一维数组,只是其数组元素也是引 用,数组元素里保存的引用指向一维数组。

    接着对这个"二维数组”执行初始化,同样可以把这个数组当成一维数组来初始化,把这个“二维 数组”当成一个一维数组,其元素的类型是type口类型,则可以釆用如下语法进行初始化:

    arrName = new type[length][]
    

    上面的初始化语法相当于初始化了一个一维数组,这个一维数组的长度是lengtho同样,因为这个 一维数组的数组元素是引用类型(数组类型)的,所以系统为每个数组元素都分配初始值:nullo
    这个二维数组实际上完全可以当成一维数组使用:使用new type[length] 初始化一维数组后,相当 于定义了 length个type类型的变量;类似的,使用 new type[length][] 初始化这个数组后,相当于定义了 length个type[]类型的变量,当然,这些type[]类型的变量都是数组类型,因此必须再次初始化这些数组。

    数组排序

    几个常见数组排序方法(冒泡排序、插入排序、快速排序、希尔排序)







    参考:
    【1】:《疯狂Java讲义》
    【2】:《Java核心技术 卷一》
    【3】:https://www.runoob.com/java/java-array.html

  • 相关阅读:
    SP笔记:交叉实现七行并成一行
    HTML tag 学习
    操作哈希表
    Efficient bipedal robots based on passivedynamic walkers
    Pushing People Around
    ZEROMOMENT PONTTHIRTY FIVE YEARS OF ITS LIFE

    Active Learning for RealTime Motion Controllers
    Accelerometerbased User Interfaces for the Control of a Physically Simulated Character
    Dynamic Response for Motion Capture Animation
  • 原文地址:https://www.cnblogs.com/three-fighter/p/13052498.html
Copyright © 2011-2022 走看看