目录
1. 数组的概念及特点
数组:
数组是存储同一种数据类型的多个元素的集合,也可以看成是一个容器。
特点:
- 既可以存储基本数据类型又可以存储引用数据类型
- 每一个元素都有编号,从0开始,最大编号是长度-1。编号的专业叫法:索引
2. 数组的定义格式
有两种,效果一样,念法不同,常用格式1
- 数据类型[] 数组名;
- 数据类型 数组名[];
int [] a;//定义一个int类型的数组a变量,此时的数组里没有元素,需要对其进行初始化操作
int a [];//定义一个int类型的a数组变量
3. 数组的初始化
Java中的数组必须先初始化,然后才能使用
3.1 概念
所谓初始化:
就是为数组中的数组元素分配内存空间,并为每个数组元素赋值。
3.2 初始化方式
3.2.1 动态初始化
动态初始化:
初始化时只指定数组长度,由系统为数组分配初始值。
数组长度其实就是数组中元素的个数
动态初始化格式:
数据类型[] 数组名 = new 数据类型[数组长度];
//举例:
int[] arr = new int[3];
//解释:定义了一个int类型的数组array,这个数组中可以存放3个int类型的值
/*
左边:
int:表示数组中的元素的数据类型为int;
[]:说明这是一个数组;
arr:这是这个数组的名称;
右边:
new:为数组分配内存空间;
int:表示数组中的元素的数据类型为int;
[]:说明这是一个数组;
3:数组长度,即数组中元素的个数
*/
注意:
- 直接访问数组名得到的是地址值
- 访问数组里的元素格式:数组名[索引]
3.2.2 静态初始化
静态初始化:
初始化时指定每个数组元素的初始值,由系统决定数组长度。
静态初始化格式:
数据类型[] 数组名 = new 数据类型[]{元素1,元素2,……};
或者:
数据类型[] 数组名 = {元素1,元素2,……};
//举例:
int[] arr = new int[]{1,2,3};
//简化写法:
int[] arr = {1,2,3};
//解释:定义了一个int类型的数组,这个数组中存放3个int类型的值,并且值分别是1,2,3
4.Java中的内存分配
4.1 概述
Java 程序在运行时,需要在内存中分配空间。
为了提高运算效率,就对空间进行了不同区域的划分,因为每一片区域都有特定的处理数据方式和内存管理方式。
4.2 5个内存空间
栈(存储局部变量)
- 局部变量:方法定义中或者方法声明上的所有变量
特点:栈内存的数据用完(脱离作用域)就释放
堆(存储new出来的东西)
特点:
- 每一个new出来的东西都有一个地址值;
- 每个变量都有默认值;(byte,short int long默认值为0;float,double默认值为 0.0;char默认值为'\u0000';boolean默认值为false;引用类型默认值为null)
- 数据使用完毕后,不会立即释放,在垃圾回收器空闲的时候回收
方法区(面向对象部分讲解)
本地方法区(和系统有关)
寄存器(给CPU用)
4.3 数组内存图解(理解)
5.数组的常用操作
5.1 数组遍历
数组遍历:即依次输出数组中每一个的元素
数组提供了一个属性:length来专门获取数组长度
//获取数组长度的格式
数组名.length
案例1:一个数组的遍历
//一个数组遍历
class ArrayTest1 {
public static void main(String[] args) {
//定义一个数组
int[] arr = {11,22,33,44,55,66};
//用格式:数组名.length来获取数组长度
for(int x = 0;x<arr.length;x++) {
System.out.println(arr[x]);
}
}
}
案例2:对多个数组遍历(使用方法)
//通过调用遍历方法对多个数组进行遍历
//方法:两个明确——返回值类型void;参数列表int [] arr
class ArrayTest2 {
public static void main(String[] args) {
//定义数组
int[] arr1 = {1,2,3,4,5};
int[] arr2 = {11,22,33,44};
//直接调用遍历数组方法
printArray(arr1);
System.out.println("----------");
printArray(arr2);
}
//遍历数组的方法
public static void printArray(int[] arr) {
for(int x = 0;x<arr.length;x++) {
System.out.println(arr[x]);
}
}
}
5.2 数组获取最值
案例3:获取数组中的最大值
思路:
- 假设数组中的第一个元素为最大值——将arr[0]暂时赋值给变量max;
- 将max与第二个元素进行比较——if语句判断;
- 如果max较小,就将第二个元素的值赋给变量max,并继续比较max与下一个元素的大小;
- 如果max较大,不进行赋值操作,直接与下一个元素比较大小——3,4步无论如何都要获取剩下的元素的值(数组遍历)
//获取数组元素中的最大值
class ArrayTest3 {
public static void main(String[] args) {
//定义一个数组
int [] arr = {34,98,12,4,69,127,88,56};
//假设数组中的第一个元素就是最大值
int max = arr[0];
//遍历剩下的元素与进行比较
for(int x = 1;x<arr.length;x++) {
//遍历的元素较大时,将其赋值给max
if(arr[x] > max) {
max = arr[x];
}
}
System.out.println("max:"+max);
}
}
用方法改进:
两个明确:
- 返回值类型——int;返回的int类型的最大值
- 参数列表——int [] arr
//用方法获取数组元素中的最大值
class ArrayTest4 {
public static void main(String[] args) {
//定义数组
int [] arr = {34,98,12,4,69,127,88,56};
//调用getMax方法并赋值给变量max,调用方法时不用再写数据类型
int max = getMax(arr);
System.out.println("max:"+max);
}
//写获取数组元素最大值的方法
public static int getMax(int[] arr) {
//定义一个变量max,将数组第一个元素赋值给它(因为在不同方法里定义的所以没有影响)
int max = arr[0];
//遍历剩余元素进行比较赋值
for(int x = 1;x<arr.length;x++) {
if(arr[x] > max) {
max = arr[x];
}
}
//循环结束后返回数组中的最大值到调用方法处
return max;
}
}
5.3 数组元素逆序
案例4:把元素顺序对调
思路:
- 将0索引的数据和arr.length-1对换;
- 将1索引的数据与arr.length-2对换;
- ……
- 对调次数:arr.length/2(偶数个元素时刚好配对,奇数个元素时由于计算时商取得整数且中间多出来的元素位置不变,无影响)
//数组元素逆序
class ArrayTest5 {
public static void main(String[] args) {
//定义一个数组
int[] arr = {1,2,3,4};
System.out.println("逆序前:");
//调用遍历方法
printArray(arr);
System.out.println("逆序后:");
//调用逆序方法
reverse(arr);
//调用数组遍历方法
printArray(arr);
}
//写逆序方法
public static void reverse(int[] arr) {
for(int x = 0;x < arr.length/2;x++) {
int temp = arr[x];
arr[x] = arr[arr.length-1-x];
arr[arr.length-1-x] = temp;
}
}
//遍历数组
public static void printArray(int[] arr) {
System.out.print("[");
for(int x=0; x<arr.length; x++) {
if(x == arr.length-1) {
System.out.println(arr[x]+"]");
}else {
System.out.print(arr[x]+", ");
}
}
}
}
5.4 数组查表法
案例5:根据键盘录入索引,查找对应星期
//根据索引查找星期
//导包
import java.util.Scanner;
class ArrayTest6 {
public static void main(String[] args) {
//定义一个字符串数组
String[] arr = {"星期一","星期二","星期三","星期四","星期五","星期六","星期日"};
//创建键盘录入对象
Scanner sc = new Scanner(System.in);
System.out.println("请输入索引号(0~6):");
int number = sc.nextInt();
System.out.println("你要查找的日期是:"+arr[number]);
}
}
5.5 数组元素查找
案例6:查找指定元素第一次在数组中出现的索引
思路:
- 定义一个数组并静态初始化;
- 键盘录入要查找的数据;
- 遍历数组,依次获取数组中的每一个元素与该数据进行比较;
- 如果想等,就返回当前索引
//导包
import java.util.Scanner;
class ArrayTest7 {
public static void main(String[] args) {
//定义一个数组
int[] arr = {12,76,90,56,349,24,35};
//创建键盘录入对象
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个数据:");
int value = sc.nextInt();
//调用方法
int index = getIndex(arr,value);
System.out.println(value+"在数组中的第一次索引是:"+index);
}
//写方法获取索引:返回值类型:int;参数列表:int[] arr,int value
public static int getIndex(int[] arr,int value) {
//遍历数组
for(int i=0;i<arr.length;i++) {
//元素与数据进行比较,相等就返回索引,不相等就没有数据返回,会报错,要在后面返回负数
if(arr[i] == value) {
//要考虑不相等时候的返回值
return i;
}
}return -1;//如果找不到数据,一般返回一个负数
}
}
5.6 数组排序和二分查找(后续讲)
6.二维数组
6.1 二维数组的定义
二维数组其实就是一个元素为一维数组的数组
6.2 二维数组的定义格式
格式1(列固定的二维数组动态初始化):
数据类型[][] 变量名 = new 数据类型[m][n];
也可以写成另外两种格式但是不推荐:
A:数据类型 数组名[][] = new 数据类型[m][n];
B:数据类型[] 数组名[] = new 数据类型[m][n];
int x,y; 等价于 int x;int y;
int[] x,y[]; 等价于 int[] x;int[] y[];//x为一位数组,y为二维数组
m表示这个二维数组有多少个一维数组
n表示每一个一维数组的元素个数
//举例:
int[][] arr = new int[3][2];
//定义了一个二维数组arr
//这个二维数组有3个一维数组,名称是arr[0],arr[1],arr[2]
//每个一维数组有2个元素,可以通过arr[m][n]来获取
//表示获取第m+1个一维数组的第n+1个元素
案例7:
//二维数组(理解内存图解)
class Array2Demo {
public static void main(String[] args) {
//定义一个二维数组
int[][] arr = new int[3][2];
//在堆里开辟一个二维数组的内存空间并分配为3块生成一个地址值并赋给栈里对应的区域
System.out.println(arr);//输出结果[[I@15db9742
/*
堆里的二维数组分配的3个空间用来存储一维数组(引用类型)初始值均为null,
等一维数组内存空间分配完毕后生成地址值替代null
*/
System.out.println(arr[0]);//输出结果[I@6d06d69c
System.out.println(arr[1]);//输出结果[I@7852e922
System.out.println(arr[2]);//输出结果[I@4e25154f
//开辟并分配一维数组的内存空间
System.out.println(arr[0][0]);//输出结果0
System.out.println(arr[0][1]);//输出结果0
}
}
格式2(列变化的二维数组动态初始化):
数据类型[][] 变量名 = new 数据类型[m][];
m表示这个二维数组有多少个一维数组
这一次没有直接给出一维数组的元素个数,可以动态的给出。
//举例:
int[][] arr = new int[3][];
arr[0] = new int[2];
arr[1] = new int[3]
arr[2] = new int[1];
//二维数组
class Array2Demo {
public static void main(String[] args) {
//定义一个二维数组
int[][] arr = new int[3][];
//输出二维数组
System.out.println(arr);//输出地址值
//此时没有为一位数组分配空间所以地址值为默认值
System.out.println(arr[0]);//输出null
System.out.println(arr[1]);//输出null
System.out.println(arr[2]);//输出null
//动态的为每一个一维数组分配空间
arr[0] = new int[2];
arr[1] = new int[3];
arr[2] = new int[1];
//输出二维数组中的一维数组
System.out.println(arr[0]);//输出地址值
System.out.println(arr[1]);//输出地址值
System.out.println(arr[2]);//输出地址值
}
}
格式3(静态初始化):
数据类型[][] 变量名 = new 数据类型[][]{{元素…},{元素…},{元素…}};
简化版格式:
数据类型[][] 变量名 = {{元素…},{元素…},{元素…}};
//举例:
int[][] arr = {{1,2,3},{4,6},{6}};
6.3 二维数组的练习
6.3.1 二维数组遍历
//二维数组遍历
class Array2Test {
public static void main(String[] args) {
//定义一个二维数组
int[][] arr = {{1,2,3},{4,5,6},{7,8,9}};
//遍历二维数组中的一维数组
for(int x = 0;x < arr.length;x++) {
//遍历一维数组中的元素
for(int y = 0;y < arr[x].length;y++){
System.out.println(arr[x][y]);
}
System.out.println("-------");
}
}
}
方法改进:
//二维数组遍历的方法改进
class Array2Test1 {
public static void main(String[] args) {
//定义一个二维数组
int[][] arr = {{1,2,3},{4,5,6},{7,8,9}};
int[][] arr2 = {{1,2,3},{4,5},{6}};
//调用方法
printArray2(arr);
printArray2(arr2);
}
//写方法:返回值类型——void;参数列表——int[][] arr;
public static void printArray2(int[][] arr) {
for(int x =0;x<arr.length;x++) {
for(int y = 0;y<arr[x].length;y++) {
System.out.println(arr[x][y]);
}
System.out.println("-------");
}
}
}
6.3.2 二维数组求和
思路:
首先获取每一个元素(遍历),然后元素累加
//二维数组元素求和
class Array2Test2 {
public static void main(String[] args) {
//定义一个二维数组
int[][] arr = {{22,66,44},{77,33,88},{25,45,65},{11,66,99}};
//定义和变量
int sum = 0;
//遍历
for(int x = 0;x<arr.length;x++) {
for(int y = 0;y<arr[x].length;y++) {
sum += arr[x][y];
}
}
System.out.println("一年的销售额为:"+sum);
}
}
6.3.3 二维数组求杨辉三角
要求行数键盘录入
分析:
- 行数与列数相等,由键盘录入;
- 每一行的第一列和最后一列都是1;
- 从第三行开始,每个数据是它上一行的前一列和本列之和(除了第一列和最后一列)
//二维数组打印杨辉三角
//导包
import java.util.Scanner;
class Array2Test3 {
public static void main(String[] args) {
//创建键盘录入对象
Scanner sc = new Scanner(System.in);
System.out.println("请输入行数:");
int n = sc.nextInt();
//定义一个二维数组
int[][] arr = new int[n][n];
//给任一行的第一列和最后一列赋值1
for(int x = 0;x < arr.length;x++) {
arr[x][0] = 1;
arr[x][x] = 1;
}
//从第三行开始,每一行第二列到第n-1列的值=上一行前一列的数+上一行该列的数
for(int x = 2;x<arr.length;x++){
for(int y = 1;y <= x-1;y++) {
arr[x][y] = arr[x-1][y-1] + arr[x-1][y];
}
}
//输出形式
for(int x=0; x<arr.length; x++) {
for(int y=0; y<=x; y++) {
System.out.print(arr[x][y]+"\t");
}
System.out.println();
}
}
}
思考题
Java中的参数传递问题
Java中只有值传递。
基本类型:形式参数的改变不影响实际参数
引用类型:形式参数的改变直接影响实际参数
//Java中的参数传递问题,在Java中只有值传递
class ArgsDemo {
public static void main(String[] args) {
int a = 10;
int b = 20;
System.out.println("a:"+a+",b:"+b); //a:10,b:20
//方法中形参的改变不影响a,b的实际参数
change(a,b);
System.out.println("a:"+a+",b:"+b); //a:10,b:20
int[] arr = {1,2,3,4,5};
//传递的是地址值,地址值指向堆内存中存储的元素
//在引用数据类型中,形参的改变直接影响实际参数
change(arr);
System.out.println(arr[1]); //4
}
public static void change(int a,int b) { //a=10,b=20
System.out.println("a:"+a+",b:"+b); //a:10,b:20
a = b; //a=20
b = a + b; //b=40
System.out.println("a:"+a+",b:"+b); //a:20,b:40
}
public static void change(int[] arr) { //arr={1,2,3,4,5};
for(int x=0; x<arr.length; x++) {
if(arr[x]%2==0) {
arr[x]*=2;
}
}
//arr={1,4,3,8,5};
}
}