Java零基础教学文档第一篇:JavaSE(4)

接上期后续
本期继续分享尚未结束的JavaSE章节
JavaSE属于初入门阶段,内容很多~
但很基础,
大家需保持耐心,慢慢的学~
争取你们学习的速度!
跟上我更新的速度哦~
Java零基础教学文档第一篇:JavaSE(4)_第1张图片

今日新篇章

数组

【主要内容】

  1. 数组的定义和特征

  2. 添加和获取元素操作

  3. 增强for循环

  4. 数组内存分配

  5. 常见数组异常

  6. 数组的常见操作

  7. 在数组中删除元素

  8. 在数组中插入元素

  9. 方法的可变参数

  10. 二维数组

【学习目标】
Java零基础教学文档第一篇:JavaSE(4)_第2张图片

1. 数组概述和特点

1.1 数组的概念

数组概念:数组就是一种能够存放相同数据类型的有序集合。(通俗来讲数组其实就是一个容器)。

1.2 数组的创建

1.2.1 动态创建数组

语法格式:数据类型[] 数组名 = new 数据类型[数组长度];

  数据类型  数组名[] = new 数据类型[数组长度];

注意:数组的声明建议大家使用第一种方式,避免数组名混淆。

【示例】

public static void main(String[] args) {

// 创建3个空间的int类型数组

int[] arr1 = new int[3];

// 创建5个空间的String类型数组

String[] arr2 = new String[5];

}

1.2.2 静态创建数组

语法格式:数据类型[] 数组名 = new 数据类型[]{元素1, 元素2, 元素3,…};

注意:使用静态的方式来创建数组,数组的长度由元素个数来确定。

【示例】

public static void main(String[] args) {

// 创建指定内容的int类型数组

int[] arr1 = new int[]{1, 2, 3, 4, 5};

// 创建指定内容的String类型数组

String[] arr2 = new String[]{“11”, “22”, “33”, “44”};

}

除了用new关键字来产生数组以外,还可以直接在定义数组的同时就为数组元素分配空间并赋值。

语法格式:数据类型[] 数组名 = {元素1, 元素2, 元素3,…};

【示例】

public static void main(String[] args) {

// 创建指定内容的int类型数组

int[] arr1 = {1, 2, 3, 4, 5};

// 创建指定内容的String类型数组

String[] arr2 = {“11”, “22”, “33”, “44”};

}

注意事项:

1、 数组类型可以是任何数据类型,包括基本类型和引用类型,例如String[]和float[]。

2、 数组中存放元素的类型,必须是创建数组时指定的类型,不允许出现混合类型。

3、 创建一个数组时,必须指定数组长度,创建成功数组的大小就不可以改变了。

1.3 数组的基本操作

数组中的元素,我们可以通过下标(索引)来访问,索引从0开始。

数组索引的取值范围为:[0,数组长度-1],如果超出索引范围来操作数组元素,会抛出ArrayIndexOutOfBoundsException异常。

Ø 数组的赋值操作

【示例】

public static void main(String[] args) {

// 初始化5个空间的int类型数组

int[] arr = new int[5];

// 添加元素

arr[0] = 11; // 给第一个元素赋值

arr[1] = 22; // 给第二个元素赋值

arr[2] = 22; // 给第三个元素赋值

// 修改第二个元素的值

arr[1] = 222;

}

Ø 数组的取值操作

【示例】

public static void main(String[] args) {

// 创建指定内容的int类型数组

int[] arr = {1, 2, 3, 4, 5};

// 获取元素

int num1 = arr[0]; // 获取第一个元素

int num2 = arr[1]; // 获取第二个元素

int num3 = arr[2]; // 获取第三个元素

}

Ø 获取数组的长度

【示例】

public static void main(String[] args) {

// 创建指定内容的int类型数组

int[] arr = {1, 2, 3, 4, 5};

// 通过length属性,来获取数组的长度

System.out.println(arr.length); // 输出:5

}

