IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> Java面试复习 -> 正文阅读

[网络协议]Java面试复习

目录

计算机网络

TCP三次握手

TCP四次挥手

TCP与UDP区别

TCP应用场景

UDP应用场景

在浏览器中输? URL 地址到显示主?的过程?

POST与GET区别

HTTP

HTTPS

HTTP与HTTPS区别

HTTP返回状态码

?

HTTP请求方法

JAVA基础

Java8新特性

标识符

访问权限修饰符

八大基本数据类型

ASCII码表

运算符

分支结构

switch结构

for循环break与continue

while循环

do-while循环

三种循环的区别

数组

创建数组

创建数组过程分析

数组工具类Arrays

面向对象

概念:

与面向过程的区别

三大特性

创建对象流程

Java 中创建对象的?种?式?

重写Override

重载Overload

重载Overload 与重写Override的区别

this与super的区别

static关键字

final关键字

代码块

异常

常见异常类型

抽象类

接口

抽象类与接口区别

Java常用类

Object

Arrays

String

StringBulider和StringBuffer

Iterator

正则表达式

包装类

IO流

分类

IO流的继承结构

File文件类

字节流读取

字节流写出

字符流读取

字符流写出

序列化与反序列化

集合Collection

List接口

ArrayList

Vector

LinkedList

ArrayList和LinkedList的区别

Set接口

HashSet

TreeSet

LinkedHashSet

Map接口

HashMap


计算机网络

TCP三次握手

首先,客户端处于closed状态,服务器端处于listen监听状态:

第一次握手:客户端向服务器发送SYN报文,并指明初始化序列号INS,此时客户端处于SYN-Send状态。

第二次握手:服务器接收客户端发送的SYN报文后,会先初始化自己序列号,同时将客户端的I

NS+1作为ACK的值,表示已经收到客户端的SYN,将自己的SYN、ACK报文作为应答发送给客户

端,此时服务器处于SYN-REVD状态。

第三次握手:客户端接收服务器发送的SYN报文后,将服务器的INS+1作为ACK的值发送给服务

器,表示已经收到服务器的SYN报文,此时客户端变为ESTABLISHED状态。服务器接收到客户端

的ACK报文,服务器变为ESTABLISHED状态,至此双方建立连接,客户端和服务器就可以相互传

输数据了。

为何不能两次握手?

1.三次握手可以阻止重复历史连接的初始化。

2.同步双方的初始序列号。

3.避免资源浪费。

三次握手能确认双方的接收、发送能力正常。

TCP四次挥手

刚开始双方都处于ESTABLISHED状态,假如客户端先发起关闭请求:

第一次挥手:客户端向服务器发送FIN报文,并指定一个序列号INS,此时客户端处于CLOSED-WAIT1状态。

第二次挥手:服务器端接收FIN报文,并将客户端的INS+1作为ACK应答报文的序列号值发送给客

户端,表示已经收到客户端的FIN报文,此时服务器处于CLOSED-WAIT2状态。

第三次挥手:如果服务器也想断开连接,则向客户端发送FIN报文,并指定一个序列号,此时服务

器处于LAST-ACK状态。

第四次挥手:客户端接收服务器的FIN报文,并将服务器的序列号+1作为ACK报文的序列号值发送

给服务器,此时客户端处于TIME-WAIT状态,需要过一段时间以确保服务器收到自己的ACK报文

后,才会进入CLOSED状态。

服务器接收客户端的ACK报文后,关闭连接,处于CLOSED状态。

TIME-WAIT状态,客户端发送ACK报文后,需等待是否会接收到服务器重新发来的FIN报文,判断

服务器是否接收到ACK报文,如果收到FIN则表示服务器未接收到之前发送的ACK报文,需重新发

送ACK报文,一般会设置等待时间(一般一个报文来回时间),超过等待时间未收到服务器重新发

送的FIN报文则表示服务器成功接收ACK报文,处于CLOSED状态。

TCP与UDP区别

1.TCP是面向连接的传输层协议,即传输数据前要先建立连接,UDP无需建立连接即可传输数据。

2.TCP是面向字节流的,不保留数据边界,但保证顺序和可靠,UDP是面向报文,保留数据边界。

3.TCP是一对一的两点服务,即一个连接只有两个端点,UDP可以一对一、一对多、多对多的交互

通信。

4.TCP是可靠交付数据,数据可以无差错、不重复、不丢失、按需到达,UDP是尽最大努力交付,

不保证可靠交付数据。

5.TCP首部开销较大,20字节,若使用选项,则更长,UDP首部固定8字节,开销小。

6、TCP传输速度相对UDP较慢。

7.TCP有流量控制和拥塞控制,UDP没有。

TCP应用场景

TCP面向连接,能保证数据的可靠性交付,常用于:

FTP文件传输

HTTP/HTTPS

UDP应用场景

UDP是面向无连接的,可以随时发送数据,加上UDP本身的处理简单又高效,常用于:

????????????????包总量较少的通信,如DNS、SNMP等。

????????????????视频、音频等。

????????????????多媒体通信、广播通信等。

????????????????游戏等对低延时要求比较高的场景。

在浏览器中输? URL 地址到显示主?的过程?

1.DNS解析:浏览器查询DNS,获取域名对应的IP地址,具体过程:浏览器搜索?身的 DNS 缓存、

搜索操作系统的 DNS 缓存、读取本地的Host ?件和向本地 DNS 服务器进?查询,查到则返回解

析结果,未查到,则依次向根域名服务器,顶级域名服务器,权威域名服务器查询,并返回对应域

名IP地址或报错。

2.TCP连接:浏览器获取到域名对应IP地址后,向服务器请求建立连接,发起三次握手与服务器建

立连接。

3.发送HTTP请求:TCP连接建立后,浏览器向服务器发送HTTP请求。

4.服务器处理请求并返回HTTP报文:服务器接收到这个请求后,并根据路径参数映射到特定的请

求处理器进行处理,并将处理结果及对应的视图返回给浏览器。

5.浏览器解析渲染页面:浏览器解析并渲染视图,若遇到js、css文件及图片等静态资源的引用,则

重复上述步骤向服务器请求这些资源,浏览器根据其请求到的资源、数据渲染页面,最终向用户呈

现一个完整的页面。

6.连接结束。

POST与GET区别

使用场景:

GET用于从服务器获取资源,POST用于传输实体,向URI指定的资源提交数据。

参数:

GET 和 POST 的请求都能使?额外的参数,但是 GET 的参数是以查询字符串出现在 URL 中,?

POST 的参数存储在实体主体中。

安全性

对影响服务器状态来讲,GET方法是安全的,只读取资源,不改变服务器状态,而POST的目的是

传送实体主体内容,服务器可能把这个数据存储在数据库,状态会发生改变。

????????安全的方法还有:HEAD、OPTIONS。

????????不安全的方法有:PUT、DELETE。

