引用类型——Java数组

数组:

一组相关数据的集合,实际上就是一连串的变量,可以分为:一维数组、二维数组、多维数组

默认值为null,暂时还没有任何指向的内存空间

Java中的数组必须先初始化,然后才可以使用。

所谓初始化,就是为数组的数组元素分配内存空间,并为每个数组元素赋初始值。

一、数组初始化

1,静态初始化

静态初始化:初始化时由程序员显式指定每个数组元素的初始值,由系统决定需要的数组长度。

静态初始化语法格式:

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

type:数组元素的数据类型,此处的type必须与定义数组变量时所使用的type相同,也可以是定义数组时所使用的type的子类;并使用花括号把所有的数组元素括起来,多个元素之间以逗号(,)隔开,定义初始化值的花括号紧跟[]之后。

代码示例:

//定义一个int数组类型的变量,变量名为intArr

int[] intArr;    //声明一维数组

//使用静态初始化,初始化数组时只指定数组元素的初始值,不指定数组长度。

intArr=new int[]{5,6,8,20};

//定义一个Object数组类型的变量,变量名为objArr

Object[] objArr;

//使用静态初始化,初始化数组时数组元素的类型是定义数组时数组元素类型的子类

objArr=new String[]{"Java","李钢"};

Object[] objArr2;

//使用静态初始化

objArr2=new Object[]{"java","鲤鱼"};

arrayName={element1,element2,element3,element4...}

代码示例:

int scorep[]={23,56,89,75,68};        //数组声明并附初值

2,动态初始化

动态初始化:初始化时程序员只指定数组长度,由系统为数组元素分配初始值

动态初始化语法格式:

arrayName=new type[length];   //分配内存给数组

length指定了数组的长度,也就是可以容纳数组元素的个数。

代码示例:

//数组的定义和初始化同时完成,使用动态初始化语法

int[] prices=new int[5];

//数组的定义和初始化同时完成,初始化数组时元素的类型是定义数组时元素类型的子类。

Object[] books=new String[4];

指定初始值时,系统按如下规则分配初始值:

(1)数组元素的类型是基本类型中的整数类型(byte、short、int和long),则数组元素的值是0.

(2)数组元素的类型是基本类型中的浮点类型(float、double),则数组元素的值是0.0.

(3)数组元素的类型是基本类型中的字符类型(char),则数组元素的值是‘\u0000‘.

(4)数组元素的类型是基本类型中的布尔类型(boolean),则数组元素的值是false.

(5)数组元素的类型是引用类型(类、接口和数组),则数组元素的值是null.

注意:

不要静态初始化和动态初始化同时使用。

数组初始化完成后就可以使用数组了。

二、使用数组

数组最常用的用法就是访问数组元素,包括对数组元素进行赋值和访问数组元素的值。

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

代码如下:

//输出objArr数组的第二个元素,将输出字符串“李钢”

System.out.println(objArr[1]);

//为objArr2的第一个数组元素赋值

objArr[0]="Spring";

如果访问数组元素时指定的索引小于0,或者大于等于数组的长度,编译程序不会出现任何错误,将运行时出现异常:java.lang.ArrayIndexOutOfBoundsException:2(数组索引越界异常),这个异常提示信息后的一个int整数,就是程序员视图访问的数组索引。

代码示例:

//访问数组元素指定的索引等于数组长度,所以下面代码将在运行时出现异常

System.out.println(objArr2[2]);

遍历数组:

//使用循环输出pricese数组的每个数组元素的值

for(int i=0;i<prices.length[i];i++)

{

System.out.println(prices[i]);

}

三、foreach循环

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

foreach循环的语法格式:

for(type variableName : array | collection)

{

//variableName自动迭代访问每个元素...

}

type 数组元素或集合元素的类型

variableName 形参名,foreach循环将自动将数组元素、集合元素依次赋给该变量。

代码示例:

String[] books={"轻量级J2EE","权威指南","Ajax宝典"};

//使用foreach循环来遍历数组元素,其中book将会自动迭代每个数组元素

for(String book:books)

{

//使用foreach循环来迭代输出数组元素或集合元素时,通常不要对循环变量进行赋值

//book="Ruby On Rails敏捷开发最佳实践";

System.out.println(book);

}

注意:

使用foreach循环迭代数组元素时,并不能改变数组元素的值,因此不要对foreach的循环变量进行赋值。

四、数组在内存中的运行机制

1,数组的运行介质

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

实际的数组元素被存储在堆(heap)内存中;数组引用变量是一个引用类型的变量,被存储在栈(stack)内存中。

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