注意事项:

  1. 通过length属性获取到的数组长度和开辟的内存空间的长度一致。

  2. 某些情况下,实际添加元素的个数(不算默认值元素),可能会小于了数组的长度。

Ø 通过for循环遍历数组

【示例】

public static void main(String[] args) {

// 创建指定内容的int类型数组

int[] arr = {1, 2, 3, 4, 5};

// 通过length属性,获取数组元素的个数

int length = arr.length;

// 通过for循环,遍历数组所有元素

for(int i = 0; i < length; i++) {

// 通过下标获取数组中的元素

System.out.println(“第”+(i+1)+“个元素值:” + arr[i]);

}

}

Ø 通过索引操作数组原理

因为数组的内存空间是连续的,我们通过数组的首地址+索引就能快速的找到数组对应的元素值,从而得出数组的优点:查找快。

索引操作数组原理:数组首地址 + 存放数据的字节数*索引。

【随堂练习】

1、 获取10个学生的成绩,然后保存在数组中,最后计算学生的总分和平均分。

1.4 数组的默认初始化

数组是引用类型,只要数组一经分配空间,那么数组中的每个元素都会被隐式的设置一个默认值。

以下是针对不同数据类型的默认值:

1、整数类型(byte、short、int、long)的基本类型变量的默认值为0。

2、浮点型(float、double)的基本类型变量的默认值为0.0。

3、字符型(char)的基本类型变量的默认为 “\u0000”。

4、布尔性的基本类型变量的默认值为 false。

5、引用类型的变量是默认值为 null(null就是空对象)。

2. JVM中的堆和栈

2.1 堆和栈的概述

JVM是基于堆栈的虚拟机,堆栈是一种数据结构,是用来存储数据的。对于一个Java程序来说,它的运行就是通过对堆栈的操作来完成的。

【栈内存stack】

栈内存:用来存放局部变量。

当在一段代码块定义一个变量时,Java就在栈中为这个变量分配内存空间,当超过变量的作用域后,Java会自动释放掉为该变量所分配的内存空间,该内存空间可以立即被另作他用。

栈内存特点:

  1. 栈内存存储特性为:“先进后出,后进先出”。

  2. 栈是一个连续的内存空间,由系统自动分配,速度快!

  3. 虚拟机会为每个线程创建一个栈,用于存放该线程执行方法的信息。

【堆内存heap】

堆内存:用来存储创建好的对象和数组(数组也是对象)

在堆中产生了一个数组或对象后,还可以在栈中定义一个特殊的变量,让栈中这个变量的取值等于数组或对象在堆内存中的首地址,栈中的这个变量就成了数组或对象的引用变量。
引用变量就相当于是为数组或对象起的一个名称,以后就可以在程序中使用栈中的引用变量来访问堆中的数组或对象。

数组和对象在没有引用变量指向它的时候,数组或对象本身占用的堆内存就变成垃圾,不能再被使用,然后由Java虚拟机的自动垃圾回收器来管理释放该内存。

堆内存特点:

  1. 虚拟机中只有一个堆,被所有的线程共享。

  2. 堆是一个不连续的内存空间,分配灵活,但速度慢!

【思考一】

public static void main(String[] args) {

int[] arr1 = {1, 2, 3, 4, 5};

int[] arr2 = arr1;

arr2[2] = 33;

System.out.println(arr1[2]); // 输出结果为???

}

【思考二】

public static void main(String[] args) {

int[] arr1 = {1, 2, 3};

int[] arr2 = arr1;

arr1 = null;

System.out.println(arr1[2]); // 输出结果为???

System.out.println(arr2[2]); // 输出结果为???

}

2.2 数据类型传递

java中没有指针(所以没有引用传递),方法中所有参数都是值传递, 传递的是值的副本。

2.2.1 基本数据类型传递

实际参数把它的值传递给对应的形式参数,方法执行中形式参数值的改变不影响实际参数的值。

【示例】交换两个变量的值

