导读
本文适合 Java 入门,不太适合Java中高级软件工程师。本文以《Java程序设计基础篇》第10版为蓝本,采用不断提出问题,然后解答问题的方式来讲述。本篇文章只是这个系列中的一篇,如果你喜欢这种讲解方式,或者觉得从中能学到知识,可以关注我,以便查阅本系列其他文章。
让我们开始愉快地学习Java语言吧!
1基本概念
声明数组变量
elementType[] arrayRef var ;
elementType:数组元素类型
arrayRefVar:数组引用变量
还可以使用elementType arrayRefVar[] 这种形式声明数组变量。这种做法不推荐。
创建数组
new elementType[arrayS1ze];
arraySize:整数,表示数组的大小。
一般创建和赋值合为一条语句:
arrayRefVar = new elementType[arraySize];
数组一旦创建,大小就固定不变,也就是容纳元素的个数不能变化。
数组元素的类型必须相同。
上面提到了数组和数组变量,他们有什么区别吗?
数组变量是数组的引用。我们的数据存放在数组里,而数组引用指向存放数组的地方。
数组被创建后,元素有默认值,数值型的默认值是0,字符型的是’u0000’,布尔型的是false。
如何访问数组元素呢?
使用下标变量访问数组,语法为arrayRefVar[index],其中index就是下标变量。
注意数组下标是从0开始的,那么最后一个数组下标为arraySize-1
变量有初始化,那么数组变量如何初始化呢?
elementType[] arrayRefVar = {value0, valuel,...,valuek};
初始化语法等效于,对创建数组后,对每个元素分别赋值。
elementType[] arrayRefVar = new e1ementType[arraySize]; arrayRefVar[0]=value0; arrayRefVar[1]=value1; ... arrayRefVar[k]=valuek;
这种方法看起来像是给素组赋值。
还可使用for、while循环遍历数组。
上面提到了for、while循环,那么还有没有其他形式的循环呢?
还有一种被称为 foreach 的循环,写法很for循环很像。
语法形式为:
for (elementType element: arrayRefVar) { //处理每一个元素 }
element代表每个数组元素,elementType和arrayRefVar的和上面的一样。
使用foreach循环可以按照数组小标从小到大的顺序遍历数组。
看下面的例子:
本意是在foreach中对每个元素重新赋值,但不起作用,这是为什么呢?
其实foreach的实现和下面这段for循环等价
for (type var : arr) { ...... } for (int i = 0; i < arr.length; i++) { type var = arr[i]; ...... }
var也仅相当于局部变量,并且是数组元素的引用,改变一个引用是不会真的改变引用所指向的元素值的!
2数组复制
复制数组有三种方法:
1)使用循环语句逐个地复制数组的元素。
2)使用System类中的静态方法arraycopy。
3)使用clone方法复制数组
要这么麻烦吗?把一个基本数据类型赋值给另一个就能达到复制的效果,这招对数组不起作用吗?
是的,把一个数组变量赋给令一个数组变量其实是把一个数组的引用复制给另一个数组变量,这样,这两个变量都指向同一个地址。我们想要的效果是“复制”,就是在内存区域开辟一块新的空间用来存储复制的数据。
让我们来看看arraycopy方法
void java.lang.System.arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
src:源数组
srcPos:源数组起始位置
dest:目标数组
destPos:目标数组起始位置
length:要拷贝的元素个数
来看一个例子:
为什么最后两个是0.0呢?
因为我们设置了拷贝的个数为fs.length-2,fs有五个元素,那么fs.length-2=3,所以是前三个元素被拷贝到了dest中。后两个0.0打印的是数组的默认值。
3将数组传递给方法
传递基本数据类型给方法,是按值传递,也就是将值传递给方法。那么数组呢?
数组是引用类型(后面谈到类时会讲这个概念),所以传递的是数组的引用。就是数组在内存中的地址传递给了方法。
那么按值传递和按引用传递有啥不同呢?
基本数据类型存放在栈中,对象存储在堆中。其实这么说不严密,因为对象的成员变量有可能是基本数据类型。如果基本数据类型的变量在方法体内的局部变量,那么它一定在栈中(这里涉及面向对象的几个概念,以后会学到)。
按值传递,若在方法中对这个变量重新赋值,那么方法外的变量值不会变。若按引用传递,由于方法外的变量和方法内的变量指向同一块内存,这样无论改变哪一个,内存中的值都会改变。
看下面的例子:
把fs第一个元素值改为10,由此可见真的可以。
可以向方法传递数组(数组的引用),那么也可以返回数组(数组的引用)。
有了数组,方法的参数列表又有了新的变化,是什么呢?
原来,我们定义方法时,一旦完成定义,参数列表是不能改变的,数据类型、参数个数,还有参数顺序都不能改变。有了数组就可以定义参数个数可变的方法了。
语法:
typeName ...parameterName
typeName:是类型名
parameterName :是参数名
注意,typeName和parameterName 之间的“…”不能省略。
Java将可变长参数当做数组对待。
看下面这个例子。
给function传递数组fs是可以的。
再看下面这个很有意思的例子。
所有传递给function的参数它都接收到了,但貌似function中对数组fs的更改不起作用,为什么呢?因为fs根本就没传递给function,虽然function的参数名和数组变量名一样!
4java.util.Arrays
java.util.Arrays提供了许多操作数组的方法。譬如,sort方法对数组排序;fill为每个元素赋值;binarySearch二分查找,适用于在已排序的数组中查找,方法返回元素的下标。
5二维数组
声明二维数组变量:
数据类型[][]数组名;
或
数据类型数组名[][];
例,float[][] fss;
创建二维数组:
例,float[][] fss=new float[3][3];
创建二维数组必须指定第一个下标,要不然两个下标都指定。
例,float[][] fss=new float[3][];也是合法的。
怎么理解二维数组呢?
二维数组的每一个元素都是一个一维数组。可以把它想象成一个表格,例如上面创建的二维数组
初始化二维数组:
例,初始化上面的fs。
fs = {{1,2,3},{4,5,6},{7,8,9}};
获得二维数组的长度:
调用length方法获得二维数组长度。
二维数组的每一个元素是一维数组,那么它们的长度一定相等吗?
可以不相等,看下面的例子。
遍历二维数组一般使用嵌套循环,例:
可以像传递一维数组一样将二维数组传递给方法。
6三维数组
声明一个三维数组变量:
数据类型[][][] 数组名;
可以认为三维数组的每一个元素都是二维数组。
看下面的例子:
float[][][] fsss = {{{1,2},{3,4}},{{1,2},{3,4}},{{1,2},{3,4}}};
大家发现了吗,三维数组的特性和二维数组是很像的,就连初始化语句都一样。
看下面的例子:例子中使用三层嵌套循环遍历数组。
7多维数组
多维数组的每一个元素都是一个数组,让我们类推一下,二维数组的元素是一维数组,三维数组的元素是二维数组,四位数组的元素是三维数组,…,依次类推。
每天30分钟,坚持一个月就能为Java开发打下坚实的基础!努力学习吧!