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

接上期后续
本期继续分享尚未结束的JavaSE章节
JavaSE属于初入门阶段,内容很多~
但很基础,
大家需保持耐心,慢慢的学~
争取你们学习的速度!
跟上我更新的速度哦~
在这里插入图片描述

今日新篇章

数组

【主要内容】

  1. 数组的定义和特征

  2. 添加和获取元素操作

  3. 增强for循环

  4. 数组内存分配

  5. 常见数组异常

  6. 数组的常见操作

  7. 在数组中删除元素

  8. 在数组中插入元素

  9. 方法的可变参数

  10. 二维数组

【学习目标】
在这里插入图片描述

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方法中。

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

例如下面代码:
在这里插入图片描述

但是此时args[]并没有赋值,我们需要从控制台命令行进行赋值,就像这样:
在这里插入图片描述

Ø 在IDEA使用String[] args参数

在工具栏,选中“Edit Configurations…”
在这里插入图片描述

出现以下窗口,在“Program arguments:”窗口中输入参数,最后点击Apply保存即可。
在这里插入图片描述

4.3 方法的可变参数

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

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

【示例】
在这里插入图片描述

可变参数的特点:

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的用法

第一步:在可能会出现问题的位置打断点,也就是在行号右侧单击打断点
在这里插入图片描述

第二步:通过IDEA进入debug调试,例如:在main方法左侧行号位置,然后选择“Debug Xxx.main()”
在这里插入图片描述

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

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

b)在“Variabls”窗口,显示当前已经存在的变量(可以查看变量的值)
在这里插入图片描述

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

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

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

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

Alt+F9:执行到下一个断点位置
在这里插入图片描述

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

  • 21
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值