public class ObjectDemo {

public static void main(String[] args) {

int a = 10, b = 20;

// 输出:交换之前:a:10 b: 20

System.out.println(“交换之前:a:” + a + " b: " + b);

// 交换变量a和b的值

swap(a, b);

// 输出:交换之后:a:10 b: 20

System.out.println(“交换之后:a:” + a + " b: " + b);

}

// 交换两个变量的值

public static void swap(int num1, int num2) {

int temp = num1;

num1 = num2;

num2 = temp;

}

}

总结: 方法调用时,实参把值拷贝给形参,在函数中交换的是那份拷贝的值,而不是实参数据本身。所以方法内部修改形参的值, 在方法外部的实参不会跟着形参一起改变。

2.2.2 引用数据类型传递

实际参数把它的值传递给对应的形式参数,方法执行中形式参数的改变直接影响实际参数。

【示例】交换两个变量的值

public class Test {
public static void main(String[] args) {
// 定义一个数组,用于交换两个数组元素的值
int[] arr = {11, 22};
// 交换之前,输出数组元素值
System.out.println("交换之前:arr[0] = " + arr[0] + " arr[1] = " + arr[1]);
// 调用方法,执行交换元素值的操作
swap(arr);
// 交换之后,输出数组元素值
System.out.println("交换之后:arr[0] = " + arr[0] + " arr[1] = " + arr[1]);
}
// 交换arr数组索引0和索引1的元素值
public static void swap(int[] arr) {
int temp = arr[0];
arr[0] = arr[1];
arr[1] = temp;
}
}

方法调用时,实参存放的地址被传递给方法中相对应的形参,因此形参和实参都指向堆中同一块地址,在方法执行中,对形参的操作实际上就是对实参的操作。所以在方法操作形式参数,那么方法外部的实参也会跟着一起改变。

3. 数组常见操作

3.1 获取数组的最值

需求:获取数组{5, 12, 90, 18, 77, 76, 45, 28, 59, 72}的最大值,也就是该数组的元素90。

实现:先假设第一个元素就是最大值,并赋值给maxValue变量保存,然后依次取出数组中的元素和maxValue作比较,如果取出元素大于maxValue,那么把该元素设置为最大值。

【示例】

/**

  • 获取数组的最大值

  • @param arr 需要查询的数组

  • @return 返回查询到的最大值

*/

public static int maxElement(int[] arr) {

// 假设第一个元素的值就是最大值

int max = arr[0];

// 遍历数组元素,依次和假设的最大值作比较

for(int i = 1; i < arr.length; i++) {

// 取出每个元素的值和value作比较

if(arr[i] > max) {

// 推翻假设,更新最大值

max = arr[i];

}

}

return max;

}

思考:获取数组中最大值的索引,我们该怎么去做呢?

3.2 通过值获取索引

需求:获取元素59在数组{5, 12, 90, 18, 77, 76, 45, 28, 59, 72}中的索引。

实现:通过for循环来遍历数组,把需要查询的值和数组中的元素一一做比较,如果需要查询的值和某个元素相等,则返回索引值并结束方法。如果循环完毕都没查找到,则返回-1。

【示例】

/**

  • 根据value值,获取它在数组中的索引位置

  • @param arr 需要查询的数组

  • @param value 需要判断的值

  • @return 找到,则返回对应的索引;未找到,则返回-1

*/

public static int search(int[] arr, int value) {

// 遍历数组,把数组中的元素依次和value作比较

for(int i = 0; i < arr.length; i++) {

// 取出元素值和value作比较

if(arr[i] == value) {

return i; // 找到相同的元素,返回索引位置

}

}

// 未找到,则返回-1

return -1;

}

3.3 数组元素的反转

需求:将数组元素反转,原数组{5, 12, 90, 18, 77, 76, 45, 28, 59, 72},反转后为{72, 59, 28, 45, 76, 77, 18, 90, 12, 5}。

