| |
|
|
开发:
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三次握手首先,客户端处于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 会?起发送。 HTTPHTTP协议是一种无状态、明文传输的协议,一大缺点不安全。 HTTP 最凸出的优点是简单、灵活和易于扩展、应??泛和跨平台。 HTTPSHTTPS 协议是由 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返回状态码?
? |
| 序号 | 异常名称 | 异常描述 |
|---|---|---|
| 1 | java.lang.ArrayIndexOutOfBoundsException | 数组索引越界异常。当对数组的索引值为负数或大于等于数组大小时抛出。 |
| 2 | java.lang.ArithmeticException | 算术条件异常。譬如:整数除零等。 |
| 3 | java.lang.SecurityException | 安全性异常 |
| 4 | java.lang.IllegalArgumentException | 非法参数异常 |
| 5 | java.lang.ArrayStoreException | 数组中包含不兼容的值抛出的异常 |
| 6 | java.lang.NegativeArraySizeException | 数组长度为负异常 |
| 7 | java.lang.NullPointerException | 空指针异常。当应用试图在要求使用对象的地方使用了null时,抛出该异常。譬如:调用null对象的实例方法、访问null对象的属性、计算null对象的长度、使用throw语句抛出null等等。 |
2.IOException
| 序号 | 异常名称 | 异常描述 |
|---|---|---|
| 1 | IOException | 操作输入流和输出流时可能出现的异常 |
| 2 | EOFException | 文件已结束异常 |
| 3 | FileNotFoundException | 文件未找到异常 |
3. 其他
| 序号 | 异常名称 | 异常描述 |
|---|---|---|
| 1 | ClassCastException | 类型转换异常类 |
| 2 | ArrayStoreException | 数组中包含不兼容的值抛出的异常 |
| 3 | SQLException | 操作数据库异常类 |
| 4 | NoSuchFieldException | 字段未找到异常 |
| 5 | NoSuchMethodException | 方法未找到抛出的异常 |
| 6 | NumberFormatException | 字符串转换为数字抛出的异常 |
| 7 | StringIndexOutOfBoundsException | 字符串索引超出范围抛出的异常 |
| 8 | IllegalAccessException | 不允许访问某类异常 |
| 9 | InstantiationException | 当应用程序试图使用Class类中的newInstance()方法创建一个类的实例,而指定的类对象无法被实例化时,抛出该异常 |
| 10 | java.lang.ClassNotFoundException | 找不到类异常。当应用试图根据字符串形式的类名构造类,而在遍历CLASSPAH之后找不到对应名称的class文件时,抛出该异常。 |
概念
Java中可以定义被abstract关键字修饰的方法,这种方法只有声明,没有方法体,叫做抽象方法。 Java中可以定义被abstract关键字修饰的类,被abstract关键字修饰的类叫做抽象类。
如果一个类含有抽象方法,那么它一定是抽象类。
抽象类中的方法实现交给子类来完成。
抽象类不能直接实例化,需要依靠子类采用向上转型的方式处理。
抽象方法必须为public或者protected(如果为private,则不能被子类继承,子类便无法实现该方法),缺省情况下默认为public。
抽象类中可以有构造方法,其存在目的是为了属性的初始化。
外部抽象类不允许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 以后可以包含。之前不能包含 是因为,接?不可以实现?
法,只可以定义?法,所以不能使?静态?法(因为静态?法必须实现)。现在可以包含了,只能直接?接?调?静态?法。
equals():用于比较两个对象是否"相等",默认是比较内存地址。可以通过重写方法来自定义 规则。
toString():用于返回对应对象的字符串表示,默认为:类名+@+哈希值。
hashCode():用于返回对象的内存地址,不同的对象有不同的hashCode值,也可能存在不同对象hashCode值相同,这是一个本地方法。
wait ?法:让当前对象等待。
clone ?法:?于创建并返回当前对象的?份拷?。
finalize ?法:实例被垃圾回收器回收时触发的?法。
数组工具类,数组工具类是围绕这数组来进行操作的,所有复杂的数组类的内部几乎都离不开这个 工具类。
数组工具类的所有方法都是静态方法,都可以通过类名来直接调用。
数组工具类操作数组的基本类型,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底层维护了字符数组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():查看字符串的长度。
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 常用于迭代集合中的元素。主要有三个方法:
(1) 使用next()获得序列中的下一个元素。
(2) 使用hasNext()检查序列中是否还有元素。
(3) 使用remove()删除迭代器最后一个元素并删除。


