主要讨论一下,一维数组。关于多维数组,请举一反三!!!!!

1. 数组

Java中,数组是引用类型数据,可以看做是对象,数组中的每个元素相当于该对象的成员变量。

数组中的元素,可以是任何数据类型(基本数据类型或者引用类型)。

数组可以分为一维数组和多为数组。

2. 数组的初始化

数组的初始化分为两步,即声明数组和为数组分配空间(此时也可以为数组手动赋值),如下:

int[] a; // 声明int型数组 a = new int[5]; // 为数组a分配空间

如果,此时打印a的各元素的内容,可以看出a[0]~a[4]都是0,这就说明如果不为数组手动赋值的话,它默认有个初始值(即下面所讲的<3>默认初始化)。关于初始值的大小可以见下表:

Java基础:数组

对于数组的元素是引用类型,默认初始值是null,如例子:

String[] str = new String[5]; for(int i=0; i<str.length; i++) { System.out.print("str[" + i + "] = " + str[i] + "/t"); }

注意:

声明数组的同时不可以为数组指定长度,如下就会报错:

int[12] a;

<1> 静态初始化:在定义数字的同时就为数组元素分配空间并赋值

// 静态创建数组 int[] b = {1, 2}; int[] c = new int[]{1, 2, 3};

<2> 动态初始化:数组定义与为数组分配空间和赋值的操作分开进行

int[] a; // 声明int型数组 a = new int[5]; // 为数组a分配空间 for(int i=0; i<a.length; i++) { System.out.print("a[" + i + "] = " + a[i] + "/t"); } System.out.println(); String[] str = new String[5]; for(int i=0; i<str.length; i++) { System.out.print("str[" + i + "] = " + str[i] + "/t"); }

<3> 默认初始化:数组是引用类型,它的元素相当于类的成员变量,因此数组分配空间后,每个元素也被按照成员变量的规则被隐士初始化。

3. 匿名数组

形如new int[] {1, 2};形式称之为匿名数组,但是匿名数组一定要赋值给数组对象,不可以单独出现在代码中,否则报错。需要这样:

int[] a = new int[] {1, 2};

4. 数组与内存

声明数组的时候,不会为该数组分配地址空间,此时数组引用为null,除非你使用new或者静态创建数组的时候,才会为其分配空间。栈空间上是数组引用,堆中是引用的成员(元素)。

int[] a; a = new int[5];

Java基础:数组

Java基础:数组

使用默认方式将各元素初始化为0。再看看引用类型数组内存分配情况,此时内存分配:

// 声明String类型数组 String[] s;


Java基础:数组

// 创建数组 s = new String[3];

此时,内存分配情况:

Java基础:数组

因为s[0]~s[2]也均是引用类型,所以默认值为null。所以记住:引用类型的数组的每一个元素都需要实例化,否则会出现null值。对于本例是String,所以实例化String有两种赋值方式,即直接赋值和new String().这里采用后者。

// 实例化元素 s[0] = "linux"; s[1] = "ubuntu"; s[2] = "kubuntu";

要明白:s[0]~s[2]在堆内存中存放的是地址,分别指向各自的成员。内存分布:

Java基础:数组

举个实例:

class Person { int age; String name; /** * 构造方法 * * @param age * @param name */ public Person(int age, String name) { this.age = age; this.name = name; } } /** * 测试类 * * @author mark */ class TestPersonArrays { public static void main(String[] args) { Person[] p; p = new Person[3]; p[0] = new Person(20, "STom"); p[1] = new Person(30, "MTom"); p[2] = new Person(40, "LTom"); } }

分析下面代码内存,见下面的图:

Person[] p; p = new Person[3]; p[0] = new Person(20, "STom"); p[1] = new Person(30, "MTom"); p[2] = new Person(40, "Ltom");

Java基础:数组

Java基础:数组

Java基础:数组

5. 数组与增强for循环

增强for循环是JDK新增特性,用法很简单。举个例子吧!

int[] a = new int[]{1, 2, 3}; for(int i : a) { System.out.println("i= " + i); } String[] str = new String[]{"10", "20", "30"}; for(String s : str) { System.out.println("s= " + s); }

其实等效下面效果:

for(int i=0; i<a.length; i++) { System.out.println(a[i]); } for(int i=0; i<str.length; i++) { System.out.println(str[i]); }

注意:增强for循环中的临时变量如上面的i,s一定要与数组类型一致。

6. 数组的复制

数组的复制,就是对数组的一份拷贝,只是内容的拷贝,不会影响各自的引用(内存),不管该数组是引用还是基本数据类型的。使用System.arraycopy方法,完成复制。JDK中对该方法声明:

arraycopy public static void arraycopy(Objectsrc, intsrcPos, Objectdest, intdestPos, intlength) 从指定源数组中复制一个数组,复制从指定的位置开始,到目标数组的指定位置结束。从src引用的源数组到dest引用的目标数组,数组组件的一个子序列被复制下来。被复制的组件的编号等于length参数。源数组中位置在srcPos到srcPos+length-1之间的组件被分别复制到目标数组中的destPos到destPos+length-1位置。 如果参数src和dest引用相同的数组对象,则复制的执行过程就好像首先将srcPos到srcPos+length-1位置的组件复制到一个带有length组件的临时数组,然后再将此临时数组的内容复制到目标数组的destPos到destPos+length-1位置一样。 If 如果dest为null,则抛出NullPointerException异常。 如果src为null, 则抛出NullPointerException异常,并且不会修改目标数组。 否则,只要下列任何情况为真,则抛出ArrayStoreException异常并且不会修改目标数组: src参数指的是非数组对象。 dest参数指的是非数组对象。 src参数和dest参数指的是那些其组件类型为不同基本类型的数组。 src参数指的是具有基本组件类型的数组且dest参数指的是具有引用组件类型的数组。 src参数指的是具有引用组件类型的数组且dest参数指的是具有基本组件类型的数组。 否则,只要下列任何情况为真,则抛出IndexOutOfBoundsException异常,并且不会修改目标数组: srcPos参数为负。 destPos参数为负。 length参数为负。 srcPos+length大于src.length,即源数组的长度。 destPos+length大于dest.length,即目标数组的长度。 否则,如果源数组中srcPos到srcPos+length-1位置上的实际组件通过分配转换并不能转换成目标数组的组件类型,则抛出ArrayStoreException异常。在这种情况下,将k设置为比长度小的最小非负整数,这样就无法将src[srcPos+k]转换为目标数组的组件类型;当抛出异常时,从srcPos到srcPos+k-1位置上的源数组组件已经被复制到目标数组中的destPos到destPos+k-1位置,而目标数组中的其他位置不会被修改。(因为已经详细说明过的那些限制,只能将此段落有效地应用于两个数组都有引用类型的组件类型的情况。) 参数: src- 源数组。 srcPos- 源数组中的起始位置。 dest- 目标数组。 destPos- 目标数据中的起始位置。 length- 要复制的数组元素的数量。 抛出: IndexOutOfBoundsException- 如果复制会导致对数组范围以外的数据的访问。 ArrayStoreException- 如果因为类型不匹配而使得无法将src数组中的元素存储到dest数组中。 NullPointerException- 如果src或dest为null。

不论是基本数据类型之间,还是引用数据类型之间的数组,均可以使用该方法进行数组之间的复制。但是不同类型之间的数组不可以进行该操作,否则报ArrayStoreException异常。详看下面的例子代码:

int[] a = new int[]{1, 2}; int[] b = new int[2]; System.out.println("arrayCopy--before--"); System.out.println("a= " + a); System.out.println("b= " + b); System.arraycopy(a, 0, b, 0, a.length); for(int i=0; i<b.length; i++) { System.out.println("b[" + i + "]= " + b[i]); } System.out.println("arrayCopy--after--"); System.out.println("a= " + a); System.out.println("b= " + b);

结果:

arrayCopy--before-- a= [[email protected] b= [[email protected] b[0]= 1 b[1]= 2 arrayCopy--after-- a= [[email protected] b= [[email protected]

引用类型的数组:

String[] aa = new String[]{"1", "2"}; String[] bb = new String[2]; System.out.println("arrayCopy--before--"); System.out.println("aa= " + aa); System.out.println("bb= " + bb); System.arraycopy(aa, 0, bb, 0, aa.length); for(int i=0; i<bb.length; i++) { System.out.println("bb[" + i + "]= " + bb[i]); } System.out.println("arrayCopy--after--"); System.out.println("aa= " + aa); System.out.println("bb= " + bb);

结果:

arrayCopy--before-- aa= [Ljava.lang.String;@f62373 bb= [Ljava.lang.String;@19189e1 bb[0]= 1 bb[1]= 2 arrayCopy--after-- aa= [Ljava.lang.String;@f62373 bb= [Ljava.lang.String;@19189e1

自定义的数组:

class Person { int age; String name; /** * 构造方法 * * @param age * @param name */ public Person(int age, String name) { this.age = age; this.name = name; } @Override public String toString() { return age + "," + name; } } Person[] p1 = new Person[]{new Person(19, "Jhon"), new Person(30, "Tom")}; Person[] p2 = new Person[2]; System.out.println("arrayCopy--before--"); System.out.println("p1= " + p1); System.out.println("p2= " + p2); System.arraycopy(p1, 0, p2, 0, p1.length); for(int i=0; i<p2.length; i++) { System.out.println("p2[" + i + "]= " + p2[i]); } System.out.println("arrayCopy--after--"); System.out.println("p1= " + p1); System.out.println("p2= " + p2);

结果:

arrayCopy--before-- p1= [Lmark.zhang.Person;@f62373 p2= [Lmark.zhang.Person;@19189e1 p2[0]= 19,Jhon p2[1]= 30,Tom arrayCopy--after-- p1= [Lmark.zhang.Person;@f62373 p2= [Lmark.zhang.Person;@19189e1

这里,可以看出不管是基本数据类型还是引用类型数组,copy之后不会改变彼此的内存。也就是说,改变任何一方不会影响另一方。

7. 数组的赋值

上面说到数组的复制,这里谈谈数组的赋值。

先看基本数据类型的。

int[] a = new int[]{1, 2}; int[] b = null; System.out.println("assign--before--"); System.out.println("a= " + a); System.out.println("b= " + b); System.out.println("a[0] = " + a[0]); System.out.println("a[1] = " + a[1]); b = a; b[0] = 60; b[1] = 80; System.out.println("assign--after--"); System.out.println("a= " + a); System.out.println("b= " + b); System.out.println("a[0] = " + a[0]); System.out.println("a[1] = " + a[1]);

结果:

assign--before-- a= [[email protected] b= null assign--after-- a= [[email protected] b= [[email protected]

再看引用类型:

String[] aa = new String[]{"1", "2"}; String[] bb = null; System.out.println("arrayCopy--before--"); System.out.println("aa[0] = " + aa[0]); System.out.println("aa[1] = " + aa[1]); System.out.println("aa= " + aa); System.out.println("bb= " + bb); bb = aa; bb[0] = "100"; bb[1] = "200"; System.out.println("arrayCopy--after--"); System.out.println("aa[0] = " + aa[0]); System.out.println("aa[1] = " + aa[1]); System.out.println("aa= " + aa); System.out.println("bb= " + bb);

结果:

assign--before-- aa[0] = 1 aa[1] = 2 aa= [Ljava.lang.String;@f62373 bb= null assign--after-- aa[0] = 100 aa[1] = 200 aa= [Ljava.lang.String;@f62373 bb= [Ljava.lang.String;@f62373

class Person { int age; String name; /** * 构造方法 * * @param age * @param name */ public Person(int age, String name) { this.age = age; this.name = name; } @Override public String toString() { return age + "," + name; } } Person[] p1 = new Person[]{new Person(19, "Jhon"), new Person(30, "Tom")}; Person[] p2 = null; System.out.println("arrayCopy--before--"); System.out.println("p1[0] = " + p1[0]); System.out.println("p1[1] = " + p1[1]); System.out.println("p1= " + p1); System.out.println("p2= " + p2); p2 = p1; p2[0] = new Person(90, "Kery"); p2[1] = new Person(290, "Bery"); System.out.println("arrayCopy--after--"); System.out.println("p1[0] = " + p1[0]); System.out.println("p1[1] = " + p1[1]); System.out.println("p1= " + p1); System.out.println("p2= " + p2);

结果:

arrayCopy--before-- p1[0] = 19,Jhon p1[1] = 30,Tom p1= [Lmark.zhang.Person;@19189e1 p2= null arrayCopy--after-- p1[0] = 90,Kery p1[1] = 290,Bery p1= [Lmark.zhang.Person;@19189e1 p2= [Lmark.zhang.Person;@19189e1

以上例子,可以看出赋值之后,数组彼此指向同一个地址空间,换句话说,改变其中一个数组的内容会影响另一个。

8. 比较数组大小

主要使用Arrays类的equals方法,这里看看比较两个字节数组大小的源码:

public static boolean equals(long[] a, long[] a2) { if (a==a2) return true; if (a==null || a2==null) return false; int length = a.length; if (a2.length != length) return false; for (int i=0; i<length; i++) if (a[i] != a2[i]) return false; return true; }

另外,该方法还可以比较对象类型的数组的大小:

public static boolean equals(Object[] a, Object[] a2) { if (a==a2) return true; if (a==null || a2==null) return false; int length = a.length; if (a2.length != length) return false; for (int i=0; i<length; i++) { Object o1 = a[i]; Object o2 = a2[i]; if (!(o1==null ? o2==null : o1.equals(o2))) return false; } return true; }

好了,仔细分析一下该类的其它equals的方法吧!!

相关文章:

  • 2021-08-07
  • 2019-08-05
  • 2021-12-03
  • 2021-06-23
  • 2022-01-04
猜你喜欢
  • 2021-04-24
  • 2022-02-22
  • 2021-11-23
  • 2021-10-03
  • 2021-08-06
  • 2020-03-26
  • 2021-11-21
相关资源
相似解决方案