对于本身传输信息来讲,GET参数会直接暴露在URL上,而POST的参数放在实体主体中,POST

相对安全一些。(并不是绝对安全,也可以通过Wireshark等抓包工具获取信息)

幂等性:

幂等的 HTTP ?法,同样的请求被执??次与连续执?多次的效果是?样的,服务器的状态也是

?样的。换句话说就是,幂等?法不应该具有副作?(统计?途除外)。

在正确实现的条件下,GET,HEAD,PUT 和 DELETE 等?法都是幂等的,? POST ?法不是。

可缓存

请求报?的 HTTP ?法本身是可缓存的,包括 GET 和 HEAD,但是 PUT 和 DELETE 不可缓存,

POST 在多数情况下不可缓存的。可以从浏览器历史记录查看GET请求,而POST不能。

XMLHttpRequest

????????XMLHttpRequest 是?个 API,它为客户端提供了在客户端和服务器之间传输

数据的功能。它提供了?个通过 URL 来获取数据的简单?式,并且不会使整个??刷新。这使得

??只更新?部分???不会打扰到?户。XMLHttpRequest 在 AJAX 中被?量使?。

????????在使? XMLHttpRequest 的 POST ?法时,浏览器会先发送 Header 再发送 Data。但不是所有浏览器会这 么做,如?狐就不会。

? GET ?法 Header 和 Data 会?起发送。

HTTP

HTTP协议是一种无状态、明文传输的协议,一大缺点不安全

HTTP 最凸出的优点是简单、灵活和易于扩展、应??泛和跨平台

HTTPS

HTTPS 协议是由 SSL + HTTP 协议构建的可进?加密传输、身份认证的?络协议。

HTTP与HTTPS区别

1.HTTP是超文本传输协议,信息是明文传输,存在安全风险。HTTPS在TCP和HTTP网络层之间

加入了SSL/TLS协议,使报文能够加密传输,消耗更多CPU和内存资源。

2.安全性:HTTP建立连接相对简单,TCP 三次握?之后便可进? HTTP 的报?传输。? HTTPS

在 TCP 三次握?之后,还需进? SSL/TLS 的握?过程,才可进?加密报?传输。

3.端口不同:HTTP端口号是80,HTTPS端口号是443.

4.开销:HTTPS协议需要向证书权威机构申请数字证书,来保证服务器的身份是可靠的,申请证书

一般需要交费。

HTTP返回状态码

?

?

HTTP请求方法

1、GET方法

用于使用给定的URI从给定服务器中检索信息,即从指定资源中请求数据。使用GET方法的请求应

该只是检索数据,并且不应对数据产生其他影响。

在GET请求的URL中发送查询字符串(名称/值对),需要这样写:/test/demo_form.php?

name1=value1&name2=value2

说明:GET请求是可以缓存的,我们可以从浏览器历史记录中查找到GET请求,还可以把它收藏到

书签中;且GET请求有长度限制,仅用于请求数据(不修改)。

注:因GET请求的不安全性,在处理敏感数据时,绝不可以使用GET请求。

2、HEAD方法

与GET方法相同,但没有响应体,仅传输状态行和标题部分。这对于恢复相应头部编写的元数据非

常有用,而无需传输整个内容。

3、POST方法

用于将数据发送到服务器以创建或更新资源,它要求服务器确认请求中包含的内容作为由URI区分

的Web资源的另一个下属。POST请求永远不会被缓存,且对数据长度没有限制;我们无法从浏览器

历史记录中查找到POST请求。

4、PUT方法

用于将数据发送到服务器以创建或更新资源,它可以用上传的内容替换目标资源中的所有当前内

容。它会将包含的元素放在所提供的URI下,如果URI指示的是当前资源,则会被改变。如果URI

未指示当前资源,则服务器可以使用该URI创建资源。

5、DELETE方法

用来删除指定的资源,它会删除URI给出的目标资源的所有当前内容。

6、CONNECT方法

用来建立到给定URI标识的服务器的隧道;它通过简单的TCP/IP隧道更改请求连接,通常实使用解

码的HTTP代理来进行SSL编码的通信(HTTPS)。

7、OPTIONS方法

用来描述了目标资源的通信选项,会返回服务器支持预定义URL的HTTP策略。

8、TRACE方法

用于沿着目标资源的路径执行消息环回测试;它回应收到的请求,以便客户可以看到中间服务器进

行了哪些(假设任何)进度或增量。

以上介绍了HTTP的8种请求方式,其中常用的是GET和POST。可以说,GET是从服务器上获取数

据,POST是向服务器传送数据,至于选择哪种,就需要根据实际情况来选择了。

JAVA基础

Java8新特性

Lambda 表达式:Lambda 允许把函数作为一个方法的参数(函数作为参数传递到方法中)。

方法引用: 方法引用提供了非常有用的语法,可以直接引用已有Java类或对象(实例)的方法或

构造器。与lambda联合使用,方法引用可以使语言的构造更紧凑简洁,减少冗余代码。

默认方法: 默认方法就是一个在接口里面有了一个实现的方法。

新工具:新的编译工具,如:Nashorn引擎 jjs、 类依赖分析器jdeps。

Stream API: 新添加的Stream API(java.util.stream) 把真正的函数式编程风格引入到Java中。

Date Time API: 加强对日期与时间的处理。

Optional 类: Optional 类已经成为 Java 8 类库的一部分,用来解决空指针异常。

Nashorn, JavaScript 引擎: Java 8提供了一个新的Nashorn javascript引擎,它允许我们在JVM

上运行特定的javascript应用。

标识符

  1. 标识符可以由字母、数字、下划线(_)、美元符($)组成,但不能包含 @、%、空格等其

  2. 它特殊字符。

  3. 不能以数字开头,。如:123name 就是不合法

  4. 标识符严格区分大小写。如: tmooc 和 tMooc 是两个不同的标识符

  5. 标识符的命名最好能反映出其作用,做到见名知意。

  6. 标识符不能是Java的关键字

访问权限修饰符

八大基本数据类型

常用的转换关系: 位 bit,来自英文bit,音译为“比特”,表示二进制位。 1 Byte = 8 Bits (1字节 = 8

位) 1 KB = 1024 Bytes 1 MB = 1024 KB 1 GB =1024 MB

类型转换

小到大,直接转 大到小,强制转 浮变整,小数没 低 ------------------------------------> 高

byte,short,char→ int→ long→float→double。

byte,short,char三种比int小的整数,运算时会先自动转换成int。

ASCII码表

运算符

分支结构

switch结构

switch case 语句用来判断一个变量与一系列值中某个值是否相等,每个值称为一个分支。

当一个case成立,从这个case向后穿透所有case,包括default,直到程序结束或者遇到break程序

才结束。

switch 语句中支持的变量类型: byte、short、int 、char、String(jdk1.7以后支持)

for循环break与continue

