Java-数组(基础篇)
Java
中的数组是一个复合数据类型。
数组中的元素具有相同的类型,元素类型可以是基本数据类型,类的对象,也可以是数组类型,数组元素在内存中是按着顺序排列的,通过一个整型下标可以访问数组中的每一个值。例如,如果a
是一个整型数组,a[i]
就是数组中下标为i
个整数。
简单来说,数组就是同种类型数据的有序集合。
数组必须经过声明、构造、赋初值三个步骤以后才能有效使用。
数组的声明
声明一个一维数组
的格式有两种:
元素数据类型[] 数组名称;
元素数据类型 数组名称[];
注释:对于上面使用声明数组的两种形式,大多数程序员喜欢使用第一种风格,因为它将类型
int[]
(整型数组)与变量名
分开了。
即在声明数组变量时,需要指出数组类型(数组元素类型紧跟[]
)和数组变量的名字。下面声明了整型数组a
;
int[] a;
不过,这条语句只声明了变量a
,并没有将a
初始化为一个真正的数组(如图1)。应该使用new
运算符创建数组。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
声明一维数组的注意事项:
- 数组的类型可以是复杂结构类型,如类类型等
- 声明数组要使用中括号
[]
,不要错用小括号或大括号。 - 在
[]
里面声明都不能有,Java
在声明数组时不允许在方括号内指定数组元素的个数。
###数组的创建
数组的声明仅确定了数组的名字和元素类型,仅此而已。所以还不能使用它,必须进一步把数组创建处理,让它具备自己的内存空间。
Java
使用new
运算符来创建数组。
一维数组创建的格式如下:
数组名称 = new 元素数据类型[元素个数];
例如前面声明的整型数组a
,则应该这样创建:
a = new int[10];//创建包含10个元素的整型数组a
这条语句创建了一个可以存储
10
10
10个整数的数组,数组长度不要求必须是常量:new int[n]
会创建一个长度为n
的数组。
这个数组的下标从
0
~
9
0~9
0~9(不是
1
~
10
1~10
1~10)。一旦创建了数组,就可以给
数
组
元
素
赋
值
数组元素赋值
数组元素赋值。
注释:计算机将会按照创建数组时中括号内整数值来为它分配内存空间,这个整数值也就是数组元素的个数,又称为数组的长度。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
警告:如果创建了一个 10 10 10个元素的数组,并且试图访问元素== a [ 10 ] a[10] a[10]==(或任何在 0 ~ 9 0~9 0~9之外的下标),程序就会引发
“array index out of bounds”
异常而终止执行。要想获得数组中的元素个数,可以使用array.length
(array
此处放的是数组名)。例如:a.length
(下面详细介绍);
import java.util.Arrays;
public class DemoJava
{
public static void main(String[] args)
{
int[] a;
a = new int[10];
a[10] = 10;
}
}
程序运行结果:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 10 out of bounds for length 10
at DemoJava.main(DemoJava.java:8)
一旦创建了数组,就不能再改变它的大小/长度(尽管可以改变每一个数组元素的值)。如果经常需要在运行过程中扩展数组的大小。即应该使用另一种**数据结构——数组列表(
array list
)**有关数组列表的详细内容以后会扩展,并且在此处放上链接(插个眼)。
创建一维数组的注意事项:
- 一维数组在声明时,
[]
里必须为空,但在使用new
运算符进行创建的时候,[]
里必须指明数组的长度,只有这样系统才知道该给这个数组分配多少内存。 Java
允许在创建数组时使用整型变量来指定数组元素的个数,这为数组的使用带来了很大的灵活性。例如:
int size = 20;
double[] doubleArray = new double[size];
数组的初始化
用new
运算符创建一个数组时,系统就自动将这个数组初始化好了,也就是说,这个数组的各个元素都被赋了初始值。各类型默认初始化值如表所示:
数组元素的类型 | 初始值 | 数组元素的类型 | 初始值 |
---|---|---|---|
对象引用 | null | 布尔变量 | false |
整型变量 | 0 | 字符变量 | '\u0000' |
浮点变量 | 0.0 |
注释:创建一个数字数组时,所有元素都初始化为
0
,boolean
数组的元素会初始化为false
,对象数组的元素则初始化为一个特殊值null
,这表示这些元素(还)未存放任何对象。
在Java
中,提供了一种创建数组对象并同时赋予初始值的简化书写形式。下面是一个例子:
int[] smallprimes = {2,3,5,7,11,13};
请注意,在使用这种语句时,不需要调用new
。
甚至还可以初始化一个匿名的数组:
new int[]{17,19,23,29,31,37};
这种表示法将创建一个新数组并且利用括号中提供的值进行初始化,数组的大小就是初始值的个数。使用这种语法形式可以在不创建新变量的情况下重新初始化一个数组。例如:
smallPrimes = new int[]{17,19,23,29,31,37};
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
这是下列语句的简写形式(只是少了一个annoymous的变量):
int[] annoymous = {17,19,23,29,31,37};
smallPrimes = annoymous;
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
注释:在
Java
中,允许数组长度为0
。在编写一个返回结果为数组的方法时,如果碰巧结果为空,则这种语法形式就显得非常有用。此时可以创建一个长度为0
的数组。
new elementType[0];
注意,数组长度为0
与null
不同;
class Demo2
{
public static void main(String[] args)
{
int[] elementType = new int[0];
System.out.println(elementType.length);
}
}
程序运行结果:
0
数组初始化的注意事项:
- 在赋值符号
=
的右边没有new
运算符,也不说明数组的长度,系统会根据所赋初值的个数自动计算数组的长度。 - 数组的初始化赋值必须把所有初值与数组的声明写在同一个语句里,如果分开则会出错。以下的写法时错误的。
int[] array;
array = {10,20,30,40,50};
数组拷贝
在Java
中,允许将一个数组变量拷贝给另一个数组变量。这时,两个变量将引用同一个数组,即==两个数组名指向同一块内存空间==,而不是两块不同的空间。例如:
int[] luckyNumbers = smallPrimes;
luckyNumbers[5] = 12;//现在smallPrimes[5]也是12
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
图片显示了拷贝的结果。如果希望将一个数组的所有值拷贝到一个新的数组中去(即在内存中是两块不同的内存空间),就要使用Arrays
类的copyOf()
方法;
int[] copiedLuckyNumbers = Arrays.copyOf(luckyNumbers, luckyNumbers.length);
第2
个参数是新数组的长度,这个方法通常用于来增加数组的大小。
import java.util.Arrays;
class Demo2
{
public static void main(String[] args)
{
int[] smallPrimes = {17,19,23,29,31,37};
int[] luckyNumbers = smallPrimes;
luckyNumbers[5] = 12;
int[] copiedLuckyNumbers = Arrays.copyOf(luckyNumbers, luckyNumbers.length);
for (int i : copiedLuckyNumbers) {
System.out.println(i);
}
}
}
程序运行结果:
17
19
23
29
31
12
C++
注释:Java
数组与C++
数组在堆栈上有很大的不同,但基本上与分配在堆(heap
)上的数组指针一样。也就是说,
int[] a = new int[10];//Java
不同于
int a[10];//C++
而等同于
int* a = new int[10]; //C++
Java
中的[]
运算符被预定义为检查数组边界,而且没有指针运算,即不能通过a
加1
得到数组的下一个元素。
数组的length属性
Java
可以使用运算符".
"和length
属性可以得到数组的长度。
例如:
int[] arr = new int[20];
int len = arr.length; //len = 20;
经常使用数组的
length
属性得到数组元素的个数,配合循环语句对数组进行遍历或者其他操作。
数组排序
要想对数值型数组进行排序,可以使用Arrays
类中的sort
方法Arrays.sort(数组名)
:
Arrays.sort(arr)
这个方法使用了优化的快速排序算法。快速排序算法对于大多数数据集合来说都是效率比较高的。Arrays
类还提供了几个使用很便捷的方法,稍后的API
注释会介绍。
例如
import java.util.Arrays;
class Demo2
{
public static void main(String[] args)
{
int[] arr = new int[10];
for(int i= 0; i < arr.length; i++)
{
arr[i] = (int)(Math.random()*100); //为arr数组随机赋值
}
System.out.println(Arrays.toString(arr)); //打印arr数组
Arrays.sort(arr); //调用sort方法为arr数组排序s
System.out.println(Arrays.toString(arr));
}
}
程序运行结果:
[75, 88, 39, 91, 71, 87, 72, 19, 14, 13]
[13, 14, 19, 39, 71, 72, 75, 87, 88, 91]
该程序用到了数组,Math.random()
方法将返回一个
0
−
1
0-1
0−1之间(包含
0
0
0、不包含
1
1
1)的随机浮点数。用
n
n
n乘以这个浮点数,就可以得到从
0
~
n
−
1
0~n-1
0~n−1之间的一个随机数。
arr[i] = (int)(Math.random()*100); //arr[i]结果为0~99的随机整数值
static String toString(type[] a)
返回包含a
中数据元素的字符串,这些数据元素被放在括号内,并用逗号分隔。
static type copyOf(type[] a, int length)
static type copyOfRange(type[] a, int start, int end)
返回与a
类型相同的一个数组,长度为length
或者end-start
,数组元素为a
的值。
参数:a
类型为int、long、short、char、byte、boolean、float
或double
的数组。
start
起始下标(包含这个值)
end
终止下标(不包含这个值)。这个值可能大于a.length
,结果为0
或false
;
否则,数组中只有前面length
个数组元素的拷贝值。static void sort(type[] a)
采用优化的快速排序算法 对数组进行排序
参数:a
类型为int、long、short、char、byte、boolean、float
或者double
的数组。static int binarySearch(type[] a, type v)
static int binarySearch(type[] a, int start, int end, type v)
采用二分搜索算法查找值v
。如果查找成功,则返回相应的下标值;否则,返回一个负数值r
。-r-1
是为保持a
有序v
应插入的位置。
参数:a
类型为int、long、short、char、byte、boolean、float
或double
的数组。
start
起始下标(包含这个值)
end
终止下标(不包含这个值)。
v
同a
的数据元素的类型相同。static void fill(type[] a, type v)
将数组的所有数据元素设置为v
;
参数a
:类型为int、long、short、char、byte、boolean、float
或double
的数组。
v
与a
数据元素类型相同的一个值。static boolean equals(type[] a, type[] b)
如果两个数组大小相同,并且下标相同的元素都对应相等,返回true
参数a
、b
:类型为int、long、short、char、byte、boolean、float
或double
的数组。
import java.util.Arrays;
class Demo2
{
public static void main(String[] args)
{
int[] arr = new int[10];
int[] brr = new int[10];
for(int i= 0; i < arr.length; i++)
{
arr[i] = (int)(Math.random()*100);
}
System.out.println(Arrays.toString(arr));
Arrays.sort(arr);
System.out.println(Arrays.toString(arr));
brr = Arrays.copyOf(arr,arr.length);
System.out.println(Arrays.toString(brr));
Arrays.fill(brr, 10);
System.out.println(Arrays.toString(brr));
System.out.println(Arrays.equals(arr, brr));
Arrays.fill(arr,10);
System.out.println(Arrays.equals(arr, brr));
}
}
程序运行结果:
[66, 17, 24, 66, 81, 53, 11, 40, 32, 2]
[2, 11, 17, 24, 32, 40, 53, 66, 66, 81]
[2, 11, 17, 24, 32, 40, 53, 66, 66, 81]
[10, 10, 10, 10, 10, 10, 10, 10, 10, 10]
false
true
###多维数组
多维数组将使用多个下标访问数组元素,它适用于表示表格或更加复杂的形式。对于一个数值表,可以使用一个**二维数组(也称为矩阵)**存储这些信息。
在Java
中,声明一个二维数组相当简单。例如:
double[][] arr;
与一维数组一样,在调用new
对多维数组进行初始化之前不能使用它。在这里可以这样初始化:
arr = new double[ROW][COLUMN];
另外,如果知道数组元素,就可以不调用new
,而直接使用简化的书写形式对多维数组进行初始化。例如:
int[][] magicSquare =
{
{16,3,2,13},
{5,10,11,8},
{9,6,7,12},
{4,15,14,1}
};
一旦数组被初始化,就可以利用两个方括号访问每个数组,例如,magicSquare[i][j]
;
注释:
foreach
循环语句不能自动处理二维数组的每一个元素。它是按照行,也就是一维数组处理的。要想访问二维数组a
的所有元素,需要使用两个嵌套的循环,如下所示:
for (int[] row: a)
{
for (int value : row)
{
do something with value;
}
}
不规则数组
到目前为止,读者所看到的数组与其他程序设计语言提供的数组没有多大区别。但实际存在着一些细微的差异。而这正是Java
的优势所在:Java
实际上没有多维数组,只有一维数组。多维数组被解释为"数组的数组"。
例如,int arr[10][6]
;arr
数组实际上是一个包含
10
10
10个元素的数组,而每个元素又是一个由
6
6
6个整数组成的数组,如图所示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
表达式arr[i]
引用第i+1
个子数组,也就是二维表的第i+1
行。它本身也是一个数组arr[i+1][j+1]
引用这个数组的第j
项,
由于可以单独地存储数组的某一行,所以可以让两行交换。
int[] temp = arr[i];
arr[i] = arr[i+1];
arr[i+1] = temp;
还可以方便的构造一个"不规则"数组,即数组的每一行有不同的长度。
import java.util.Arrays;
class DemoJava
{
public static void main(String[] args)
{
final int MAX = 10;
int[][] odds = new int[MAX+1][];
for (int n = 0; n <= MAX; n++)
{
odds[n] = new int[n+1];
}
for(int n = 0; n < odds.length; n++)
{
for (int k = 0; k < odds[n].length; k++)
{
int lotteryOdds = 1;
for (int i = 1; i <= k; i++)
{
lotteryOdds = lotteryOdds * (n - i +1)/i;
}
odds[n][k] = lotteryOdds;
}
}
for (int[] row: odds)
{
for (int odd : row)
{
System.out.printf("%4d",odd);
}
System.out.println();
}
}
}
程序运行示例:
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
1 6 15 20 15 6 1
1 7 21 35 35 21 7 1
1 8 28 56 70 56 28 8 1
1 9 36 84 126 126 84 36 9 1
1 10 45 120 210 252 210 120 45 10 1
252 210 120 45 10 1