实现(一):引入一个外部数组变量,用于保存反序后的数组,然后把原数组中的元素倒序保存于新创建的数组中。

【示例一】

/**

  • 将数组反序输出

  • @param arr 需要反序的数组

  • @return 返回反序后的数组

*/

public static int[] reverseOrderArray(int[] arr) {

// 定义一个反序后的数组

int[] desArr = new int[arr.length];

// 把原数组元素倒序遍历

for(int i = 0; i < arr.length; i++) {

// 把arr的第i个元素赋值给desArr的最后第i个元素中

desArr[arr.length - 1 - i] = arr[i];

}

// 返回倒序后的数组

return desArr;

}

实现(二):直接对数组中的元素进行收尾交换。

【示例二】

/**

  • 将数组反序输出

  • @param arr 需要反序的数组

*/

public static void reverseOrderArray(int[] arr) {

// 把原数组元素倒序遍历

for(int i = 0; i < arr.length/2; i++) {

// 把数组中的元素收尾交换

int temp = arr[i];

arr[i] = arr[arr.length - i - 1];

arr[arr.length - i - 1] = temp;

}

}

3.4 数组元素的删除
需求:删除数组{5, 12, 90, 18, 77, 76, 45, 28, 59, 72}索引为2的元素,删除后:{5, 12, 18, 77, 76, 45, 28, 59, 72,0}。

实现:把数组索引2以后的元素向前移动一位,最后把数组的最后一个元素的值设置为默认值(整数类型的默认值为0)。

【示例】

/**

  • 根据索引删除数组中的元素

  • @param arr 需要删除元素的数组

  • @param index 需要删除数组元素的索引

*/

public static void deleteElement(int[] arr, int index) {

// 第一步:判断索引是否合法

if(index < 0 || index >= arr.length) {

System.out.println(“索引越界”);

return; // 索引不合法,直接结束方法

}

// 第二步:从index个元素开始,将后一个元素向前移动一位

for(int i = index; i < arr.length - 1; i++) {

// 将后一个元素向前移动一位

arr[i] = arr[i + 1];

}

// 第三步:将最后一个元素设置为默认值

arr[arr.length - 1] = 0;

}

数组的缺点:因为数组是连续的内存空间,当数组进行删除和插入操作的时候,效率相对低下!

3.5 数组元素的插入

需求:在数组{5, 12, 90, 18, 77, 76, 45, 28, 59, 72}索引为2的位置插入元素222,插入后:{5, 12, 222, 90, 18, 77, 76, 45, 28, 59, 72}。

实现:首先准备给数组扩容,然后把插入索引位置之后的元素往后移动一位,最后在插入索引的位置插入元素。

【示例】

/**

  • 在数组指定位置插入元素

  • @param arr 需要插入元素的数组

  • @param index 插入元素的位置

  • @param value 需要插入的元素值

  • @return 返回插入元素成功的数组

*/

public static int[] insertElement(int[] arr, int index, int value) {

// 第一步:判断索引是否合法

if(index < 0 || index >= arr.length) {

System.out.println(“索引越界”);

// 抛出一个索引越界异常(异常第六章学习)。

throw new ArrayIndexOutOfBoundsException(“索引越界:”+index);

}

// 第二步:给数组扩容

// 定义一个变量,用于保存实际存放元素的个数

int size = 10;

// 如果数组的空间长度等于实际存放元素的个数,则执行扩容操作
if (arr.length == size) {
// 创建一个更大的数组

 int[] newArr = new int[arr.length + 1];

 // 把原数组中的数据,复制给新创建的数组

 for (int i = 0; i < arr.length; i++) {

 newArr[i] = arr[i];// 拷贝操作

 }

 // 让arr指向堆里面的newArr数组

 arr = newArr;   

}

// 第三步:插入索引位置之后的元素往后移动一位

for (int i = arr.length - 2; i >= 2; i–) {

arr[i + 1] = arr[i];

}

// 第四步:给index索引位置赋值

arr[index] = value;

// 返回插入元素成功的数组

return arr;

}