break: 直接结束当前循环,跳出循环体,简单粗暴

break以后的循环体中的语句不会继续执行,循环体外的会执行。 注意如果是嵌套for循环,在内层循

环遇到了break,只会跳出当前这一层内循环。

continue: 跳出本轮循环,继续下一轮循环

continue后本轮循环体中的语句不会继续执行,但是会继续执行下轮循环,循环体外的也会执行。

while循环

先判断再执行

do-while循环

先执行,再判断,循环体代码保证最少执行一次

三种循环的区别

  1. for:知道循环次数。

  2. while/do while:当循环次数不确定时。

  3. while:先判断,不符合规则,不执行代码。

  4. do while:代码最少被执行一次,再去判断,符合规则,再次执行代码。

  5. 循环之间都可以互相替代,但是一般最好选择合适的循环结构来完成代码。

数组

数组Array,标志是[ ] ,用于储存多个相同类型数据的集合想要获取数组中的元素值,可以通过脚标

(下标)来获取数组下标是从0开始的,下标的最大值是数组的长度减1

创建数组

数组的创建方式一般分为动态初始化和静态初始化

  1. 动态初始化 int[] a = new int[5];

  2. 静态初始化 int[] b = new int[]{1,2,3,4,5}; int[] c = {1,2,3,4,5};

数组的长度用 length属性来表示,数组一旦创建,长度不可改变

创建数组过程分析

程序创建数组 int[] a = new int[5]; 时发生了什么?

1.在内存中开辟连续的空间,用来存放数据,长度是5。

2.给数组完成初始化过程,给每个元素赋予默认值,int类型默认值是0。

3.数组完成初始化会分配一个唯一的地址值。

4.把唯一的地址值交给引用类型的变量a去保存。

数组名是个引用类型的变量,它保存着的是数组的地址,不是数组中的数据

数组工具类Arrays

Arrays.toString(数组)

把数组里的数据,用逗号连接成一个字符串[值1,值2]。

Arrays.sort(数组)

对数组进行排序,对于基本类型的数组使用的是优化后的快速排序算法,效率高 对引用类型数组,使用

的是优化后的合并排序算法。

Arrays.copyOf(数组,新的长度)

把数组赋值成一个指定长度的新数组 新数组的长度 大于 原数组, 相当于复制,并增加位置 新数组的

长度 小于 原数组, 相当于截取一部分数据

面向对象

概念:

?向对象是?种基于?向过程的编程思想,强调的是结果,由 执?者变为指挥者,在现实?活中

的任何物体都可以归为?类事物,?每?个个体都是?类事物的实例。?向对象 的编程是以对象

为中?,以消息为驱动。

与面向过程的区别

(1)编程思路不同:?向过程以实现功能的函数开发为主,??向对象要?先抽象出类、属性及

其?法,然后通过实例化类、执??法来完成功能。

(2)封装性:都具有封装性,但是?向过程是封装的是功能,??向对象封装的是数据和功能。

(3)?向对象具有继承性和多态性,??向过程没有继承性和多态性,所以?向对象优势很明

显。

三大特性

1.封装:通常认为封装是把数据和操作数据的?法封装起来,对数据的访问只能通过已定义的接

?。

2.继承:继承是从已有类得到继承信息创建新类的过程。提供继承信息的类被称为?类(超类/基

类),得到继承信息 的被称为?类(派?类)。

继承作为面向对象编程的特性,可以大大的减少代码的冗余,实现代码的复用,继承了父类的子类

可以继承其除private权限修饰所有的属性和功能,并且可以对其进行拓展。

继承的实现,其本质都是通过super来实现对父类对象的引用,super代表的是父类的一个引 用对

象。对于子类使用父类的属性和方法实际上都是调用

了super方法来实现的。即引用对 象指向父类的实际地址,本质上还是同一个内存地址上的对象。

3.多态:多态是同一个行为具有多个不同表现形式或形态的能力,分为编译时多态(?法重载)和

运?时多态(?法重写)。

实现多态的前提:继承、重写、父类引用指向子类对象

编译看左边 运行看右边。解释:

必须要父类定义这个方法,才能通过编译,编译时,把多态对象看作是父类类型。 必须要子类重

写这个方法,才能满足多态,运行时实际干活的是子类。

好处:

1.多态可以让我们不用关心某个对象到底具体是什么类型,就可以使用该对象的某些方法。

2.提高了程序的可扩展性和可维护性。

向上转型:可以把不同的子类对象都当作父类来看,进而屏蔽不同子类对象之间的差异,写出通用

的代码,做出通用的编程,统一调用标准。 比如:

父类Parent,子类Child。

父类的引用指向子类对象:Parent p=new Child();

说明:向上转型时,子类对象当成父类对象,只能调用父类的功能,如果子类重写了父类中声明过

的方法,方法体执行的就是子类重过后的功能。但是此时对象是把自己看做是父类类型的,所以其

他资源使用的还是父类型的。

向下转型(较少):子类的引用的指向子类对象,过程中必须要采取到强制转型。这个是之前向上造

型过的子类对象仍然想执行子类的特有功能,所以需要重新恢复成子类对象。

Parent p = new Child();//向上转型,此时,p是Parent类型。

Child c = (Child)p;//此时,把Parent类型的p转成小类型Child。

其实,相当于创建了一个子类对象一样,可以用父类的,也可以用自己的。

说明:向下转型时,是为了方便使用子类的特殊方法,也就是说当子类方法做了功能拓展,就可以

直接使用子类功能。

创建对象流程

Person p = new Person();//短短这行代码发生了很多事情:

1.把Person.class文件加载进内存。

2.在栈内存中,开辟空间,存放引用变量p。

3.在堆内存中,开辟空间,存放Person对象。

4.对成员变量进行默认的初始化。

5.对成员变量进行显示初始化。

6.执行构造方法(如果有构造代码块,就先执行构造代码块再执行构造方法)。

7.堆内存完成。

8.把堆内存的地址值赋值给变量p ,p就是一个引用变量,引用了Person对象的地址值。

Java 中创建对象的?种?式?

1、使? new 关键字;

2、使? Class 类的 newInstance ?法,该?法调??参的构造器创建对象(反射):

Class.forName.newInstance();

3、使? clone() ?法;

4、反序列化,?如调? ObjectInputStream 类的 readObject() ?法。

重写Override

1.继承以后,子类就拥有了父类的功能。

2.在子类中,可以添加子类特有的功能,也可以修改父类的原有功能。

3.子类中方法的签名与父类完全一样时,会发生覆盖/复写的现象。

4.注意: 父类的私有方法不能被重写。

5.重写的要求:两同两小一大。

两同:方法名 参数列表 要完全一致

两小: 子类返回值类型小于等于父类的返回值类型(注意此处说的是继承关系,不是值大小)。 子类抛

出异常小于等于父类方法抛出异常。