当一个方法执行时,每个方法都会建立自己的内存栈,在这个方法内定义的变量将会逐个放入这块栈内存里,随着方法的执行结束,这个方法的内存栈随之销毁。因此,所有在方法中定义的变量都是放在栈内存中的;当我们在程序中创建一个对象时,这个对象将被保存在运行时数据区中,以便反复利用(因为对象的创建成本通常较大),这个运行时数据区就是堆内存。堆内存的独享不会随方法的结束而销毁,即使方法结束后,这个对象还可能被另一个引用变量引用,则这个对象依然不会被销毁。只有当一个对象没有任何引用变量引用它时,系统的垃圾回收机制才会在合适的时候回收它。

代码示例:

//定义并初始化数组,使用静态初始化

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

5

7

20

0

0

0

0

b数组的长度为:3

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

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

内存的存储示意图如下图所示:

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

当执行了b=a之后,堆内存中第一个数组中具有了两个引用:a变量和b便来那个都指向了第一个数组。

此时第二个数组失去了作用,变成垃圾,只有等待垃圾回收来回收它——但它的长度依然不会改变,直到它彻底消失。

2,基本类型数组的初始化

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

代码示例如下:

//定义一个int[]类型的数组常量

int[] iArr;  //仅定义一个数组变量此时内存示意图如下:

//动态初始化数组,数组长度为5

iArr=new int[5];  //动态初始化后,系统将负责为该数组分配内存空间,并分配默认的初始值:所有数组元素都被赋为0,此时内存中的存储示意图为:

//采用循环方式为每个数组元素赋值

for(int i=0;i<iArr.length;i++)

{

iArr[i]=i+10;

}

//当循环为该数组的每个数组元素依次赋值后,此时每个数组元素的值都变成程序制定的值。显式制定数组元素值后存储示意图如下所示:

从上图中可以看到基本类型数组的存储示意图,每个数组元素的值直接存储在对应的内存里。

操作基本数据类型数组的数组元素时,实际上就是操作基本类型的变量。

3,引用类型数组的初始化

引用类型数组的数组元素是引用:每个数组元素里存储还是引用,它指向另一块内存,这块内存里存储了有效数据。

class Person

{

//年龄

public int age;

//身高

public double height;

//定义一个info方法

public void info()

{

System.out.println("我的年龄是:"+age+" 我的身高是:"+height);

}

}

//定义一个students数组变量,其类型是Person[]

Person[] students;   //这行代码仅仅在栈内存中定义了一个引用变量,也就是一个指针,这个指针并未指向任何有效的内存区。此时内存中存储示意图如下所示:

//执行动态初始化

students =new Person[2]; //

//创建一个Person示例,并将这个Person示例赋给zhang变量

Person zhang=new Person();

//为zhang所引用的Person对象的属性赋值

zhang.age=15;

zhang.height=158;

//创建一个Person示例,并将这个Person实例赋值给lee变量

Perosn lee=new Person();

//为lee所引用的Person对象的属性赋值

lee.age=16;

lee.height=161;

//定义两个Person实例,定义这两个实例实际上分配了4块内存,在栈内存中存储了zhang和lee两个引用变量,还在堆内存中存储了两个Person实例。此时的内存存储示意图如下所示:

//将zhang变量的值赋给第一个数组元素

students[0]=zhang;

//将lee变量的值赋给第二个数组元素

students[1]=lee;

//当程序把张赋给students数组的第一个元素,把lee赋给students数组的第二个元素,students数组的两个数组元素将会指向有效的内存区。此时的内存存储示意图如下所示:

从上面图可以看出:此时zhang和students[0]指向同一个内存区,而且它们都是引用类型变量,因此通过zhang和student[0]来访问Person实例的属性和方法的效果完全一样,不论修改students[0]所指向的Person实例的属性,还是修改zhang变量所指向的Person实例的属性,所修改的其实是同一个内存区,所以必然互相影响。同理,lee和students[1]也有相同的效果。

//下面两行代码的结果完全一样,因为lee和students[1]指向的是同一个Person实例

lee.info();

students[1].info();

运行结果:

我的年龄是:16 我的身高是:161.0

我的年龄是:16 我的身高是:161.0

五、操作数组的工具类

java.util.Arrays

Java提供的Arrays类里包含了一些static修饰的方法可以直接操作数组,这个Arrays类里包含了如下几个static修饰的方法(static修饰的方法可以直接通过类名调用)。

binarySearch(type[] a,type key):

使用二分法查询key元素值在a数组中出现的索引;如果a数组不包含key元素值,则返回负数。

调用该方法时要求数组中元素已经按生序排列,这样才能得到正确结果。

binarySearch(type[] array, int fromIndex, int toIndex, type value):

与前面的方法类似,但它只搜索a数组中fromIndex到toIndex索引的元素。

调用该方法时要求数组中元素已经按生序排列,这样才能得到正确结果。

copyOf(type[] original, int newLength):

这个方法会把original数组复制成一个新数组,其中length是新数组的长度。

如果length小于original数组的长度,则新数组就是原数组的前面length个元素;如果length大于original数组的长度,

