理解数组:数组也是一种类型
Java的数组要求所有的数组元素具有相同的数据类型。因此,在一个数组中,数组元素的类型是唯一的;
一旦数组的初始化完成,数组在内存中所占的空间将被固定下来,因此数组的长度将不可改变。即使把某个数组元素的数据清空,但它所占的空间依然被保留,依然属于该数组,数组的长度依然不变;
Java的数组既可以存储基本类型的数据,也可以存储引用类型的数据,只要所有的数组元素具有相同的类型即可。
定义数组
type[] arrayName //强烈推荐第一种
type arrayName[]
数组是一种引用类型的变量,因此使用它定义一个变量时,仅仅表示定义了一个引用变量,这个引用变量还未指向任何有效的内存,因此定义数组时不能指定数组的长度。而且由于定义数组只是定义了一个引用变量,并未指向任何有效的内存空间,所以还没有内存空间来存储数组元素,因此这个数组也不能使用,只有对数组进行初始化后才可以使用;
数组的初始化
Java语言中数组必须先初始化,然后才可以使用。所谓初始化,就是为数组的数组元素分配内存空间,并为每个数组元素赋初始值;
数组的初始化有如下两种方式:
- 静态初始化:初始化时由程序员显式指定每个数组元素的初始值,由系统决定数组长度;
- 动态初始化:初始化时程序员只指定数组长度,由系统为数组元素分配初始值;
1:静态初始化
arrayName = new type[]{element1,element2,element3,element4...}
//定义一个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" , "李刚"};
静态初始化还有如下简化格式:
type[] arrayName = {element1,element2,element3,element4...}
//数组的定义和初始化同时完成,使用简化的静态初始化写法
int[] a = {5, 6 , 7, 9};
2:动态初始化
动态初始化只指定数组的长度,由系统为每个数组元素指定初始值。语法格式如下:
arrayName = new type[length];
//数组的定义和初始化同时完成,使用动态初始化语法
int[] prices = new int[5];
//数组的定义和初始化同时完成,初始化数组时元素的类型是定义数组时元素类型的子类
Object[] books = new String[4];
执行动态初始化时,程序员只需指定数组的长度,即为每个数组元素指定所需的内存空间,系统将负责为这些数组元素分配初始值。指定初始值时,系统按如下规则分配初始值:
- 数组元素的类型是基本类型中的整数类型(byte、short、int和long),则数组元素的值是0;
- 数组元素的类型是基本类型中的浮点类型(float、double),则数组元素的值是0.0;
- 数组元素的类型是基本类型中的字符类型(char),则数组元素的值是’\u0000’;
- 数组元素的类型是基本类型中的布尔类型(boolen),则数组元素的值是false;
- 数组元素的类型是引用类型(类、接口和数组),则数组元素的值是null;
使用数组
//输出objArr数组的第二个元素,将输出字符串"李刚"
System.out.println(objArr[1]);
//为objArr2的第一个数组元素赋值
objArr2[0] = "Spring";
//所有的数组都提供了一个length属性,通过这个属性可以访问到数组的长度
//使用循环输出prices数组的每个数组元素的值
for (int i = 0; i < prices.length ; i ++ )
{
System.out.println(prices[i]);
}
foreach循环
使用foreach循环变量数组和集合元素时,无须获得数组和集合长度,无须根据索引来访问数组元素和集合元素,foreach循环自动遍历数组和集合的每个元素;
for(type variableName : array | collection)
{
//variableName 自动迭代访问每个元素...
}
public class TestForEach
{
public static void main(String[] args)
{
String[] books = {"轻量级J2EE企业应用实战" ,
"Struts2权威指南",
"基于J2EE的Ajax宝典"};
//使用foreach循环来遍历数组元素,其中book将会自动迭代每个数组元素
for (String book : books)
{
System.out.println(book);
}
}
}
当使用foreach来迭代访问数组元素时,foreach中的循环变量相当于一个临时变量,系统会把数组元素依次赋给这个临时变量,而这个临时变量并不是数组元素,它只是保存了数组元素的值:
public class TestForEachError
{
public static void main(String[] args)
{
String[] books = {"轻量级J2EE企业应用实战" ,
"Struts2权威指南",
"基于J2EE的Ajax宝典"};
//使用foreach循环来遍历数组元素,其中book将会自动迭代每个数组元素
for (String book : books)
{
book = "Ruby On Rails敏捷开发最佳实践";
System.out.println(book);
}
System.out.println(books[0]);
}
}
//输出
Ruby On Rails敏捷开发最佳实践
Ruby On Rails敏捷开发最佳实践
Ruby On Rails敏捷开发最佳实践
轻量级J2EE企业应用实战
内存中的数组
实际的数组对象被存储在堆内存中;而数组对象的引用被存储在栈内存中;
如果堆内存中的数组不再有任何引用变量指向自己,则这个数组将成为垃圾,该数组所占的内存将会被系统的垃圾回收机制回收。因此,为了让垃圾回收机制回收一个数组所占的内存空间,可以将该数组变量赋为null,也就切断了数组引用变量和实际数组之间的引用关系,实际的数组也就成了垃圾;
public class ArrayInRam
{
public static void main(String[] args)
{
//定义并初始化数组,使用静态初始化
int[] a = {5, 7 , 20};
//定义并初始化数组,使用动态初始化
int[] b = new int[4];
//输出b数组的长度4
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数组的长度变为3
System.out.println("b数组的长度为:" + b.length);
}
}
运行结果数组b的长度由4变为3,看起来数组长度似乎是可变的,但这只是一个假象;
牢记:定义并初始化一个数组后,在内存中分配了两个空间,一个用于存放数组的引用变量,另一个用于存放数组本身;
由图可知,a变量和b变量都引用了第一个数组。此时第二个数组失去了引用,变成垃圾,只有等待垃圾回收机制来回收它------但它的长度依然不会改变,直到它彻底消失;
基本类型数组的初始化
public class TestPrimitiveArray
{
public static void main(String[] args)
{
//定义一个int[]类型的数组变量。
int[] iArr;
//动态初始化数组,数组长度为5。
iArr = new int[5];
//采用循环方式为每个数组元素赋值。
for (int i = 0; i <iArr.length ; i++ )
{
iArr[i] = i + 10;
}
}
}
对应图解:
引用类型数组的初始化
public class Person
{
//年龄
public int age;
//身高
public double height;
//定义一个info方法
public void info()
{
System.out.println("我的年龄是:" + age + ",我的身高是:" + height);
}
}
public class TestReferenceArray
{
public static void main(String[] args)
{
//定义一个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变量
Person lee = new Person();
//为lee所引用的Person对象的属性赋值
lee.age = 16;
lee.height = 161;
//将zhang变量的值赋给第一个数组元素
students[0] = zhang;
//将lee变量的值赋给第二个数组元素
students[1] = lee;
//下面两行代码的结果完全一样,因为lee和students[1]指向的是同一个Person实例。
lee.info();
students[1].info();
}
}
对应图解:
多维数组
//同时初始化二维数组的2个维数
int[][] b = new int[3][4];
//使用静态初始化的语法来初始化一个二维数组
String[][] str1 = new String[][]{new String[3] , new String[]{"hello"}};
//使用简化的静态初始化语法来初始化二维数组
String[][] str2 = {new String[3] , new String[]{"hello"}};
书籍:疯狂Java讲义
学习所做的笔记,特此记录下来