一大:子类方法的修饰符权限要大于等于父类被重写方法的修饰符权限。

重载Overload

一个类中定义多个同名的方法,但是每个方法的参数列表不同(也就是指参数的个数和类型不同),程

序在调用方法时,可以通过传递给他们的不同个数和类型的参数来决定具体调用哪个方法,不能根

据返回类型进?区分。

重载Overload 与重写Override的区别

  1. 重载: 是指在一个类中的现象,是指一个类中有很多同名的方法,但是方法的参数列表不同。

  2. 重写: 是指发生了继承关系以后(两个类),子类去修改父类原有的功能。

  3. 重载的意义: 是为了方便外界对方法进行调用,什么样的参数程序都可以找到对应的方法来执

  4. 行,体现的是程序的灵活性。

  5. 重写的意义:是在不修改源码的前提下,进行功能的修改和拓展。(OCP原则:面向修改关闭,面向

  6. 拓展开放)

this与super的区别

1.This代表本类对象的引用。

class Cat{ this.XXX } 可以理解成: Cat this = new Cat();

2.super代表父类对象的引用。

class Father{ }

class Son extends Father{ super.XXX }

可以理解成: Father super = new Father();

3.this可以在两个变量名相同时,用于区分成员变量和局部变量。

4.this 可以在本类的构造方法之间调用,位置必须是第一条语句,注意,不能相互调用,会死循环。

5.super是建立了继承关系以后,子类如果想用父类的功能,可以通过super调用。

6.如果重写后还想用父类的功能,需要使用super来调用。

7.super在调用父类构造方法时,必须出现在子类构造方法的第一条语句,而且如果父类中没有提供无

参构造,子类可以通过super来调用父类其他的含参构造。

static关键字

  1. 可以修饰成员变量与成员方法。

  2. 随着类的加载而加载,优先于对象加载。

  3. 只加载一次,就会一直存在,不再开辟新空间, 直到类消失才一起消失。

  4. 静态资源也叫做类资源,全局唯一,被全局所有对象共享。

  5. 可以直接被类名调用。

  6. 静态只能调用静态,非静态可以随意调用。

  7. static不能和this或者super共用,因为有static时可能还没有对象。

final关键字

  1. 被final修饰的类,不能被继承。

  2. 被final修饰的方法,不能被重写。

  3. 被final修饰的字段是个常量,值不能被修改。

  4. 常量的定义形式:final 数据类型 常量名 = 值。

代码块

  1. 静态代码块:在类加载时就加载,并且只被加载一次,一般用于项目的初始化。

  2. 构造代码块:在创建对象时会自动调用,每次创建对象都会被调用,提取构造共性。

  3. 局部代码块:方法里的代码块,限制局部变量的范围。

执行顺序:静态代码块->构造代码块->构造方法【对象创建成功】->局部代码块

异常

1.异常概述

异常机制是指当程序出现错误后,程序如何处理。具体来说,异常机制提供了程序退出的安全通

道。当出现错误后,程序执行的流程发生改变,程序的控制权转移到异常处理器。

程序错误分为三种:1.编译错误;2.运行时错误;3.逻辑错误

(1)编译错误是因为程序没有遵循语法规则,编译程序能够自己发现并且提示我们错误的原因和

位置,这个也是大家在刚接触编程语言最常遇到的问题。

(2)运行时错误是因为程序在执行时,运行环境发现了不能执行的操作。

(3)逻辑错误是因为程序没有按照预期的逻辑顺序执行。异常也就是指程序运行时发生错误,而

异常处理就是对这些错误进行处理和控制。

2.异常结构

在 Java 中,所有的异常都有一个共同的祖先 Throwable(可抛出)。Throwable 指定代码中可用

异常传播机制通过 Java 应用程序传输的任何问题的共性。

Throwable: 有两个重要的子类:Exception(异常)和 Error(错误),二者都是 Java 异常处理

的重要子类,各自都包含大量子类。异常和错误的区别是:异常能被程序本身可以处理,错误是无

法处理。

Error(错误):是程序无法处理的错误,表示运行应用程序中较严重问题。大多数错误与代码编

写者执行的操作无关,而表示代码运行时JVM

(Java 虚拟机)出现的问题。

Exception(异常):是程序本身可以处理的异常。Exception 类有一个重要的子类

RuntimeException。RuntimeException 类及其子类表示“JVM 常用操作”引发的错误。例如,若试

图使用空值对象引用、除数为零或数组越界,则分别引发运行时异常

(NullPointerException、ArithmeticException)和 ArrayIndexOutOfBoundException。

Exception(异常)分为两大类:

1.运行时异常:都是RuntimeException类及其子类异常。

2.非运行时异常 (编译异常):是RuntimeException以外的异常,类型上都属于Exception类及其

子类。

3.异常处理机制

1. 抛出异常:当一个方法出现错误引发异常时,方法创建异常对象并交付运行时系统,异常对象中

包含了异常类型和异常出现时的程序状态等异常信息。运行时系统负责寻找处置异常的代码并执

行。

(1)throws 抛出异常

throws语句用在方法定义时声明该方法要抛出的异常类型,如果抛出的是Exception异常类型,则

该方法被声明为抛出所有的异常。多个异常可使用逗号分割。throws语句的语法格式为:

methodname throws Exception1,Exception2,..,ExceptionN { }

方法名后的throws Exception1,Exception2,…,ExceptionN 为声明要抛出的异常列表。当方法抛出

异常列表的异常时,方法将不对这些类型及其子类类型的异常作处理,而抛向调用该方法的方法,

由他去处理。

使用throws关键字将异常抛给调用者后,如果调用者不想处理该异常,可以继续向上抛出,但最终

要有能够处理该异常的调用者。

(2)throw 抛出异常

throw总是出现在方法体中,用来抛出一个Throwable类型的异常。程序会在throw语句后立即终

止,它后面的语句执行不到,然后在包含它的所有try块中(可能在上层调用函数中)从里向外寻找

含有与其匹配的catch子句的try块。

2. 捕获异常:在方法抛出异常之后,运行时系统将转为寻找合适的异常处理器(exception

handler)。

(1)try-catch语句

        try { ?
            // 可能会发生异常的程序代码 ?
        } catch (Type1 id1){ ?
            // 捕获并处置try抛出的异常类型Type1 ?
        } catch (Type2 id2){ ?
            //捕获并处置try抛出的异常类型Type2 ?
        }   

Java方法在运行过程中出现异常,则创建异常对象。将异常抛出监控区域之外,由Java运行时系统试图寻找匹配的catch子句以

捕获异常。若有匹配的catch子句,则运行其异常处理代码,try-catch语句结束。

匹配的原则是:如果抛出的异常对象属于catch子句的异常类,或者属于该异常类的子类,则认为生成的异常对象与catch块捕获

的异常类型相匹配。

注意:一旦某个catch捕获到匹配的异常类型,将进入异常处理代码。一经处理结束,就意味着整个try-catch语句结束。其他的

