文章目录
JavaSE
本文是对宋老师以及Java编程的逻辑总结形成的JavaSE基础笔记,分成Java基础核心、面向对象、泛型与容器、文件、并发以及动态与函数式编程六大模块。
一、Java基础核心
第1章 Java语言概述
1 Java基础知识图解
1.1 JavaSE框架
- Java基础核心:基础语法、数组、分支
- Java面向对象核心:OPP、封装、继承、多态、异常、API
- Java泛型与容器:泛型、Collection、
- 文件处理
- 并发操作
- 动态与函数式编程:反射、注解、动态代理
2 Java语言概述
主要包括Java的技术体系、应用领域、主要特性、核心机制以及Java环境
2.1 Java技术体系
- Java SE标准版
- Java EE企业版
- Java ME小型版
- Java Card
2.2 Java应用领域
- 企业级应用
- Android平台应用
- 大数据平台开发
2.3 Java主要特性
- 面向对象:提供类、接口和继承等原语
- 分布式的:网络应用编程接口
- 健壮性:内存管理和访问机制
- 安全的:安全防范机制
- 跨平台性:JVM
2.4 核心机制:
- Java虚拟机(Java Virtal machine)
- 垃圾收集机制(Carbage Collection)
2.5 Java环境
-
JDK:Java开发工具包
-
JRE:Java运行环境
-
JVM:Java虚拟机
3 Hello World
/**
* 1.编写:HelloWorld.java
* 2.编译:Javac HelloWorld.java
* 3.运行:java HelloWorld
*/
public class HelloWorld {
public static void main(String[] args){
System.out.println("Hello World");
}
}
4 软件开发及语言介绍
(1)软件开发:
软件,即一系列按照特定顺序组织的计算机数据和指令的集合。有系统软件和应用软件之分。
(2)人机交互方式:
图形化界面、命令行方式
(3)常用DOS命令
dir : 列出当前目录下的文件以及文件夹
md : 创建目录
rd : 删除目录
cd : 进入指定目录
cd.. : 退回到上一级目录
cd\: 退回到根目录
del : 删除文件
exit : 退出 dos 命令行
补充:echo javase>1.doc
(4)计算机编程语言:
人与计算机交流的方式。
-
第一代语言:机器语言。指令以二进制存在。
-
第二代语言:汇编语言。助记符表示一条机器指令。
-
第三代语言:高级语言。Java跨平台纯面向对象的语言。
5 数据背后的二进制
5.1 进制
所有数字在计算机底层都以二进制形式存在。
(1) 数据存储的单位:
- 位:bit 最小的单元
- 字节:byte 机器语言的单位:1byte=8bits
(2) 进制:
-
二进制(binary):0,1 ,满2进1.以0b或0B开头。
-
十进制(decimal):0-9 ,满10进1。
-
八进制(octal):0-7 ,满8进1. 以数字0开头表示。
-
十六进制(hex):0-9及A-F,满16进1. 以0x或0X开头表示。此处的A-F不区分大小写。
5.2 二进制
Java整数常量默认是int类型,当用二进制定义整数时,其第32位是符号位;当是long类型时,二进制默认占64位,第64位是符号位。
(1)二进制的整数表现形式:
- 原码:直接将一个数值换成二进制数。最高位是符号位
- 负数的反码:是对原码按位取反,只是最高位(符号位)确定为1。
- 负数的补码:其反码加1。
(2)计算机以二进制补码的形式保存所有的整数。
- 正数的原码、反码、补码都相同
- 负数的补码是其反码
6 字符与编码
6.1 字符相关概念:
- 字符:是各种文字和符号的总称
- 字符集:字符集是多个符号的集合,每个字符集包含的字符个数不同。
- 字符编码:字符集只是规定了有哪些字符,采用哪些字符,每一个字符用多少字节表示等问题,则是由编码来决定的
6.2 常见字符编码:
Unicode编码给世界所有字符分配了唯一数字编号,并未规定二进制表示。
- Unicode编码:UTF-32、UTF-16
- 非Unicode编码:ASCII、ISO、GB2312
6.3 Unicode编码
Unicode编码给世界上所有的字符都分配了一个唯一的数字编码,并未规定其二进制表示。编号对应二进制表示主要有UTF-32、UTF-16、UTF-8
(1)二进制表示
- UTF-32:即字符编号是整数二进制形式,4个字节
- UTF-16:使用变长字节。
- UTF-8:使用变长字节,unicode编号小的使用字节少,编号大的使用字节多。
UTF-8编号范围对应的二进制格式
(2)小结
Unicode给世界所有字符都规定了一个统一的编号,并未规定编号对应的二进制形式。
UTF-32、UTF-16、UTF-8均是将Unicode编号对应到二进制格式,但只有UTF-8兼容ASCII
6.4 非Unicode编码
常见的非Unicode编码包括ASCII、ISO、GB2312、GBK等。
- ASCII码全称为美国信息互换标准代码。
- GB2312固定两个字节表示汉字,针对简体中文常见字符。
- GBK则是在GBK2312的基础上,向下兼容GBK2312,
ASCII是基础,使用一个字节表示,最高位为0,其他七位表示128个字符。其他编码兼容ASCII,最高位使用1来进行区分。
6.5 编码转换
有了Unicode之后,每一个字符有多种不同的编码格式,不同的编码格式可以通过Unicode编号进行编码转换。
字符A编码到B编码:A编码通过A编码映射表找到字符对应的Unicode编号,通过字符Unicode编号查询B的映射表,找到其编码格式。
乱码有两种常见原因“:第一种是简单的解析错误,第二种是在错误解析的基础上进行编码转换。
恢复乱码常见方法:
public static void recover(String str)
throws UnsupportedEncodingException {
String[] Charsets = new String[]{"windows-1252","GB18030","Big5","UTF-8"};
for (int i = 0; i < Charsets.length; i++) {
for (int j = 0; j< Charsets.length; j++) {
if (i!=j){
String s = new String(str.getBytes(Charsets[i]),Charsets[j]);
System.out.println("原来编码假设是(A):"+Charsets[j]);
System.out.println("被错误解读成(B):"+Charsets[i]);
System.out.println(s);
}
}
}
}
第2章 基本语法
1 注释
Java注释分为单行注释、多行注释以及Java特有的文档注释。
1.1 单行注释
//注释文字
1 .2 多行注释
/* 注释文字 */
1.3 文档注释(Java特有)
/**
@author 指定java程序的作者
@version 指定源文件的版本
*/
注释内容可以被JDK提供的工具 javadoc 所解析,生成一套以网页文件形
式体现的该程序的说明文档
2 标识符
2.1 关键字
定义:关键字被Java语言赋予了特殊含义,用做专门用途的字符串(单词)。
特点:字母均小写。
分类:数据类型、流程控制、访问权限、类有关、异常处理、包、修饰符
2.2 保留字
现有Java版本尚未使用,但以后版本可能会作为关键字使用。goto 、const
2.3 标识符
Java 对各种变量、方法和类等要素命名时使用的字符序列称为标识符.
命名规范:
- 包名:多单词组成时所有字母都小写
- 类名、接口名:多单词组成时,所有单词的首字母大写:
- 变量名、方法名:多单词组成时,第一个单词首字母小写,第二个单词开始每个单词首字母大写
- 常量名:所有字母都大写。多单词时每个单词用下划线连接:
3 变量
3.1 变量
(1)概念
- 内存中的一个存储区域,数据可在同一类型中不断变化。
- 是程序中最基本的存储单元,包含变量类型、变量名和存储的值。
- 变量可以理解为给数据起名,方便寻找不同数据,值变含义不变。
- 作用:用于在内存中保存数据
(2)注意事项
- Java中每个变量必须先声明,后使用。
- 使用变量名来访问这块区域的数据。
- 变量的作用域,在定义的{}中才有效
(3)变量的声明与赋值
-
声明:<数据类型> <变量名称>
-
声明并赋值: <数据类型> <变量名> = <初始化值>
3.2 按数据类型分类
数据类型用于对数据的归类,以便于理解和操作。每一种数据类型在内存分配不同大小的空间。
(1)基本数据类型:
- 整数类型:4种整型,byte/short/int/long
- 小数类型:2种类型float/double
- 字符类型:char,表示单个字符。本质是固定两个字节的无符号整数。
- 真假类型:boolean
(2)引用数据类型
- 类(class)
- 接口(interface)
- 数组([])
- 字符串(String)
3.3 按声明位置分类
可根据方法与类体内可分为成员变量与局部变量。
3.4 数据类型转化
数据类型转换包括自动类型转换与强制类型转换。
(1)自动类型转换
- 多种数据类型混合运算,系统会将所有数据转换成容量最大的数据类型
- byte,short,char之间不会相互转换,它们运算时会转换为int类型。
- 任何基本数据类型与String类型进行连接运算(+),均会自动转换string类型。
- String属于引用数据类型,可以串接自身以及其他类型数据。
(2)强制类型转换
强制类型转换是将容量大的类型转换为容量小的类型。是自动类型转换的逆过程。
- 使用时需要加上强制转换符:(),可能会造成精度降低或者溢出。
- 通常,字符串类型不会转换为基本类型,通过包装类可以把对应字符串转换为基本类型。
- boolean类型不能转换为其它的数据类型
4 运算符
运算符是一种特殊的符号,用以表示数据的运算、赋值和比较等。 一般有算术运算符、赋值运算符、比较运算符(关系运算符)、逻辑运算符、位运算符和三元运算符。运算符是有不同优先级的。
4.1 算数运算
算术运算符有加、减、乘、除,符号分别是+、-、*、/,另外还有取模运算符%,以及自增(++)和自减(–)运算符。
注意:
- 取模适用于所有数值类型和字符类型。负数取模忽略负号
- 加、减、乘、除注意结果的范围
- 小数计算结果不精确
- “+”除字符串相加功能外,还能把非字符串转换成字符串.
4.2 赋值运算符
赋值运算符有=、+=、 -=、 *=、 /=、%=
注意:
- 当“=”两侧数据类型不一致时,可以使用自动类型转换或使用强制类型转换原则进行处理。
- 支持连续赋值。
4.3 比较运算
比较运算就是计算两个值之间的关系,结果是一个布尔类型(boolean)的值。
4.4 逻辑运算
逻辑运算包括逻辑与 、逻辑或 、逻辑非、短路与 、短路或 、逻辑异或。
(1)“&”和“&&”的区别:
- 单&时,左边无论真假,右边都进行运算;
- 双&时,如果左边为真,右边参与运算,如果左边为假,那么右边不参与运算。
(2) “|”和“||”的区别
- 同理,||表示:当左边为真,右边不参与运算
(3)异或( ^ )与或( | )区别:
- 异或当左右都为true时,结果为false。
- 理解:异或,追求的是“异”!
4.5 位运算
(1)位运算符
(2)位运算符细节
4.6 三元运算符
(条件表达式)?表达式1:表达式2;
条件表达式为true时,采用表达式1,否则采用表达式2.
5 程序流程控制
流程控制主要有两种,一种是条件控制,一种是循环执行。
5.1 顺序结构
程序从上到下逐行地执行,中间没有任何判断和跳转。
Java中定义成员变量时采用合法的前向引用。
public class Test{
int num1 = 12;
int num2 = num1 + 2;
}
5.2 分支结构
根据条件,选择性地执行某段代码。有if…else和switch-case两种分支语句。
(1)if-else结构
if-else具有三种结构
//满足单个条件
if(条件语句){
//代码块
}
//满足与不满足条件执行逻辑不同
if(条件语句){
//代码块1
}else{
//代码块2
}
//三元运算符
//判断条件 ? 表达式1 : 表达式2
//多个判断条件
if(条件表达式1){
//代码块1;
}
else if (条件表达式2){
//代码块2;
}
……
else{
//代码块n;
}
(2)switch-case结构
switch(表达式){
case 常量1:
语句1;
// break;
case 常量2:
语句2;
// break; … …
case 常量N:
语句N;
// break;
default:
语句;
// break;
}
细节:
- switch(表达式)中表达式的值类型必须是:byte,short,char,int,枚举 (jdk 5.0),String (jdk 7.0);
- case子句中的值必须是常量
- break语句用来在执行完一个case分支后使程序跳出switch语句块
- default子句是可任选的
5.3 循环结构
根据循环条件,重复性的执行某段代码。有while、do…while、for三种循环语句。JDK1.5提供了foreach循环,方便的遍历集合、数组元素。
(1)循环语句组成部分
循环语句的四个组成部分
-
初始化部分(init_statement)
-
循环条件部分(test_exp)
-
循环体部分(body_statement)
-
迭代部分(alter_statement)
(2)循环1:for循环
- 在for中,每条语句都是可以为空的
for (①初始化部分; ②循环条件部分; ④迭代部分){
③循环体部分;
}
//执行顺序:1-2-3-4-2-3-4...
(3)循环2:while循环
①初始化部分
while(②循环条件部分){
③循环体部分;
④迭代部分;
}
//执行顺序:1-2-3-4-2-3-4...
(4)循环3:do-while循环
do-while循环至少执行一次循环体**
①初始化部分;
do{
③循环体部分
④迭代部分
}while(②循环条件部分);
//执行顺序:1-2-3-4-2-3-4...
(5)循环4:foreach
/**
* element一般每次会自动更新
*/
int[] arr = {1,2,3,4};
for(int element : arr){
System.out.println(element);
}
(6)循环控制
特殊关键字:break、continue、return
特殊流程控制语句1:break
- break只能用于switch语句和循环语句中
- break是终止本层循环。
//break语句用于终止某个语句块的执行
{ ……
break;
……
}
//break语句出现在多层嵌套的语句块中时,通过标签设置
label1: { ……
label2: { ……
label3: { ……
break label2;
……
}
}
}
特殊流程控制语句2:continue:
- continue只能使用在循环结构中
- continue是终止本次循环。
- continue语句用于跳过其所在循环语句块的一次执行,继续下一次循环
- continue语句出现在多层嵌套的循环语句体中时,可以使用标签
//单层循环语句
for (int i = 0; i < 100; i++) {
if (i%10==0)
continue;
System.out.println(i);
}
特殊流程控制语句3:return:
- retun并非结束循环体,而是结束方法。
第3章 数组
数组(Array),是多个相同类型数据按一定顺序排列的集合,并使用一个名字命名,并通过编号的方式对这些数据进行统一管理。
1 数组概述
数组就是存储数据长度固定的容器,存储多个数据类型要一致
1.1 数组常见概念
- 数组名
- 下标(或索引)
- 元素
- 数组的长度
1.2 数组特性
- 数组是引用数据类型,而数组中的元素可以是任何数据类型
- 创建数组对象会在内存中开辟一整块连续的空间,而数组名中引用的是这块连续空间的首地址。
- 我们可以通过下标访问指定位置的元素
- 数组长度一旦确定,就不能修改
1.3 数组的分类
- 按照维度:一维数组、二维数组、三维数组…
- 按照元素数据类型:基本数据类型元素的数组、引用数据类型元素的数组(即对象数组)
2 一维数组
2.1 声明
//第一种:数据类型[] 数组名
int[] arr;
//第二种:数据类型 数组名[]
int arr[]
2.2 初始化
动态初始化:
//动态初始化:数组声明且为数组元素分配空间与赋值的操作分开进行
int[] arr = new int[3];
arr[0] = 3;
arr[1] = 9;
arr[2] = 8;
静态初始化:
//静态初始化:在定义数组的同时就为数组元素分配空间并赋值。
int arr[] = new int[]{ 3, 9, 8};
int[] arr = {3,9,8};
2.3 数组元素的引用
- 定义并用运算符new为之分配空间后,才可以引用数组中的每个元素;
- 数组元素的引用方式:数组名[数组元素下标]
- 每个数组都有一个属性length指明它的长度,数组一旦初始化,其长度是不可变的
2.4 数组元素的默认初始化值
数组是引用类型,它的元素相当于类的成员变量,因此数组一经分配空间,其中的每个元素也被按照成员变量同样的方式被隐式初始化。
注意:
- 对于基本数据类型而言,默认初始化值各有不同
- 对于引用数据类型而言,默认初始化值为null(注意与0不同!)
3 多维数组
多维数组可以理解为一维数组中每个元素还可以是一个数组。从数组底层运行机制来说多维数组并不存在,
3.1 初始化
动态初始化:
/**
* 格式1(动态初始化):
* 1.定义了名称为arr的二维数组
* 2.二维数组中有3个一维数组
* 3.每一个一维数组中有2个元素
*/
int[][] arr = new int[3][2];
/**
* 格式2(动态初始化)
* 1.二维数组中有3个一维数组。
* 2.每个一维数组都是默认初始化值null
* 3.可以对这个三个一维数组分别进行初始化
*/
int[][] arr = new int[3][];
静态初始化:
//格式3(静态初始化):
int[][] arr = new int[][]{{3,8,2},{2,7},{9,0,1,6}};
注意特殊写法情况:
- int[] x,y[]; x是一维数组,y是二维数组。
- Java中多维数组不必都是规则矩阵形式
4 常见算法
4.1 二分查找
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wAYjxQtI-1657707944906)(img/3.4_2.png)]
4.2 排序
(1)概述
排序:
- 假设含有n个记录的序列为{R1,R2,…,Rn},其相应的关键字序列为{K1,K2,…,Kn}。将这些记录重新排序为{Ri1,Ri2,…,Rin},使得相应的关键字值满足条Ki1<=Ki2<=…<=Kin,这样的一种操作称为排序。
衡量排序算法的优劣:
-
1.时间复杂度:分析关键字的比较次数和记录的移动次数
-
2.空间复杂度:分析排序算法中需要多少辅助内存
-
3.稳定性:若两个记录A和B的关键字值相等,但排序后A、B的先后次序保持不变,则称这种排序算法是稳定的
(2)分类
排序算法分类:内部排序和外部排序。
**内部排序:**所有排序操作均在内存中完成
- **选择排序:**直接选择排序、堆排序
- 交换排序:冒泡排序、快速排序
- **插入排序:**直接插入排序、折半插入排序、Shell排序
- 归并排序
- 桶式排序
- 基数排序
**外部排序:**数据量多,需要用到外部存储器,可以认为外部排序是由多次内部排序组成
(3)算法5大特征
(4)冒泡排序
冒泡排序的原理非常简单,它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。
-
1.比较相邻的元素。如果第一个比第二个大(升序),就交换他们两个。
-
2.对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。
-
3.针对所有的元素重复以上的步骤,除了最后一个。
-
4.持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较为止。
(5)快速排序
快速排序通常明显比同为O(nlogn)的其他算法更快,因此常被采用,快排采用了分治法的思想。
- 1.从数列中挑出一个元素,称为"基准"(pivot)
- 2.重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区结束之后,该基准就处于数列的中间位置。这个称为分区(partition)操作。
- 3.递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。
- 4.递归的最底部情形,是数列的大小是零或一,也就是永远都已经被排序好了。
(6)内部排序性能
-
1.从平均时间而言:快速排序最佳。但在最坏情况下时间性能不如堆排序和归并排序。
-
2.从算法简单性看:由于直接选择排序、直接插入排序和冒泡排序的算法比较简单,将其认为是简单算法。对于Shell排序、堆排序、快速排序和归并排序算法,其算法比较复杂,认为是复杂排序。
-
3.从稳定性看:直接插入排序、冒泡排序和归并排序时稳定的;而直接选择排序、快速排序、 Shell排序和堆排序是不稳定排序
-
4.从待排序的记录数n的大小看,n较小时,宜采用简单排序;而n较大时宜采用改进排序。
(7)排序算法的选择
- 若n较小(如n≤50),可采用直接插入或直接选择排序。
- 若文件初始状态基本有序(指正序),则应选用直接插入、冒泡或随机的快速排序为宜;
- 若n较大,则应采用时间复杂度为O(nlgn)的排序方法:快速排序、堆排序或归并排序。
5 Arrays
Java.util.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) //对排序后的数组进行二分法检索指定的值。
6 Java中常见异常
- 数组脚标越界异常(ArrayIndexOutOfBoundsException)
- 空指针异常(NullPointerException)