一.数组分类
1、基本数据类型的数组:默认值0;
2、引用数据类型的数组:默认值null;
二.数组的定义
1.方法一
格式:
数组存储的数据类型[] 数组名字 = new 数组存储的数据类型[⻓度];
数组定义格式详解
(1).数组存储的数据类型:创建的数组容器可以存储什么数据类型。
(2).[]:表示数组。
(3).数组名字:为定义的数组起个变量名,满⾜标识符规范,可以使⽤名字操作数组。
(4).new:关键字,创建数组使⽤的关键字。
(5).数组存储的数据类型:创建的数组容器可以存储什么数据类型。
(6).[⻓度]:数组的⻓度,表示数组容器中可以存储多少个元素。
注意:数组有定⻓特性,⻓度⼀旦指定,不可更改
举例:
定义可以存储3个整数的容器,代码如下:
int[] arr=new int[3];
2.方法二
格式:
数据类型[] 数组名 = new 数据类型[]{元素1, 元素2, 元素3…};
举例:
定义存储1,2,3,4,5整数的数组容器。
int[] arr = new int[] {1, 2, 3, 4, 5};
3.方法三
格式:
数据类型[] 数组名 = {元素1, 元素2, 元素3…};
定义存储1,2,3,4,5整数的数组容器
int[] arr = {1, 2, 3, 4, 5};
三、数组的遍历
数组遍历:就是将数组中的每个元素分别获取出来,就是遍历。遍历也是数组操作中的基⽯。
public static void main(String[] args) {
int[] arr = {1, 2, 3};
arr = null;
System.out.println(arr[0]);
}
以上代码是可以将数组中每个元素全部遍历出来,但是如果数组元素⾮常多,这种写法肯定
不⾏,因此我们需要改造成循环的写法。数组的索引是 0 到 lenght - 1 ,可以作为循环的
条件出现。
如:数组获取最⼤值元素
最⼤值获取:从数组的所有元素中找出最⼤值。
实现思路:
1.定义变量,保存数组0索引上的元素
2.遍历数组,获取出数组中的每个元素
3.将遍历到的元素和保存数组0索引上值的变量进⾏⽐较
4.如果数组元素的值⼤于了变量的值,变量记录住新的值
6.数组循环遍历结束,变量保存的就是数组中的最⼤值
public static void main(String[] args) {
int[] arr = {1, 2, 3, 4, 5};
System.out.println(arr[0]);
System.out.println(arr[1]);
System.out.println(arr[2]);
System.out.println(arr[3]);
System.out.println(arr[4]);
}
public static void main(String[] args) {
int[] arr = {1, 2, 3, 4, 5};
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
四、内存
⼀个数组内存图
public static void main(String[] args) {
int[] arr = new int[3];
System.out.println(arr);// [I@5f150435
}
以上⽅法执⾏,输出的结果是[I@5f150435,这个是什么呢?是数组在内存中的地址。new出来
的内容,都是在堆内存中存储的,⽽⽅法中的变量arr保存的是数组的地址。
输出arr[0],就会输出arr保存的内存地址中数组中0索引上的元素。
两个数组内存图
public static void main(String[] args) {
int[] arr = new int[3];
int[] arr2 = new int[2];
System.out.println(arr);
System.out.println(arr2);
}
两个变量指向⼀个数组
public static void main(String[] args) {
// 定义数组,存储3个元素
int[] arr = new int[3];
// 数组索引进⾏赋值
arr[0] = 5;
arr[1] = 6;
arr[2] = 7;
// 输出3个索引上的元素值
System.out.println(arr[0]);
System.out.println(arr[1]);
System.out.println(arr[2]);
// 定义数组变量arr2,将arr的地址赋值给arr2
int[] arr2 = arr;
arr2[1] = 9;
System.out.println(arr[1]);
}
五、数组作为⽅法传参和返回值:
1.数组作为方法参数
数组作为方法参数传递时,传递的参数是数组内存的地址
public static void main(String[] args) {
int[] arr = {1, 3, 5, 7, 9};
// 调⽤⽅法,传递数组
printArray(arr);
}
/*
* 创建⽅法,⽅法接收数组类型的参数
* 进⾏数组的遍历
*/
public static void printArray(int[] arr) {
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
2. 数组作为⽅法返回值
数组作为方法的返回值,返回的数组的内存地址
public static void main(String[] args) {
// 调⽤⽅法,接收数组的返回值
// 接收到的是数组的内存地址
int[] arr = getArray();
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
} }
/*
* 创建⽅法,返回值是数组类型
* return返回数组的地址
*/
public static int[] getArray() {
int[] arr = {1, 3, 5, 7, 9};
// 返回数组的地址,返回到调⽤者
return arr; }
六.⽅法的参数类型区别
(1)基本数据类型作为参数
public static void main(String[] args) {
int a = 10;
int b = 20;
int result = getSum(a, b);
}
public static int getSum(int a, int b) {
int sum = a+ b;
return sum; // 方法结束了, 所在的方法栈也就释放了
}
对应内存图
(2).引用类型作为参数
public static void main(String[] args) {
int[] arr = new int[]{1,2,3,4,5};
printArray1(arr);
// printArray2(arr);
System.out.println(arr[0]); // 7
}
public static void printArray1(int[] arr) {
arr[0] = 7;
}
public static void printArray2(int[] arr) {
arr = new int[]{7,8,9};
System.out.println(arr[0]); // 7
}`.
对应内存图
(3) 分析下列程序代码,计算输出结果。
public static void main(String[] args) {
int a = 1;
System.out.println(a);
change(a);
System.out.println(a);
}
public static void change(int a) {
a=10;
}
/* 1
1
*/
change ( )方法在被调用的时候,在内存中也分配一个空间来存储,存的是传过来的值,即10 .而当方法结束时,这块内存就等垃圾回收了,而在main 方法中,它打印的a 的值是在调用main方法时分配的内存空间,他们俩之间没有任何关系,所以打印的还是1.
分析下列程序代码,计算输出结果。
public static void main(String[] args) {
int[] arr = {1, 3, 5};
System.out.println(arr[0]);
change(arr);
System.out.println(arr[0]);
}
public static void change(int[] arr) {
arr[0] = 200; }
/*1
200*/
总结: ⽅法的参数为基本类型时,传递的是数据值。⽅法的参数为引⽤类型时,传递的是
地址值
七、数组使用中的问题
1.数组越界 ArrayIndexOutOfBoundsException
public static void main(String[] args) {
int[] arr = {1, 2, 3};
System.out.println(arr[3]);
}
创建数组,赋值3个元素,数组的索引就是0,1,2,没有3索引,因此我们不能访问数组中不存
在的索引,程序运⾏后,将会抛出 ArrayIndexOutOfBoundsException 数组越界异常。在开发
中,数组的越界异常是不能出现的,⼀旦出现了,就必须要修改我们编写的代码。
2.空指针异常 NullPointerException
出现原因: 调用了空值(null) 的属性或方法
public static void main(String[] args) {
int[] arr = {1, 2, 3};
arr = null;
System.out.println(arr[0]);
}
arr = null 这⾏代码,意味着变量arr将不会在保存数组的内存地址,也就不允许再操作数组
了,因此运⾏的时候会抛出 NullPointerException 空指针异常。在开发中,数组的越界异常是
不能出现的,⼀旦出现了,就必须要修改我们编写的代码。
八、数组相关的方法
1.数组的打印 Arrays.toString(array),返回String结果
2.数组的扩容或者缩容(复制)
(1) Arrays.copyOf(T[] original, int newLength)
复制指定的数组,新数组的长度
该方法会返回一个全新的数组, 源数组没有影响
// 使用数组方法的方式来扩容
int[] src = new int[]{1,3,2,4,5};
// 扩容+复制+赋值(src重新指向)
// Arrays.copyOf(src,src.length+1) 需要扩容的数组和需要扩容的长度
src= Arrays.copyOf(src,src.length+1);
src[src.length-1]=6;
// Arrays.toString(src) 快速打印
System.out.println(Arrays.toString(src));
// Arrays.sort(src) 从小到大排序
Arrays.sort(src);
System.out.println(Arrays.toString(src));
}
//结果 [1, 3, 2, 4, 5, 6]
[1, 2, 3, 4, 5, 6]
(2) System.arraycopy()
方法: static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
从指定源数组中复制一个数组,复制从指 定的位置开始,到目标数组的指定位置结束
public static void main(String[] args) {
int i, j;
int[] array = new int[]{1, 2, 3, 4, 5, 7};
int[] newArray=new int[7];
//System.arraycopy(原数组,原数组下标,新数组,新数组开始复制的下标,复制的长度);
System.arraycopy(array,1,newArray,2,3);
System.out.println(Arrays.toString(newArray));
}
结果 [0, 0, 2, 3, 4, 0, 0]
复制的效率System.arraycopy>clone>Arrays.copyOf>for循环
3.数组的排序 Arrays.sort(arr);
默认排序从小到大;
九、数组的应用
1.双色球: 红球 1~32, 随机生成5个, 不能重复
存在数组中, 并且红球先由小到大排好序
再在数组中, 额外添加一个蓝色球, 范围1~16
public class BichromaticSphere {
public static void main(String[] args) {
int[] balls = new int[5];
for (int i = 0; i < balls.length; i++) {
balls[i] = (int) (Math.random() * 32) + 1;
for (int j = 0; j < i; j++) {
if (balls[i] == balls[j]) {
i--;
break;
}
}
}
Arrays.sort(balls);
System.out.println("输出从小到大排序后的红色球:");
System.out.println(Arrays.toString(balls));
//扩容+复制
balls = Arrays.copyOf(balls, balls.length + 1);
//添加最后一个球
balls[balls.length - 1] = (int) (Math.random() * 16) + 1;
System.out.println("输出添加蓝球后双色球:");
System.out.println(Arrays.toString(balls));
}
}
2.猜字母游戏
1.生成 5 个随机的字母 char[] char 可以用== , toCharArray() 将String类型 转换成char类型
2.用户猜字母 next()
3.比较 正确答案:ERWAG 猜:ABCDE 结果:2个字母正确,其中位置正确的有0个
猜:EABCD 结果:2个字母正确,其中位置正确的有1个
4.输入byebye, 退出程序
public class GuessTheLetters {
public static void main(String[] args) {
char[] letter = answer();
while (true) {
System.out.println("正确字母"+Arrays.toString(letter));
System.out.println("输入5个不重复的大写字母,输入byebye可退出程序:");
Scanner sc = new Scanner(System.in);
String guessLetter;
guessLetter = sc.next();
if ("byebye".equals(guessLetter))
break;
//toCharArray() 将String类型 转换成char类型
char guessLetterChar[];
guessLetterChar = guessLetter.toCharArray();
int[] result = compare(letter, guessLetterChar);
System.out.println(+result[0] + "个字母正确且" + result[1] + "个位置正确");
if (result[1] == 5) {
System.out.println("程序结束");
break;
}
}
}
//生成5个字母的方法
public static char[] answer() {
char[] letter = new char[5];
char[] letter_26 = new char[26];
//生成26个大写字母
for (int i = 0; i < letter_26.length; i++) {
letter_26[i] = (char) (65 + i);
}
for (int i = 0; i < letter.length; i++) {
int random = (int) (Math.random() * 26);
letter[i] = letter_26[random];
//生成不重复的5个字母
for (int j = 0; j < i; j++)
if (letter[i] == letter[j]) {
i--;
break;
}
}
return letter;
}
//比较方法
public static int[] compare(char[] guessLetterChar, char[] letter) {
int[] result = new int[2];
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++)
if (guessLetterChar[j] == letter[i]) {
result[0]++;
if (guessLetterChar[i] == letter[i])
result[1]++;
}
}
return result;
}
}