catch子句不再有匹配和捕获异常类型的机会。

(2)try-catch-finally语句

 ? ? ?  try { ?
 ? ? ? ? ?  // 可能会发生异常的程序代码 ?
 ? ? ?  } catch (Type1 id1){ ?
 ? ? ? ? ?  // 捕获并处置try抛出的异常类型Type1 ?
 ? ? ?  } catch (Type2 id2){ ?
 ? ? ? ? ? ? //捕获并处置try抛出的异常类型Type2 ?
 ? ? ?  }finally { ?
 ? ? ? ? ?  // 无论是否发生异常,都将执行的语句块 ?
 ? ? ?  } 

try、catch、finally语句块的执行顺序:

(1)当try没有捕获到异常时:try语句块中的语句逐一被执行,程序将跳过catch语句块,执行finally语句块和其后的语句;

(2)当try捕获到异常,catch语句块里没有处理此异常的情况:此异常将会抛给JVM处理,finally语句块里的语句还是会被执

行,但finally语句块后的语句不会被执行;

(3)当try捕获到异常,catch语句块里有处理此异常的情况:在try语句块中是按照顺序来执行的,当执行到某一条语句出现异

常时,程序将跳到catch语句块,并与catch语句块逐一匹配,找到与之对应的处理程序,其他的catch语句块将不会被执行,而try语句块

中,出现异常之后的语句也不会被执行,catch语句块执行完后,执行finally语句块里的语句,最后执行finally语句块后的语句。

小结:

1.try 块:用于捕获异常。其后可接零个或多个catch块,如果没有catch块,则必须跟一个finally块。

2.catch 块:用于处理try捕获到的异常。

3.finally 块:无论是否捕获或处理异常,finally块里的语句都会被执行。finally里的 return语句会把 try/catch块里的 return语句

效果给覆盖掉。当在try块或catch块中遇到return语句时,finally语句块将在方法返回之前被执行。在以下4种特殊情况下,finally块不会

被执行: (1)在finally语句块中发生了异常。 (2)在前面的代码中用了System.exit()退出程序。 (3)程序所在的线程死亡。 (4)关闭CPU。

常见异常类型

1.RuntimeException子类:

序号异常名称异常描述
1java.lang.ArrayIndexOutOfBoundsException数组索引越界异常。当对数组的索引值为负数或大于等于数组大小时抛出。
2java.lang.ArithmeticException算术条件异常。譬如:整数除零等。
3java.lang.SecurityException安全性异常
4java.lang.IllegalArgumentException非法参数异常
5java.lang.ArrayStoreException数组中包含不兼容的值抛出的异常
6java.lang.NegativeArraySizeException数组长度为负异常
7java.lang.NullPointerException空指针异常。当应用试图在要求使用对象的地方使用了null时,抛出该异常。譬如:调用null对象的实例方法、访问null对象的属性、计算null对象的长度、使用throw语句抛出null等等。

2.IOException

序号异常名称异常描述
1IOException操作输入流和输出流时可能出现的异常
2EOFException文件已结束异常
3FileNotFoundException文件未找到异常

3. 其他

序号异常名称异常描述
1ClassCastException类型转换异常类
2ArrayStoreException数组中包含不兼容的值抛出的异常
3SQLException操作数据库异常类
4NoSuchFieldException字段未找到异常
5NoSuchMethodException方法未找到抛出的异常
6NumberFormatException字符串转换为数字抛出的异常
7StringIndexOutOfBoundsException字符串索引超出范围抛出的异常
8IllegalAccessException不允许访问某类异常
9InstantiationException当应用程序试图使用Class类中的newInstance()方法创建一个类的实例,而指定的类对象无法被实例化时,抛出该异常
10java.lang.ClassNotFoundException找不到类异常。当应用试图根据字符串形式的类名构造类,而在遍历CLASSPAH之后找不到对应名称的class文件时,抛出该异常。

抽象类

概念

Java中可以定义被abstract关键字修饰的方法,这种方法只有声明,没有方法体,叫做抽象方法。 Java中可以定义被abstract关键字修饰的类,被abstract关键字修饰的类叫做抽象类。

  1. 如果一个类含有抽象方法,那么它一定是抽象类。

  2. 抽象类中的方法实现交给子类来完成。

  3. 抽象类不能直接实例化,需要依靠子类采用向上转型的方式处理。

  4. 抽象方法必须为public或者protected(如果为private,则不能被子类继承,子类便无法实现该方法),缺省情况下默认为public。

  5. 抽象类中可以有构造方法,其存在目的是为了属性的初始化。

  6. 外部抽象类不允许static声明,内部抽象类可以,继承的时候使用“外部类.内部类”的形式表示类名称。

特点

1.abstract 可以修饰方法或者类。

2.被abstarct修饰的类叫做抽象类,被abstract修饰的方法叫做抽象方法。

3.抽象类中可以没有抽象方法。

4.如果类中有抽象方法,那么该类必须定义为一个抽象类。

5.子类继承了抽象类以后,要么还是一个抽象类,要么就把父类的所有抽象方法都重写。

6.多用于多态中。

7.抽象类不可以被实例化。

abstract注意事项

子类继承父类:

1.子类继续抽象,作为抽象子类。

2.子类重写父类中所有未实现的抽象方法。

abstract与这些关键字搭配无意义:

1.private:被私有化后,子类无法重写,与abstract相违背。 2.static:静态优先于对象存在,存在加载顺序问题。 3.final:被final修饰后,无法重写,与abstract相违背。

接口

概念

Java接口是一系列方法的声明,是一些方法特征的集合,一个接口只有方法的特征没有方法的实现,因此这些方法可以在不同的地方被不

同的类实现,而这些实现可以具有不同的行为(功能)。

接口是解决Java无法使用多继承的一种手段,但是接口在实际中更多的作用是制定标准的。

特点:

1.通过interface关键字来定义接口。

2.通过implements让子类来实现接口。

3.接口中的方法全部都是抽象方法(JAVA8)。

4.可以把接口理解成一个特殊的抽象类(但接口不是类!!!)。

5.类描述的是一类事物的属性和方法,接口则是包含实现类要实现的方法。

6.接口突破了java单继承的局限性。

7.接口和类之间可以多实现,接口与接口之间可以多继承。

8.接口是对外暴露的规则,是一套开发规范。

9.接口提高了程序的功能拓展,降低了耦合性。

10.接口里是没有构造方法的,在创建实现类的对象时默认的super(),是调用的默认Object的无参构造。

11.接口里没有成员变量,都是常量。所以,你定义一个变量没有写修饰符时,默认会加上:public static final。

12.接口里的方法,默认就都是抽象的,如果你不写明是abstract的,那会自动补齐。例如:public abstract void save。

抽象类与接口区别

1.抽象类是一个特殊的类,特殊在:抽象类中可以包含没有方法体的方法(抽象方法)。

