一、IntelliJ IDEA
1. IDEA中的快捷键
常用快捷键 | 介绍 |
---|---|
Ctrl + / | 注释光标所在行代码,会根据当前不同文件类型使用不同的注释符号 |
Ctrl + Shift + / | 代码块注释 |
Ctrl + Space | 基础代码补全,默认在 Windows 系统上被输入法占用,需要进行修改,建议修改为 Ctrl + 逗号 |
Alt + Enter | 根据光标所在问题,提供快速修复选择,光标放在的位置不同提示的结果也不同 |
Ctrl + Y | 删除光标所在行 或 删除选中的行 |
Ctrl + D | 复制光标所在行 或 复制选择内容,并把复制内容插入光标位置下面 |
Ctrl + Shift + Enter | 自动结束代码,行末自动添加分号 |
Ctrl + Z | 撤销 |
Ctrl + Shift + Z | 取消撤销 |
Ctrl + F | 在当前文件进行文本查找 |
Ctrl + Shift + F | 根据输入内容查找整个项目 或 指定目录内文件 |
Ctrl + R | 在当前文件进行文本替换 |
Ctrl + Shift + R | 根据输入内容替换对应内容,范围为整个项目 或 指定目录内文件 |
2. IDEA中的Module (模块)
- 在Eclipse中,有Workspace (工作空间) 和Project (工程) 的概念,而在IDEA中,则只有Project (工程) 和Module (模块) 的概念
- Eclipse中的Workspace相当于IDEA中的Project
- Eclipse中的Project相当于IDEA中的Module
- 在IDEA中,Project是最高级的级别,Module是次级别,一个Project可以有多个Module
- 目录结构详见本地项目D:\Workspaces\IDEA Workspaces\JavaStudy\module01
3. IDEA中的设置
- 设置鼠标滚轮修改字体大小
- 勾选后可以使用Ctrl + 鼠标滚轮快捷键来控制代码字体的大小显示
- 设置鼠标悬浮提示
- 设置自动导包功能
- 设置显示行号和方法间的分隔符
- 设置忽略大小写提示
- 设置取消单行显示tabs
- 设置默认的字体、字体大小和字体行间距
- 字体Consolas,大小20
- 设置项目文件编码
- 设置自动编译
4. IDEA中的Templates (模板)
- Editor - Live Templates (实时模板)
- Editor - General - Postfix Completion (后缀补全)
二、数组
1. 数组的概述
- 定义:数组是多个相同类型数据按照一定顺序排列的集合,并使用一个名字命名,并通过编号的方式对这些数据进行统一管理
- 常见概念:数组名、下标 (或索引)、元素和数组的长度
- 数组本身是引用数据类型,而数组中的元素可以是任何数据类型,包括基本数据类型和引用数据类型
- 创建数组对象会在内存中开辟一整块连续的空间,而数组名中引用的是这块连续空间的
- 数组的长度一旦确定,就不能修改
2. 一维数组的使用
- 一维数组的声明和初始化
- 调用一维数组的指定位置的元素
- 获取一维数组的长度
- 遍历一维数组
- 一维数组元素的默认初始化值
- 一维数组的内存解析
3. 一维数组的声明和初始化
- 静态初始化和动态初始化
-
public class ArrayTest { public static void main(String[] args) { //一维数组的声明和初始化 //静态初始化:数组的初始化和数组元素的赋值同时进行 int[] ids = new int[]{1001, 1002, 1003, 1004}; //动态初始化:数组的初始化和数组元素的赋值分开进行 String[] names = new Striing[5]; } }
4. 调用一维数组的指定位置的元素
- 通过下标 (或索引) 的方式调用,数组的下标 (或索引) 从0开始,到数组长度-1结束
-
public class ArrayTest { public static void main(String[] args) { //调用一维数组的指定位置的元素:通过下标的方式调用 //数组的下标 (或索引) 从0开始,到数组长度-1结束 String[] names = new Striing[5]; names[0] = "王一"; names[1] = "王二"; names[2] = "王三"; names[3] = "王四"; names[4] = "王五"; } }
5. 获取一维数组的长度
- 使用属性length
-
public class ArrayTest { public static void main(String[] args) { String[] names = new Striing[5]; names[0] = "王一"; names[1] = "王二"; names[2] = "王三"; names[3] = "王四"; names[4] = "王五"; //获取一维数组的长度 //属性:length System.out.println(names.length); //输出5 } }
6. 遍历一维数组
-
public class ArrayTest { public static void main(String[] args) { String[] names = new Striing[5]; names[0] = "王一"; names[1] = "王二"; names[2] = "王三"; names[3] = "王四"; names[4] = "王五"; //遍历一维数组 for(int i = 0; i < names.length; i++) { System.out.println(names[i]); //输出王一\n王二\n王三\n王四\n王五 } } }
7. 一维数组元素的默认初始化值
- 数组元素为整型:0
- 数组元素为浮点型:0.0
- 数组元素为char型:0或'\u000',而不是'0'
- 数组元素为boolean型:false
- 数组元素为引用数据类型:null
-
public class ArrayTest { public static void main(String[] args) { //一维数组元素的默认初始化值 int[] arr = new int[4]; for(int i = 0; i < arr.length; i++) { System.out.println(arr[i]); //输出0\n0\n0\n0\n0 } } }
8. 一维数组的内存解析
- 栈 (stack):存放局部变量
- 堆 (heap):存放new出来的结构,即对象和数组
- 方法区 (method area):分为常量池和静态域
-
public class ArrayTest { public static void main(String[] args) { int[] arr1 = new int[]{1, 2, 3}; String[] arr2 = new Striing[4]; arr2[1] = "王二"; arr2[2] = "王三"; arr2 = new String[3]; System.out.println(arr2[1]); //输出null,而不是王二 //垃圾回收器中的引用计数算法 //详解见视频课P146 144. } }
9. 二维数组的理解
- 可以看成是一个一维数组array1又作为另一个一维数组array2的元素而存在
- 其实,从数组的底层运行机制来看,并没有多维数组
10. 二维数组的使用
- 二维数组的声明和初始化
- 调用二维数组的指定位置的元素
- 获取二维数组的长度
- 遍历二维数组
- 二维数组元素的默认初始化值
- 二维数组的内存解析
11. 二维数组的声明和初始化
- 静态初始化和动态初始化
-
public class ArrayTest { public static void main(String[] args) { //二维数组的声明和初始化 //静态初始化 int[][] arr1 = new int[][]{{1, 2, 3}, {4, 5}, {6, 7, 8}}; //动态初始化1 String[][] arr2 = new Striing[3][2]; //3行2列 //动态初始化2 String[][] arr3 = new Striing[3][]; //错误的情况 String[][] arr4 = new Striing[][4]; } }
12. 调用二维数组的指定位置的元素
-
public class ArrayTest { public static void main(String[] args) { int[][] arr1 = new int[][]{{1, 2, 3}, {4, 5}, {6, 7, 8}}; String[][] arr2 = new Striing[3][2]; //3行2列 String[][] arr3 = new Striing[3][]; //调用二维数组的指定位置的元素:同样是通过下标的方式调用 System.out.println(arr1[0][1]); //输出2 System.out.println(arr2[1][1]); //输出null System.out.println(arr3[1][0]); //报错,空指针异常 arr3[1] = new String[4]; System.out.println(arr3[1][0]); //输出null } }
13. 获取二维数组的长度
-
public class ArrayTest { public static void main(String[] args) { int[][] arr1 = new int[][]{{1, 2, 3}, {4, 5}, {6, 7, 8}}; String[][] arr2 = new Striing[3][2]; //3行2列 String[][] arr3 = new Striing[3][]; //获取二维数组的长度 //属性:length System.out.println(arr1.length); //输出3 System.out.println(arr1[1].length); //输出2 System.out.println(arr3[1][0]); //报错,空指针异常 arr3[1] = new String[4]; System.out.println(arr3[1][0]); //输出null } }
14. 遍历二维数组
-
public class ArrayTest { public static void main(String[] args) { int[][] arr1 = new int[][]{{1, 2, 3}, {4, 5}, {6, 7, 8}}; String[][] arr2 = new Striing[3][2]; //3行2列 String[][] arr3 = new Striing[3][]; //遍历二维数组 for(int i = 0; i < arr1.length; i++) { for(int j = 0; j < arr1[i].length; j++) { System.out.print(arr1[i][j]); //输出123\n45\n678 } System.out.println(); } } }
15. 二维数组元素的默认初始化值
- 二维数组分为外层数组的元素和内层数组的元素
-
public class ArrayTest { public static void main(String[] args) { int[][] arr1 = new int[4][3]; //外层元素:arr1[0], arr1[1]等 //内层元素:arr1[0][1], arr1[1][2]等 //二维数组元素的默认初始化值 System.out.println(arr1[0]); //输出地址值 System.out.println(arr1[0][1]); //输出0 String[][] arr2 = new String[4][]; System.out.println(arr1[0]); //输出null System.out.println(arr1[0][1]); //报错,空指针异常 } }
16. 二维数组的内存解析
-
public class ArrayTest { public static void main(String[] args) { int[][] arr1 = new int[4][]; arr1[1] = new int[]{1, 2, 3}; arr1[2] = new int[4]; arr1[2][1] = 30; //详解见视频课P153 151. } }
17. 数组中涉及的常见算法
- 数组元素的赋值 (杨辉三角、回形数等)
- 求数值型数组中元素的最大值、最小值、平均数和总数等
- 数组的复制、反转和查找 (线性查找和二分法查找)
- 数组元素的排序算法
18. 数组元素的赋值 (以回形数为例)
题目
从键盘输入一个整数 (1-20)
则以该数字为矩阵的大小,把1, 2, 3, … n*n 的数字按照顺时针螺旋的形式填入其中
例如:输入数字2,则程序输出:
1 2
4 3输入数字3,则程序输出:
1 2 3
8 9 4
7 6 5输入数字4, 则程序输出:
1 2 3 4
12 13 14 5
11 16 15 6
10 9 8 7
import java.util.Scanner;
public class ArrayAlgorithm01 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int len = scanner.nextInt();
int[][] arr = new int[len][len];
int count = 0; //要显示的数据
int minX = 0; //行的最小下标
int maxX = len - 1; //行的最大下标
int minY = 0; //列的最小下标
int maxY = len - 1; //列的最大下标
while (minX <= maxX) {
for (int y = minY; y <= maxY; y++) {
arr[minX][y] = ++count;
}
minX++;
for (int x = minX; x <= maxX; x++) {
arr[x][maxY] = ++count;
}
maxY--;
for (int y = maxY; y >= minY; y--) {
arr[maxX][y] = ++count;
}
maxX--;
for (int x = maxX; x >= minX; x--) {
arr[x][minY] = ++count;
}
minY++;
}
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < arr[i].length; j++) {
// // 输出错误,因为当+连接符连接int型和char型变量时,char型变量自动提升为其对应的ASCII码,然后与int型变量进行算数相加
// System.out.print(arr[i][j] + '\t');
System.out.print(arr[i][j] + "\t");
}
System.out.println();
}
}
}
19. 数组的复制、反转和查找
-
public class ArrayTest { public static void main(String[] args) { String[] arr1 = new String[]{"A", "B", "C", "D", "E", "F"}; //数组的复制 (区别于数组的赋值:arr2 = arr1) //数组的复制:堆中有2个数组 //数组的赋值:堆中有1个数组 String arr2 = new String[arr1.length]; for(int i = 0; i < arr1.length; i++) { arr2[i] = arr1[i]; } } }
-
public class ArrayTest { public static void main(String[] args) { String[] arr = new String[]{"A", "B", "C", "D", "E", "F"}; //数组的反转 for(int i = 0; i < arr.length / 2; i++) { String temp = arr[i]; arr[i] = arr[arr.length - i - 1]; arr[arr.length - i - 1] = temp; } } }
-
public class ArrayTest { public static void main(String[] args) { String[] arr = new String[]{"A", "B", "C", "D", "E", "F"}; String desy = "C"; boolean isFlag = true; //数组的线性查找 for(int i = 0; i < arr.length; i++) { if(dest.equals(arr[i])) { System.out.println("找到了指定元素,位置为:" + i); isFlag = false; break; } } if(isFlag) { System.out.println("很遗憾没有找到!"); } } }
-
public class ArrayTest { public static void main(String[] args) { // String[] arr = new String[]{"A", "B", "C", "D", "E", "F"}; //不适合二分法查找 int[] arr = new int[]{-98, -34, 2, 34, 54, 66, 79, 105, 210, 333}; int desy = -34; boolean isFlag = true; //数组的二分法查找 //前提:所要查找的数组必须是有序的 int head = 0; //初始的首索引 int end = arr.length - 1; //初始的末索引 while(head <= end) { int middle = (head + end) / 2; if(dest == arr[middle]) { System.out.println("找到了指定元素,位置为:" + i); isFlag = false; break; }else if(dest < arr[middle]) { end = middle - 1; }else { head = middle + 1 } } if(isFlag) { System.out.println("很遗憾没有找到!"); } } }
20. 数组元素的排序算法
- 排序的目的是快速查找
- 衡量排序算法的优劣
- 时间复杂度:分析关键字的比较次数和记录的移动次数
- 空间复杂度:分析排序算法中需要多少辅助内存
- 稳定性:若两个记录A和B的关键字值相等,但排序后A和B的先后次序保持不变,则称这种排序算法是稳定的
- 排序算法的分类
- 内部排序:整个排序过程不需要借助外部存储器 (如磁盘等),所有排序操作都在内存中完成
- 外部排序:参与排序的数据非常多,数据量非常大,计算机无法把整个排序过程放在内存中完成,必须借助外部存储器,外部排序最常见的是多路归并排序,可以认为外部排序是由多次内部排序组成
- 十种内部排序算法
- 选择排序:直接选择排序、堆排序
- 交换排序:冒泡排序、快速排序
- 插入排序:直接插入排序、折半插入排序、Shell排序
- 归并排序
- 桶式排序
- 基数排序
21. 数组的冒泡排序
- 排序思想
- 比较相邻的元素,如果第一个比第二个大 (升序),就交换它们两个
- 对每一对相邻元素做同样的工作,从开始第一对到结尾最后一对,这步做完后,最后的元素将会是最大的数
- 针对所有的元素重复以上步骤,除了最后一个
- 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较为止
- 具体过程
- 若序列中有n个元素,通常进行n-1趟。第1趟,针对第R[1]至R[n]个元素进行。第2趟,针对第R[1]至R[n-1]个元素进行。……第n-1趟,针对第R[1]至R[2]个元素进行。
- 每一趟进行的过程:从第一个元素开始,比较两个相邻的元素,若相邻的元素的相对位置不正确,则进行交换,否则继续比较下面两个相邻的元素
-
import java.util.Arrays; public class BubbleSortTest { public static void main(String[] args) { int[] arr = new int[]{43, 32, 76, -98, 0, 64, 33, -21, 32, 99}; for (int i = 0; i < 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; } } } //输出[-98, -21, 0, 32, 32, 33, 43, 64, 76, 99] System.out.println(Arrays.toString(arr)); } }
22. 数组的快速排序
- 排序思想
- 从数列中挑出一个元素,称为”基准“
- 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆放在基准后面 (相同的数可以摆放到任一边),在这个分区结束之后,该基准就处于数列的中间位置,这个成为分区操作
- 递归地把小于基准值的元素的子数列和大于基准值的元素的子数列排序
- 递归的最底部情形,是数列的大小是0或1,也就是永远都已经被排序好了,虽然一直递归下去,但是这个算法总会结束,因为在每次的迭代中,它至少会把一个元素摆放到它最后的位置去
23. 排序算法的横向对比
24. Arrays工具类的使用
Java Arrays工具类 (biancheng.net)http://c.biancheng.net/view/5885.html
常用Arrays工具类 | 介绍 |
---|---|
boolean equals(int[] a, int[] b) | 判断两个数组是否相等 |
String toString(int[] a) | 输出数组信息 |
void fill(int[] a, int val) | 将指定值填充到数组中 |
void sort(int[] a) | 对数组进行排序 |
int binarySearch(int[] a, int key) | 对排序后的数组进行二分法检索指定的值 |
public class ArraysTest {
public static void main(String[] args) {
//boolean equals(int[] a, int[] b):判断两个数组是否相等
int[] arr1 = new int[]{1, 2, 3, 4, 5};
int[] arr2 = new int[]{1, 3, 2, 4, 5};
boolean isEquals = Arrays.equals(arr1, arr2);
System.out.println(isEquals); //输出false
//String toString(int[] a):输出数组信息
System.out.println(Arrays.toString(arr1)); //输出[1, 2, 3, 4, 5]
//void fill(int[] a, int val):将指定值填充到数组中
Arrays.fill(arr1, 10);
System.out.println(Arrays.toString(arr1)); //输出[10, 10, 10, 10, 10]
Arrays.fill(arr1, 2, 4, 6); //将arr1的第3个元素 (包括) 到第5个元素 (不包括) 赋值为6
System.out.println(Arrays.toString(arr1)); //输出[10, 10, 6, 6, 10]
//void sort(int[] a):对数组进行排序
Arrays.sort(arr2);
System.out.println(Arrays.toString(arr2)); //输出[1, 2, 3, 4, 5]
//int binarySearch(int[] a, int key):对排序后的数组进行二分法检索指定的值
int arr3 = new int[]{-98, -34, 2, 34, 54, 66, 79, 105, 210, 333};
int index = Arrays.binarySearch(arr3, 210);
if(index >= 0) {
System.out.println(index); //输出8
}else {
System.out.println("未找到!");
}
}
}
25. 数组使用中的常见异常
- 数组下标越界异常:ArrayIndexOutOfBoundsException
- 空指针异常:NullPointerException
-
public class ArrayTest { public static void main(String[] args) { //数组下标越界异常:ArrayIndexOutOfBoundsException int[] arr1 = new int[]{1, 2, 3, 4, 5}; //情况1 for(int i = 0; i <= arr1.length; i++) { System.out.println(arr1[i]); } //情况2 System.out.println(arr1[-2]); //空指针异常:NullPointerException //情况1 int[] arr2 = new int[]{1, 2, 3}; arr2 = null; System.out.println(arr2[0]); //情况2 int[][] arr3 = new int[4][]; System.out.println(arr3[0][0]); //情况3 String[] arr4 = new String[]{"AA", "BB", "CC"}; arr4[0] = null; System.out.println(arr4[0].toString); } }
26. 对象数组
-
//生成随机数:Math.random() //系统随机选取大于等于0.0且小于1.0的数,返回值类型为double //产生一个[0,1)之间的随机数 Math.random(); //产生一个[m,n)之间的随机整数 (int)(Math.random()*(n - m) + m); //产生一个[m,n]之间的随机整数。 (int)(Math.random()*(n - m + 1) + m);
-
/* 题目 定义类Student,包含3个属性:学号number (int),年级grade (int),成绩score (int) 创建20个学生对象,学号1-20,年级和成绩都随机确定 问题1:打印出3年级的学生信息 问题2:使用冒泡排序按学生成绩排序,并遍历所有学生的信息 提示: 1. 生成随机数:Math.random(),返回值类型为double 2. 四舍五入取整:Math.round(double d),返回值类型为long */ public class ObjectArrayTest { public static void main(String[] args) { //声明Student类型的数组 Student[] stus = new Student[20]; //为Student类型的数组的元素赋值 for (int i = 0; i < stus.length; i++) { stus[i] = new Student();//注意!!! //学号,[11, 30] stus[i].number = i + 11; //年级,[1, 6] stus[i].grade = (int) (Math.random() * (6 - 1 + 1) + 1); //成绩,[0, 100] stus[i].score = (int) (Math.random() * (100 - 0 + 1) + 0); } //声明Student类型的变量 Student test = new Student(); //遍历所有学生的信息 test.printAllInfo(stus); System.out.println("******************************"); //问题1:打印出3年级的学生信息 test.searchGrade(stus, 3); System.out.println("******************************"); //问题2:使用冒泡排序按学生成绩排序,并遍历所有学生的信息 test.sortByScore(stus); test.printAllInfo(stus); System.out.println("******************************"); } } class Student { int number; //学号 int grade; //年级 int score; //成绩 /** * 显示学生的信息 * @return 学生的信息 */ public String info() { return "学号:" + number + ",年级:" + grade + ",成绩:" + score; } /** * 遍历所有学生的信息 * @param stus 要遍历的数组 */ public void printAllInfo(Student[] stus) { for (int i = 0; i < stus.length; i++) { System.out.println(stus[i].info()); } } /** * 打印出指定年级的学生信息 * @param stus 要遍历的数组 * @param assignedGrade 指定的年级 */ public void searchGrade(Student[] stus, int assignedGrade) { for (int i = 0; i < stus.length; i++) { if (stus[i].grade == assignedGrade) { System.out.println(stus[i].info()); } } } /** * 使用冒泡排序按学生成绩排序 * @param stus 要遍历的数组 */ public void sortByScore(Student[] stus) { for (int i = 0; i < stus.length - 1; i++) { for (int j = 0; j < stus.length - 1 - i; j++) { if (stus[j].score > stus[j + 1].score) { //交换的是数组的元素,是Student对象!!! Student temp = stus[j]; stus[j] = stus[j + 1]; stus[j + 1] = temp; } } } } }
- 对象数组的内存解析,详解见视频课P202 200.
- 引用数据类型的变量,只可能存储两类值:null或地址值 (含变量的类型)