Posted on 八月 26, 2016
深入分析Java数组
数组的基本介绍:
数组对于每一门编辑应语言来说都是重要的数据结构之一;
数组基本用法:
声明数组变量
首先必须声明数组变量,才能在程序中使用数组。
下面是声明数组变量的语法:
type[] values; // 首选的方法 或type values[]; // 效果相同,但不是首选方法
创建数组
Java语言使用new操作符来创建数组,语法如下:
values = new type [size];
上面的语法语句做了两件事:
一、使用type [size]创建了一个数组。
二、把新创建的数组的引用赋值给变量values。
数组变量的声明,和创建数组可以用一条语句完成,如下所示:
type[] values = new type[10];
另外,你还可以使用如下的方式创建数组。
type[] values = {value0, value1, ..., value10};
数组的元素是通过索引访问的。数组索引从0开始,所以索引值从0到values.length-1。
实例:
下面的语句首先声明了一个数组变量myList,接着创建了一个包含10个double类型元素的数组,并且把它的引用赋值给myList变量。
double[] myList = new double[10];
下面的图片描绘了数组myList,这里myList数组里有10个double元素,它的下标从0到9。
处理数组
数组的元素类型和数组的大小都是确定的,所以当处理数组元素时候,我们通常使用基本循环或者foreach循环。
常见的数据错误:
使用数组常见错误一:编译出错,没有声明数组初始化大小;
int []array=new int[];
使用数组常见错误二。数组越界。
int []array=new int[1];
array[2]=1;
使用数组常见错误三。语法错误。
二、数组的深入分析:
数组的内存分配:
java中的数组是用来存储同一种数据类型的数据结构,一旦初始化完成,即所占的空间就已固定下来,初始化的过程就是分配对应内存空间的过程。即使某个元素被清空,但其所在空间仍然保留,因此数组长度将不能被改变。 要向改变数组的空间必须扩容数组操作如下:
//从指定源数组中复制一个数组,复制从指定的位置开始,到目标数组的指定位置结束。
Arrays.copyOf(T[] original, int newLength);
或者是System.arraycopy(elementData, index, elementData, index + 1, size - index);
当仅定义一个数组变量(int[] numbers)时,该变量还未指向任何有效的内存,因此不能指定数组的长度,只有对数组进行初始化(为数组元素分配内存空间)后才可以使用。
数组初始化分为静态初始化(在定义时就指定数组元素的值,此时不能指定数组长度)和动态初始化(只指定数组长度,由系统分配初始值)。
//静态初始化
int[] numbers = new int[] { 3, 5, 12, 8, 7 };
String[] names = { "Miracle", "Miracle He" };//使用静态初始化的简化形式
//动态初始化
int[] numbers = new int[5];
String[] names = new String[2];
当初始化完毕后,就可以按索引位置(0~array.length-1)来访问数组元素了。
当使用动态初始化时,如在对应的索引位未指定值的话,系统将指定相应数据类型对应的默认值(整数为0,浮点数为0.0,字符为’\u0000’,布尔类型为false,引用类型(包括String)为null)。
public class TestArray {
public static void main(String[] args) {
String[] names = new String[3];
names[0] = "Miracle";
names[1] = "Miracle He";
/*
for(int i = 0; i
System.out.print(names[i] + " ");
}
*/
//还可以使用foreach来遍历
for(String name : names) {
System.out.print(name + " ");
}
}
}
结果如下:
Miracle Miracle He null
Miracle Miracle He null
数组在内存中如何储存
如图:
数组引用变量是存放在栈内存(stack)中,数组元素本质是一个对象,是存放在堆内存(heap)中。通过栈内存中的指针指向对应元素的在堆内存中的位置来实现访问。
基本数据类型的数组在内存分配情况:
public class TestPrimitiveArray {
public static void main(String[] args) {
//1.定义数组
int[] numbers;
//2.分配内存空间
numbers = new int[4];
//3.为数组元素指定值
for(int i = 1;i <= numbers.length;i++) {
numbers[i] = i ;
}
}
}
内存分布如图:
从图中可看出数组元素直接存放在堆内存中,当操作数组元素时,实际上是操作基本类型的变量。
2、存放引用类型数组在内存中如何储存
先来再看一段存储引用类型数组的实例:
class Person {
public int age;
public String name;
public void display() {
System.out.println(name + "的年龄是: " + age);
}
}
public class TestReferenceArray {
public static void main(String[] args) {
//1.定义数组
Person[] persons;
//2.分配内存空间
persons = new Person[2];
//3.为数组元素指定值
Person p1 = new Person();
p1.age = 28;
p1.name = "Miracle";
Person p2 = new Person();
p2.age = 30;
p2.name = "Miracle He";
persons[0] = p1;
persons[1] = p2;
//输出元素的值
for(Person p : persons) {
p.display();
}
}
}
元素为引用类型的数组,在内存中的存储与基本类型完全不一样。
此时数组元素存放引用,指向另一块内存,在其中存放有效的数据。如图:
在数组参数传递的时候,数组是作为引用参数,传递的是数组的引用指针,将数组引用传递给另一数组引用,但仍然不能改变数组长度(仅仅只是调整数组引用指针的指向)。
二维数组及用法
用法: 定义方式和一维数组类似,如下:
type arrayName[ ][ ];
type [ ][ ]arrayName;
1、初始化:
静态初始化:
int intArray[ ][ ]={{1,2},{2,3},{3,4,5}};
2、动态初始化:
int a[ ][ ] = new int[2][3];
a[0] = new int[3];
a[1] = new int[3];
a[0][1] = new int[4];
a[0][2] = new int[4];
a[0][3] = new int[4];
对二维引用类型的数组,必须首先为最高维分配引用空间,然后再顺次为低维分配空间。而且,必须为每个数组元素单独分配空间。
获取二维数组:
int a[][] = { { 1, 5, 2, 8 }, { 5, 9, 10, -3 }, { 2, 7, -5, -18 } };// 静态初始化一个二维数组
例子:
int a[][] = { { 1, 5, 2, 8 }, { 5, 9, 10, -3 }, { 2, 7, -5, -18 } };
for (int i = 0; i
for (int j = 0; j <4; j++) {
System.out.println(a[i] + "_" + a[i][j]);
}
}
输出结果:
[I@901a4f3_1
[I@901a4f3_5
[I@901a4f3_2
[I@901a4f3_8
[I@48b02c5_5
[I@48b02c5_9
[I@48b02c5_10
[I@48b02c5_-3
[I@42049d11_2
[I@42049d11_7
[I@42049d11_-5
[I@42049d11_-18
多维数组内存分配:
以二维数组为例:
public static void main(String[] args) {
// 1.定义二维数组
int[][] numbers;
// 2.分配内存空间
numbers = new int[2][];
// 可以把numbers看作一维数组来处理
for (int i = 0; i
System.out.print(numbers[i] + ",");// null,null,null
}
System.out.println("");
// 3.为数组元素指定值
numbers[0] = new int[2];
numbers[0][1] = 1;
numbers[1] = new int[2];
numbers[1][0] = 11;
numbers[1][1] = 15;
for (int i = 0; i
for (int j = 0; j
System.out.print(numbers[i][j] + ",");
}
System.out.println("");
}
}
结果如下:
null,null,
0,1,
11,15,
以一个图展示这个数组在内存中的存储:
Array类的用法:
java.util.Arrays类能方便地操作数组,它提供的所有方法都是静态的。静态方法是属于类的,不是属于类的对象。所以可以直接使用类名加方法名进行调用。Arrays作为一个工具类,能很好的操作数组。下面介绍主要使用的几个函数。
1.fill方法:
fill方法主要用来填充数组,这里我们举最简单的int类型吧(其它类型的一样)
看Arrays的fill源码:
示例代码:
public static void main(String[] args) {
int a[] = new int[5];
// fill填充数组
Arrays.fill(a, 1);
for (int i = 0; i
// 输出5个1
System.out.println(a[i]);
}
结果:1 1 1 1 1 1;
填充部分数组源码:
示例:
public static void main(String[] args) {
int a[] = new int[5];
// fill填充数组
Arrays.fill(a, 1, 2, 1);
for (int i = 0; i
// a[1]=1,其余默认为0
System.out.println(a[i]);
}
结果:0 1 0 0 0;
2.sort方法:
从方法名看都知道是给数组排序,依然用int类型来说,其它类型一样的。
3. equals方法:
用于比较两个数组中的元素值是否相等,还是看int类型的数组。看Arrays源码
4.binarySearch方法
通过binarySearch方法能对排序好的数组进行二分查找法操作。看源码如下
5.copyof方法
复制数组,Arrays的copyOf()方法传回的数组是新的数组对象,所以您改变传回数组中的元素值,也不会影响原来的数组
6……. 方法;
注:在浏览的过程中如果遇到代码样式问题,建议使用Chrome浏览器查看。