2.接口可以理解成一个特殊的抽象类,特殊在:接口里的都是抽象方法,没有普通方法。

3.接口会为方法自动拼接public abstract,还会为变量自动拼接public final static。

4.抽象类可以有构造方法–用来给子类创建对象,接口中没有构造方法。

5.抽象类和接口都不能实例化(创建对象)。

6.接口可继承接口,并可多继承接口,但类只能单继承。

7.抽象方法只能声明,不能实现,接口是设计的结果 ,抽象类是重构的结果。

8.抽象类中可以有抽象?法和具体?法,?接?中只能有抽象?法(public abstract)。

9.抽象类中的成员权限可以是 public、默认、protected(抽象类中抽象?法就是为了重写,所以不能被 private 修饰),?接?中的成员

只可以是 public(?法默认:public abstrat、成员变量默认:public static final)。

在 JDK1.8中,允许在接?中包含带有具体实现的?法,使? default 修饰,这类?法就是默认?法。

抽象类中可以包含静态?法,在 JDK1.8 之前接?中不能包含静态?法,JDK1.8 以后可以包含。之前不能包含 是因为,接?不可以实现?

法,只可以定义?法,所以不能使?静态?法(因为静态?法必须实现)。现在可以包含了,只能直接?接?调?静态?法。

Java常用类

Object

equals():用于比较两个对象是否"相等",默认是比较内存地址。可以通过重写方法来自定义 规则。

toString():用于返回对应对象的字符串表示,默认为:类名+@+哈希值。

hashCode():用于返回对象的内存地址,不同的对象有不同的hashCode值,也可能存在不同对象hashCode值相同,这是一个本地方法。

wait ?法:让当前对象等待。

clone ?法:?于创建并返回当前对象的?份拷?。

finalize ?法:实例被垃圾回收器回收时触发的?法。

Arrays

数组工具类,数组工具类是围绕这数组来进行操作的,所有复杂的数组类的内部几乎都离不开这个 工具类。

数组工具类的所有方法都是静态方法,都可以通过类名来直接调用。

数组工具类操作数组的基本类型,int,long,double,float,char,boolean,short,object,byte 数组类型,而String[]类型的数组

本质是对字符类型操作的数组。

常用方法

Arrays.toString(Array[] a):打印数组
Arrays.copyOf(Array[] a,int):拷贝指定大小数组。
Arrays.sort(Array[] a):排序数组。
        默认从小到大排序
        默认字母大写先排序
        Arrays.sort(strArray, String.CASE_INSENSITIVE_ORDER):忽略大小写排序
        Arrays.sort(strArray, Collections.reverseOrder()):反向排序
Arrays.equals():比较数组元素是否相等
Arrays.fill():填充数组
Arrarys.asList():转换为list

String

String底层维护了字符数组char[],底层被final修饰,字符串不可变,是常量,值存在常量池中。

创建方式

1.通过引号创建

String s2 = "hello";

先创建引用s2,并在常量池中寻找是否有equals("abc"), 如果没有,将"abc"放入常量池中,并令s2指向它。 如果有,则将引用指

向常量池中的地址。

2.通过new创建

String s3 = new String("abc");

若常量池存在相同的字符串常量,先在堆中创建s3变量的对象引用,将这个对象引用指向字符串常量池中的已经存在的常量;

若常量池不存在相同的字符串常量,会直接在堆中创建一个字符串对象然后返回给变量。

new String() 不管常量池中有没有,都会在堆中新建一个对象。

String常用方法

equals():判断两个值是否相等,当地址不等时,则逐一比较char字符的值。

toCharArray():将字符串转变为字符数组。

split():使用指定字符切割为字符数组。

valueOf(data):返回字符串,是一个静态方法。

trim():去掉首尾两端的空格。

replace(Char old, Char new):指定字符代替字符串中的指定字符。

indexOf(int ch): 返回指定字符在此字符串中第一次出现处的索引。

charAt():返回指定索引处的字符。

toUpperCase():变成全大写。

toLowerCase():变成全小写。

length():查看字符串的长度。

StringBulider和StringBuffer

1.两者都是用来操作字符串的。

2.两者都是可变字符序列(字符串变量),使用时对象本身进行操作,而不是生成新的对象并改变对象引用。

3.StringBuilder:效率高、线程不安全。

4.StringBuffer:效率低,线程安全,底层方法使用synchronized修饰实现同步。

String是线程安全的,因为常量池存在于方法区,被所有线程共享,不存在数据不安全问题。 在单线程操作大量数据,推荐使用

StringBuilder,在多线程操作大量数据,推荐使用StringBudffer。

常用方法

append(str):追加,实现对字符串的追加。

reverse():字符串反转。

insert():在指定位置插入字符串。

toString():返回当前字符串。

setLength():设置长度。

charAt():根据下标获取值。

delete(int start, int end):删除指定位置的值。

replace(int start, int end, String str):用指定字符串更换指定位置值。

String substring(int start, int end):切割指定位置字符,左闭右开。

insert():插入值。

Iterator

Iterator 常用于迭代集合中的元素。主要有三个方法:

(1) 使用next()获得序列中的下一个元素。

(2) 使用hasNext()检查序列中是否还有元素。

(3) 使用remove()删除迭代器最后一个元素并删除。

正则表达式

包装类

自动装箱:把 基本类型 包装成对应的 包装类型 的过程 Integer a = 5;//a是引用类型,引用了包装对象的地址。 编译器会完成对象的自动装箱:Integer a = Integer.valueOf(5);

自动拆箱:从包装类型的值,自动变成 基本类型的值 int i = a;//a现在是包装类型,没法给变量赋值,需要把5取出来。 编译器会完成自动拆箱:int i = a.intValue();

IO流

分类

按照流的流向分,可以分为输入流和输出流; 按照操作单元划分,可以划分为字节流和字符流; 按照流的角色划分为节点流和处理流

IO流的继承结构

File 字节流:针对二进制文件 InputStream FileInputStream BufferedInputStream ObjectInputStream

OutputStream FileOutputStream BufferedOutputStream ObjectOutputStream 字符流:针对文本文件 Reader FileReader BufferedReader InputStreamReader

Writer FileWriter BufferedWriter OutputStreamWriter PrintWriter一行行写出

File文件类

概述

封装一个磁盘路径字符串,对这个路径可以执行一次操作可以封装文件路径、文件夹路径、不存在的路径。

常用方法

read()每次调用都会读取一个字节,如果读到了数据的末尾,返回-1

字节流读取

InputStream抽象类

此抽象类是表示字节输入流的所有类的超类/抽象类,不可创建对象。

FileInputStream子类

直接插在文件上,直接读取文件数据。

BufferedInputStream子类

BufferedInputStream 为另一个输入流添加一些功能,在创建BufferedInputStream 时,会创建一个内部缓冲区数组(默认8k大小)。

