IDE相关
vsCode调试Java输出中文乱码——解决方法
1、切换VS Code 的终端为 CMD(vsCode默认使用的PowerShell 有时兼容性差)
打开 VS Code 设置(Ctrl+,),搜索terminal.integrated.defaultProfile.windows;
把默认终端从PowerShell改成Command Prompt(CMD);
2. 修改 settings.json(VS Code 终端编码)
按 Ctrl+, 打开设置,搜索 encoding
找到 Files: Encoding,设置为 UTF-8
搜索 terminal.integrated.defaultProfile.windows,设置为 Command Prompt(CMD)
搜索 terminal.integrated.profiles.windows,添加 CMD 配置:
1 | "terminal.integrated.profiles.windows": { |
关闭当前终端
再按F5运行代码,乱码必解决。
Java 代码逻辑优化
执行效率
1、开发中,如果既可以使用条件运算符,又可以使用if-else,推荐使用条件运算符。因为执行效率稍高。
- 条件运算符格式:
1 | (条件表达式)? 表达式1:表达式2 |
- 说明:条件表达式是boolean类型的结果,根据boolean的值选择表达式1或表达式2
2、逻辑运算符
区分“&”和“&&”:
相同点:如果符号左边是true,则二者都执行符号右边的操作
不同点:& : 如果符号左边是false,则继续执行符号右边的操作
&& :如果符号左边是false,则不再继续执行符号右边的操作
- 建议:开发中,推荐使用 &&
区分“|”和“||”:
相同点:如果符号左边是false,则二者都执行符号右边的操作
不同点:| : 如果符号左边是true,则继续执行符号右边的操作
|| :如果符号左边是true,则不再继续执行符号右边的操作
建议:开发中,推荐使用 ||
3、if-else语句与switch-case语句比较
- 结论:凡是使用switch-case的结构都可以转换为if-else结构。反之,不成立。
- 开发经验:如果既可以使用switch-case,又可以使用if-else,建议使用switch-case。因为效率稍高。
- 细节对比:
- if-else语句优势
- if语句的条件是一个布尔类型值,if条件表达式为true则进入分支,可以用于范围的判断,也可以用于等值的判断,
使用范围更广。 - switch语句的条件是一个常量值(byte,short,int,char,枚举,String),只能判断某个变量或表达式的结果是否等于某个常量值,
使用场景较狭窄。
- if语句的条件是一个布尔类型值,if条件表达式为true则进入分支,可以用于范围的判断,也可以用于等值的判断,
- switch语句优势
- 当条件是判断某个变量或表达式是否等于某个固定的常量值时,使用if和switch都可以,习惯上使用switch更多。因为
效率稍高。当条件是区间范围的判断时,只能使用if语句。 - 使用switch可以利用
穿透性,同时执行多个分支,而if…else没有穿透性。
- 当条件是判断某个变量或表达式是否等于某个固定的常量值时,使用if和switch都可以,习惯上使用switch更多。因为
- if-else语句优势
Java 语言规则特别注意的地方
1、boolean类型数据只有两个值:true、false,无其它。
数组知识点总结
数组定义
数组(Array),是多个相同类型数据按一定顺序排列的集合,并使用一个名字命名,并通过编号的方式对这些数据进行统一管理。
数组中的概念
- 数组名
- 下标(或索引)
- 元素
- 数组的长度
数组的特点
- 数组本身是
引用数据类型,而数组中的元素可以是任何数据类型,包括基本数据类型和引用数据类型。 - 创建数组对象会在内存中开辟一整块
连续的空间。占据的空间的大小,取决于数组的长度和数组中元素的类型。 - 数组中的元素在内存中是依次紧密排列的,有序的。
- 数组名中引用的是这块连续空间的首地址。
- 数组,一旦初始化完成,其长度就是确定的。数组的
长度一旦确定,就不能修改。如果想扩容或者是缩容,只能重新建一个数组,把旧数组的值赋给新数组,然后再把新数组的地址复制给旧数组即可。 - 我们可以直接通过下标(或索引)的方式调用指定位置的元素,速度很快。
- 数组下标为什么是0开始,因为第一个元素距离数组首地址间隔0个单元格。
一维数组
声明
格式:
1 | //推荐 |
举例:
1 | int[] arr; |
注意:Java语言中声明数组时不能指定其长度(数组中元素的个数)。 例如: int a[5]; //非法
初始化
静态初始化
如果数组变量的初始化和数组元素的赋值操作同时进行,那就称为静态初始化。
静态初始化,本质是用静态数据(编译时已知)为数组初始化。此时数组的长度由静态数据的个数决定。
一维数组声明和静态初始化格式1:
1
2
3
4
5
6数据类型[] 数组名 = new 数据类型[]{元素1,元素2,元素3,...};
或
数据类型[] 数组名;
数组名 = new 数据类型[]{元素1,元素2,元素3,...};new:关键字,创建数组使用的关键字。因为数组本身是引用数据类型,所以要用new创建数组实体。
静态初始化不需要手动表明数组长度,编译器会自动根据大括号{}中提供的元素个数,计算并确定数组的长度,无需开发者手动指定,这也是静态初始化的便捷性体现。如果在静态初始化时手动添加数组长度,属于语法错误,编译器会直接报错,无法通过编译。
动态初始化
数组变量的初始化和数组元素的赋值操作分开进行,即为动态初始化。
动态初始化中,只确定了元素的个数(即数组的长度),而元素值此时只是默认值,还并未真正赋自己期望的值。真正期望的数据需要后续单独一个一个赋值。
格式:
1 | 数据类型[] 数组名字 = new 数据类型[长度]; |
[长度]:数组的长度,表示数组容器中可以最多存储多少个元素。
注意:数组有定长特性,长度一旦指定,不可更改。和水杯道理相同,买了一个2升的水杯,总容量就是2升是固定的。
数组元素的默认值
数组是引用类型,当我们使用动态初始化方式创建数组时,元素值只是默认值。
对于基本数据类型而言,默认初始化值各有不同。
| 数组元素类型 | 初始默认值 |
|---|---|
| byte | 0 |
| short | 0 |
| int | 0 |
| long | 0L |
| float | 0.0F |
| double | 0.0 |
| char | 0或\u0000 |
| boolean | false |
| 引用类型 | null |
对于引用数据类型而言,默认初始化值为null(注意与0不同!)
二维数组
声明
1 | //推荐 |
面试题:
1 | int[] x, y[]; |
5.2.2 静态初始化
格式:
1 | int[][] arr = new int[][]{{3,8,2},{2,7},{9,0,1,6}}; |
定义一个名称为arr的二维数组,二维数组中有三个一维数组
- 每一个一维数组中具体元素也都已初始化
- 第一个一维数组 arr[0] = {3,8,2};
- 第二个一维数组 arr[1] = {2,7};
- 第三个一维数组 arr[2] = {9,0,1,6};
- 第三个一维数组的长度表示方式:arr[2].length;
- 注意特殊写法情况:int[] x,y[]; x是一维数组,y是二维数组。
动态初始化
如果二维数组的每一个数据,甚至是每一行的列数,需要后期单独确定,那么就只能使用动态初始化方式了。动态初始化方式分为两种格式:
格式1:规则二维表:每一行的列数是相同的
1 | //(1)确定行数和列数 |
格式2:不规则:每一行的列数不一样
1 | //(1)先确定总行数 |
举例1:
1 | int[][] arr = new int[3][2]; |
举例2:
1 | int[][] arr = new int[3][]; |
- 二维数组中有3个一维数组。
- 每个一维数组都是默认初始化值null (注意:区别于格式1)
- 可以对这个三个一维数组分别进行初始化:arr[0] = new int[3]; arr[1] = new int[1]; arr[2] = new int[2];
- 注:
int[][]arr = new int[][3];//非法
数组的工具类
java.util.Arrays类即为操作数组的工具类,包含了用来操作数组(比如排序和搜索)的各种方法。 比如:
数组元素拼接- static String toString(int[] a) :字符串表示形式由数组的元素列表组成,括在方括号(”[]”)中。相邻元素用字符 “, “(逗号加空格)分隔。形式为:[元素1,元素2,元素3。。。]
- static String toString(Object[] a) :字符串表示形式由数组的元素列表组成,括在方括号(”[]”)中。相邻元素用字符 “, “(逗号加空格)分隔。元素将自动调用自己从Object继承的toString方法将对象转为字符串进行拼接,如果没有重写,则返回类型@hash值,如果重写则按重写返回的字符串进行拼接。
数组排序- static void sort(int[] a) :将a数组按照从小到大进行排序
- static void sort(int[] a, int fromIndex, int toIndex) :将a数组的[fromIndex, toIndex)部分按照升序排列
- static void sort(Object[] a) :根据元素的自然顺序对指定对象数组按升序进行排序。
- static
void sort(T[] a, Comparator<? super T> c) :根据指定比较器产生的顺序对指定对象数组进行排序。
数组元素的二分查找- static int binarySearch(int[] a, int key) 、static int binarySearch(Object[] a, Object key) :要求数组有序,在数组中查找key是否存在,如果存在返回第一次找到的下标,不存在返回负数。
数组的复制- static int[] copyOf(int[] original, int newLength) :根据original原数组复制一个长度为newLength的新数组,并返回新数组
- static
T[] copyOf(T[] original,int newLength):根据original原数组复制一个长度为newLength的新数组,并返回新数组 - static int[] copyOfRange(int[] original, int from, int to) :复制original原数组的[from,to)构成新数组,并返回新数组
- static
T[] copyOfRange(T[] original,int from,int to):复制original原数组的[from,to)构成新数组,并返回新数组
比较两个数组是否相等- static boolean equals(int[] a, int[] a2) :比较两个数组的长度、元素是否完全相同
- static boolean equals(Object[] a,Object[] a2):比较两个数组的长度、元素是否完全相同
填充数组- static void fill(int[] a, int val) :用val值填充整个a数组
- static void fill(Object[] a,Object val):用val对象填充整个a数组
- static void fill(int[] a, int fromIndex, int toIndex, int val):将a数组[fromIndex,toIndex)部分填充为val值
- static void fill(Object[] a, int fromIndex, int toIndex, Object val) :将a数组[fromIndex,toIndex)部分填充为val对象
举例:java.util.Arrays类的sort()方法提供了数组元素排序功能:
1 | import java.util.Arrays; |
Java虚拟机的内存划分
| 区域名称 | 作用 |
|---|---|
| 虚拟机栈 | 用于存储正在执行的每个Java方法的局部变量表等。局部变量表存放了编译期可知长度的各种基本数据类型、对象引用,方法执行完,自动释放。 |
| 堆内存 | 存储对象(包括数组对象),new来创建的,都存储在堆内存。 |
| 方法区 | 存储已被虚拟机加载的类信息、常量、(静态变量)、即时编译器编译后的代码等数据。 |
| 本地方法栈 | 当程序中调用了native的本地方法时,本地方法执行期间的内存区域 |
| 程序计数器 | 程序计数器是CPU中的寄存器,它包含每一个线程下一条要执行的指令的地址 |
算法
衡量算法的优劣:
时间复杂度:分析关键字的比较次数和记录的移动次数
常见的算法时间复杂度由小到大依次为:
Ο(1)<Ο(log2n)<Ο(n)<Ο(nlog2n)<Ο(n2)<Ο(n3)<…<Ο(2n)<Ο(n!)<O(nn)
注意,经常将以2为底n的对数简写成logn。
O(1) < O(logn) < O(n) < O(nlogn) < O(n^2) < O(n^3) < O(2^n) < O(n!) < O(n^n)
空间复杂度:分析排序算法中需要多少辅助内存1
一个算法的空间复杂度S(n)定义为该算法所耗费的存储空间,它也是问题规模n的函数。
稳定性:若两个记录A和B的关键字值相等,但排序后A、B的先后次序保持不变,则称这种排序算法是稳定的。
需要掌握的算法
冒泡排序
快速排序(重要)




