数组
一、数组概述
- 数组的概念:
- 数组(array),就是多个相同类型的数据按一定顺序排列的集合,并使用一个名字命名,然后用编号区分这些数据。
- 数组就是一个数据容器。
- 相关概念:
- 数组名
- 下标(或脚标、索引)(index)
- 元素(element)
- 数组的长度(length)
- 数组的特点:
- 数组的长度一旦确定就不能修改(重要)
- 存储的元素为相同的数据类型,可以是基本数据类型或引用数据类型
- 有索引,创建数组时会在内存中开辟一整块连续的空间。
- 存取元素的速度快,因为可以通过[下标],直接定位到任意一个元素。
二、数组初始化
数组使用之前需要先初始化,什么是数组初始化?就是给数组分配内存空间,并给元素赋值。
数组有两种初始化方式:
- 方式一:静态初始化
定义数组的同时为数组分配内存空间,并赋值。程序员只给定数组元素的初始值,不指定数组长
度,由系统决定数组的长度
格式
数据类型[] 数组名 = new 数据类型[]{元素1,元素2,元素3...};
或
数据类型[] 数组名;
数组名 = new 数据类型[]{元素1,元素2,元素3...};
简化方式:
数据类型[] 数组名 = {元素1,元素2,元素3...};//必须在一个语句中完成,不能分开两个语句写
例:
int[] arr = new int[]{1,2,3,4,5};//正确
int[] arr;
arr = new int[]{1,2,3,4,5};//正确
int[] arr = new int[5]{1,2,3,4,5};//错误的,后面有{}指定元素列表,就不需要在 [长度]指定长度。
//简化方式:
int[] arr = {1,2,3,4,5};//正确
int[] arr;
arr = {1,2,3,4,5};//错误
- 方式二:动态初始化
程序员只给定数组的长度,后期再给给元素赋值(实际系统会先给出元素的默认值)
格式:
数据类型[] 数组名字 = new 数据类型[长度];
或
数据类型[] 数组名字;
数组名字 = new 数据类型[长度];
-
数据类型: 指定创建的数组容器可以存储什么数据类型的数据。
-
[] : 表示数组。
-
数组名字:为定义的数组起个变量名,满足标识符规范,可以使用名字操作数组。
-
new:关键字,理解为开辟内存空间。因为数组本身是引用数据类型,所以要用new创建数组对象。
-
[长度]:数组的长度,表示数组容器中可以存储多少个元素。
- 注意:数组有定长特性,长度一旦指定,不可更改。
- 和水杯道理相同,买了一个2升的水杯,总容量就是2升,不能多也不能少。
例:
int[] arr = new int[5];
int[] arr;
arr = new int[5];
三、数组元素的访问
- 索引: 每一个存储到数组的元素,都会自动的拥有一个编号,从0开始,这个自动编号称为数组索引(index),可以通过数组的索引访问到数组中的元素。
- 索引范围:[0, 数组的长度-1]
- 格式:
数组名[索引]
- 访问数组元素:
- 数组名[索引],表示指定索引位置的元素
- 数组名[索引]=值,表示为数组中指定索引位置的元素赋值
public static void main(String[] args) {
//定义存储int类型数组,赋值元素1,2,3,4,5
int[] arr = {1, 2, 3, 4, 5};
//为0索引元素赋值为6
arr[0] = 6;
//获取数组0索引上的元素
int i = arr[0];
System.out.println(i);//6
//直接输出数组0索引元素
System.out.println(arr[0]);//6
}
四、数组的遍历
- 数组遍历: 就是将数组中的每个元素分别获取出来,就是遍历。遍历也是数组操作中的基石。
- 数组的长度属性: 每个数组都具有长度,而且是固定的,Java中赋予了数组的一个属性,可以获取到数组的长度,语句为: 数组名.length ,属性length的执行结果是数组的长度,int类型结果。由次可以推断出,数组的最大索引值为 数组名.length-1 。
public static void main(String[] args) {
int[] arr = {11, 22, 33, 44, 55};
//打印输出数组的长度
System.out.println("数组长度:" + arr.length);//5
//数组遍历(正序):
System.out.println("数组遍历:");
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]);
}
}
五、数组元素的默认值
当我们使用动态初始化创建数组时:
数据类型[] 数组名字 = new 数据类型[长度];
此时只确定了数组的长度,那么数组的元素是什么值呢?
数组的元素有默认值:
六、 数组内存图
数组内存图分析
(1)一个数组内存图
public static void main(String[] args) {
int[] arr = new int[3];
System.out.println(arr);//[I@5f150435
}
思考:打印arr为什么是[I@5f150435,它是数组的地址吗?
答:它不是数组的地址。
问?不是说arr中存储的是数组对象的首地址吗?
答:arr中存储的是数组的首地址,但是因为数组是引用数据类型,打印arr时,会自动调用arr数组对象的toString()方法,默认该方法实现的是对象类型名@该对象的hashCode()值的十六进制值。
问?对象的hashCode值是否就是对象内存地址?
答:不一定,因为这个和不同品牌的JVM产品的具体实现有关。例如:Oracle的OpenJDK中给出了5种实现,其中有一种是直接返回对象的内存地址,但是OpenJDK默认没有选择这种方式。
(2)两个数组内存图
public static void main(String[] args) {
int[] arr = new int[3];
int[] arr2 = new int[2];
System.out.println(arr);
System.out.println(arr2);
}
(3)两个变量指向一个数组
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]);
}
来点小练习吧!!!
/**
用一个数组存储26个小写英文字母,并遍历显示,显示要求如:a->A
*/
public class Demo {
public static void main(String[] args) {
char[] chars = new char[]{'a', 'b','c','d','e', 'f','g','h','i', 'j', 'k','l','m', 'n','o','p','q', 'r','s','t','u', 'v','w','x','y','z'};
for (int i = 0; i < chars.length; i++) {
char s= (char) (chars[i]-32);
System.out.println(chars[i]+"->"+s);
}
}
}
/**
* 求某年某月某日是这一年的第几天
* 闰年(1)能被 4 整除不能被 100 整除(2)能被 400 整除
* int[] daysOfMonth = {31,28,31,30,31,30,31,31,30,31,30,31};
*/
public class Demo {
public static void main(String[] args) {
System.out.println(dayOfYear(2000, 11, 13));
}
public static int dayOfYear(int year, int month, int days) {
int[] daysOfMonth = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
int sum = days;
for (int i = 0; i < month - 1; i++) {
sum += daysOfMonth[i];
}
System.out.println(sum);
if (month > 2) {
if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) {
sum++;
}
}
return sum;
}
}
/**
* 从1990年1月1日开始,三天打鱼两天晒网,问某年某月某日是打鱼还是晒网
* 闰年(1)能被 4 整除不能被 100 整除(2)能被 400 整除
* int[] daysOfMonth = {31,28,31,30,31,30,31,31,30,31,30,31};
*/
public class Demo {
public static void main(String[] args) {
int date = getDate(2000, 11, 22);
if (date % 5 <=3&&date % 5>=1) {
System.out.println("打鱼呢");
} else {
System.out.println("晒网呢");
}
}
public static int getDate(int year, int month, int day) {
if (year <= 1990) {
System.out.println("要大于1990年哦");
}
if (month < 1 && month > 12) {
System.out.println("月份要在1~12哦");
}
if (day<1 && day > 31) {
System.out.println("日期要在1~31内哦");
}
int[] daysOfMonth = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
int sum = day;
int count = 0;
count += (year - 1 - 1990) * 365;
for (int i = 1990; i < year - 1; i++) {
if (i % 4 == 0 && i % 100 != 0 || i % 400 == 0) {
count++;
System.out.println(i+"是闰年哦");
}
}
for (int i = 0; i < month - 1; i++) {
sum += daysOfMonth[i];
}
if (month > 2) {
if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) {
sum++;
System.out.println(year+"是闰年哦");
}
}
sum += count;
System.out.println(sum);
return sum;
}
}
七、数组的基础算法
(1)统计
求数组元素的总和、均值、统计偶数个数等
思路:遍历数组,挨个的累加,判断每一个元素
public static void main(String[] args) {
int[] arr = {4, 5, 6, 1, 9};
//求总和、均值
int sum = 0;//因为0加上任何数都不影响结果
for (int i = 0; i < arr.length; i++) {
sum += arr[i];
}
//均值
double avg = (double) sum / arr.length;
System.out.println(sum);
System.out.println(avg);
}
public static void main(String[] args) {
int[] arr = {4, 5, 6, 1, 9};
//求总乘积
long result = 1;
// 因为1乘以任何数都不影响结果
for (int i = 0; i < arr.length; i++) {
result *= arr[i];
}
System.out.println(result);
//统计偶数个数
int even = 0;
for (int i = 0; i < arr.length; i++) {
if (arr[i] % 2 == 0) {
even++;
}
}
System.out.println(even);
}
(2)查找指定元素
查找某个指定元素在数组中的首次出现的位置(索引)
常见查找算法有顺序查找,二分查找(折半查找,前提要求数组中元素是按照大小顺序排序的)
//查找value第一次在数组中出现的index
public static void main(String[] args) {
int[] arr = {4, 5, 6, 1, 9};
int value = 1;
int index = -1;
for (int i = 0; i < arr.length; i++) {
if (arr[i] == value) {
index = i;
break;
}
}
if (index == -1) {
System.out.println(value + "不存在");
} else {
System.out.println(value + "的下标是" + index);
}
}
(3)查找最值及其位置
查找最值及其第一次出现的下标
思路:
(1)先假设第一个元素最大/最小,用变量index表示其位置,
(2)然后用index位置的元素与后面的元素一一比较
(3)用变量index时刻记录目前比对的最大/小的下标
public static void main(String[] args) {
//求最大值及其位置
int[] arr = {4, 5, 6, 1, 9};
int maxIndex = 0;
//假定索引0位置的元素最大
for (int i = 1; i < arr.length; i++) {
if (arr[i] > arr[maxIndex]) {
maxIndex = i;
}
}
System.out.println("最大值的下标:" + maxIndex);
System.out.println("最大值:" + arr[maxIndex]);
}
(4)排序之冒泡排序
Java中的经典算法之冒泡排序(Bubble Sort)
原理:比较两个相邻的元素,将值大的元素交换至右端,最大值出现在最后位置。
思路:
依次比较相邻的两个数,将小数放到前面,大数放到后面。
即第一趟,首先比较第1个和第2个元素,将小数放到前面,大数放到后面。
然后比较第2个和第3个元素,将小数放到前面,大数放到后面。
如此继续,直到比较最后两个数,将小数放到前面,大数放到后面。
重复第一趟步骤,直至全部排序完成。
public static void main(String[] args) {
int[] arr = {6, 3, 8, 2, 9, 1};//arr.length = 6
// i=1,2,3,4,5 一共5轮
for (int i = 1; i < arr.length; i++) {//轮数
/*
i=1,第1轮,j=0,1,2,3,4 arr[j]与arr[j+1]
i=2,第2轮,j=0,1,2,3 arr[j]与arr[j+1]
i=3,第3轮,j=0,1,2 arr[j]与arr[j+1]
i=4,第4轮,j=0,1 arr[j]与arr[j+1] i=5,
第5轮,j=0 arr[j]与arr[j+1]
j=0, j<=arr.length-1-i
*/
for (int j = 0; j <= arr.length - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
//交换位置
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
//结果
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
}
(5)数组的反转
方法有两种:
1、借助一个新数组
2、首尾对应位置交换
第一种方式:
public static void main(String[] args) {
int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9};
//(1)先创建一个新数组
int[] newArr = new int[arr.length];
//(2)复制元素
int len = arr.length;
for (int i = 0; i < newArr.length; i++) {
newArr[i] = arr[len - 1 - i];
}
//(3)舍弃旧的,让arr指向新数组
arr = newArr;//这里把新数组的首地址赋值给了arr
// (4)遍历显示
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
缺点:需要借助一个数组,浪费额外空间,原数组需要垃圾回收
第二种方式
**实现思想:**数组对称位置的元素互换
public static void main(String[] args) {
int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9};
//(1)计算要交换的次数: 次数 = arr.length/2
// (2)首尾对称位置交换
for (int i = 0; i < arr.length / 2; i++) {
//循环的次数就是交换的次数
int temp = arr[i];
arr[i] = arr[arr.length - 1 - i];
arr[arr.length - 1 - i] = temp;
}
//(3)遍历显示
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
(6)数组的扩容
示例:当原来的数组长度不够了需要扩容,例如需要新增位置来存储10
public static void main(String[] args) {
int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9};
//如果要把arr数组扩容,增加1个位置
// (1)先创建一个新数组,它的长度 = 旧数组的长度+1,或者也可以扩大为原来数组长度的1.5倍,2倍等
int[] newArr = new int[arr.length + 1];
//(2)复制元素
// 注意:i<arr.length 因位arr比newArr短,避免下标越界
for (int i = 0; i < arr.length; i++) {
newArr[i] = arr[i];
}
//(3)把新元素添加到newArr的最后
newArr[newArr.length - 1] = 10;
//(4)如果下面继续使用arr,可以让arr指向新数组
arr = newArr; //(4)遍历显示
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
(1)至于新数组的长度定义多少合适,看实际情况,如果新增的元素个数确定,那么可以增加指
定长度,如果新增元素个数不确定,那么可以扩容为原来的1.5倍、2倍等
(2)数组扩容太多会造成浪费,太少会导致频繁扩容,效率低下
(6)数组元素的插入
在原数组的某个[index]插入一个元素
情形一:原数组未满
public static void main(String[] args) {
String[] arr = new String[5];
arr[0] = "张三";
arr[1] = "李四";
arr[2] = "王五";
/*
* 那么目前数组的长度是5,而数组的实际元素个数是3
* ,如果此时需要在“张三”和“李四”之间插入一个“赵 六”,
* 即在[index=1]的位置插入“赵六”,
* */
//(1)移动2个元素,需要移动的起始元素下标是[1],它需要移动到[2],一共一共2个
System.arraycopy(arr, 1, arr, 2, 2);
//(2)插入新元素
arr[1] = "赵六";
//(3)遍历显示
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
情形一:原数组已满
public static void main(String[] args) {
String[] arr = new String[3];
arr[0] = "张三";
arr[1] = "李四";
arr[2] = "王五";
/*
* 那么目前数组的长度是3,而数组的实际元素个数是3,
* 如果此时需要在“张三”和“李四”之间插入一个“赵 六”,
* 即在[index=1]的位置插入“赵六”,
* */
//(1)先扩容
String[] newArr = new String[4];
for (int i = 0; i < arr.length; i++) {
newArr[i] = arr[i];
}
arr = newArr;
//(2)移动2个元素,需要移动的起始元素下标是[1],它需要移动到[2],
// 一共一共2个
System.arraycopy(arr, 1, arr, 2, 2);
//(3)插入新元素
arr[1] = "赵六";
//(4)遍历显示
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
(7)数组元素的删除
public static void main(String[] args) {
String[] arr = new String[3];
arr[0] = "张三";
arr[1] = "李四";
arr[2] = "王五";
/*
现在需要删除“李四”,我们又不希望数组中间空着元素,该如何处理呢?
* */
//(1)移动元素,需要移动元素的起始下标[2],该元素需要移动到[1],一共需要移动1个元素
System.arraycopy(arr, 2, arr, 1, 1);
//(2)因为数组元素整体往左移动,这里本质上是复制,原来最后一个元素需要置空
arr[2] = null;//使得垃圾回收尽快回收对应对象的内存
}
(8)数组的二分查找
二分查找:对折对折再对折
要求:要求数组元素必须支持比较大小,并且数组中的元素已经按大小排好序
public static void main(String[] args) {
int[] arr = {2, 5, 7, 8, 10, 15, 18, 20, 22, 25, 28};//数组是有序的
int value = 18;
int index = -1;
int left = 0;
int right = arr.length - 1;
int mid = (left + right) / 2;
while (left <= right) {
//找到结束
if (value == arr[mid]) {
index = mid;
break;
}//没找到
else if (value > arr[mid]) {//往右继续查找
// 移动左边界,使得mid往右移动
left = mid + 1;
} else if (value < arr[mid]) {//往左边继续查找
right = mid - 1;
}
mid = (left + right) / 2;
}
if (index == -1) {
System.out.println(value + "不存在");
} else {
System.out.println(value + "的下标是" + index);
}
}
八、数组工具类
Java提供了现成的工具类,方便实现数组的相关操作。
java.util.Arrays数组工具类,提供了很多静态方法来对数组进行操作,而且如下每一个方法都有各种重载形式,以下只列出int[]类型的,其他类型的数组类推:
- static int binarySearch(int[] a, int key) :要求数组有序,在数组中查找key是否存在,如果存在返回第一次找到的下标,不存在返回负数
- static int[] copyOf(int[] original, int newLength) :根据original原数组复制一个长度为newLength的新数组,并返回新数组static int[] copyOfRange(int[] original, int from, int to) :复制original原数组的[from,to)构成新数组,并返回新数组
- static boolean equals(int[] a, int[] a2) :比较两个数组的长度、元素是否完全相同
- static void fill(int[] a, int val) :用val填充整个a数组
- static void fill(int[] a, int fromIndex, int toIndex, int val):将a数组[fromIndex,toIndex)部分填充为val
- static void sort(int[] a) :将a数组按照从小到大进行排序
- static void sort(int[] a, int fromIndex, int toIndex) :将a数组的[fromIndex, toIndex)部分按照升序排列
- static String toString(int[] a) :把a数组的元素,拼接为一个字符串,形式为:[元素1,元素2,元素3。。。]
public static void main(String[] args) {
int[] arr = new int[5];
// 打印数组,输出地址值
System.out.println(arr); // [I@2ac1fdc4
// 数组内容转为字符串
System.out.println("arr数组初始状态:" + Arrays.toString(arr));
Arrays.fill(arr, 3);
System.out.println("arr数组现在状态:" + Arrays.toString(arr));
Random rand = new Random();
for (int i = 0; i < arr.length; i++) {
arr[i] = rand.nextInt(100);//赋值为100以内的随机整数
}
System.out.println("arr数组现在状态:" + Arrays.toString(arr));
int[] arr2 = Arrays.copyOf(arr, 10);
System.out.println("新数组:" + Arrays.toString(arr2));
System.out.println("两个数组的比较结果:" + Arrays.equals(arr, arr2));
Arrays.sort(arr);
System.out.println("arr数组现在状态:" + Arrays.toString(arr));
}
九、二维数组
二维数组:本质上就是元素为一维数组的一个数组。
二维数组的标记:[] []
int[][] arr; //arr是一个二维数组,可以看成元素是int[]一维数组类型的一个数组
二维数组也可以看成一个二维表,行*列组成的二维表,只不过这个二维表,每一行的列数还可能不同。但是每一个单元格中的元素的数据类型是一致的,例如:都是int,都是String等
二维数组的声明与初始化
//推荐
元素的数据类型[][] 二维数组的名称;
//不推荐
元素的数据类型 二维数组名[][];
//不推荐
元素的数据类型[] 二维数组名[];
//声明一个二维数组
int[][] arr;
静态初始化
程序员给定元素初始值,由系统决定数组长度
//声明二维数组
int[][] arr;
//静态初始化
arr = new int[][]{{1,2,3},{4,5,6},{7,8,9}};
//arr = new int[3][3]{{1,2,3},{4,5,6},{7,8,9}};//错误,静态初始化,右边new 数据类型[] 中不能指定长度
//声明并同时初始化
int[][] arr = new int[][]{{1,2,3},{4,5,6},{7,8,9}}; //声明并同时初始化的简化写法
int[][] arr = {{1,2,3},{4,5,6},{7,8,9}};//声明与初始化必须在一句完成
动态初始化
程序员指定数组的长度,后期再赋值(系统会先给定元素默认初始值)
规则二维表:每一行的列数是相同的
//(1)确定行数和列数
元素的数据类型[][] 二维数组名 = new 元素的数据类型[m][n];
m:表示这个二维数组有多少个一维数组。或者说一共二维表有几行
n:表示每一个一维数组的元素有多少个。或者说每一行共有一个单元格
//此时创建完数组,行数、列数确定,而且元素也都有默认值
//(2)再为元素赋新值
二维数组名[行下标][列下标] = 值;
public static void main(String[] args) {
//定义一个二维数组
int[][] arr = new int[3][2];
//定义了一个二维数组arr
//这个二维数组有3个一维数组的元素
//每一个一维数组有2个元素
//输出二维数组名称
System.out.println(arr); //地址值 [[I@175078b
//输出二维数组的第一个元素一维数组的名称
System.out.println(arr[0]); //地址值 [I@42552c
System.out.println(arr[1]); //地址值 [I@e5bbd6
System.out.println(arr[2]); //地址值 [I@8ee016
//输出二维数组的元素
System.out.println(arr[0][0]); //0
System.out.println(arr[0][1]); //0
//...
}
动态初始化(不规则二维表)
不规则二维表:每一行的列数可能不一样
//(1)先确定总行数
元素的数据类型[][] 二维数组名 = new 元素的数据类型[总行数][];
//此时只是确定了总行数,每一行里面现在是null
//(2)再确定每一行的列数,创建每一行的一维数组
二维数组名[行下标] = new 元素的数据类型[该行的总列数];
//此时已经new完的行的元素就有默认值了,没有new的行还是null
//(3)再为元素赋值
二维数组名[行下标][列下标] = 值;
public static void main(String[] args) {
//定义数组
int[][] arr = new int[3][];
System.out.println(arr); //[[I@175078b
System.out.println(arr[1][0]);//NullPointerException
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]); //[I@42552c
System.out.println(arr[1]); //[I@e5bbd6
System.out.println(arr[2]); //[I@8ee016
System.out.println(arr[0][0]); //0
System.out.println(arr[0][1]); //0
//ArrayIndexOutOfBoundsException
//System.out.println(arr[0][2]); //错误
arr[1][0] = 100;
arr[1][2] = 200;
}
二维数组的遍历
for (int i = 0; i < 二维数组名.length; i++) {
for (int j = 0; j < 二维数组名[i].length; j++) {
System.out.print(二维数组名[i][j]);
}
System.out.println();
}
数组操作的常见异常
1 、数组越界异常
public static void main(String[] args) {
int[] arr = {1,2,3};
System.out.println(arr[3]);
}
创建数组,赋值3个元素,数组的索引就是0,1,2,没有3索引,因此我们不能访问数组中不存在的索引,程序运行后,将会抛出 ArrayIndexOutOfBoundsException 数组越界异常。在开发中,数组的越界异常是不能出现的,一旦出现了,就必须要修改我们编写的代码。
2、 数组空指针异常
观察一下代码,运行后会出现什么结果。
public static void main(String[] args) {
//定义数组
int[][] arr = new int[3][];
System.out.println(arr[0][0]);//NullPointerException
}
因为此时数组的每一行还未分配具体存储元素的空间,此时arr[0]是null,此时访问arr[0][0]会抛出
NullPointerException 空指针异常。
例:输出一个如下图形,一共有 n 行,第n 行有 2n-1 个*,
完成方法 public void printStar(int n)的方法体
*
***
*****
*******
*********
public void printStar(int n) {
for (int i = 1; i <= n; i++) {
for (int j = 0; j < n - i; j++) {
System.out.print(" ");
}
for (int j = 0; j < 2 * i - 1; j++) {
System.out.print("*");
}
System.out.println();
}
}