在读取或跳过流中的字节时,可根据需要从包含的输入流再次填充该内部缓冲区,一次填充多个字节。

字节流写出

OutputStream抽象类

此抽象类是表示输出字节流的所有类的超类.输出流接受输出字节并将这些字节发送到某个接收器。

FileOutputStream 子类

直接插在文件上,直接写出文件数据。

BufferedOutputstream 子类

该类实现缓冲的输出流,通过设置这种输出流,应用程序就可以将各个字节写入底层输出流中,而不必每次针对字节写出调用底层系统。

字符流读取

Reader抽象类

用于读取字符流的抽象类。

FileReader子类

用来读取字符文件的便捷类。此类的构造方法假定默认字符编码和默认字节缓冲区大小都是适当的。要自己指定这些值,可以先在

FileInputStream 上构造一个 InputStreamReader。

BufferedReader子类

从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。可以指定缓冲区的大小,或者可使用默认的大小。大多数情况下,默认值就足够大了。

字符流写出

Writer 抽象类

写入字符流的抽象类。

FileWriter 子类

用来写入字符文件的便捷类,此类的构造方法假定默认字符编码和默认字节缓冲区大小都是可接受的.如果需要自己自定义这些值,可以先在

FileOutputStream上构造一个OutputStreamWriter。

BufferedWriter子类

将文本写入字符输出流,缓冲各个字符,从而提供单个字符,数组和字符串的高效写入.可以指定缓冲区的大小,或者接受默认的大小,在大多数

情况下,默认值就足够大了。

序列化与反序列化

序列化是指将对象的状态信息转换为可以存储或传输形式的过程,在序列化期间,对象将其当前状态写入到临时或持久性存储区,以后可以通

过从存储区中读取或者反序列化对象的状态,重新创建该对象。

序列化:利用ObjectOutputStream,把对象的信息,按照固定的格式转成一串字节值输出并持久保存到磁盘。

反序列化:利用ObjectInputStream,读取磁盘中之前序列化好的数据,重新恢复成对象。

特点/应用场景

1.需要序列化的文件必须实现Serializable接口,用来启用序列化功能。

2.不需要序列化的数据可以修饰成static,原因:static资源属于类资源,不随着对象被序列化输出。

3.每一个被序列化的文件都有一个唯一的id,如果没有添加此id,编译器会自动根据类的定义信息计算产生一个。

4.在反序列化时,如果和序列化的版本号不一致,无法完成反序列化。

5.常用与服务器之间的数据传输,序列化成文件,反序列化读取数据。

6.常用使用套接字流在主机之间传递对象。

7.不需要序列化的数据也可以被修饰成transient(临时的),只在程序运行期间在内存中存在,不会被序列化持久保存。

集合Collection

什么是集合(Collection)?集合就是“由若干个确定的元素所构成的整体”,是一种容器。

集合的英文名称是Collection,是用来存放对象的数据结构,而且长度可变,可以存放不同类型的对象,并且还提供了一组操作成批对象的方

法。Collection接口层次结构 中的根接口,接口不能直接使用,但是该接口提供了添加元素/删除元素/管理元素的父接口公共方法。

集合框架图

Collection方法速查表

List接口

List列表,是一个有序的元素集合。它的特点如下:

  1. 数据是有序的。

  2. 允许存放重复的元素。

  3. 元素都有下标。

    它提供一些统一的方法来供其子类ArrayList和LinkedList使用。

常用方法

get(index):得到指定位置的元素。
set(index, value):修改指定位置的值。
add(index, value):在指定位置插入值。
indexOf(Object):根据元素值返回下标。
addAll(index, Collection):在指定位置插入集合的所有元素。
remove(index):根据下标删除元素
remove(Object):根据内容删除元素
toArray(int len):转换为数组
listIterator(listiterator):返回列表迭代器。
toArray(Object[]):可以不传参,但是会造成数据类型的丢失。

List迭代方式

// 方式一:通过集合迭代器迭代
Iterator<Integer> iterator = c.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
// 方式二:通过list迭代器迭代
ListIterator<Integer> iterator1 = c.listIterator();
while (iterator1.hasNext()){
System.out.println(iterator1.next());
}
// 通过for循环遍历
for (int i = 0; i < c.size(); i++) {
System.out.println(c.get(i));
}
// 通过for迭代
for(Integer i: c){
System.out.println(i);
}

ArrayList

数组列表

  1. 其底层维护了一个对象数组。

  2. 内部数组默认的初始容量是10,如果不够会以1.5倍扩容。

  3. 具有数组的特性,查询效率高,增删数据效率低。

  4. 排列有序,可重复,线程不安全。

    ArrayList的本质是对数组进行操作,在ArrayList底层就是使用对象数组来实现各种操作。

    它的常用方法基本和List的方法相同。

Vector

数组列表

1.底层维护了一个对象数组。

2.查询效率高,增删数据效率低。

3.内部数组默认的初始容量是10,容量不够时,扩展一倍容量。

4.线程安全,效率低。

LinkedList

链表列表

1.内部是用双向链表结构存放数据。

2.每次读取都要从头开始读。

3.查询效率低,增删数据效率高。

4.排列有序,可重复,线程不安全。

LinkedList本质是对链表进行操作。在ArrayList底层就是使用链表结构来实现各种操作。

因为LinkedLsit增加了很多独有的方法,所以创建时不推荐使用接口来引用实例化对象.

LinkedList c = new LinkedList<>()

常用方法

它同样可以使用List的所有方法,但是为了体现链表两头效率的高效性,它定义了很多头节点或者尾节点 的读取方法。

add():在头部添加元素。

addFirst():在头部插入指定元素。

addLast():在尾部插入指定元素。

offer():在尾部添加元素并返回布尔值。

offerFirst():在头部添加元素并返回布尔值。

offerLast():在尾部添加元素并返回布尔值。

element():获取头部元素。

getFirst():获取头部元素。

getLast():获取尾部元素。

peek():获取头部元素。

peekFirst():获取头部元素。

peekLast():获取尾部元素。

poll():获取并删除头部元素。

pollFirst():获取并删除头部元素。

pollLast():获取并删除尾部元素。

ArrayList和LinkedList的区别

ArrayList底层是基于数组实现的,查询效率高,增删效率低。

LinkedList底层是基于链表实现的,查询效率低,增删效率高。

链表结构会占用较大的内存,但都是离散的,数组会占用连续的内存,但是小。

Set接口

如果说List是一个有序的有下标的可以重复的集合,那么Set的特性和它相反

  1. Set是一个不包含重复数据的Collection。

  2. Set集合中的数据存储是无序的,因为底层使用Map结构。

  3. Set集合中的元素不可以重复 ,常用来给数据去重。

    Set的底层是利用map来存储数据的,所以,很多Set集合的特性都是由于Map的结构特性演变而来的,比

    如元素不可重复,因为key值不能重复,无序的,因为Map使用的是链表或红黑树来存储的,其内部也是

    无序的。

