JavaSE——数组

First Post:

Last Update:

Word Count:
2.1k

Read Time:
8 min

数组

数组的优点和缺点,并且要理解为什么。
第一:空间存储上,内存地址是连续的。
第二:每个元素占用的空间大小相同。
第三:知道首元素的内存地址。
第四:通过下标可以计算出偏移量。通过一个数学表达式,就可以快速计算出某个下标位置上元素的内存地址,直接通过内存地址定位,效率非常高。

优点:检索效率高。
缺点:随机增删效率较低,数组无法存储大数据量。
注意:数组最后一个元素的增删效率不受影响。

一维数组

一维数组的静态初始化和动态初始化

静态初始化:

1
2
int[] arr = {1,2,3,4};
Object[] objs = {new Object(), new Object(), new Object()};

动态初始化:

1
2
int[] arr = new int[4]; // 4个长度,每个元素默认值0
Object[] objs = new Object[4]; // 4个长度,每个元素默认值null

一维数组的遍历

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

一维数组储存对象的调用 多态的调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
package com.bjpowernode.javase.array;

/**
* 一维数组的深入,数组中存储的类型为:引用数据类型
* 对于数组来说,实际上只能存储java对象的“内存地址”。数组中存储的每个元素是“引用”。
*/
public class ArrayTest07 {
public static void main(String[] args) {

// a是一个数组
// a[0] 是数组中的一个元素。
// a[1] 是数组中的一个元素。
int[] a = {100, 200, 300};
System.out.println(a[1]);
//a[2] = 400;

int[] array = {1,2,3};
for (int i = 0; i < array.length; i++) {
/*int temp = array[i];
System.out.println(temp);*/
System.out.println(array[i]);
}

// 创建一个Animal类型的数组
Animal a1 = new Animal();
Animal a2 = new Animal();
Animal[] animals = {a1, a2};

// 对Animal数组进行遍历
for (int i = 0; i < animals.length; i++) {
/*Animal a = animals[i];
a.move();*/
// 代码合并
animals[i].move(); // 这个move()方法不是数组的。是数组当中Animal对象的move()方法。
}

// 动态初始化一个长度为2的Animal类型数组。
Animal[] ans = new Animal[2];
// 创建一个Animal对象,放到数组的第一个盒子中。
ans[0] = new Animal();

// Animal数组中只能存放Animal类型,不能存放Product类型。
//ans[1] = new Product();

// Animal数组中可以存放Cat类型的数据,因为Cat是一个Animal。
// Cat是Animal的子类。
ans[1] = new Cat();

// 创建一个Animal类型的数组,数组当中存储Cat和Bird
Cat c = new Cat();
Bird b = new Bird();
Animal[] anis = {c, b};

//Animal[] anis = {new Cat(), new Bird()}; // 该数组中存储了两个对象的内存地址。
for (int i = 0; i < anis.length; i++){
// 这个取出来的可能是Cat,也可能是Bird,不过肯定是一个Animal
// 如果调用的方法是父类中存在的方法不需要向下转型。直接使用父类型引用调用即可。
//anis[i]
//Animal an = anis[i];
//an.move();

//Animal中没有sing()方法。
//anis[i].sing();

// 调用子对象特有方法的话,需要向下转型!!!
if(anis[i] instanceof Cat){
Cat cat = (Cat)anis[i];
cat.catchMouse();
}else if(anis[i] instanceof Bird){
Bird bird = (Bird)anis[i];
bird.sing();
}
}

}
}

class Animal{
public void move(){
System.out.println("Animal move...");
}
}

// 商品类
class Product{

}

// Cat是子类
class Cat extends Animal {
public void move(){
System.out.println("猫在走猫步!");
}
// 特有方法
public void catchMouse(){
System.out.println("猫抓老鼠!");
}
}

// Bird子类
class Bird extends Animal {
public void move(){
System.out.println("Bird Fly!!!");
}
// 特有的方法
public void sing(){
System.out.println("鸟儿在歌唱!!!");
}
}

二维数组

二维数组的静态初始化和动态初始化

静态初始化:

1
2
3
4
int[][] arr = {{1,2,34},{54,4,34,3},{2,34,4,5}};
Object[][] arr = {{new Object(),new Object()},
{new Object(),new Object()},
{new Object(),new Object(),new Object()}};

动态初始化:

1
2
3
4
5
6
int[][] arr = new int[3][4];
Object[][] arr = new Object[4][4];
Animal[][] arr = new Animal[3][4];
// Person类型数组,里面可以存储Person类型对象,以及Person类型的子类型都可以。
Person[][] arr = new Person[2][2];
....

二维数组的遍历

for(int i = 0; i < arr.length; i++){ // 外层for循环负责遍历外面的一维数组。
    // 里面这个for循环负责遍历二维数组里面的一维数组。
    for(int j = 0; j < arr[i].length; j++){
        System.out.print(arr[i][j]);
    }
    // 换行。
    System.out.println();
}

main方法上“String[] args”参数的使用

(非重点,了解一下,以后一般都是有界面的,用户可以在界面上输入用户名和密码等参数信息。)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/*
模拟一个系统,假设这个系统要使用,必须输入用户名和密码。
*/
public class ArrayTest06 {
// 用户名和密码输入到String[] args数组当中。
public static void main(String[] args) {
if(args.length != 2){
System.out.println("使用该系统时请输入程序参数,参数中包括用户名和密码信息,例如:zhangsan 123");
return;
}

// 程序执行到此处说明用户确实提供了用户名和密码。
// 接下来你应该判断用户名和密码是否正确。
// 取出用户名
String username = args[0];
// 取出密码
String password = args[1];

// 假设用户名是admin,密码是123的时候表示登录成功。其它一律失败。
// 判断两个字符串是否相等,需要使用equals方法。
//if(username.equals("admin") && password.equals("123")){
// 这样编写是不是可以避免空指针异常。
// 采用以下编码风格,及时username和password都是null,也不会出现空指针异常。(这是老程序员给的一条编程经验。)
if("admin".equals(username) && "123".equals(password)){
System.out.println("登录成功,欢迎[" + username + "]回来");
System.out.println("您可以继续使用该系统....");
}else{
System.out.println("验证失败,用户名不存在或者密码错误!");
}
}
}

数组的拷贝:System.arraycopy()方法的使用

数组有一个特点:长度一旦确定,不可变。 所以数组长度不够的时候,需要扩容,扩容的机制是:新建一个大数组,将小数组中的数据拷贝到大数组,然后小数组对象被垃圾回收。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
/**
* 关于一维数组的扩容。
* 在java开发中,数组长度一旦确定不可变,那么数组满了怎么办?
* 数组满了,需要扩容。
* java中对数组的扩容是:
* 先新建一个大容量的数组,然后将小容量数组中的数据一个一个拷贝到大数组当中。
*
* 结论:数组扩容效率较低。因为涉及到拷贝的问题。所以在以后的开发中请注意:尽可能少的进行数组的拷贝。
* 可以在创建数组对象的时候预估计以下多长合适,最好预估准确,这样可以减少数组的扩容次数。提高效率。
*/
public class ArrayTest08 {
public static void main(String[] args) {
// java中的数组是怎么进行拷贝的呢?
//System.arraycopy(5个参数);

// 拷贝源(从这个数组中拷贝)
int[] src = {1, 11, 22, 3, 4};

// 拷贝目标(拷贝到这个目标数组上)
int[] dest = new int[20]; // 动态初始化一个长度为20的数组,每一个元素默认值0

// 调用JDK System类中的arraycopy方法,来完成数组的拷贝
//System.arraycopy(src, 1, dest, 3, 2);

// 遍历目标数组
/*
for (int i = 0; i < dest.length; i++) {
System.out.println(dest[i]); // 0 0 0 11 22 ... 0
}
*/

System.arraycopy(src, 0, dest, 0, src.length);
for (int i = 0; i < dest.length; i++) {
System.out.println(dest[i]);
}

// 数组中如果存储的元素是引用,可以拷贝吗?当然可以。
String[] strs = {"hello", "world!", "study", "java", "oracle", "mysql", "jdbc"};
String[] newStrs = new String[20];
System.arraycopy(strs, 0, newStrs, 0, strs.length);
for (int i = 0; i < newStrs.length; i++) {
System.out.println(newStrs[i]);
}

System.out.println("================================");
Object[] objs = {new Object(), new Object(), new Object()};
Object[] newObjs = new Object[5];
// 思考一下:这里拷贝的时候是拷贝对象,还是拷贝对象的地址。(地址。)
System.arraycopy(objs, 0, newObjs, 0, objs.length);
for (int i = 0; i < newObjs.length; i++) {
System.out.println(newObjs[i]);
}
}
}