文章目录
数组
一维数组
- 为什么要有数组
现在需要统计某公司员工的工资情况,例如计算平均工资、找到最高工资等。假设该公司有80名员工,
用前面所学的知识,程序首先需要声明80个变量来分别记住每位员工的工资,然后在进行操作,这样做会显得很麻烦。
为了解决这种问题,Java就提供了数组供我们使用
结论:
数组是存储多个变量(元素)的东西(容器)
这多个变量的数据类型要一致 - 数组概念
数组是存储同一种数据类型多个元素的集合。也可以看成是一个容器。
数组既可以存储基本数据类型,也可以存储引用数据类型(后面讲解)。 - 数组定义格式
数据类型[] 数组名;//格式1
数据类型 数组名[];//格式2
//举例:
int[] a; //定义了一个int类型的数组a; //推荐使用第一种定义方式。
int a[]; //定义了一个int类型的a数组;
package org.westos.demo;
public class MyTest {
public static void main(String[] args) {
//数组:可以理解为一个容器,可以存储多个相同数据类型的数据
//数组:既可以存储基本类型的数据,也可也存储引用数据类型
//数组属于引用数据类型
//数据类型:基本数据类型4类8种和引用数据类型(类 数组 接口)
// new 出来的都是引用数据类型 // 每new一次都会在堆内存开辟新的空间
//定义数组: 数据类型[] 数组名=new 数据类型[数组长度]
//int[] arr = new int[3]; //3 代表数组长度
//new 是为了初始化这个数组,数组只要初始化之后,才可以使用
//所谓初始化:就是为数组中的数组元素分配内存空间,并为每个数组元素赋值。
//动态初始化:由我们指定数组长度,由系统给数组元素,赋值默认值0
int[] arr=new int[3];
//通过索引给数组元素重新赋值
arr[0]=10;
arr[1]=20;
arr[2]=30;
//我们可以取数组中的元素
//元素有索引,索引从0开始
int num=arr[0];
System.out.println(num);
System.out.println(arr[1]);
System.out.println(arr[2]);
}
}
数组的初始化(动态初始化 / 静态初始化)
——什么是数组的初始化
Java中的数组必须先初始化,然后才能使用。
所谓初始化:就是为数组中的数组元素分配内存空间,并为每个数组元素赋值。
——初始化的分类:
a:动态初始化: 只指定长度,由系统给出初始化值
b:静态初始化: 给出初始化值,由系统决定长度
注意事项: 这两种方式,只能使用一种,不能进行动静结合
- 数组的初始化,动态初始化
数据类型[] 数组名 = new 数据类型[数组长度];
//数组长度其实就是数组中元素的个数。
//举例: int[] arr = new int[3]; 定义了一个int类型的数组arr,这个数组可以存放3个int类型的值。
- 数组的初始化,静态初始化
数据类型[] 数组名 = new 数据类型[]{元素1,元素2,…};
//举例: int[] arr = new int[]{1,2,3};
数据类型[] 数组名 = {元素1,元素2,…}; //简化格式
//举例: int[] arr = {1,2,3};
- 举例
package org.westos.demo;
import com.sun.media.sound.SoftTuning;
public class MyTest {
public static void main(String[] args) {
//动态初始化:由我们指定长度,由系统给出初始化值
double[] arr = new double[5];
System.out.println(arr[0]); //系统赋值double类型 默认值是0.0
boolean[] booleans = new boolean[2];
System.out.println(booleans[0]);//系统赋值boolean类型 默认值是false
char[] chars = new char[2];
System.out.println("bbbb"+(chars[0])+"aaaa");//系统赋值char类型 默认值是 (一个空字符)//输出bbbb aaaa
//静态初始化:由我们给元素赋值,由系统计算长度
int[] arr2=new int[]{20,10,30,40};
arr2[0]=100;//arr2[0]原本20 重新赋值arr2[0]为100
System.out.println(arr2[0]);//100
//数组的静态初始化的简写方式
int[] arr3={200,300,400};//直接大括号{}赋值
System.out.println(arr3[0]);//200
System.out.println(arr3);//数组的引用 //打印出来的是arr3的地址值
//数组中的属性:获取动态获取数组长度的属性 length
int len= arr3.length; // arr3的长度: arr3.length
System.out.println(len);
//数组的注意事项:数组一旦定义好,长度就 不可变了
System.out.println(arr3[5]); //这行会报错:ArrayIndexOutOfBoundsException //数组角标越界的异常
int[] arr4 = {200, 300, 400,20,2,30,92,30,20};
System.out.println(arr4[arr4.length-1]); // 最后一个元素的索引=数组长度-1
}
}
Java中的内存分配以及栈和堆的区别
package org.westos.demo;
import com.sun.media.sound.SoftTuning
public class MyTest {
//局部变量:定义在 方法中 的变量或 方法声明(形参)上 的变量
public static void main(String[] args) {// String[] args是个数组 args是方法声明(形参)上的变量 是局部变量
int a=100;//定义在main方法中的 a 是方法中的变量 是局部变量
public static void test(int b){ //b是方法声明(形参)上的变量 是局部变量
int a=1; //定义在test方法中的a是方法中的变量 是局部变量
b=10;
}
}
数组的内存图解
- 数组的内存图解1:一个数组
定义一个数组,输出数组名称和数组中的元素值,给数组赋值,再次输出数组名称和数组中的元素值
- 数组的内存图解2:二个数组
定义两个数组,分别输出数组名称和数组中的元素值,分别给两个数组赋值,再次输出数组名称和数组中的元素值
- 数组的内存图解3:三个引用2个数组
定义第一个数组,定义完毕后,给数组元素赋值。赋值完毕后,再输出数组名称和元素。
定义第二个数组,定义完毕后,给数组元素赋值。赋值完毕后,再输出数组名称和元素。
定义第三个数组,把第一个数组的地址值赋值给它。(注意类型一致),通过第三个数组的名称去把元素重新赋值。
最后,再次输出第一个数组数组名称和元素。
数组操作的两个常见小问题越界和空指针
A:案例演示
a:ArrayIndexOutOfBoundsException:数组索引越界异常
原因:你访问了不存在的索引。
b:NullPointerException:空指针异常
原因:数组已经不在指向堆内存了。而你还用数组名去访问元素。
package org.westos.demo;
import com.sun.media.sound.SoftTuning
public class MyTest {
public static void main(String[] args) {
int[] arr = new int[2];
System.out.println(arr);
arr=null; //人为置空
System.out.println(arr.length);//会报错:NullPointerException 空指针异常
//会报错 因为被人为置空后这个引用不再指向堆内存任何一个东西
}
}
数组的操作
- 数组的操作1遍历
案例演示: 数组遍历:就是依次输出数组中的每一个元素。
package org.westos.demo;
public class MyTest {
public static void main(String[] args) {
//遍历数组中的元素
int[] arr = {10, 20, 30, 40, 50, 60};
for(int i=0;i<arr.length;i++){
System.out.println(arr[i]);
}
System.out.println("-------------------------");
//如果是 反向遍历
for(int i=arr.length-1;i>=0;i--){
System.out.println(arr[i]);
}
}
}
package org.westos.demo;
public class MyTest {
public static void main(String[] args) {
//遍历 抽取成一个方法
int[] arr={10,20,30,40,50,60};
showArray(arr);
int[] arr2 = {10, 20, 30, 40, 50, 60,30,60};
showArray(arr2);
}
public static void showArray(int[] arr){
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
}
- 数组的操作2获取最值
案例演示: 数组获取最值(获取数组中的最大值或者最小值)
//看 听懂------自己动手做出来---逻辑思维才能培养出来
package org.westos.demo;
public class MyTest {
public static void main(String[] args) {
int[] arr = {10, 20, 30, 50, 400, 60, 20};
//定义一个参照值
int max = arr[0];
for (int i = 1; i < arr.length; i++) {
if (arr[i] > max) { // 如果是求最小值 就换成 if(arr[i]<max) 就行
max = arr[i];
}
}
System.out.println("最大值" + max);
}
}
package org.westos.demo;
public class MyTest {
public static void main(String[] args) {
//求最大值 抽取成一个方法
int[] arr = {10, 20, 30, 50, 400, 60, 20};
int max = getMax(arr);
System.out.println("最大值" + max);
int[] arr2 = {10, 20, 30, 50, 400, 60, 20, 200, 800};
int max1 = getMax(arr2);
System.out.println("最大值" + max1);
}
public static int getMax(int[] arr) {
int max = arr[0];
for (int i = 1; i < arr.length; i++) {
if (arr[i] > max) {
max = arr[i];
}
}
return max;
}
}
- 数组的操作3反转
案例演示: 数组元素反转(就是把元素对调)
package org.westos.demo;
public class MyTest {
public static void main(String[] args) {
//值值交换
int a = 10;
int b = 20;
// a 和b 的值交换一下 a=20 b=10;
//方式1:采用中间变量来做 开发常用
int t;
t=a; //t=10
a=b;//a=20
b=t;//b=10
System.out.println("a的值是" + a);
System.out.println("b的值是" + b);
//方式2:采用 ^ 也能换: ^ 一个数被另一数位异或两次该数不变
/* a=a^b;
b=a^b;//a^b^b----> b=a; //到这一步只给b重新赋值使得b的值是a 但a的值还是上一步的a^b
a=a^b;//a^b^a--->a=b;
*/
//方式3
/*
a=a+b;
b=a-b;
a=a-b;
*/
//方式4
/* a=(a+b)-(b=a);
*/
}
}
package org.westos.demo;
public class MyTest {
public static void main(String[] args) {
//把数组元素反转
int[] arr = {10, 20, 30, 40, 50, 60}; //{60,50,40,30,20,10}
//遍历数组:首尾元素对调 ,遍历数组的一半
for (int i = 0; i < arr.length/2; i++) {
int t = arr[i]; //采用中间变量t 进行值值交换
arr[i] = arr[arr.length - 1 - i];
arr[arr.length - 1 - i] = t;
//例如 int t = arr[0]; arr[0] = arr[arr.length - 1]; arr[arr.length - 1 ] = t;--->10和60对调
}
System.out.println("----------------------");
//再遍历下对调后的数组
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + ",");
}
}
}
package org.westos.demo;
public class MyTest {
public static void main(String[] args) {
int[] arr = {10, 20, 30, 40, 50, 60, 70, 80}; //{60,50,40,30,20,10}
for (int i = 0, j = arr.length - 1; i < j; i++, j--) { //首尾两个元素一起换
int t = arr[i];
arr[i] = arr[j];
arr[j] = t;
}
}
}
package org.westos.demo;
public class MyTest {
public static void main(String[] args) {
int[] arr = {10, 20, 30, 40, 50, 60,70,80}; //{60,50,40,30,20,10}
reverseArray(arr);
System.out.println("----------------------");
showArray(arr);
}
//反转数组元素
private static void reverseArray(int[] arr) {
for (int i = 0, j = arr.length - 1; i < j; i++, j--) {
int t = arr[i];
arr[i] = arr[j];
arr[j] = t;
}
}
//遍历数组元素
private static void showArray(int[] arr) {
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + ",");
}
}
}
- 数组的操作4查表法
案例演示: 数组查表法(根据键盘录入索引,查找对应星期)
package org.westos.demo;
import java.util.Scanner;
public class MyTest {
public static void main(String[] args) {
//数组查表法(根据键盘录入索引, 查找对应星期)
String[] arr={"星期一","星期二","星期三","星期四","星期五","星期六","星期天"};
Scanner scanner = new Scanner(System.in);
System.out.println("请输入索引 1------7");
int index = scanner.nextInt();
String str= getEle(index,arr);
System.out.println(str);
}
private static String getEle(int index, String[] arr) {
if(index>=0&&index<=arr.length-1){
return arr[index];
}
return "错误 没有输入要求的索引";
}
}
- 数组的操作5基本查找
案例演示: 数组元素查找(查找指定元素第一次在数组中出现的索引)
package org.westos.demo5;
import java.util.Scanner;
public class MyTest2 {
public static void main(String[] args) {
//根据元素查索引
String[] arr = {"星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期天"};
Scanner scanner = new Scanner(System.in);
System.out.println("请输入一个星期");
String s = scanner.nextLine(); //录入字符串 用 nextLine
int index= getIndex(s,arr);// 调用方法
System.out.println("该元素的索引是"+index );
}
private static int getIndex(String s, String[] arr) {
for(int i=0 ; i < arr.length ; i++){
if(s.equals(arr[i])){ //判断字符串是否相等 用 s.equals , boolean b= s.equals("星期一");
return i;
}
}
return -1; //-1 代表没找到
}
}
二维数组
- 我们学校的Java基础班每个班有很多个学生,所以,可以用数组来存储,而我们又同时有很多个Java基础班。
这个也应该用一个数组来存储。如何来表示这样的数据呢?Java就提供了二维数组供我们使用
由此可见:其实二维数组其实就是每一个元素为一维数组的数组。
package org.westos.demo;
import com.sun.media.sound.SoftTuning;
public class ArrayDemo {
public static void main(String[] args) {
//一维数组:
//二维数组:数组的元素是一个一维数组,那么这个数组叫做二维数组,数组套数组
//定义二维数组的语法
//动态初始化
int[][] arr=new int[2][3]; //这个2 表示的是二维数组的长度 //这个3 表中二维数组中一维数组的长度
//取一个二维数组中的第一个元素
System.out.println(arr[0]); //打印出来 是二维数组中 第一个 一维数组的地址值
System.out.println(arr[1]); //打印出来 是二维数组中 第二个 一维数组的地址值
//取出 第一个 一维数组 中的第一个元素
int num=arr[0][0]; //第一个 一维数组 中的第一个元素
System.out.println(num); // 打印出来是0 是系统赋的默认值
System.out.println(arr[0][1]); //第一个 一维数组 中的第二个元素
//另一个写法
// int arr2[][] = new int[2][3];
//还有一种写法
// int[] arr3[] = new int[2][3];
}
}
二维数组格式1的讲解及其内存图解
//二维数组格式1
数据类型[][] 变量名 = new 数据类型[m][n];
//m表示这个二维数组有多少个一维数组 必须写上
//n表示每一个一维数组的元素个数 可选
//举例:
int[][] arr = new int[3][2];
//定义了一个二维数组arr
//这个二维数组有3个一维数组,名称是arr[0],arr[1],arr[2]
//每个一维数组有2个元素,可以通过arr[m][n]来获取
//表示获取第m+1个一维数组的第n+1个元素
//以下格式也可以表示二维数组 //这两种格式不推荐使用
数据类型 数组名[][] = new 数据类型[m][n];
数据类型[] 数组名[] = new 数据类型[m][n];
-
注意下面定义的区别
int x,y;
int[] x,y[];区别是:
int[] x,y[];//定义了两个数组 一个是一维数组x 一个是二维数组y
x=new int[3];
y=new int[3][];
// int x, y; //定义了两个int类型的变量 x,y
// int[] x, y[]; //定义了一个一维数组x 一个二维数组y
// x=new int[2];
// y=new int[3][6];
- 二维数组格式1的内存图解
1.字节码文件“MyTest.class”加载进方法区 // JVM把“main(){}”方法加载进栈内存执行,“int[][] arr”对象的引用被放在栈内存 //
2.要new 所以在堆内存开辟空间 // 自己定义的二维数组长度为3,所以分配个3个长度的空间,其地址值是0x001,其默认值是null(因为数组是引用类型,引用类型的默认值是null) //
3.因为这个二维数组长度为3 // 有3个一维数组 且每个一维数组有2个元素 // 所以还会初始化3个长度为2的一维数组 地址值为 0x0001 0x0002 0x0003 其默认值是0 //
地址值 0x0001 0x0002 0x0003 会把三个null覆盖掉(二维数组里面的地址值0x0001 0x0002 0x0003通过引用指向一维数组)//
4.初始化完成后 堆内存把二维数组的地址值0x001给向栈内存引用 // 然后栈内的0x001地址指向堆内的空间 //
二维数组格式2的讲解及其内存图解
//二维数组格式2
数据类型[][] 变量名 = new 数据类型[m][];
//m表示这个二维数组有多少个一维数组
//这一次没有直接给出一维数组的元素个数,可以动态的给出。
举例:
int[][] arr = new int[3][];
arr[0] = new int[2];
arr[1] = new int[3];
arr[2] = new int[1];
package org.westos.demo;
public class ArrayDemo {
public static void main(String[] args) {
//定义二维数组
int[][] arr = new int[2][2];
//定义两个一维数组
int[] arrone={10,20,30};
int[] arrrtwo={20,100,30};
//重新给二维数组中的元素赋值
arr[0]=arrone;
arr[1]=arrrtwo;
//取出100
int i = arr[1][1];
System.out.println(i);
arr[1][2]=300;
arr[1][arrrtwo.length-1]=300; //相当于 arr[1][2] = 300;
System.out.println(arr[arr.length-1][arrrtwo.length - 1]); //打印出来300
}
}
- 二维数组格式2的内存图解
二维数组格式3的讲解及其内存图解
//二维数组格式3
数据类型[][] 变量名 = new 数据类型[][]{{元素…},{元素…},{元素…}...};
//简化版: //这个格式属于静态初始化:由我们指定具体的元素值,由系统给分配长度
数据类型[][] 变量名 = {{元素…},{元素…},{元素…}};
//举例:
int[][] arr = {{1,2,3},{4,5,6},{7,8,9}};
int[][] arr = {{1,2,3},{5,6},{7}};
package org.westos.demo;
public class ArrayDemo {
public static void main(String[] args) {
//静态初始化
int[][] arr=new int[][]{{10,20,30},{5,6},{6,8}};
//简写
int[][] arr2 = {{10, 20, 30}, {5, 6}, {6, 8}};
System.out.println(arr[2][1]); // 8
arr[1][0]=50;// 5改成50
}
}
二维数组的操作
- 二维数组练习1遍历
案例演示
需求:二维数组遍历
外循环控制的是二维数组的长度,其实就是一维数组的个数。
内循环控制的是一维数组的长度。
package org.westos.demo;
public class ArrayDemo {
public static void main(String[] args) {
int[][] arr = new int[][]{{10, 20, 30}, {5, 6}, {6, 8}};
/* System.out.println(arr[0][0]); //一个一个遍历 太慢了
System.out.println(arr[0][1]);
System.out.println(arr[0][2]);
System.out.println(arr[1][0]);
System.out.println(arr[1][1]);
System.out.println(arr[2][0]);
System.out.println(arr[2][1]);*/
//二维数组的遍历
for (int i = 0; i < arr.length; i++) { // arr.length为3 i < 3
// System.out.println(arr[i]); // 打印三个一维数组的地址值
for (int j = 0; j < arr[i].length; j++) { //arr[0].length为3;arr[1].length为2;arr[2].length为2
System.out.println(arr[i][j]);
}
}
}
}
- 二维数组练习2求和
案例演示
需求:公司年销售额求和
某公司按照季度和月份统计的数据如下:单位(万元)
第一季度:22,66,44
第二季度:77,33,88
第三季度:25,45,65
第四季度:11,66,99
package org.westos.demo;
public class ArrayDemo {
public static void main(String[] args) {
// int[][] arr={{22, 66, 44},{77, 33, 88},{25, 45, 65},{11, 66, 99}}; //静态初始化
int[][] arr = new int[4][3]; //动态初始化
int[] one={22, 66, 44};
int[] two={77, 33, 88};
int[] three={25, 45, 65};
int[] four={11, 66, 99};
arr[0]=one;
arr[1]=two;
arr[2]=three;
arr[3]=four;
//遍历二维数组的元素,累加求和
int sum=0;
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < arr[i].length; j++) {
sum+=arr[i][j];
}
}
System.out.println("总销售额"+sum);
}
}
案例演示
需求:打印杨辉三角形(行数可以键盘录入)
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
分析:看这种图像的规律
A:任何一行的第一列和最后一列都是1
B:从第三行开始,每一个数据是它上一行的前一列和它上一行的本列之和。
步骤:
A:首先定义一个二维数组。行数如果是n,我们把列数也先定义为n。
这个n的数据来自于键盘录入。
B:给这个二维数组任何一行的第一列和最后一列赋值为1
C:按照规律给其他元素赋值
从第三行开始,每一个数据 是它 上一行的前一列 和它 上一行的本列 之和。
D:遍历这个二维数组。
package org.westos.demo;
import java.util.Scanner;
public class MyTest {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入行数");
int n = scanner.nextInt();
//构建二维数组
int[][] arr = new int[n][n]; // [n][n]是正方形 后续再变成三角形
//1.把第一元素和最后一个元素置为1
for (int i = 0; i < arr.length; i++) {
arr[i][0]=1; //第一个元素置1
arr[i][i]=1; //对角线元素置1
}
//2.算出中间元素
//从第三行开始,从第二列开始,中间的数等于上一行的前一列和本列之和
for (int i = 2; i < arr.length; i++) { //从第三行开始 i = 2
for (int j = 1; j <= i; j++) { //从第二列开始 j = 1
arr[i][j]=arr[i-1][j-1]+arr[i-1][j]; //前行前列 arr[i-1][j-1] ; 前行本列 arr[i-1][j]
}
}
//3,打印出三角形
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j <=i; j++) { // 打印 三角形: j <=i
System.out.print(arr[i][j]+"\t");
}
System.out.println();
}
}
}