则新数组的前面元素就是原数组的所有元素,后面补充0(数值型)、false(布尔型)或者null(引用型)。

copyOfRange(type[] original, int from, int to):

这个方法与前面方法类似,但这个方法只复制original数组的from索引到to索引的元素。

equals(type[] array1, type[] array2):

如果把array1数组和array2数组的长度相等,而array1数组和array2数组的数组元素一一相同,该方法返回true。

fill(type[] array, type value):

该方法将会把a数组所有元素值都赋值为value。

fill(type[] array, int fromIndex, int toIndex, type value):

这个方法与前面方法类似,区别是该方法仅仅对fromIndex到toIndex索引的数组元素赋值为value。

sort(type[] array):

该方法对数组array的数组元素进行排序。

sort(type[] array, int fromIndex, int toindex):

这个方法与前面方法类似,区别是该方法仅仅对fromIndex到toIndex索引的元素进行排序。

toString(type[] array):

该方法将一个数组转换成一个字符串。该方法按顺序把多个数组元素连缀在一起,

多个数组元素使用英文逗号(,)和空格隔开。

代码示例:

//定义一个a数组

int[] a=new int[]{3,4,5,6};

//定义一个a2数组

int[] a2=new int[]{3,4,5,6};

//a数组和a2数组的长度相等,每个元素依次相等,将输出true

System.out.println("a数组和a2数组是否相等:"+Arrays.equals(a,a2));

//通过赋值a数组,生成一个新的b数组

int[] b=Arrays.copyOf(a,6);

System.out.println("a数组和a2数组是否相等:"+Arrays.equals(a,b));

//输出b数组的元素,将输出{3,4,5,6,0,0}

System.out.println("b数组的元素为::"+Arrays.toString(b));

//将b数组的第3个元素(包括)到第五个元素(不包括)赋为1

Arrays.fill(b,2,4,1);

//输出b数组的元素,将输出{3,4,1,1,0,0}

System.out.println("b数组的元素为::"+Arrays.toString(b));

//对b数组进行排序

Arrays.sort(b);

//输出b数组的元素,将输出{0,0,1,1,3,4}

System.out.println("b数组的元素为::"+Arrays.toString(b));

运行结果:

a数组和a2数组是否相等:true

a数组和a2数组是否相等:false

b数组的元素为::[3, 4, 5, 6, 0, 0]

b数组的元素为::[3, 4, 1, 1, 0, 0]

b数组的元素为::[0, 0, 1, 1, 3, 4]

为了在程序中使用Arrays类,必须在程序中导入java.util.Arrays类。

System类的一个方法:

static void arraycopy(Object arc,int srcPos,Object dest,int destPos,int length):

该方法可以将src数组里的元素值赋给dest数组的元素,其中srcPos指定从src数组的第几个元素开始复制,

length参数指定将src数组的多少个元素赋给dest数组的元素。

六、其他

二维数组

数据类型 数组名[]=null;        //声明一维数组

数组名=new 数据类型[行的个数][列的个数];    //分配内存给数组

多维数组

int a[][][][]=new int[][][][];

代码实例:

public class JavaArray {

public static void main(String args[])

{

//一维数组

int score[]={52,1,26,89,75,5,6,78,90,23};

int max=0;

int min=0;

max=min=score[0];

for (int i = 0; i < score.length; i++) {

if(score[i]>max)

{

max=score[i];

}

if(score[i]<min)

{

min=score[i];

}

}

System.out.println("最大数值:"+max);

System.out.println("最小数值:"+min);

//动态定义

int a[]=new int[3];

a[0]=3;

a[1]=3;

a[2]=3;

for (int i = 0; i < a.length; i++) {

System.out.print(score[i]+"\t");

}

System.out.println();

//给数组进行排序

for (int i = 1; i < score.length; i++) {

for (int j = 0; j < score.length; j++) {

if(score[i]<score[j])

{

int temp=score[i];

score[i]=score[j];

score[j]=temp;

}

}

}

for (int i = 0; i < score.length; i++) {

System.out.print(score[i]+"\t");

}

//二维数组

int aEr[][]=new int[4][3];

aEr[0][0]=30;

aEr[1][1]=28;

aEr[0][2]=45;

aEr[2][0]=28;

aEr[3][2]=8;

for (int i = 0; i < aEr.length; i++) {

for (int j = 0; j < aEr[i].length; j++) {

System.out.print(aEr[i][j]+"\t");

}

System.out.println("");

}

}

}

时间: 2024-11-10 21:16:11

引用类型——Java数组的相关文章

Java数组与内存控制