自动装箱:把 基本类型 包装成对应的 包装类型 的过程 Integer a = 5;//a是引用类型,引用了包装对象的地址。 编译器会完成对象的自动装箱:Integer a = Integer.valueOf(5);
自动拆箱:从包装类型的值,自动变成 基本类型的值 int i = a;//a现在是包装类型,没法给变量赋值,需要把5取出来。 编译器会完成自动拆箱:int i = a.intValue();
按照流的流向分,可以分为输入流和输出流; 按照操作单元划分,可以划分为字节流和字符流; 按照流的角色划分为节点流和处理流
File 字节流:针对二进制文件 InputStream FileInputStream BufferedInputStream ObjectInputStream
OutputStream FileOutputStream BufferedOutputStream ObjectOutputStream 字符流:针对文本文件 Reader FileReader BufferedReader InputStreamReader
Writer FileWriter BufferedWriter OutputStreamWriter PrintWriter一行行写出
概述
封装一个磁盘路径字符串,对这个路径可以执行一次操作可以封装文件路径、文件夹路径、不存在的路径。
常用方法

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方法速查表

List列表,是一个有序的元素集合。它的特点如下:
数据是有序的。
允许存放重复的元素。
元素都有下标。
它提供一些统一的方法来供其子类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);
}
数组列表
其底层维护了一个对象数组。
内部数组默认的初始容量是10,如果不够会以1.5倍扩容。
具有数组的特性,查询效率高,增删数据效率低。
排列有序,可重复,线程不安全。
ArrayList的本质是对数组进行操作,在ArrayList底层就是使用对象数组来实现各种操作。
它的常用方法基本和List的方法相同。
数组列表
1.底层维护了一个对象数组。
2.查询效率高,增删数据效率低。
3.内部数组默认的初始容量是10,容量不够时,扩展一倍容量。
4.线程安全,效率低。
链表列表
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底层是基于链表实现的,查询效率低,增删效率高。
链表结构会占用较大的内存,但都是离散的,数组会占用连续的内存,但是小。
如果说List是一个有序的有下标的可以重复的集合,那么Set的特性和它相反
Set是一个不包含重复数据的Collection。
Set集合中的数据存储是无序的,因为底层使用Map结构。
Set集合中的元素不可以重复 ,常用来给数据去重。
Set的底层是利用map来存储数据的,所以,很多Set集合的特性都是由于Map的结构特性演变而来的,比
如元素不可重复,因为key值不能重复,无序的,因为Map使用的是链表或红黑树来存储的,其内部也是
无序的。
常用方法
add(E):添加元素。
addAll(Collection):添加集合。
remove(Object):删除指定元素。
removeAll(Collection):删除集合。
size():集合内元素的大小。
isEmpty():集合是否为空。
contains(Object):集合内是否包含某元素。
1.HashSet底层是用HashMap的结构来进行存储的。
2.排列无序,不可重复,允许为null。
3.存取速度快。
HashSet作为Set接口的实现类,它可以使用Set接口提供的所有方法,即Collection的方法。
1.底层是TreeMap(即红黑树)实现。
2.排序存储,不可重复。
3.内部是TreeMap的SortedSet。
1.采用hash表存储,并用双向链表记录元素的插入顺序。
2.具有HashSet的查找效率。
类型参数 : K - 表示此映射所维护的键 V – 表示此映射所维护的对应的值。
也叫做哈希表、散列表. 常用于键值对结构的数据.其中键不能重复,值可以重复。
特点
Map可以根据键来提取对应的值。
Map的键不允许重复,如果重复,对应的值会被覆盖。
Map存放的都是无序的数据。
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+"}");
? ? ? }
1.以key-value键值对方式存储,key键不能重复,值可重复,key-value允许为null值。
2.数据存储结构为数组+链表+红黑树(jdk1.8)。
3.线程不安全。
4.初始数组长度为16,负载因子为0.75,扩容因子为2,即到达12时进行扩容,每次扩容2倍。
插入数据原理

判断数组是否为空,为空进行初始化,存入数据。
不为空,计算Key的hash值,通过(n-1)& hash 计算应当存放在数组中的下标index。
查看table[index] 是否存在数据,没有数据就构造一个Node节点存放在table[index]中,判断链表长度是否大于 8并且数组长度大于
64, 大于的话链表转换为红黑树。
存在数据,说明发生了hash冲突(存在两个节点key的hash值一样),继续判断key是否相等,相等,相等,用新的value替换原来数
据。
如果不相等,判断当前节点类型是不是树型节点,如果是树型节点,创造树型节点插入红黑树中,(如果当前节点是树型节点证明当
前已经是红黑树了)。
如果不是树型节点,创建普通Node加入链表中;判断链表长度是否大于 8并且数组长度大于64, 大于的话链表转换为红黑树;
插入完成之后判断当前节点数是否大于阈值,如果大于开始扩容为原数组的二倍。
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地址范围 |
|
|
| 上一篇文章 下一篇文章 查看所有文章 |
|
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
| 360图书馆 购物 三丰科技 阅读网 日历 万年历 2025年12日历 | -2025/12/1 2:26:33- |
|
| 网站联系: qq:121756557 email:121756557@qq.com IT数码 |