第一章 Java基础(概述)
1.1 java语言特点
开源,简单、高效,面向对象,平台无关性,交互式特性,多线程机制,动态的内存管理机制(自动垃圾回收),安全性.
跨平台性:
通过虚拟机,将java程序指令翻译给不同的操作系统,这样就实现了Java程序的跨平台性,也称为Java具有良好的可移植性,前提是在不同的平台上安装不同的java虚拟机
JVM是Java Virtual Machine(Java虚拟机)的缩写,
JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的,因为有了不同的JVM,所以同一个Java程序在三个不同的操作系统中都可以执行。这样就实现了Java程序的跨平台性,也称为Java具有良好的可移植性, 但是前提是要具有不同的jvm.
1.2 Java语言的运行机制
核心机制为Java虚拟机
- Java虚拟机可以理解成一个翻译器。
- 对于不同的运行平台,有不同的虚拟机。
- Java虚拟机机制屏蔽了底层运行平台的差别,实现了“一次编译,随处运行”。
其具体运行机制如下:
开发一个源代码(XXX.java) —-编译—-> 字节码文件(.class) —-JVM(虚拟机) 翻译—-> 操作系统 编译–>JDK
1.3 Java运行环境(JDK,JRE、JVM关系)
-
JDK(Java Development Kit Java开发工具包)
JDK是Java开发工具包,在其安装目录下有六个文件夹、一些描述文件、一个src压缩文件。bin、include、lib、jre这四个文件夹起作用,demo、sample是一些例子。
-
JRE(Java Runtime Environment Java运行环境)
包括Java虚拟机和Java程序所需要的核心类库等。,如果想要运行一个开发好的Java程序,计算机中只需要安装JRE即可。
-
JVM (Java Virtual Machine Java虚拟机)
JVM是java虚拟机,它是整个java实现跨平台的核心的部分,所有的java程序会首先被编译为.class的类文件,这种类文件可以在虚拟机上执行,也就是说class并不直接与机器的操作系统相对应,而是经过虚拟机间接与操作系统交互,由虚拟机将程序解释给本地系统执行。
-
三者之间关系
JDK 包含JRE,JRE包含JVM。
第二章 JavaSE基础语法
2.1 注释
是对代码功能进行说明,使用特定的符号进行标注。当程序运行时,注释不被执行。
(1)单行注释:// 是对某一行代码进行说明。
快捷键(单行注释或取消单行注释):ctrl+/
(2)多行注释:/* */是对多行代码的注释说明。
快捷键(多行注释或取消多行注释):ctrl+shift+/
(3)注释的附加作用:调试代码。
(4)文档注释:对类属性,方法进行注释,调用时可看到注释信息。
2.2 关键字
定义:被Java语言赋予了特殊含义,用作专门用途的字符串(单词)
特点:关键字都是小写字母。主要用来修饰包、类、变量和方法。
部分关键字解释(转载自之前所编辑的部分关键字解释):
https://blog.csdn.net/weixin_51720882/article/details/121175167?spm=1001.2014.3001.5502
2.3 Java数据类型
Java中数据类型分为基本数据类型与引用数据类型
-
基本数据类型
数值型:
(1)整数:byte short int long;
(2)浮点:float double;
字符型:char;
布尔型:boolean;
-
引用数据类型:类, 接口,数组。
-
基本数据类型转换
除了布尔型以外,其他7种基本数据类型之间可以相互转换,即默认转换和强制转换。
<1>默认转换:有容量小的类型转换为容量大的类型。
byte short char(这三种类型不分大小)—>int—>long—>float—>double
<2>强制转换
带来的问题:
(1)数据溢出
(2)精度降低
在混合运算中,小类型会默认自动上升为大类型。
2.4 运算符
-
关系(比较)运算符:>,<,>=,<=,==,!=
1.>,<,>=,<=只能进行数值之间的比较;
2.==,!=:
(1)能进行数值之间的比较;
(2)逻辑值与逻辑值的比较;
(3)引用类型与引用类型的比较。
-
逻辑运算符
逻辑运算符:!,&,|,&&,||,^
1.逻辑值与逻辑值之间的运行:true & false = false;
2.逻辑与& 与 短路与&& 的区别:
如:(a<b & ++b<c)
(a<b && ++b<c)
短路与:出现第一个false,整个表达式短路,后面的表达式不执行。
3.逻辑或| 与 短路或|| 的区别:
逻辑或:当出现第一个true时,继续执行后面的表达式,结果为true;
短路或:表达式中有一个true,输出为true;当出现第一个true时,发生短路,结果为true。
4.&,|,^还可以进行位运算。
-
赋值运算符
1.= :将右边的值赋给左边,变量=值;
2.== : 判断是否相等;
-
条件表达式
(条件表达式)?表达式1:表达式2;
当条件表达式返回为true时,执行表达式1;
当条件表达式返回为false时,执行表达式2.
-
位运算
位运算为bit位进行运算。
1.<< :二进制bit位向左移位; >> :二进制bit位向右移位;
2.>>> :二进制bit位向右移位,无符号右移
-
表达式的运算顺序
2.5 控制语句
-
if选择语句:
-
if(条件表达式){
(条件表达式为真执行代码块)}else(条件表达式){
(条件表达式为假不执行代码块)}
- 若在if else中,条件语句相同,满足一个条件,流程自动结束。
-
if(条件表达式){
-
switch语句
-
switch(表达式){
case 值:代码块;[break]; //case必须是字面量(常量),值不能重复
default:默认代码块
}
- 表达式类型有:byte,short,int,char,枚举,String;
- 选项值类型需要和表达式的类型一致。匹配的case语句块执行完成后,如果没有break结束,则继续向下执行下一个case,直到出现break;如果没有出现与表达式匹配的选项,则执行default语句;若没有default则结束switch。
-
switch(表达式){
-
if与switch语句比较
if条件更加灵活,switch适用于一些固定项的选择
2.6break & continue
- break:用于终止某个语句块的执行。用在循环语句体中,可以强行退出循环;
- continue:用于终止某 次循环过程,跳过循环体中 continue 语句下面未执行的循环,开始下一次循环过程。
2.7 while & do while语句
-
while
语句为如下形式:
while(逻辑表达式){ 语句;…;}
while:
先判断逻辑表达式的值。若为true(符合条件).则执行其后面的语句,然后再次判断条件并反复执行,直到条件不成立为止;
-
do while
语句为如下形式:
do { 语句; … ; } while(逻辑表达式);
do while:
先执行语句,再判断逻辑表达式的值,若为true(符合条件),再执行语句,否则结束循环。
2.8 Java方法
Java的方法类似于其它语言的函数(如C语言中的函数),方法是解决一类问题的步骤的有序组合,方法包含于类或对象中;
-
语法格式:
[访问权限修饰符(public) 修饰符] [返回值类型] 方法名(形式参数类型 参数名){
Java语句;… … …
[return 返回值;]
}
-
修饰符:这是可选的,告诉编译器如何调用该方法。定义了该方法的访问类型;
-
形参: 在方法被调用时用于接收外界输入的数据;
-
实参:调用方法时实际传给方法的数据;
-
返回值:方法在执行完毕后返还给调用它的环境的数据;
-
返回值类型:事先约定的返回值的数据类型,如无返回值,必须给出返回值类型void。
-
注:int void表示方法没有返回值;
-
static修饰方法属于类,可以直接通过类名调用;不加static修饰,方法属于对象,需要通过对象调用。
第三章 数组
3.1 数组的基本概念
-
数组:数组是相同数据类型元素的集合,一组数据类型相同的数。
数组是引用数据类型,即对象。数组可以存储基本类型数据,也可以存储引用类型数据。
-
特点:在
内存
中的空间是连续的。
3.2 数组的创建
1.数组声明有两种方式:
- int [] a;
- int a [];
-
注意:int[] a,b: a,b都是数组
int x[]y: x是数组,y不是
2.数组的创建方式(三种):
-
方式一:
创建数组时必须为其指定长度。而且长度一旦定义了就不能改变。如:
int [] a = new int[10];
此为输出对象的地址,默认输出的是对象在内存中的地址。
-
方式二:
创建数组的同时,为数组每个空间赋值,同时确定了数组的长度。如:
int [] x = new int[]{1,2,3,4,5,6};
-
方式三(与方式二相同,只是语法相对简略):
隐式的创建。如:
int [] y = {1,2,3,4,5,6};
3.数组的创建可以分为静态和动态两种
-
动态创建数组:
没有为元素赋值,可以结合for循环进行赋值。
char[] a = new char[10];
-
静态创建数组:
在创建的时候,即为每个元素赋初值。
int[] b = new int[]{1, 2, 3, 4, 5};
-
数组的长度:
length属性。
int [] b1 = new int []{1,2,3,4,5,6,7}; System.out.println(b1.length);
3.3 数组的索引
- 索引:数组中的索引可以看作指针,且索引是从0开始。
- 数组元素的访问:
数组名字[索引] 例如:a[0],a[1];
- 索引特点:整数,数据类型为整型;最小值为0,索引最大值和数组长度始终差1。
3.4数组元素的遍历
- 方式一:for循环:
int [] a = new int[]{1,2,3};
for (int i = 0; i < a.length; i++) {
System.out.println(a[i]);
}
方式二:增强for循环
int [] b = new int[]{1,2,3,4,5,6};
for (int x : b){
System.out.println(x);
}
3.5 数组的优缺点
-
优点
:1.按照索引查询元素速度快;
2.能存储大量数据;
3.按照索引遍历数组方便。
-
缺点
:1.根据内容查找元素速度慢;
2.数组的大小一经确定不能改变;
3.数组只能存储一种类型的数据;
4.增加、删除元素效率慢;
5.数组空间须是连续的,因此数组在内存中分配空间时必须找到一块连续的内存空间。
第四章 面向对象
4.1 什么是面向过程?什么是面向对象?
面向过程
(procedure oriented programming 缩写 POP):
- 分析出解决问题所需要的步骤,然后把步骤一步一步实现。
- 面向过程直接关注流程
- 面向过程侧重的是过程,第一步要干嘛,第二步要干嘛,第三步要干嘛,是一步一步实现的
面向对象
(object oriented programming 缩写 OOP):
何为对象?就是我们能够看到的,真实存在的。
-
以分类的方式进行思考和解决问题;
-
面向对象先对整体关系作出分类,然后根据不同的类深入细节的处理;
-
面向对象的思想符合人类的认知习惯。
-
面向对象侧重的是对象,它先设计,对现实中客观事物进行分类,创建出类(在类中定义功能),创建出具体的对象,让对象去做具体的事情。
-
面向对象于面向过程的关系
面向对象无法取代面向过程,他们是相辅相成的。面向对象关注于从宏观上把握事物之间的关系,在具体到如何实现某个细节时,仍然采用面向过程的思维方式。面向对象如果离开了面向过程,就无法实现真正的落地,成为无源之水。
4.2 构造方法
特点:构造方法名与类名相同,且没有返回值,不需要使用void修饰。
作用:在构造方法中为创建的对象初始化赋值。
每个类中都至少有一个构造方法,也可以有多个;
每创建一个对象时,至少调用一个构造方法;
如果类中无构造方法,默认会提供一个无参的,一旦定义有参的构造方法,默认的会失效。
4.3 方法的重载,重写
方法的重载是指在同一个类中具有相同的名字,但参数不同的多个方法。
-
参数不同(三方面):
数量不同
类型不同
顺序不同
其在调用时根据不同的参数表选择对应的方法。
注:方法的重载跟方法的返回值类型没有任何关系。
那么重写(Override)是什么呢?
是指子类中的方法与父类中继承的方法有完全相同的返回值类型、方法名、参数个数以及参数类型。这样,实现了对父类方法的覆盖。
重写体现了Java的优越性,重写是建立在继承关系上,使得语言结构更加丰富。
-
方法重写须满足以下条件
(遵循两同两小一大原则):子类的方法必须和父类中被重写的方法的名称相同;
子类的方法必须和父类中被重写的的方法参数相同,包括参数的个数、数据类型以及顺序
子类声明的异常小于等于父类中的异常类型;
子类的访问权限大于等于父类的访问权限;
子类的返回值类型小于等于父类的返回值类型。
4.4 值传递与引用传递
Java中进行方法调用中传递参数时,参数传递有两种(值传递和引用传递):
1.值传递
(形参类型是基本数据类型):
方法调用时,实际参数把它的值传递给对应的形式参数,形式参数只是用实际参数的值初始化自己的存储单元内容;是两个不同的存储单元,所以方法执行中形式参数值的改变不影响实际参数的值。
public class Demo1 {
public static void main(String[] args) {
Demo1 a = new Demo1();
int b = 10;
a.test(b);
System.out.println(b);
}
/*
形参c
用实参b的值,直接对c进行了赋值,在内存中有两个独立的存储空间b,c
*/
public void test(int c){
c = 20;//c的值发生改变不影响b
}
}
2.引用传递
(形参数类型是引用数据类型参数):
引用传递也称为传地址。方法调用时,实际参数是对象,这时实际参数与形式参数指向同一个地址;方法执行中形式参数的改变将会影响实际参数。基本类型传递的是该数据值本身。引用类型传递的是对对象的引用,而不是对象本身。
public class Demo2 {
public static void main(String[] args) {
Demo2 a = new Demo2();
Person zs = new Person("张三",'男',20);
a.test(zs);//只是把对象地址传递给了b
System.out.println(zs.name);
}
public void test(Person b){ //b和zs指向的是同一个对象
b.name = "王五";
}
}
4.5 访问权限修饰符
是用来修饰类,成员变量,成员方法,内部类
在Java语言中有四个权限访问修饰符:public(公共的),protected(受保护的),default(默认的),private(私有的)。
它们的权限大小从大到小依次为:public,protected,default,private
public | protected | default | private | |
---|---|---|---|---|
同类 | √ | √ | √ | √ |
同包 | √ | √ | √ | |
不同包子类 | √ | √ | ||
不同包的其他类 | √ |
4.6Java中的包(package)
包的作用:
- 避免类重名;
- 按照不同功能管理类;
- 控制访问权限。
包的命名规范:
在包名中可以使用.号区分包的级别;包名一般情况下是小写
第一级:指该项目的类型;
第二级:指项目所开发或者运行的公司名称;
第三级:指项目的名称;
第四级:指项目模块的名称。
4.7 代码块,static关键字
**代码块:**类似一个没有名字的方法;
代码块分为:实例代码块和静态代码块;
- 实例代码块:在创建对象之后,调用构造方法之前执行,每创建一个对象,执行一次;
- 静态代码块:在类加载时执行,只执行一次;
**static关键字:**静态,可以修饰属性、方法、代码块、内部类。
- 被static修饰的内容,随着类的加载而加载,优先于对象存在,被所有对象共享,可以通过类名直接调用。
- 静态方法不能使用非静态的成员变量,静态资源随着类先加载;非静态的随着对象的创建而加载。
- 非静态方法可以使用静态变量,非静态方法必须通过对象来调用,对象创建之前先加载类。
类在什么时候加载?
- 类在程序执行时加载;
- main方法在哪个类中执行,这个类加载;
- 创建某个类的对象;
- 调用某个类中静态属性、方法。
4.8 面向对象特征
面向对象语言有三大特征:封装、继承、多态
1 封装
- 是将类的某些信息隐藏起来(用到访问权限修饰符来实现),不允许外部程序直接访问,而是通过该类提供的方法来实现对隐藏信息的操作和访问。
封装的好处:
- 只能通过规定的方法访问;
- 隐藏类的实现细节;
- 方便加入控制语句;
- 方便修改实现。
2 继承
- 在Java中使用extends关键字来表示继承关系;
- 继承是从已有的类中派生出新的类,新的类能吸收已有类的属性和行为,并能扩展新的能力。
- 一个类只能直接继承一个父类,继承后子类就可以使用父类中非私有的成员
类继承中有以下几种情况:
- 一个类只能有一个直接父类;
- 多个类可以继承一个父类;
- 继承具有传递性:C继承B,B继承A,这样C类就具有B,A类中非私有的属性和方法
- 一个类的父类可以再去继承另外的父类。
继承中的构造方法
- 子类构造方法会先调用父类构造方法;
- 使用super关键字调用父类任意一个构造方法,
3 多态
什么是多态?
- 多态是同一种事物,在不同时刻表现不同的状态
- 条件:要有继承关系(类继承类,类继承抽象类,类实现接口)
多态存在的三个必要条件
- 要有继承(包括接口的实现)(前提条件)
- 要有重写(前提条件)
- 父类引用指向子类对象
多态转型:
- 自动转型:子 继承 父
- 向上转型:子类型自动转为(上升为)父类类型
- 强制转型:向下转型,父类类型 转为 子类自己的类型
- 优缺点:父类引用表示子类对象,提升程序的扩展性
- 缺点:父类不能调用子类中特有的方法
多态环境下对成员方法、静态成员方法、对成员变量的调用
-
针对非静态成员方法:
编译期间看左边,运行期间看右边
-
针对静态方法:
编译期间看左边,运行期间还看左边
-
针对成员变量:
编译期间看左边,运行期间还是看左边
4.9 super关键字,this关键字,final关键字
super关键字用途
- 使用super关键字访问父类成员
- 使用super成员变量名来引用父类成员变量
- 使用super方法名(参数列表)访问父类的方法
- 使用super构造方法(参数列表)访问父类构造方法
this关键字
- this关键字代表当前对象
- 使用this关键字引用成员变量
- 使用this关键字引用成员方法
- 在一个类的方法或构造方法内部,可以使用“this.成员变量名”这样的格式来引用成员变量名,常常用来区分同名的成员变量和局部变量;
final关键字
final关键字用于声明属性,方法和类
- 修饰类:该类不能被其他类所继承
- 修饰方法:在当一个类的方法被final关键字修饰后,这个类的子类不能重写该方法
4.10 抽象类
抽象方法
- 抽象方法是一种特殊的方法:它只有声明,没有具体的实现
- 抽象方法必须用abstract关键字修饰,在定义方法时不需要实现方法体
- 当一个类中包含了抽象方法,那么该类也必须使用abstract关键字修饰
- 抽象类可能包含了抽象方法,也可能不包含抽象方法
- 如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类
特点
- 抽象类不能被实例化,但可以有构造方法,因为抽象类中含有无具体实现的方法,所有不能用抽象类创建对象
- 如果想调用抽象类中定义的抽象方法,需要创建一个子类,在子类中实现抽象类中的抽象方法
4.11 接口
概述
- 如果一个抽象类中所有方法都是抽象的,则可以将这个类定义为Java中的另一种形式:接口;
- 接口是一种特殊的抽象类,这种抽象类中包含抽象方法。
- 接口类似于抽象类(可以看作是一个更彻底的抽象类)
- 接口和抽象类都是用于在顶层类
- 接口由interface修饰
意义
Java中一个类只能有一个父类,所以用接口可以实现多继承的逻辑
注:
- 接口中没有构造方法,不能创建对象
- 接口表示抽象,也是需要其他类来实现的(继承)
特点
- JDK8之前接口只能定义静态常量和抽象方法;JDK8之后接口增加了静态方法,默认方法
- 一个接口可以继承多个接口
- 一个类可以实现多个接口
- 一个类只能直接继承一个类
第五章 API_常用类
5.1 概述
API(Application Programming Interface):应用程序编程接口
是Java语言中实际提供的类和接口
5.2 基本数据封装类
- 基本数据包装类是八种基本数据类型对应的引用包装数据类型
-
基本类型没有面向对象的使用方式,所以Java为每种基本类型定义了一个类,来表示基本类型数据,这个类称为包装类
通过包装类可以将基本数据类型的值包装为引用数据类型的对象,在Java中,每种基本类型都有对应的包装类
基本数据类型 | 包装类 |
---|---|
byte | Byte |
short | Short |
char | Character |
int | Integer |
long | Long |
float | Float |
double | Double |
boolean | Boolean |
5.3 装箱和拆箱
装箱:
- 自动将基本数据类型转换为包装器类型
- 装箱的时候自动调用的是Integer的valueOf(int)方法
拆箱:
- 自动将包装器类型转换为基本数据类型
- 拆箱的时候自动调用的是Integer的intValue方法
5.4 Object类
Object类是所有类的基类(超类or祖宗类);
Java中所有类直接或简介继承Object类;
在类中如果没有声明使用extends关键字指明基类,则默认基类为Object类.
toString方法
toString()返回对象的字符串表示形式
在输出一个对象时,默会调用类中toString(),我们的类中如果没有定义toString(),找父类中toString()
equals与==的区别
equals方法:
- 若重写了equals()方法,则是比较两个对象的内容
- 若没有重写equals()方法,则比较的是两个对象的内存地址是否相同
==:
- 用于基本类型比较:比较的值是否相等
- 用于引用类型比较:比较的是引用地址(对象地址)是否相等
5.5 Arrays类
equals方法
- 比较两个非同一数组是否相等,而数组本身的equals判断另一个数组是否它本身。
- 声明:public static boolean equals(type[]a,type[]a2)
- 参数的类型可以是原生数据类型和引用类型的任意一种类型。
- 返回:如果两个相等,则返回true,否则返回false
import java.util.Arrays;
public class EqualsDemo {
/*
Arrays类中包含了许多关于数组操作的静态方法
*/
public static void main(String[] args) {
int[] a = {1,2,3,4,5};
int[] b = {1,2,3,4,5};
System.out.println(Arrays.equals(a,b));
/*
Arrays.equals(a,b)比较的是数组中的内容是否相等
*/
}
}
sort排序
是作用于数组的所有元素
自定义对象排序:
- 自定义类实现Comparable接口
- 重写compareTo方法
-
compareTo:
为我们的引用类型提供一个自定义排序规则,方法会在Arrays类中的sort()方法底层调用
结果是用来判断大小 (有三种情况): 小于0 等于0 大于0
binarySearch -使用二分搜索算法搜索指定数组
其使用二分查找的前提:数组是有序的
在对无序数组进行二分查找时若输出返回为负数则表示没有找到,所以需将数组进行排序方可进行二分查找
5.6 String类
字符串是由多个字符组成的一串数据(字符序列)的字符串常量,java中所有字符串都是String类的实例.
String类有两种创建形式:
- 直接在堆中创建对象:
String s = new String(“str”);
- 简化的创建方式:
先在字符串常量池中查找有没有abc,如果没有就在字符串常量中创建一个对象(abc),如果字符串常量中已经存在abc,那么直接指向已有的对象即可.
Java
String s = "abc";
String s1 = "abc";
System.out.println(s==s1);//true
System.out.println(s.equals(s1));//true
5.7 String,StringBuffer,StringBuilder的区别
-
String:String类是final类型的,底层都是数组(底层是
final char [ ] value
)实现,内容和长度不能改变,使用String定义的字符串是一个常量,改变后会创建一个新的对象; - StringBuffer:线程安全的,可变字符串;适用于多线程下在字符缓冲区进行大量操作的情况;
- StringBuilder:线程不安全的,可变字符串;适用于单线程下在字符缓冲区进行大量操作的情况;
- StringBuffer类和StringBuilder类最大的区别就在于它的内容和长度是可以改变的
第六章 异常
6.1 概述
异常:在Java中将程序执行中发生的不正常情况称为异常
在Java程序执行过程中所发生的异常事件分为:
- **Error:**Java虚拟机无法解决的严重问题。如:JVM系统内部错误、资源耗尽等严重情况。一般不编写针对性的代码进行处理。
- **Exception:**其他因编程错误或偶然的外在因素导致的一般性问题,可以使用针对性的代码进行处理。
6.2 运行时异常&编译期异常
运行时异常:
-
程序运行时抛出的异常,RuntimeException类及其子类都是运行时异常。其在程序运行时由Java虚拟机自动进行捕获处理的,即使没有try{}catch{}语句或使用throws关键字声明抛出,程序也能编译通过,只是在运行时可能报错。
如:算术异常(ArithmeticException)
空指针异常(NullPointerException)
类型转换异常(ClassCastException)
数组越界异常(ArrayIndexOutOfBoundsException)
编译期异常:
-
在Exception的子类中,除了RuntimeException类及其子类外,其他子类都是编译期异常(除去运行期的异常都是编译期异常),也称为检测异常。
如:IOException,SQLException等
6.3 异常处理(try{} catch{} finally{})
当程序发生异常时,会立即终止,无法继续向下执行。为了保证程序能够有效的执行,Java中提供了一种对异常进行处理的方式——异常捕获
(1)try{ } catch( ){ }
try{
编写可能出现异常的代码
}catch(捕获的异常类型){
异常处理 提示 做其他操作
}
(2)try{ } catch( ){ } finally{ }
try,catch,finally通常配合使用;
在try{}代码块中捕获异常;在catch{} 代码块中进行异常处理;
无论异常是否被处理,finally{}代码块中的代码都会被执行;若有return返回值时,先执行finally代码块中的语句。
(3)try{ } finally{ }
try中代码发生异常,但没有处理,程序无法继续向后执行,但finally中代码可执行。
6.4 throw和throws
- throw用于方法体中,用来抛出一个实际的异常对象,使用throw后,要么使用try catch捕获异常,要么使throws声明异常
- throws用于方法声明处,用来声明该方法可能发生的异常类型,可以是多个异常类型,用来强制调用该方法时处理这些异常
- 抽象方法也可以使用throws
第七章 集合
7.1 概念
通过前期学习,如果我们需要保存一组元素时,我们使用了数组这样的容器去存储,但是数组一经定义,它的长度是无法变化的,所以我们需要能够动态增长长度的容器来保存我们的数据。在Java中对于各种数据结构的实现就是我们用到的集合。
7.2 Collection接口(List集合与Set集合)
接口中常用的方法(单列集合共有的方法),定义了存取一组对象的方法,其子接口Set和List分别定义了存储方式。
List集合:
ArryList
-
数组列表,数据采用的是数组方式存储。
-
查询效率快(可以参见数组优点),但是中间添加、删除效率低
-
实现了长度可变的数组,在内存中分配连续的空间
-
其在创建对象时不会创建数组,第一次添加时创建一个容量为10的数组
-
在添加时,先判断元素添加进去后数组是否放的下,如果可以直接添加进去,如果不可以会创建一个数组(扩容)
LinkedList
-
链表,查询慢,中间添加、删除效率高
Vector
-
基于数组实现,增删慢,查询快,但是线程安全。 默认长度为10;扩容速度为2倍;
List接口集合迭代的方式:
-
for循环遍历
支持在遍历的过程中删除集合中的元素
-
增强for循环遍历
不支持在遍历时删除元素
-
迭代器遍历(Iterator)
调用Iterator(),返回一个迭代器对象
Set集合:
- Set中所存储的元素是不重复的,但是是无序的
- Set接口主要有两个实现类:HashSet和TreeSet
- Set集合只能用增强for循环和迭代器遍历
HashSet集合:
-
HashSet类中的元素不能重复,即彼此调用equals方法比较,都返回false,并且元素都是无序的
-
其底层数据结构是哈希表和链表
-
在向HashSet集合中添加元素时,先用内容调用hashCode()方法计算出一个int类型的hash值,用哈希值比较是否相同,但只用哈希值比较是不安全的,就要调用equals方法对每个字符进行比较
TreeSet集合:
-
其内部采用平衡二叉树来存储元素,保证了TreeSet集合中没有重复的元素,且可以对元素进行排序
7.3 Map
Map接口是一种双列集合,它的每一个元素都包含一个key(键对象)和Value(值对象)。Map中的映射关系是一对一的,即一个键对象(key)只能对应一个值对象(Value),键和值对象可以是任意数据类型。
HashMap集合
-
HashMap中元素的key值不能重复,排列顺序是不固定的,可以存储一个null值
-
底层是由哈希表结构组成,即“数组+链表”的组合体,Java8时数据存储方式变为“数组+链表+红黑树”;当链表的元素超过8个时,HashMap将链表结构转换为红黑树;
-
在HashMap中为保证键不重复,采用了 hashCode()方法与equals()方法双重检查法,保障键不重复;
TreeMap集合
-
TreeMap集合不允许出现重复的键,内部是通过二叉树原理保证建的唯一性
HashTable集合
-
HashTable是Map接口的一个实现类,不能存储null的键,其线程是安全的,但效率不如HashMap
7.4 Collections类
Collections是集合类的工具类,与数组的工具类Arrays类似.如将集合中的元素排序,从集合中查找某个元素等。
第八章 IO
8.1 File类
- File类是java.io包中很重要的一个类
- File对象可以对文件或目录的属性进行操作,但无法操作文件的具体数据(不能直接对文件进行读/写操作)
- 构造方法详见https://blog.csdn.net/weixin_51720882/article/details/123085745?spm=1001.2014.3001.5502
8.2 流
- 按照方向可分为:输入流、输出流
- 从数据编码格式分为:字节流,字符流
- 根据封装类型不同流分为:节点流,处理流
- 按照功能可分: 节点流、缓冲流
- 打印流(Print打印流):只做输出没有输入,分为字节打印流与字符打印流(PrintWrite)
8.3 序列化与反序列化
- 对象的输出流将指定的对象写入到文件的过程,就是将对象序列化的过程
- 对象的输入流将指定序列化好的文件读出来的过程,就是对象反序列化的过程。
- 既然对象的输出流将对象写入到文件中称之为对象的序列化,所以必须要实现Serializable接口。
- Serializable接口中没有任何方法。当一个类声明实现Serializable接口后,表明该类可被序列化。
第九章 网络编程
9.1 网络编程的概述及目的
概述:
Java提供的网络类库,可以实现网络连接,联网的底层细节被隐藏在Java 的本机安装系统里,由 JVM 进行控制。并且 Java 实现了一个跨平台的网络库,
程序员面对的是一个统一的网络编程环境。
网络编程的主要目的:
直接或间接地通过网络协议与其它计算机进行通讯
9.2 网络模型
OSI七层模型及TCP/IP四层模型
9.3 网络通信要素
网络编程中三要素:IP地址、端口号和通信协议地址
IP地址:是指互联网协议地址,网络中地计算机使用IP地址进行唯一标识
端口号:用来区分不同地应用程序
通信协议:计算机网络中实现通信须有一些约定,即通信协议,对速率、传输代码、代码结构、 传输控制步骤、出错控制等制定标准
9.4 网络通信协议(TCP&UDP)
TCP(传输控制协议):
- 使用TCP协议前,须先建立TCP连接,形成传输数据通道
-
传输前,采用“
三次握手
”方式,是可靠的 - TCP协议进行通信的两个应用进程:客户端、服务端
- 在连接中可进行大数据量的传输
- 传输完毕,需释放已建立的连接,效率低
- 在断开时要进行**“四次挥手”**
UDP(用户数据报协议):
- 将数据、源、目的封装成数据包,不需要建立连接
- 每个数据报的大小限制在64K内
- 因无需连接,故是不可靠的
- 发送数据结束时无需释放资源,速度快
9.5 TCP三次握手与四次挥手
三次挥手:
第一次握手:
客户端向服务端发送一个SYN(发起一个新连接)报文,并指明客户端地初始化序列号ISN
第二次握手:
服务器收到客户端发送的SYN报文后,会以自己的SYN报文作为应答
第三次握手:
客户端收到SYN报文后,回应ACK(确认序号有效)报文,进入连接状态
四次挥手:
第一次挥手:
客户端发送一个 FIN(释放一个连接) 报文,报文中会指定一个序列号。此时客户端处于 FIN_WAIT1(等待状态1) 状态。
第二次挥手:
服务端收到 FIN 之后,会发送 ACK 报文,且把客户端的序列号值 +1 作为 ACK 报文的序列号值,表明已经收到客户端的报文了,此时服务端处于 CLOSE_WAIT (关闭等待)状态
第三次挥手:
服务端断开连接前,发送FIN报文,请求客户端确认关闭连接,服务器进入LAST-ACK(最后确认)状态
第四次挥手:
客户端收到FIN后,同样会发送ACK确认报文作为应答,此时客户端处于TIME_WAIT等待状态,设置的超时时间结束后才到关闭状态
第十章 线程
10.1 进程与线程及两者之间的关系
●
进程
((process)就是正在执行的程序,从Windows角度讲,进程是操作系统进行资源分配的最小单位. 含有内存和资源以及存放线程
●
线程
(thread)进程可进一步细化为线程,是一个进程内部的最小执行单元,是操作系统进行任务调度的最小单元,隶属于进程
关系:
● 一个进程可以包含多个线程,一个线程只能属于一个进程,线程不能脱离进程 而独立运行;
● 每一个进程至少包含一个线程(称为主线程);在主线程中开始执行程序,
java程序的入口main()方法就是在主线程中被执行的。
● 在主线程中可以创建并启动其它的线程;
● 一个进程内的所有线程共享该进程的内存资源
10.2 线程的创建
-
继承Thread类的方式
在Java中要实现线程,扩展Thread类,重写其中的run方法,当线程启动时,它将执行run方法。
-
实现Runnable接口的方式
Runnable接口的存在主要是为了解决Java中不允许多继承的问题,因在Java中当一个类继承一个其他的父类,那么就无法通过继承Thread类方式创建线程,所以可以实现Runnable接口的方式来创建线程
-
实现Callable接口的方式
实现的Callable接口后,需重写它的call()方法, -
使用线程池
10.3 线程的优先级
- 在计算机中事实上只有一个CPU,各个线程轮流获得CPU使用权才能执行任务
- 优先级取值范围在1~10,一般线程的默认优先级都是5
- 优先级较高的线程有更多获得CPU的机会
10.4 线程状态
线程在它的生命周期中会处于不同的状态
新建–>就绪–>运行–>阻塞–>死亡
**新建:**当一个Thread类或其子类的对象被声明并创建时,新生的线程对象处于新建状态
**就绪:**当处于新建状态的线程调用start()后,进入线程队列等待CPU资源可用
**运行:**当就绪的线程被调度并获得CPU资源时,进入运行状态,其中run()方法定义了线程的操作和功能
**阻塞:**线程休眠、等待、阻塞进入阻塞状态,在某种特殊情况下被人为挂起或执行输入输出操作时,让出CPU并临时中止自己的执行进入阻塞状态
**死亡:**线程完成了它的全部工作或线程被提前强制性地中止或出现异常导致结束。注意:线程执行了stop()时,线程会进入到死亡状态
10.5 多线程
多线程即包含多个执行单元,即在一个程序中可以同时运行多个不同的线程来执行不同的任务,即允许单个程序创建多个并行执行的线程来完成各自任务
何时需要多线程
- 当程序需要同时执行两个或多个任务时
- 当程序需要实现一些需要等待的任务时(如用户输入、文件读写操作等)
- 需要一些后台运行的程序时
优点:
- 能够提高程序的响应
- 提高CPU的利用率
- 能够改善程序结构,即可以将执行的复杂任务分为多个线程如何独立运行
缺点:
- 当线程越多时内存占用也越多
- 多线程需要协调和管理,所以需要CPU时间跟踪线程
- 线程间对于共享资源的访问会产生影响,因此需要解决资源共享的问题
10.6 线程安全及解决办法
何时出现?
- 线程安全问题主要是出现在多线程的情况下,即在同一时间有多个线程同时抢占并使用同一资源(线程并发)时出现
- 多线程对数据的共享造成了操作不完整,破坏数据出现线程安全问题
如何解决?
第一种方式:同步代码块
同步代码块:synchronized关键字可以用于方法中的某个区块中,表示只对这个区块的资源实行互斥访问
注:在Java代码中实现同步:
使用synchronized(同步监视器)关键字同步方法或代码块。
synchronized (同步监视器){
// 需要被同步的代码;
}
synchronized还可以放在方法声明中,表示整个方法,为同步方法。
例如:
public synchronized void show (String name){
// 需要被同步的代码;
}
同步锁:
对象的同步锁只是一个概念,可以想象为在对象上标记了一个锁:
- 锁对象 可以是任意类型
- 多个线程对象 要使用同一把锁
第二种方式:同步方法
同步方法
:使用synchronized修饰的方法,就叫做同步方法,保证线程执行该方法的时候,其他线程只能在方法外等着。
第三种方式:Lock锁
- java.util.concurrent.locks.Lock接口是控制多个线程对共享资源进行访问的工具。
- 锁提供了对共享资源的独占访问,每次只能有一个线程对Lock对象加锁,线程开始访问共享资源之前应先获得Lock对象
-
可重入锁:外层方法获取到锁之后,在内层的调用方法中也能获取这把锁;
非公平锁:线程释放锁资源后,线程们一拥而上获取锁,而不是规矩的排队等待获取锁;
独占式锁:当前的锁被一个线程使用时,其他线程不能来使用。 - ReentarntLook作为显示锁,,它拥有与synchronized相同的并发性和内存语义可用来修饰代码块;在使用时需要手动加锁,手动释放锁。可以显式加锁、释放锁
10.7 sleep()&wait()
**sleep():**使当前线程进入休眠阻塞状态,不释放锁,结束休眠后回到就绪状态
**wait():**使当前线程进入等待阻塞状态,释放锁