4. 数组知识点补充

4.1 for-each循环遍历

for-each是java SE 5.0增加了一种功能很强的循环结构,可以用来一次处理数组中的每个元素(其他类型的元素集合亦可)而不必为指定下标值而分心。

这种增强的for-each循环的语法格式为:

for (type element : array) {

System.out.println(element); // 输出数组中的每一个元素

}

【示例】

public static void main(String[] args) {

int[] arr = {1, 2, 3, 4, 5, 6};

// 通过增强for循环遍历数组

for(int element : arr) {

// 依次输出数组的元素

System.out.println(element);

}

}

优点:语法简洁,比普通for循环的效率高。

缺点:相比较普通for循环,增强for循环无法获得数组下标。

4.2 main方法的形参【了解】

参数String[] args的作用就是可以在main方法运行前将参数传入main方法中。

Ø 从控制台,输入编译执行命令时传参数

例如下面代码:
Java零基础教学文档第一篇:JavaSE(4)_第3张图片

但是此时args[]并没有赋值,我们需要从控制台命令行进行赋值,就像这样:
Java零基础教学文档第一篇:JavaSE(4)_第4张图片

Ø 在IDEA使用String[] args参数

在工具栏,选中“Edit Configurations…”
Java零基础教学文档第一篇:JavaSE(4)_第5张图片

出现以下窗口,在“Program arguments:”窗口中输入参数,最后点击Apply保存即可。
Java零基础教学文档第一篇:JavaSE(4)_第6张图片

4.3 方法的可变参数

可变参数:适用于参数个数不确定,但类型确定的情况,java把可变参数当做数组处理。

我们使用…表示可变长参数,…位于变量类型和变量名之间,前后有无空格都可以。

【示例】
Java零基础教学文档第一篇:JavaSE(4)_第7张图片

可变参数的特点:

1、 一个方法中可变参数最多只能有一个,并且只能出现在参数列表的最后面。

2、 调用可变参数的方法时可以给出任意个参数,在方法体中以数组的形式访问可变参数。

5. Arrays工具类

Arrays用于操作数组工具类,里面定义了常见操作数组的静态方法。

注意:要使用Arrays工具类,必须导入Arrays工具类。

import java.util.Arrays;

5.1 toString方法

public static String toString(Type[] arr),返回指定数组内容的字符串表示形式。

【示例】

int[] arr = {3, 5, 1, 7, 6, 2, 4};

// 把数组转化为字符串输出

System.out.println(Arrays.toString(arr)); // 输出:[1, 2, 3, 4, 5, 6]

5.2 equals判断

public static boolean equals(Type[] a1, Type[] a2), 判断两个数组中的内容是否相同。

【示例】

int[] arr1 = {3, 5, 1, 7, 6, 2, 4};

int[] arr2 = {3, 5, 1, 7, 6, 2};

// 判断两个数组的内容是否相同

boolean flag = Arrays.equals(arr1, arr2);

System.out.println(flag); // 输出:false

5.3 sort排序

public static void sort(Type[] arr) ,对数组中的内容进行升序排序。

【示例】

int[] arr = {3, 5, 1, 7, 6, 2, 4};

// 对数组中的内容进行升序排序

Arrays.sort(arr);

System.out.println(Arrays.toString(arr)); // 输出:[1, 2, 3, 4, 5, 6, 7]

5.4 二分法查找

public static int binarySearch(Type[] arr, Type key),查找key在数组中的索引位置。如果找到,则返回索引位置;如果没找到,则返回一个负数。

注意:在调用此调用之前,必须先对数组进行排序。

【示例】

// 排序好的数组

int[] arr = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};

// 查找6在数组中的索引位置

int index = Arrays.binarySearch(arr, 6);

System.out.println(index); // 输出:6

// 查找18在数组中的索引位置

index = Arrays.binarySearch(arr, 18);

