数组是复合类型
数组是复合类型,内建的复合类型。它与字符串同属于"类--对象"范畴,有着与“基本类型”很不同的行为和特性。
首先的不同是,这些复合类型都有“方法”,可以通过“点“操作来调用。
比如:
String s = "abc";
int n = s..length(); //取得字符串的长度
基本类型如 int double char 等是不能进行点操作的。
另外,有些复合类型还有“属性”,其调用与方法类似,只是不加圆括号。
比如,求数组的长度就不是调用方法,而是属性。
int[] a = {1,2,3,4};
int n = a.length;
还有最最重要的一个不同,复合类型是有引用这个说法的。
当我们写:int a = 5; 的时候,a 变量里装的就是一个整数。
double b = 3.14; 则 b 中装的就是浮点数。b 占用的空间比 a 要大。
如果换成复合类型就不同了。
String a = "1234";
String b = "1234567";
这里的 a 和 b 都不是字符串本身,而是指向字符串对象的引用(类似于 c 语言中的指针),
引用的本质就是对象在内存中的地址。因而,不管对象有多大,引用的大小总是固定的,只占用很小的内存。
既然引用和对象是分离的实体,如果我们写:
String s;
这时,只建立了一个引用变量,还没有关联到某个对象。
如果我们需要明确地说:我的这个引用就是不指向任何对象,可以这样写:
String s = null;
关于类,对象,引用等面向对象的更多的理论,在以后的专题中讨论。
这里,只要先知道这种类型与基本类型有些不同,提高警惕也就是了。
创建数组的方法
可以直接通过给出数组的元素来创建数组对象,并初如化。
double[] a = {1.0, 1.5, 2.0, 2.5, 4.0, 4.3};
上面的代码先创建了一个引用 a,它的类型是:double[],即指向浮点数组的引用。
然后,创建了一个数组对象,该数组对象包含 6 个元素(即数组的长度为 6),元素的类型是 double
然后,用花括号中的数据为每一个元素进行初始化。
最后,把新创建的数组对象的地址写入到 a 中,即让 a 引用指向这个刚刚创建的数组对象。
也可以:
double[] a = new double[6]; a[0] = 1.0; a[1] = 1.5; a[2] = 2.0; ...
这段代码则是先创建了 包含 6 个元素的数组,但并不去分别对每个元素赋值。
接下来的代码再一个元素一个元素地赋值。
需要注意的是,不同于 c 语言,这里如果没有其下的赋值代码,元素中也是有固定值的,并不是一个随机数字。
java 中约定,变量总是会默认初始化,根据类型不同有不同的初始化值。
int double char 都是 0
boolean 是 false, 引用类型则是 null
数组的基本操作
数组的基本操作是:求它的长度,读取每个元素的值,为某个元素赋值。
下面的代码求一个数组中所有元素的最大值。
1 public class A0410 2 { 3 public static void main(String[] args){ 4 double[] a = {2.3, 4.5, 12.6, 0.4, 7.8, 9.2, 1.7}; 5 double m = a[0]; 6 for(int i=1; i<a.length; i++){ 7 if(a[i] > m) m = a[i]; 8 } 9 System.out.println(m); 10 } 11 }
这是求多个数中最大值的基本手段,应该尽早熟悉,其思想类似于擂台赛。
请注意,java 与 c 语言一样,数组的下标都是从 0 开始的。所以最大的下标是: a.length-1
下面看这样一个问题:
假设你面前有 50 个空盒子,其编号是 1 ~ 50
现还,你在第 1 个盒子里放 1 颗豆子,在第 2 个盒子里放 2 颗豆子, 在第 3 个盒子里放 4 颗豆子 ....
总之,后面的盒子中的豆子数是前一个盒子的 2 倍。
那么,要完成这个任务,你一共需要多少颗豆子?
1 public class A0410 2 { 3 public static void main(String[] args){ 4 long[] a = new long[50]; 5 // 放豆子 6 a[0] = 1; 7 for(int i=1; i<a.length; i++){ 8 a[i] = a[i-1] * 2; 9 } 10 // 统计总数 11 long sum = 0; 12 for(int i=0; i<a.length; i++){ 13 sum += a[i]; 14 } 15 16 System.out.println(sum); 17 } 18 }
这里需要注意,豆子的数目会很快地增长,用 int 类型存储是不够的。你可能会想,如果盒子更多怎么办?
不用急,java提供了 BigInteger 类型,可以表示任意大的整数。
为了逻辑上的清晰,我们把放豆子和求和这两个步骤分开了,实际上,可以边放豆子,边统计总数。
甚至是,根本不用数组,直接累加就可以!!
数组作为参数传递
数组可以像其它类型一样,在调用方法时,作为参数传递。
但需要高度警惕,数组是对象,而程序中写出的貌似数组的变量,实际上只是指向数组的指针而已。
我们在方法间传递的是引用,不是数组对象本身,这十分重要!!
因为这意味着:被调方与主调方共享同一个数组对象,一方修改,另一方可见!!
如果在逻辑上不希望共享数组,可以在方法中,把传进来的数组复制一下。
下面的程序演示了对一个数组中的所有工资进行加薪处理。
1 public class A0410 2 { 3 // salary: 工资数组 4 // per: 加薪的百分点 5 static void raise(double[] salary, double per){ 6 for(int i=0; i<salary.length; i++){ 7 salary[i] *= 1 + per / 100; 8 } 9 } 10 11 static void show(double[] salary){ 12 for(int i=0; i<salary.length; i++){ 13 System.out.print(salary[i] + " "); 14 } 15 System.out.println(); 16 } 17 18 public static void main(String[] args){ 19 double[] salary = {4520,5311,3766,8600,4700,7125}; 20 raise(salary,10); // 加薪 21 show(salary); // 显示新的薪资 22 } 23 }
显示一个数组中的全部元素是很常见的任务,我们也可以调用 java.util.Arrays.toString 方法来完成。