一.Java数组初始化 Java数组是静态的,即当数组被初始化之后,该数组的长度是不可变的.Java数组使用之前必须先对数组对象进行初始化,所谓初始化,就是为数组的所有元素分配内存空间,并为每个数组元素指定初始值.(文章来源于李刚老师的<突破java程序员的16课>) 1:基本类型数组的两种初始化方式 静态初始化:初始化时由程序员显式指定每个数组元素的初始值,由系统决定数组长度. 动态初始化:初始化时程序员只指定数组长度,由系统为数组元素分配初始值. 不要同时使用静态初始化和动态初始化,也就是

把Java数组转换为List时的注意事项

本文由 ImportNew - 飘扬叶 翻译自 mlangc.欢迎加入翻译小组.转载请见文末要求. 不幸的是并不是每件事都尽如人意.举个例子,现在将一个Java数组转换为List.当然,我们可以使用Arrays.asList方法,但是如果没有慎重思考就随便使用几乎肯定会产生令人讨厌的意外.考虑完下面这段程序并预测其输出你就明白我的意思了: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 package com.wordpress.mla

java数组学习

1. java数组的静态特性:          java是静态语言,java中数组的长度是固定的.还有,数组元素的类型也是在定义时指定了的. 2. java数组里的关键词:          数组变量 : 引用变量 , 不过这个引用的类型是数组类型.数组类型很奇特,不需要程序员来设计类的属性和方法,只要在已知的引用类型(类,接口,还有数组)后加一个[], JVM就自动生成了这样的新类型.         作为一个变量,它是存在于栈空间中的.不过由于其是一个引用变量,其所指向的内容(保存的值)是

七、java数组

目录 一.一维数组 声明方式 数组对象的创建 元素为引用数据类型的数组 数组初始化 数组元素默认初始化 数组元素的引用 二.二维数组 概念 初始化 二维数组举例 三.数组的拷贝 四.练习 数组可以堪称是多个相同类型数据组合,对这些数据的统一管理 数组变量属于引用类型,数组也可以看成是对象,数组中的每个元素相当于该对象的成员变量 数组中的元素可以是任何数据类型,包括基本类型和引用类型 一.一维数组 1.声明方式: type var [ ] ; 或 type [ ] var ; 例如: int a1

java 数组及数组得内存管理总结

一:一维数组的声明及初始化 数组变量属于引用类型,他的元素可以是引用类型,也可以是基本类型. int[] a=new int[3]; a[0]=1; a[1]=2; a[2]=3; int[] b={1,2,3}; int c[]={1,2,3}; // int d[5]; 错误表达方式 a的内存图: b与c引用的内存图与a一样.b与c引用只是a引用得简写. 1 public class Test1 { 2 3 public static void main(String[] args) { 4

Java 数组基础,java.util.Arrays

定义数组 方式1(推荐,更能表明数组类型) 方式2(同C语言) 方式3?定义时直接初始化 数组运用基础 数组长度 equals() 数组元素不为基本数据类型时 二维数组 二维数组基础 变长的二维数组 java.utils.Arrays 类 参考文献: ? 数组(Array):相同类型数据的集合. 定义数组 方式1(推荐,更能表明数组类型) type[] 变量名 = new type[数组中元素的个数]; 比如: int[] a = new int[10]; 数组名,也即引用a,指向数组元素的首地

Java数组备忘录

前言 最近用Java做ACM题目的时候,经常忘记数组如何实现静态初始化,所以这里记录一下Java数组使用的常识. Java数组常识 数组在Java中是一个对象,数组实例需要通过new操作符进行创建. 常识知识: 数组大小可以通过Array.length获取. 数组索引起始为0,负数索引在Java中是无效的.并且,和C语言数组不同,Java中的数组会进行越界判断,无效的索引会抛出ArrayIndexOutOfBoundException. 数组存储在Java堆的连续内存空间. 数组是一个固定长度的

最新java数组的详解

java中HashMap详解 http://alex09.iteye.com/blog/539545 总结: 1.就像引用类型的数组一样,当我们把 Java 对象放入数组之时,并不是真正的把 Java 对象放入数组中,只是把对象的引用放入数组中,每个数组元素都是一个引用变量. 2.HashMap 采用一种所谓的“Hash 算法”来决定每个元素的存储位置. 3.HashMap 底层采用一个 Entry[] 数组来保存所有的 key-value 对,当需要存储一个 Entry 对象时,会根据 Has

Java数组一定要初始化才能使用吗?

数组是大多数编程语言提供的一种复合结构,如果程序需要多个类型相同的变量时,就可以考虑定义一个数组.Java语言的数组变量是引用类型的变量,因此具有Java独有的特性. 在正常的Java开发中,使用Java数组之前,我们都会对数组进行初始化,为数组中的元素分配内存空间.赋值等,但Java数组一定要初始化吗?不初始化可以 么? 其实,java的数组变量是引用类型的变量,并不是数组对象本身,只要让数组变量指向有效的数组对象,程序中就可使用该数组变量,比如下面这个例子: public class T {