System.out.println(index); // 输出:-11,证明没找到

5.5 fill填充数组

public static void fill(Type[] a, Type val),给数组填充指定内容。

【示例】

int[] arr = new int[5];

Arrays.fill(arr, 89);

System.out.println(Arrays.toString(arr)); // 输出:[89, 89, 89, 89, 89]

5.6 数组拷贝

public static Type[] copyOf(Type[] original, Type newLength),从数组的第一个元素开始拷贝,拷贝指定长度的数组,拷贝完成返回一个新的数组。

【示例】

int[] arr = {1, 2, 3, 4, 5};

int[] newArr = Arrays.copyOf(arr, 3);

System.out.println(Arrays.toString(newArr)); // 输出:[1, 2, 3]

public static Type[] copyOfRange(Type[] original, int from, int to),从指定范围拷贝数组,拷贝完成返回一个新的数组。

【示例】

int[] arr = {1, 2, 3, 4, 5, 6, 7, 8};

int[] newArr = Arrays.copyOfRange(arr, 2, 5);

System.out.println(Arrays.toString(newArr)); // 输出:[3, 4, 5]

6. 二维数组【了解】
6.1 二维数组的定义

二维数组本质上是以数组作为数组元素的数组,即“数组的数组”。(通俗来讲二维数组的每一个元素又是一个一维数组)

6.2 二维数组的创建

Ø 创建格式一,创建等长的二维数组

语法语法:数据类型[][] 数组名 = new 数据类型[m][n];

m: 表示这个二维数组的长度。
n: 表示二维数组中每个元素的长度。

注意以下格式也可以表示二维数组:

数据类型 数组名[][] = new 数据类型[m][n];

数据类型[] 数组名[] = new 数据类型[m][n];

Ø 创建格式二,创建不定长二维数组

语法格式:数据类型[][] 数组名 = new 数据类型[m][];

m: 表示这个二维数组的长度。
二维数组中元素的长度没有给出,可以动态的给。

Ø 创建格式三,创建静态二维维数组

基本格式

数据类型[][] 数组名 = new 数据类型[][]{{元素1,元素2…},{元素1,元素2…},{元素1,元素2…}};

简化格式

数据类型[][] 数组名 = {{元素1,元素2…},{元素1,元素2…},{元素1,元素2…}};

【随堂练习】

1.有三个班级,第一个班级3个学生,第二个班级4个学生,第三个班级5个学生。要求通过键盘录入三个班级学生的成绩,并计算每个班级学生的的平均成绩。

7. debug调试基础
7.1 debug的概述

debug用来追踪代码的运行流程,通常在程序运行过程中出现异常,启用debug模式可以分析定位异常发生的位置,以及在运行过程中参数的变化。

7.2 debug的用法

第一步:在可能会出现问题的位置打断点,也就是在行号右侧单击打断点
Java零基础教学文档第一篇:JavaSE(4)_第8张图片

第二步:通过IDEA进入debug调试,例如:在main方法左侧行号位置,然后选择“Debug Xxx.main()”
Java零基础教学文档第一篇:JavaSE(4)_第9张图片

进入debug调试后,代码直接在“断点”位置停止,此时debug窗口分两部分:

a)在“Frames”窗口,显示当前代码的停留位置(类、方法、行号)

b)在“Variabls”窗口,显示当前已经存在的变量(可以查看变量的值)
Java零基础教学文档第一篇:JavaSE(4)_第10张图片

第三步:通过debug调试来控制代码的执行

F8:直接执行下一行代码。

F7:如果当前行代码有调用方法,则进入该方法

Shift+F8:结束当前方法,回到方法的调用位置

Alt+F9:执行到下一个断点位置
Java零基础教学文档第一篇:JavaSE(4)_第11张图片

第四步:结束debug调试,首先取消断点(单击断点位置),然后结束程序,最后关闭debug窗口。

你可能感兴趣的:(Java零基础教学文档,java,开发语言)