常用方法

add(E):添加元素。

addAll(Collection):添加集合。

remove(Object):删除指定元素。

removeAll(Collection):删除集合。

size():集合内元素的大小。

isEmpty():集合是否为空。

contains(Object):集合内是否包含某元素。

HashSet

1.HashSet底层是用HashMap的结构来进行存储的。

2.排列无序,不可重复,允许为null。

3.存取速度快。

HashSet作为Set接口的实现类,它可以使用Set接口提供的所有方法,即Collection的方法。

TreeSet

1.底层是TreeMap(即红黑树)实现。

2.排序存储,不可重复。

3.内部是TreeMap的SortedSet。

LinkedHashSet

1.采用hash表存储,并用双向链表记录元素的插入顺序。

2.具有HashSet的查找效率。

Map接口

类型参数 : K - 表示此映射所维护的键 V – 表示此映射所维护的对应的值。

也叫做哈希表、散列表. 常用于键值对结构的数据.其中键不能重复,值可以重复。

特点

  1. Map可以根据键来提取对应的值。

  2. Map的键不允许重复,如果重复,对应的值会被覆盖。

  3. Map存放的都是无序的数据。

  4. Map的初始容量是16,默认的加载因子是0.75。

常用方法

put(key, value):添加键值对。

get(key):根据key获取value。

remove(key):根据key移除键值对。

replace(key, value):使用value代替key位置上的原value。

containsKey(key):查看是否包含指定key。

containsValue(value):查看是否包含指定value。

isEmpty():判断集合是否为空。

size():集合键值对个数。

equals():判断与集合内元素是否相等,因为我们是以键值对形式存储的,除了数值相等,映射关系也要相等。

hashCode():返回映射关系的hash值。

values():返回集合内的所有value。

map集合迭代方式

        /**方式一:
 ? ? ? ? * 遍历map中的数据,但是map本身没有迭代器,所以需要先转换成set集合
 ? ? ? ? * Set<Key>:把map中的所有key值存入到set集合当中--keySet()*/
 ? ? ?  //4.1将map集合中的key值取出存入set集合中,集合的泛型就是key的类型Integer
 ? ? ?  Set<Integer> keySet = map.keySet();
 ? ? ?  //4.2想要遍历集合就需要获取集合的迭代器
 ? ? ?  Iterator<Integer> it = keySet.iterator();
 ? ? ?  //4.3循环迭代集合中的所有元素
 ? ? ?  while(it.hasNext()){//判断是否有下一个元素可以迭代
 ? ? ? ? ?  Integer key = it.next();//拿到本轮循环中获取到的map的key
 ? ? ? ? ?  String value = map.get(key);
 ? ? ? ? ?  System.out.println("{"+key+","+value+"}");
 ? ? ?  }
?
 ? ? ?  /**方式二:
 ? ? ? ? * 遍历map集合,需要把map集合先转成set集合
 ? ? ? ? * 是把map中的一对键值对key&value作为一个Entry<K,V>整体放入set
 ? ? ? ? * 一对K,V就是一个Entry*/
 ? ? ?  Set<Map.Entry<Integer, String>> entrySet = map.entrySet();
 ? ? ?  //获取迭代器
 ? ? ?  Iterator<Map.Entry<Integer, String>> it2 = entrySet.iterator();
 ? ? ?  while(it2.hasNext()){//判断是否有下一个元素可迭代
 ? ? ? ? ?  //本轮遍历到的一个Entry对象
 ? ? ? ? ?  Map.Entry<Integer, String> entry = it2.next();
 ? ? ? ? ?  Integer key = entry.getKey();//获取Entry中的key
 ? ? ? ? ?  String value = entry.getValue();//获取Entry中的value
 ? ? ? ? ?  System.out.println("{"+key+","+value+"}");
 ? ? ?  }

HashMap

1.以key-value键值对方式存储,key键不能重复,值可重复,key-value允许为null值。

2.数据存储结构为数组+链表+红黑树(jdk1.8)。

3.线程不安全。

4.初始数组长度为16,负载因子为0.75,扩容因子为2,即到达12时进行扩容,每次扩容2倍。

插入数据原理

  1. 判断数组是否为空,为空进行初始化,存入数据。

  2. 不为空,计算Key的hash值,通过(n-1)& hash 计算应当存放在数组中的下标index。

  3. 查看table[index] 是否存在数据,没有数据就构造一个Node节点存放在table[index]中,判断链表长度是否大于 8并且数组长度大于

    64, 大于的话链表转换为红黑树。

  4. 存在数据,说明发生了hash冲突(存在两个节点key的hash值一样),继续判断key是否相等,相等,相等,用新的value替换原来数

    据。

  5. 如果不相等,判断当前节点类型是不是树型节点,如果是树型节点,创造树型节点插入红黑树中,(如果当前节点是树型节点证明当

    前已经是红黑树了)。

  6. 如果不是树型节点,创建普通Node加入链表中;判断链表长度是否大于 8并且数组长度大于64, 大于的话链表转换为红黑树;

  7. 插入完成之后判断当前节点数是否大于阈值,如果大于开始扩容为原数组的二倍。

HashMap怎么设定初始容量大小

new HashMap() 不传值,默认大小是16,负载因子是0.75, 如果自己传入初始大小k,初始化大小为 大于k的 2的整数次方,例如如果传

10,大小为16。

链表转红黑树,链表长度阈值是8,红黑树转链表阈值为6。

原因:因为经过计算,在hash函数设计合理的情况下,发生hash碰撞8次的几率为百万分之6,概率说话。。因为8够用了,至于为什么转回来是6,因为如果hash碰撞次数在8附近徘徊,会一直发生链表和红黑树的互相转化,为了预防这种情况的发生。

1.8对hash的优化

1.数组+链表改成了数组+链表或红黑树;

原因:防止发生hash冲突,链表长度过长,将时间复杂度由O(n)降为O(logn);

2.链表的插入方式从头插法改成了尾插法,简单说就是插入时,如果数组位置上已经有元素,1.7将新元素放到数组中,原始节点作为新节

点的后继节点,1.8遍历链表,将元素放置到链表的最后;

原因:因为1.7头插法扩容时,头插法会使链表发生反转,多线程环境下会产生环;

3.扩容的时候1.7需要对原数组中的元素进行重新hash定位在新数组的位置,1.8采用更简单的判断逻辑,位置不变或索引+旧容量大小;

原因:

4.在插入时,1.7先判断是否需要扩容,再插入,1.8先进行插入,插入完成再判断是否需要扩容;

在多线程环境下,1.7 会产生死循环、数据丢失、数据覆盖的问题,1.8 中会有数据覆盖的问题,

  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2021-09-09 12:08:14  更:2021-09-09 12:10:32 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 23:11:11-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码