计算机网络

TCP/IP模型与OSI模型

​ OSI(Open Systems Interconnection)是国际标准化组织(ISO)在1984年发布的,目的是创建一个标准化的网络通信框架,以便不同厂商的设备可以相互操作。

物理层(Physical Layer):主要用于比特流传输的物理连接,如光纤、网线、无线电波等。

数据链路层(Data Link Layer) :同一个数据链路内的帧传输,对应物理地址(MAC)寻址,错误检测与纠正,如以太网等。

网络层(Network Layer) :负责端到端的通信,主要用于路径选择和逻辑地址(IP)管理。

传输层(Transport Layer) :用于可靠传输,流量控制,错误检测,如TCP, UDP等。

会话层(Session Layer):建立、管理、终止会话,如NetBIOS、RPC等

表示层(Presentation Layer) :用于数据格式转换、加密、解密,如JPEG, MPEG, SSL/TLS等。

应用层(Application Layer):用户交互界面,提供网络服务,如HTTP、FTP等。

数据链路层和网络层

​ 数据链路层负责相邻设备(同一链路)之间的通信,即从电脑和交换机之间、路由器和路由器之间的直接数据传输。

​ 网络层负责端到端的通信(跨多个网络)

可以把数据传输比喻成寄快递

  • 数据链路层 相当于快递员在同一个城市内派送包裹,按照门牌号(MAC 地址)找到收件人。
  • 网络层 相当于快递公司的物流系统,负责决定包裹从上海到北京要经过哪些中转站(路由)。

会话层

协议 功能
RPC(远程过程调用协议) 允许程序在远程计算机上执行某个过程,比如分布式系统。
SQL(结构化查询语言) 通过会话层维护数据库连接。
NetBIOS 用于局域网中的计算机名称解析和会话管理。
SMPP(短消息对等协议) 用于短信传输,比如短信网关的通信。
PPTP(点对点隧道协议) 用于VPN连接,建立加密隧道。

TCP三次握手

(1) 三次握手的过程

  1. 第一次握手:客户端向服务器发送一个SYN (同步序列编号)报文,请求建立连接,客户端进入SYN_SENT 状态。
  2. 第二次握手:服务器收到SYN 报文后,如果同意建立连接,则会发送一个SYN-ACK (同步确认)报文作为响应,同时进入SYN_RCVD(Synchronize Received) 状态。
  3. 第三次握手:客户端收到服务器的SYN-ACK 报文后,会发送一个ACK (确认)报文作为最终响应,之后客户端和服务器都进入ESTABLISHED(建立) 状态,连接建立成功。

(2)为什么需要三次握手

通过三次握手,客户端和服务器都能够确认对方的接收和发送能力。第一次握手确认了客户端到服务器的通道是开放的;第二次握手确认了服务器到客户端的通道是开放的;第三次握手则确认了客户端接收到服务器的确认,从而确保了双方的通道都是可用的。

而如果仅使用两次握手,服务器可能无法确定客户端的接收能力是否正常,比如客户端可能已经关闭了连接,但之前发送的连接请求报文在网络上延迟到达了服务器,服务器就会主动去建立一个连接,但是客户端接收不到,导致资源的浪费。

TCP四次挥手

(1)四次挥手的过程

  1. 第一次挥手:客户端发送一个FIN报文给服务端,表示自己要断开数据传送,报文中会指定一个序列号 (seq=x)。然后,客户端进入FIN-WAIT-1 状态。
  2. 第二次挥手:服务端收到FIN报文后,回复ACK报文给客户端,且把客户端的序列号值+1,作为ACK报文的序列号(seq=x+1)。然后,服务端进入CLOSE-WAIT(seq=x+1)状态,客户端进入FIN-WAIT-2状态。
  3. 第三次挥手:服务端也要断开连接时,发送FIN报文给客户端,且指定一个序列号(seq=y+1),随后服务端进入LAST-ACK状态。
  4. 第四次挥手:客户端收到FIN报文后,发出ACK报文进行应答,并把服务端的序列号值+1作为ACK报文序列号(seq=y+2)。此时客户端进入TIME-WAIT状态。服务端在收到客户端的ACK 报文后进入CLOSE 状态。如果客户端等待2MSL没有收到回复,才关闭连接。

(2)为什么需要四次挥手

TCP是全双工通信,可以双向传输数据。任何一方都可以在数据传送结束后发出连接释放的通知,待对方确认后进入半关闭状态。 当另一方也没有数据再发送的时候,则发出连接释放通知,对方确认后才会完全关闭 TCP 连接。因此两次挥手可以释放一端到另一端的TCP连接,完全释放连接一共需要四次挥手。

只有通过四次挥手,才可以确保双方都能接收到对方的最后一个数据段的确认,主动关闭方在发送完最后一个ACK后进入TIME-WAIT 状态,这是为了确保被动关闭方接收到最终的ACK ,如果被动关闭方没有接收到,它可以重发FIN 报文,主动关闭方可以再次发送ACK

而如果使用三次挥手,被动关闭方可能在发送最后一个数据段后立即关闭连接,而主动关闭方可能还没有接收到这个数据段的确认。

服务器不等待客户端的ack直接关闭,可能会出现客户端想要继续数据传输的情况

背诵

​ 客户端向服务器发送 fin,服务器收到后返回ack,之后服务器向客户端发送fin,客户端收到后向服务器发送ack后等待一段时间断开连接。

Mysql

sql语言和方言的区别

sql语言:所有的关系型数据库的通用规则(通用性

方言:每一种关系型数据库特有的规则(不具有通用性

sql语句的分类

DDL语句

​ 用来操作

DML语句

​ 用来操作数据增删改,不包括查询

DQL语句

​ 用来操作数据查询

DCL语句(了解)

​ 用来给用户授权 (DBA)

mysql中double类型和decimal类型的区别

float/double(m,d)

存储的近似值

m 表示所有的位数 d 小数的位数

95.5 double(3,1)

3.1415926 double(8,7)

decimal(m,d)

存储的是准确值,和钱相关的只能decimal

95.5 decimal(3,1)

null值参与计算的结果是什么

null值参与四则运算,结果为null

解决方案:使用ifnull函数

1
2
-- 如果comm是NULL,则返回0;如果comm不是NULL,则返回comm的实际值
IFNULL(comm,0)

关系型数据库中,null值参与排序的结果

mysql中,作为最小值

oracle中,作为最大值

null值是否参与聚合函数的计算

null值不参与聚合函数

常见的聚合函数

  1. max(字段名):求最大值

  2. min(字段名):求最小值

  3. sum(字段名):求和

  4. avg(字段名):求平均值

  5. count(字段名):计数

where和having的区别

where:是分组前过滤,后面不能跟聚合函数

having:分组后过滤,后面可以跟聚合函数

数据库中约束的分类有哪些

  1. 非空约束:not null

  2. 唯一约束:unique

  3. 默认约束:default

  4. 主键约束:primary key

  5. 外键约束:foreign key

主键约束和非空且唯一约束的区别

主键约束:一张表只能有一个

非空+唯一约束:一张表可以有多个

一对多关系怎么设置外键

在多的一方建立外键指向一的一方的主键

数据库设计的三大范式

第一范式:每一列都是不可再分的原子数据项

第二范式:消除部分依赖,从而消除冗余数据

第三范式:消除传递依赖

内连接和左外连接的区别

内连接:查询的是两个表公共部分

左外连接:查询的是左表的所有+公共部分

数据库中是否支持全连接

full join

mysql不支持,oracle支持

union all和union的区别

作用:求并集

  1. union all:返回两个集合的所有数据,包含重复值

  2. union:返回两个集合的所有数据,不包含重复值

什么是事务

其实就是我们现实生活中的业务,银行转账业务(张三给李四转500块钱)

在mysql中事务指的是多条增删改语句组成的整体,要么全部执行成功,要么回滚失败。

事务是怎么保证同时成功或者同时失败的

通过事务的三个操作

start transaction:开启事务

​ 会把接下来的操作都作为一个整体,整体里面的每一个增删该语句产生的都是临时值,此时并不会改变数据库中真正的数据。

​ 如果回滚,回滚到start transaction的位置

commit:提交操作

​ 判断执行的过程中,有没有问题,没有问题,则把临时值真正地更新到数据库中

rollback:回滚操作

​ 判断执行的过程中,有没有问题,有问题,则把临时值取消掉

事务的四大特征

事务的四大特性通常被称为 ACID 特性

  1. 原子性(atomicity):把事务当成一个整体,要么同时成功,要么同时失败。
  2. 一致性(consistency):事务执行前后,数据的总和不变。
  3. 隔离性(isolation):多个事务之间,是相互独立的。
  4. 持久性(durability):执行了commit操作的时候,会把数据库更新到硬盘上。

事务的隔离级别及可能出现的问题

​ 多个事务之间,是相互独立的,但是当多个事务操作同一批数据的时候,就会出现问题,我们需要设置不同的隔离级别来解决

可能出现的问题:

脏读

​ 一个事务读取到另外一个事务还没有提交的数据

不可重复读(虚读)

​ 一个事务读取到另外一个事物已经提交的update语句 // 数量不变 ,内容变

幻读

​ 一个事务读取到另外一个事物已经提交的insert语句 // 数量变化

隔离级别:

​ Read Uncommited:读未提交

​ 可能出现脏读、不可重复读(虚读)、幻读

​ Read Commited:读已提交 (oracle数据库的默认隔离级别

​ 可能出现不可重复读(虚读)、幻读

​ Repeatable Read:可重复读 (mysql数据库的默认隔离级别

​ 可能出现幻读

​ Serializable:串行化

​ 没有问题

慢查询语句的作用是什么

使用慢查询语句explain查看DQL是否走了索引

1
2
3
4
5
6
EXPLAIN SELECT * FROM person WHERE NAME = 'test0.6239561854153464';

-- 给person表的name字段添加索引
CREATE INDEX person_name ON person(NAME);
-- 删除person表的name字段的索引
ALTER TABLE person DROP INDEX person_name;

使用模糊查询时是否会导致索引失效

  1. 如果占位符(% _) 在开头,不走索引
  2. 如果占位符(% _) 在末尾,走索引

联合索引走索引的条件是什么

最左前缀原则(最左匹配原则)

索引的底层结构是什么

B+树

B树和B+树的区别

  1. B+树的叶子节点之间有指针相互指向

  2. B+树的非叶子节点中的数据在叶子节点中都冗余了一份

JavaSE

Java的版本分类有哪些

  1. JavaSE:可以用来进行桌面开发(已弃用)

  2. JavaME:用来作为小型设备开发

  3. JavaEE:用来作为大型服务器开发的

JavaSE是其他两种(JavaME和JavaEE)的基础

Java中跨平台的原理是什么

Java通过JVM实现跨平台:针对不同的操作系统,都会有不同版本的虚拟机

JDK、JRE和JVM的区别

JDK

JDK(Java Development Kit):Java开发工具集

特点:可开发、可运行

JRE

JRE(Java Runtime Environment):Java运行环境

特点只能运行、不能开发

JVM

JVM(Java Virtual Machine):Java虚拟机

特点:在不同的操作系统中运行Java代码

面试题:JDK、JRE、JVM三者之间的关系

JDK > JRE > JVM(>号是包含)

Java中的注释有哪几种,分别怎么表示

  1. 单行注释: // 注释的内容

  2. 多行注释: /* 注释内容 */

  3. 文档注释: /* * 注释内容 */

Java中常量的分类

  1. 整数

  2. 浮点数

  3. 布尔

  4. 字符:单引号引起来的,单引号中只有一个字符

  5. 字符串

  6. 空常量:一个特殊的值:null,”null”是字符串

Java中的数据类型有哪些

java中基本数据类型四类八种

a++和++a的区别

a++:先赋值,再自增(++在后)

++a:先自增,再赋值(++在前)

为什么要使用Idea

可以把编写代码、编译代码、运行代码等多种功能都综合到一起

方法的分类

  1. 无参无返回值

  2. 无参有返回值

  3. 有参无返回值

  4. 有参有返回值

什么是方法重载

同一个类中的多个方法之间,满足以下条件的构成重载:

  1. 方法名相同

  2. 参数列表不同

  3. 与返回值无关

switch语句中小括号里的表达式可以是哪些数据类型

只能是byte、short、int、char,JDK5以后可以是枚举,JDK7以后可以是String

数组的特点

  1. 数组的长度不能改变

  2. 数组中的元素的类型必须是同一种数据类型(基本类型/引用类型)

  3. 存入数组中的元素,按照存入的顺序排列

数组的动态创建方式和静态创建方式的区别

动态方式:只指定长度,由系统给出初始化值

1
int arr2[] = new int[5];

静态方式:给出初始化值,由系统指定长度

1
int[] arr1 = new int[]{1, 3, 5};

Java中的内存划分

Java的内存区域主要分为以下几个部分:

  1. 程序计数器:和CPU相关。
  2. 本地方法栈:和系统相关。
  3. Java虚拟机栈(栈):方法、局部变量、对象的引用
  4. :所有new出来的东西。
  5. 方法区:字节码文件对象、常量池、静态区。

背诵:方局对,自(字)常静

面向对象和面向过程的区别

面向对象和面向过程是软件分析、设计和开发中解决问题的思想

面向对象和面向过程解决问题的思路不同

  1. 面向对象:我找能做这件事的”对象”帮我去做
  2. 面向过程:强调的是自己”一步一步”去做

什么是类?什么是对象?

类:对某一类事物的抽象表示,是一种分类

对象:是能解决问题的具体存在

类和对象的关系

类是对象的一个分类/模板

学生:张三、李四

学校:南邮、南师

成员变量和局部变量的区别

区别 成员变量 局部变量
类中位置不同 类中方法外 方法内或者方法声明上
内存中位置不同 堆内存 栈内存
生命周期不同 随着对象的存在而存在,随着对象的消失而消失 随着方法的调用而存在,随着方法的调用完毕而消失
初始化值不同 有默认的初始化值 没有默认的初始化值,必须先定义,赋值,才能使用

类那(内)牲畜(生初)

面向对象的三大特征

封装、继承、多态

封装的作用和原则

作用

​ 封装是将对象的属性(成员变量)和行为(成员方法)结合在一起,并隐藏内部的实现细节,只暴露出一个可以被外界访问的接口。

原则

  1. 使用private关键字对成员变量进行隐藏

被private修饰的成员变量,在类外部无法直接访问,类内部可以访问

  1. 提供对应的getXxx和setXxx方法给外界使用

使用idea自动生成 快捷键:alt + ins

给成员变量赋值的方式有哪些

  1. 构造方法

  2. set方法赋值

继承的优点和缺点

优点

​ 提高了代码的复用性维护性

复位(维)

缺点

​ 提高了类的耦合性,当父类发生变化时,子类也要跟着变化。

继承中成员变量、构造方法、成员方法的访问特点

成员变量

就近原则

构造方法

优先完成父类的构造初始化

成员方法

优先访问子类的成员方法

方法重载和方法重写的区别

方法重载:在同一个类中的多个方法之间,满足以下条件的构成重载:

  1. 方法名相同

  2. 参数列表不同

  3. 与返回值无关

方法重写:子类中重写和父类中一模一样的成员方法

  1. 方法名相同

  2. 参数列表相同

  3. 与返回值相同

package、import、class的顺序关系

package > import > class

  1. package:一个类中只能有一个

  2. import:一个类中可以有多个

  3. class:可以是多个,推荐是一个

四种权限修饰符

权限修饰符 同类 无关类/子类-同包 子类-不同包 不同包
private-私有 1
default-默认(空着不写) 1 1
protected-受保护 1 1 1
public-公有 1 1 1 1

1表示“可访问”

final特点

  1. final修饰成员变量,表明该变量是一个常量,在定义的时候就必须要赋值,不能再次赋值

  2. final修饰成员方法,该方法不能被重写

  3. final修饰类,该类不能被继承

  4. final修饰局部变量

    final修饰基本数据类型变量:基本数据类型的不能发生改变

    final修饰引用数据类型变量:引用数据类型的地址值不能发生改变

static的作用和特点

作用

  1. 被类的所有对象共享

  2. 可以通过类名调用,也可以通过对象名调用

特点

静态只能访问静态,非静态可以访问所有

静态代码块、构造代码块、构造方法的执行顺序和特点

执行顺序

静态代码块—->构造代码块—->构造方法

特点

静态代码块:只执行一次

构造代码块:执行多次,每次执行构造方法,构造代码块都会执行一次。

多态的前提

  1. 要有继承或者实现关系

  2. 要有方法重写

  3. 要有父类引用指向子类对象

多态中的成员访问特点

成员变量:编译看左边(父类),运行看左边

成员方法:编译看左边(父类),运行看右边(子类)

抽象类的特点

  1. 抽象类和抽象方法都必须使用abstract修饰

  2. 类中如果有抽象方法,该类必须定义成抽象类

  3. 抽象类中可以有抽象方法,也可以有非抽象方法

  4. 抽象类的子类可以是抽象类,也可以是具体类,如果是具体类需要重写所有的抽象方法

  5. 抽象类中可以有成员变量、构造方法、成员方法

  6. 抽象类不能直接初始化,需要依赖具体子类,使用多态的方式创建对象

背诵技巧:前三条只涉及类和方法,后三条和子类和类的成员有关。

抽象类的成员特点

成员变量

变量或常量

构造方法

无参构造或带参构造

成员方法

抽象方法或普通方法

接口中成员变量和成员方法的默认修饰符

成员变量

public、static、final

成员方法

public abstract

接口的成员特点

成员变量

只能是常量

构造方法

接口没有构造方法,因为接口中没有需要初始化的成员变量(常量)

成员方法

只能是抽象方法(JDK8以前)

接口和抽象类的区别

  1. 抽象类需要被继承,只能单继承;接口需要被实现,可以多实现
  2. 抽象类的继承,描述的是is a的关系,是共性关系;接口的实现,描述的是has a的关系,是额外关系
  3. 抽象类中可以定义常量,也可以定义变量;接口中只能定义常量
  4. 抽象类可以有构造方法;接口没有构造方法
  5. 抽象类中可以定义普通方法,也可以定义抽象方法;接口中只能定义抽象方法(JDK8以前)

背诵技巧:继承、性质、成员特点比较;背了这个相当于背了抽象类和接口的成员特点。

多态的三种方式

  1. 普通类多态
1
2
Animal animal = new Cat();
// Animal 是一个普通类
  1. 抽象类多态
1
2
Animal animal = new Cat();
// Animal 是一个抽象类
  1. 接口多态
1
2
Flyable bird = new Bird();
// Flyable 是一个接口

内部类的分类

  1. 成员内部类

  2. 局部内部类

  3. 静态内部类

  4. 匿名内部类(重要

你(匿)竟(静)成局

匿名内部类的前提和本质

前提:存在一个或者接口

本质:是一个对象

注意:这里的类可以是普通类也可以是一个抽象类

Object类中有哪些常见的方法

  1. toString()
  2. equals(Object obj)
  3. hashCode()
  4. wait()
  5. notify()

部分方法的详细介绍

  1. String toString() 返回对象的字符串表示形式,在javabean中必须要被重写

    1. 重写前显示对象地址值
    2. 重写后显示对象的字符串表示
  2. boolean equals(Object obj) 指示是否有其他对象”等于”这一个,也需要被重写

    1. 重写前判断地址值是否相等
    2. 重写后判断属性值是否相等
1
2
3
4
5
6
7
8
9
10
11
12
/*

* 测试Object类的相关方法
* */
public class ObjectDemo1 {
public static void main(String[] args) {
Student student = new Student();
System.out.println(student);
//com.hu.obj.Student@1b6d3586
System.out.println(student.toString());
}
}

Object类中的finalize方法的作用

Object类中,有一个protected void finalize() ,在JVM清理完垃圾之后,自动调用这个方法

1
2
3
4
5
6
public class Animal {
@Override
protected void finalize() throws Throwable {
System.out.println("垃圾被回收了");
}
}

Java中垃圾回收机制(gc方法)的原理

  1. 垃圾回收机制只回收JVM中堆内存的对象
  2. 堆内存中的对象在长时间不用,垃圾回收机制会自动回收
  3. 回收时间不确定

基本数据类型和包装类的对应关系

基本数据类型 包装类
byte Byte
short Short
int Integer
long Long
float Float
double Double
char Character
boolean Boolean

基本数据类型与字符串互转

基本数据类型怎么转字符串?

  1. String s1 = 12.3 + “”;

  2. String s2 = String.valueOf(12);

字符串怎么转基本数据类型?

Integer类的static int parseInt(String s) 方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*
* 字符串和基本数据类型之间的相互转换
* */
public class IntegerDemo3 {
public static void main(String[] args) {
//基本数据类型--------->字符串
int i = 10;
String s = i + "";
String s1 = 12.3 + "";
String s2 = String.valueOf(12);
String s3 = String.valueOf(12.3);

//字符串------->基本数据类型
int i1 = Integer.parseInt("10086");
float v = Float.parseFloat("12.3F");
System.out.println(v);

long l = Long.parseLong("100");
System.out.println(l);
}
}

length和length()、size()的区别

length:数组的长度,是属性

length():字符串的长度,是方法

size() :集合的长度

背诵技巧:数字集

String、StringBuffer、StringBuilder的区别

特性 String StringBuffer StringBuilder
是否可变 不可变 可变 可变
是否线程安全 不安全 安全 不安全

编译期异常和运行期异常的区别

编译期异常 运行期异常
时机 在执行编译命令(javac)的时候,出现异常 在执行运行命令(java)的时候,出现异常
idea显示 在Idea中有红色波浪线提示 在Idea中没有红色波浪线提示
继承关系 都继承自Exception 都继承自RuntimeException

是(时)IG(继)

try—catch和throws的区别

try—catch

通过catch抓取指定的异常,在catch中强行处理异常,就不会再次出现异常

throws

把异常抛给调用该方法的上一级,如果一直往上抛,最终由JVM按照异常的默认处理机制处理。

throw和throws的区别

throw

  1. 位置:用在方法体内

  2. 后面跟的是:异常的对象,只跟一个对象

  3. 执行该关键字代码,一定会出现异常

throws

  1. 位置:用在方法的签名位置

  2. 后面跟的是:异常名,而且可以是多个

  3. 执行该关键字代码,不一定出异常

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/*
* throw关键字
*
* */
public class ExceptionDemo5 {
public static void main(String[] args) {
int a = 10;
int b = 0;

if (b == 0) {
throw new ArithmeticException("b=0");
} else {
int i = a / b;
}

System.out.println("over");
}
}

设计模式的七大原则是什么

开闭原则

单一职责原则

里氏替换原则

依赖倒转原则

接口隔离原则

迪米特法则(最少知道原则)

合成复用原则

背诵口诀:合理(里)解(接)开第(迪)一(依)弹(单)

Java中对方法的增强的方式有哪些

继承

增强的内容不能改变,被增强对象不能改变

装饰者模式/静态代理模式

增强的内容不能改变,被增强对象能改变

动态代理

增强的内容能改变,被增强对象能改变

背诵:(与String、StringBuffer和StringBuilder相对应)

继承方式 继承 动态代理 装饰者模式/静态代理模式
被增强对象 不可变 可变 可变
增强的内容 不可变 可变 不可变

集合和数组的区别是什么

长度区别

集合的长度可以改变,数组的长度不能改变

元素的数据类型

集合中只能存储引用数据类型数据

数组中既可以存储基本数据类型,也可以存储引用数据类型

存储的数据不同

集合可以存储单列数据,也可以存储双列数据

数组只能存储单列数据

背诵:原(元)长存

在List集合中删除元素的注意事项

反向遍历

ArrayList、LinkedList、Vector的区别(需检查vector)

ArrayList

A:底层结构是数组(查询快、增删慢)

B:线程不安全、效率高

LinkedList

A:底层结构是链表(查询慢、增删快)

B:线程不安全、效率高

Vector

A:底层结构是数组(查询快、增删慢)

B:线程安全、效率低

ArrayList集合底层结构是什么

Object数组

ArrayList集合的扩容机制

如果第一次使用无参构造,那么第一次添加元素的时候会扩容成长度为10的数组,当添加的元素超过数组的长度时,按照1.5倍扩容

1
int newCapacity = oldCapacity + (oldCapacity >> 1);

HashSet、LinkedHashSet、TreeSet集合的底层结构

HashSet

底层结构:哈希表

数组+链表 (JDK7及以前)

数组+链表+红黑树 (JDK8及以后)

特点:存取无序、无索引、元素唯一

LinkedHashSet

底层结构:链表+哈希表

特点:存取有序、无索引、元素唯一

TreeSet

底层结构:二叉树

特点:按照给定的规则排序、无索引、元素唯一

HashSet集合是怎么保证元素唯一性的

依赖hashCode和equals两个方法

先通过hash计算在数组中的位置,然后用equals方法与链表或红黑树中的每个元素做对比,如果有相同元素就覆盖,如果没有相同元素则添加。

TreeSet集合是怎么保证元素唯一性的

比较接口中重写的比较方法,返回值为0表示元素重复

可变参数的本质是什么

是一个数组

HashMap集合的底层结构

JDK7及以前:数组+链表

JDK8及以后:数组+链表+红黑树

HashMap集合的无参构造,在第一次添加元素的时候数组的初始大小

16

HashMap集合加载因子为什么是0.75

泊松分布

加载因子较大,哈希冲突的概率变大,导致链表过长,查询效率变低

加载因子过小,数据过于稀疏,会导致空间浪费

HashMap集合中链表什么时候转红黑树

链表的长度达到阈值8,且数组的长度大于64

HashMap集合中红黑树什么时候转链表

链表的长度达到6

HashMap集合中数组的扩容为什么都是2的n次幂

因为在添加元素计算数组的下标时,使用的是key的哈希值和数组的长度减一做&运算

HashMap集合添加元素的时候,计算数组下标为什么不使用取余,而使用按位与

  • 按位与的效率较高

  • 取余可能出现负数

File和IO的区别

  • file用来操作文件载体
  • io用来操作文件内容

flush和close的区别

  • flush:将数据从操作系统缓存刷新到硬盘

  • close:将数据从操作系统缓存刷新到硬盘,然后释放资源

IO流中的相对路径和绝对路径

  • IO流中的相对路径,是相对于Project(项目)路径

  • 绝对路径:Windows是相对于盘符开始路径,Linux是相对于根路径开始

程序、进程、线程、协程的区别

  1. 程序:没有运行的代码
  2. 进程:运行起来的代码,资源分配和调度的基本单位
  3. 线程:进程执行的最小单位
  4. 协程:也称为虚拟线程,JDK19出现的;协程的本质是一种用户态的轻量级线程,一个线程能支持多个协程的运行,且多个协程能并发执行

并发和并行的区别

  • 并发:多个事件在同一个时间段内发生(实际中研究的)
  • 并行:多个事件在同一个时间点内发生(理想状态)

run和start的区别

  • run方法:调用不会开启新的线程,只能在main方法中执行(单线程)

  • start方法:调用会开启一个新的线程,让jvm调用run方法在新的线程中执行(多线程)

描述线程的生命周期

新建、就绪、运行、阻塞、死亡

HashMap和Hashtable的区别

HashMap Hashtable
是否允许null值 允许null键和null值 不允许null键和null值
线程是否安全 线程不安全,效率高 线程安全的,效率低

volatile关键字的作用

在多线程中有三个常见问题:可见性、有序性、原子性

volatile可以解决可见性和有序性,不能解决原子性

使用线程池的好处是什么

  1. 避免了频繁地创建和销毁线程
  2. 提高了每个线程的利用率

ThreadPoolExecutor的七大参数,以及分别表示什么意思

背诵技巧:前四个是线程相关的,后三个是整体线程池相关的。

ThreadPoolExecutor线程池的工作原理

实现多线程的方式

  1. 继承Thread类
  2. 实现Runnable接口
  3. 实现Callable接口
  4. 使用线程池

类加载的过程

加载—>连接(验证、准备、解析)—>初始化—>使用—>卸载

类加载器的分类

从上到下依次是

启动类加载器 扩展类加载器 系统类加载器 自定义类加载器
名称 Bootstrap class loader Platform/Extension class loader App/System class loader
加载路径 JAVA_HOME/jre/lib JAVA_HOME/jre/lib/ext 类路径(src目录) 自定义
显示形式 null ExtClassLoader AppClassLoader

双亲委派机制的原理

​ 如果一个类加载器收到了类加载请求,默认先将该请求委托给其父级加载器处理。只有当父级加载器无法加载该类时,才会尝试自行加载。双亲委派机制能够提高安全性,避免了类的重复加载。

特点

  1. 向上找缓存
  2. 向下找对应的类加载器

图解

反射获取字节码文件的三种方式

(1)类名.class

(2)对象.getClass()

(3)Class.forName(String 全类名)

​ 全类名:包名+类名

反射中getMethods和getDeclaredMethods方法的区别

  1. 方法 getMethods() :获取当前类的所有的public修饰的+继承自父类的public修饰成员方法对象

  2. 方法 getDeclaredMethods() :获取当前类的所有成员方法对象,无视权限修饰符

注解的属性(抽象方法)的返回值要求

  1. 基本数据类型

  2. String

  3. 枚举

  4. 注解

  5. 以上数据类型的数组形式

注意事项:返回值不能是void

lambda表达式和匿名内部类的区别

匿名内部类 lambda表达式
所需的类型不同 匿名内部类可以new接口、抽象类、普通类 lambda表达式只能是接口
使用限制 匿名内部类的接口中,可以有一个也可以有多个抽象方法 lambda表达式的接口中,只能有一个抽象方法
生成字节码文件的方式不同 匿名内部类的字节码文件在硬盘中 lambda表达式的字节码文件在内存中

背诵技巧:省(生)市(使)所

jdk8有哪些新特性

  1. lambda表达式

  2. 接口的组成更新(默认方法和静态方法)。

  3. Stream流

  4. 新日期类Localdate和LocalDatetime

注意:接口的组成更新产生了函数式接口的说法,jdk8以前接口只能有抽象方法。

在jdbc中事务是由谁管理的

JDBC中事务是由Connection管理的

start transaction

1
2
void setAutoCommit(boolean autoCommit)  
参数autoCommit: true---自动提交 **false**---手动提交

commit

1
void commit()  

rollback

1
void rollback()  

Web

get请求和post请求的区别

get

  1. 安全性低,速度快
  2. 使用场景:搜索
  3. 参数的大小会受到限制,最大几十kb
  4. 提交的参数在地址栏中可见

post

  1. 安全性高,速度慢
  2. 使用场景:上传文件
  3. 参数的大小没有限制
  4. 提交的参数在地址栏不可见

背诵技巧:俺(安)是(使)三(参)体(提)

input标签中type属性有哪些取值,分别表示什么

列举

type取值 描述
text 文本框
password 密码框
radio 单选框
checkbox 复选框
file 上传图像
hidden 隐藏字段
submit 提交按钮
reset 重置按钮
button 普通按钮
image 图片按钮

背诵技巧:文秘(密)担(单)负(复)上瘾(隐)重提谱(普)图

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="#" method="post">
<input type="hidden" name="id" value="123">

<label for="username">用户名:</label>
<input type="text" name="username" id="username"><br>

<label for="password">密码:</label>
<input type="password" name="password" id="password"><br>

性别:
<input type="radio" name="gender" value="1" id="male"> <label for="male"></label>
<input type="radio" name="gender" value="2" id="female"> <label for="female"></label>
<br>

爱好:
<input type="checkbox" name="hobby" value="1"> 旅游
<input type="checkbox" name="hobby" value="2"> 电影
<input type="checkbox" name="hobby" value="3"> 游戏
<br>

头像:
<input type="file"><br>

城市:
<select name="city">
<option>北京</option>
<option value="shanghai">上海</option>
<option>广州</option>
</select>
<br>

个人描述:
<textarea cols="20" rows="5" name="desc"></textarea>
<br>
<br>
<input type="submit" value="免费注册">
<input type="reset" value="重置">
<input type="button" value="一个按钮">
</form>
</body>
</html>

效果

CSS中选择器的分类

基础选择器

  1. 标签选择器
  2. 选择器
  3. id选择器
  4. 通配符选择器

关系选择器

  1. 交集选择器:没有符号
  2. 并集选择器:以逗号隔开
  3. 亲子选择器:以>隔开
  4. 后代选择器:以空格隔开

属性选择器

两种情况,一种是方括号中属性名+属性值,一种是方括号中只有属性名

伪类选择器

伪类通过冒号来定义元素的状态

背诵技巧:机(基)关属委(伪)

不算技巧的技巧:标类i通,交并亲后

JS中的基础数据类型

  1. number类型:整数、浮点数、NaN、infinity(正负无穷大)
  2. boolean类型:true 、false
  3. string类型:有三种表示形式,单引号、双引号、反引号,在js中没有字符的概念
  4. null类型
  5. undefined类型:既是一个数据类型,也是一个值;undefined作用是用来提醒我们该变量没有赋值就被使用了

背诵技巧:对应java中常量的分类来背。

不算技巧的技巧:nb s nu

JS中==和===的区别

  1. ==:只比较值,不比较类型
  2. ===:既比较值,也比较类型

JS中数组和Java中数组的区别

  1. js中数组的长度是可变的,而java中的数组长度不能改变

  2. js中数组可以存放多种类型的数据,而java中的数组只能存放同一种类型的元素

背诵技巧:常(长)数

ES6新特性有哪些

  1. let关键字,防止变量被重复声明,定义的变量具有块级作用域,必须先声明再使用
  2. const关键字,定义常量,声明时就要赋值,赋值一次之后,不能再次赋值
  3. 字符串支持反引号
  4. 箭头函数(java中的lambda)+ 可变参数

背诵技巧:class —- c(const)l(let)a(arrow)s(string)

JS中innerHtml和innerText的区别

  • innertext:只能获取文本信息,不能获取标签信息
  • innerhtml:既可以获取文本信息,也能获取标签信息

动态资源和静态资源的区别

静态资源

每个用户访问相同资源后,得到的结果一样

特点:可以被浏览器直接解析

例如:html、css、js

动态资源

每个用户访问相同资源后,得到的结果可能不一样

特点:不能被浏览器直接解析,需要由服务器将动态资源转成静态资源,再返回给浏览器

例如:servlet、jsp、asp、php

背诵技巧:用户访问,流(浏)利(例)

tomcat的默认端口号?http协议的默认端口号

8080;80

Servlet生命周期方法和特点

方法 init方法 service方法 destroy方法
特点 只执行一次,默认在浏览器第一次访问的时候执行,创建Servlet 可以执行多次,浏览器每访问一次,就会执行一次 只执行一次,Servlet正常销毁的时候执行

列举5个常见的状态码

200、302、304、404、405、500

200:表示请求和访问正常

302:重定向

304:访问缓存

404:请求路径没有对应的资源

405:请求方式没有对应的doXxx方法

500:服务器内部出现异常

转发和重定向的区别

转发

  1. 转发浏览器地址栏不会发生改变

  2. 转发只能在当前服务器内部资源跳转,不能跳出项目外

  3. 转发是一次请求,一次响应

  4. 转发是request调用的,request是域对象,可以共享数据

重定向

  1. 重定向浏览器地址栏会发生改变

  2. 重定向可以跳出项目外,访问外部资源

  3. 重定向是多次请求和多次响应

  4. 重定向是response调用的,response不是域对象,不能共享数据

背诵技巧:当第(地)一啊(R)

Cookie在浏览器中的存活时间

通过cookie的void setMaxAge(int expiry) 方法来设置

参数expiry:表示失效时间,单位为

参数有三种情况:

  1. 正数:持久化到硬盘,存储的时间为参数的值

  2. 0:删除cookie

  3. 负数:默认值,关闭浏览器时删除

文件上传前端三要素

  1. type=”file”
  2. method=”post”
  3. enctype=”multipart/form-data”

cookie和session的区别

  1. cookie存储在客户端,session存储在服务器端

  2. cookie的大小有限制,session的的大小没有限制

  3. cookie相对不安全,session相对安全

背诵技巧:存大象(相)

maven的两大核心功能

  1. 依赖管理(必须使用):传统方式是把jar包放在项目中,jar在项目中占据大量的空间,每个项目都需要导入jar包。而maven把jar放在仓库中,项目中只放jar包的坐标(依赖)
  2. 项目的一键构建(非必须使用):maven自身集成了tomcat,可以对项目进行编译、测试、打包、安装、部署等操作。

背诵技巧:鞭(编)策(测),不(部)打俺(安)

SSM框架

Mybatis的定义/概念

  1. ORM(Object Relational Mapping,对象关系映射) 持久层框架
  2. 消除了几乎所有的JDBC代码
    1. 参数设置:parameterType
    2. 结果集封装:resultType,resultMap
  3. 内置数据库连接池

resultType,resultMap的区别

​ resultMap 相对于 resultType 可以在列名和 pojo 属性名之间作一个映射关系,以满足查询出来的结果的列名和实体属性不一致的情况;

Mybatis的数据库连接流程

  1. 构建 xml
  2. 构建 SqlSessionFactory
  3. 构建 SqlSession

Mybatis事务涉及语句

  1. insert:不会返回主键
  2. update:根据主键更新 ,可以通过动态SQL 实现动态更新
  3. delete:根据主键删除

$和#的区别

  1. $是字符串拼接
  2. #是参数传递,对sql语句进行了预编译

Spingboot总览

背诵技巧:聘(p)请(启)A佬(l),请(启)快快活(获)

创建工程流程

Springboot创建工程流程

  1. pom.xml
  2. 启动类
  3. application.yml

springmvc环境搭建

  1. pom.xml
  2. 入口工程
  3. 配置类

springboot的特点

快速构建快速部署 web 服务器的框架。

  1. 快速构建:依赖于 parent

  2. 快速部署:内置tomcat

Springboot启动过程starter

  1. springboot 解析 application.yml
  2. 读取 spring.factories 文件,找到 EnableAutoConfiguration 类
  3. 将参数设置到需要的业务对象

获取application.yml中数据的方式

  1. Environment 通过环境变量获取
  2. @Value(“${user.name}”) 通过 Value 注解获取
  3. @ConfigurationProperties(prefix = “user”) 通过 ConfigurationProperties 注解获取

Controller常用注解

@RequestMapping

1
2
3
4
5
6
7
8
// 公共的请求路径
@RequestMapping("/depts")

// 相关的增删改查对应
// 增 @PostMapping
// 删 @DeleteMapping
// 改 @PutMappin
// 查 @GetMapping

@PathVariable、@RequestBody

特性 @PathVariable @RequestBody
数据来源 URL路径部分 请求体
常用场景 GET请求获取资源,DELETE删除 POST/PUT请求提交数据
数据格式 简单类型(String, Long等) 复杂对象(JSON/XML等)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 根据id查询部门
@GetMapping("/{id}")
public Result getById(@PathVariable Integer id){
log.info("根据id查询部门, id:{}",id);
Dept dept = deptService.getById(id);
return Result.success(dept);
}

public Result add(@RequestBody Grades grades){
log.info("新增年级: {}" , grades);
//调用service新增部门
gradesService.add(grades);
return Result.success();
}

@RequestParam(defaultValue=”默认值”) 、@RequestParam()

1
2
3
4
5
6
7
8
// 设置请求参数默认值
@RequestParam(defaultValue = "1") Integer page

// @GetMapping("/greet")
public String greet(@RequestParam String name) {
return "Hello, " + name;
}
// 访问 /greet?name=John 会返回 "Hello, John"

不算技巧的技巧:request,mbp,p

拦截器,统一异常处理图解

拦截器(⭐业务)

流程图

实现HandlerInterceptor

位置

interceptor目录下

具体流程
  • 当我们打开浏览器来访问部署在web服务器当中的web应用时,此时我们所定义的过滤器会拦截到这次请求。拦截到这次请求之后,它会先执行放行前的逻辑,然后再执行放行操作。而由于我们当前是基于springboot开发的,所以放行之后是进入到了spring的环境当中,也就是要来访问我们所定义的controller当中的接口方法。

  • Tomcat并不识别所编写的Controller程序,但是它识别Servlet程序,所以在Spring的Web环境中提供了一个非常核心的Servlet:DispatcherServlet(前端控制器),所有请求都会先进行到DispatcherServlet,再将请求转给Controller。

  • 当我们定义了拦截器后,会在执行Controller的方法之前,请求被拦截器拦截住。执行preHandle()方法,这个方法执行完成后需要返回一个布尔类型的值,如果返回true,就表示放行本次操作,才会继续访问controller中的方法;如果返回false,则不会放行(controller中的方法也不会执行)。

  • 在controller当中的方法执行完毕之后,再回过来执行postHandle()这个方法以及afterCompletion() 方法,然后再返回给DispatcherServlet,最终再来执行过滤器当中放行后的这一部分逻辑的逻辑。执行完毕之后,最终给浏览器响应数据。

简略流程
  1. preHandle : 调用controller之前
  2. postHandle:调用controller之后
  3. afterCompletion:视图渲染之后(这里的视图渲染指的是服务器将动态资源转化为静态资源)
核心代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Component
public class LoginCheckInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle .... ");

return true; //true表示放行
}

@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle ... ");
}

@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion .... ");
}
}

配置拦截器

位置

config目录下

简略流程
  1. 实现 WebMvcConfigurer
  2. 重写 addInterceptors
核心代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 拦截器关键代码
@Configuration
public class WebConfig implements WebMvcConfigurer {

// 拦截器对象
@Autowired
private LoginCheckInterceptor loginCheckInterceptor;

@Override
public void addInterceptors(InterceptorRegistry registry) {
// 注册自定义拦截器对象
registry.addInterceptor(loginCheckInterceptor)
.addPathPatterns("/**") //拦截所有请求
.excludePathPatterns("/login"); //不拦截登录请求
}
}

统一异常处理(⭐业务)

核心注解

  1. @ControllerAdvice :异常控制器,推荐使用@RestControllerAdvice(整体代码更简洁)
  2. @ExceptionHandler: 声明异常类型

核心代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// @ControllerAdvice
// public class GlobalExceptionHandler {
//
// // 需要手动添加 @ResponseBody 才能返回 JSON
// @ExceptionHandler(Exception.class)
// @ResponseBody
// public Result ex(Exception ex){
// ex.printStackTrace();
// return Result.error("对不起,操作失败,请联系管理员");
// }
// }

@RestControllerAdvice
public class GlobalExceptionHandler {

@ExceptionHandler(Exception.class)//捕获所有异常
public Result ex(Exception ex){
ex.printStackTrace();
return Result.error("对不起,操作失败,请联系管理员");
}

}

Spring容器管理Bean

Spring 容器管理Bean有两个核心接口:BeanFactoryApplicationContext

  1. BeanFactory只提供 Bean 的创建与管理功能。
  2. ApplicationContext是 BeanFactory 的扩展,提供了自动扫描注解支持等功能。

背诵技巧:自助(注)

Sping中常用注解

@Autowired

自动注入Bean实例

1
2
3
// 在controller中加入@Autowired注解是字段注入,Spring容器会自动查找匹配的Bean并注入。
@Autowired
private StudentsService studentsService;

基本注解(增加可读性)

注解 用途 适用场景
@Component 通用组件 普通 Bean
@Service 业务逻辑层 Service 类
@Repository 数据访问层 DAO/Repository 类
@Controller Web 控制器 MVC 的 Controller
@Configuration 配置类 Java 配置类

@ComponentScan

​ 自动扫描指定包及其子包下的所有带有 @Component@Service@Repository@Controller 等注解的类(基本注解),并将它们注册为 Spring Bean。

1
2
3
4
5
@Configuration
@ComponentScan("com.example")
public class AppConfig {
// 其他配置...
}

IOC

什么是 IOC

​ Spring的IOC(inverse of contorl),也就是控制反转,它的核心思想是让对象的创建和依赖关系由容器来控制,不是我们自己new出来的,这样各个组件之间就能保持松散的耦合。

​ 举例来说,在实际项目中一个 Service 类可能有几百甚至上千个类作为它的底层,假如我们需要实例化这个 Service,每次都要搞清这个 Service 所有底层类的构造函数,如果利用 IOC 的话,你只需要配置好,然后在需要的地方引用就行了。

如何配置

​ 使用配置可以告诉Spring容器如何创建对象、如何管理对象的生命周期。Spring 时代我们一般通过 XML 文件来配置,后来开发人员觉得 XML 文件来配置不太好,于是 SpringBoot 注解配置就慢慢开始流行起来。

​ 总结来说,Spring的IOC容器是一个中央化的、负责管理应用中所有对象生命周期的强大工具

AOP

​ 面向切面编程(Aspect Oriented Programming),或者面向方法编程。

​ 面向切面编程,可以说是面向对象编程的补充和完善。OOP(Object Oriented Programming) 引入封装、继承、多态等概念来建立一种对象层次结构。OOP允许开发者定义纵向的关系,但并不适合定义横向的 关系,例如日志功能。AOP 技术恰恰相反,它利用一种称为”横切”的技术,剖解开封装的对象内部,将那些影响了多个类的公共行为封装到一个可重用模块,并将其命名为切面,降低模块之间的耦合度,有利于未来的操作和维护。

SpringAOP代理由 Spring 的IOC容器负责生成、管理,其依赖关系也由 IOC 容器负责管理。因此, AOP 代理可以直接使用容器中的其它 bean 实例作为目标。Spring 创建代理的规则为:

  1. 默认使用 JDK 动态代理来创建AOP代理,这样就可以为任何接口实例创建代理了
  2. 当需要代理类,而不是代理接口的时候,Spring 会切换为使用 CGLIB代理 ,也可强制使用 CGLIB

纵观 AOP 编程,程序员只需要参与三个部分:

  1. 定义普通业务组件
  2. 定义切入点,一个切入点可能横切多个业务组件
  3. 定义增强处理,增强处理就是在 AOP 框架为普通业务组件织入的处理动作

​ 所以进行 AOP 编程的关键就是定义切入点和定义增强处理,一旦定义了合适的切入点和增强处理,AOP 框架将自动生成 AOP 代理,即: 代理对象的方法=增强处理+被代理对象的方法。

切入点代码

@Pointcut(“execution(* com.iweb.spring..(..))”)

Spring中AOP的通知类型

  1. @Around(“pointCut()”) :环绕通知,此注解标注的通知方法在目标方法前、后都被执行
  2. @Before(“pointCut()”):前置通知,此注解标注的通知方法在目标方法前被执行
  3. @After(“pointCut()”):后置通知,此注解标注的通知方法在目标方法后被执行,无论是否有异常都会执行
  4. @AfterReturning(“pointCut()”): 返回后通知,此注解标注的通知方法在目标方法后被执行,有异常不会执行
  5. @AfterThrowing(“pointCut()”): 异常后通知,此注解标注的通知方法发生异常后执行

额外补充

索引的分类

  1. 主键索引:创建主键的时候自动构建
  2. 唯一索引:唯一 create unique index
  3. 普通索引:create index
  4. 复合(联合)索引:在多个列上面的索引
1
2
3
4
5
6
7
-- 创建普通索引
CREATE INDEX idx_email
ON users (email);

-- 创建复合索引
CREATE INDEX index_name
ON table_name (column1, column2, column3, ...);

背诵技巧:维(唯)普伏(复)诛(主)

mysql

  1. 聚簇索引:主键索引,索引和数据保存在一起
  2. 非聚簇索引:非主键索引,二级索引,保存的是索引和主键

索引失效的场景

索引失效意味着查询操作不能有效利用索引进行数据检索,从而导致性能下降,下面一些场景会发生索引失效。

联合索引:

  1. 不遵循最左前缀法则:最左前缀法则指的是查询从联合索引的最左列开始。
  2. 使用非等值查询:当使用!=<>等范围索引号时,索引可能不会被使用。

B+树结构

  1. 使用LIKE语句:以通配符%开头的LIKE查询会导致索引失效(加在前面会导致失效,加在后面不会)。

其它

  1. 函数或表达式:使用函数或表达式作为查询条件(运算操作),通常会导致索引失效。
  2. 使用OR条件:当使用OR连接多个条件,并且每个条件用到不同的索引列时,索引可能不会被使用。
  3. 对列进行类型转换: 如果在查询中对列进行类型转换,例如将字符列转换为数字或日期(不加引号),索引可能会失效。

HashMap数组扩容的两种情况

  1. 数组长度<64,链表长度达到阈值8
  2. 添加元素超过承重

java集合的分类

详细介绍

Java中的集合类主要分为两大类: Collection接口(单列集合)和Map接口(双列集合);前者是存储对象的集合类,后者存储的是键值对(key-value)的集合类。

Collection接口下又分为List、Set和Queue接口,每个接口有其具体实现类, Map接口下有很多接口,比如HashMap,LinkedHashMap, TreeMap, Hashtable, ConcurrentHashMap

  • List下有ArrayList (基于动态数组,查询速度快,插入、删除慢) , LinkedList (基于双向链表,插入、删除快,查询速度慢) ;
  • Set下有HashSet (基于哈希表,元素无序,不允许重复) , LinkedHashSet (基于链表和哈希表,维护插入顺序,不允许重复) ,TreeSet (基于红黑树,元素有序,不允许重复) ;

Map 接口:存储的是键值对,也就是给对象(value)设置了一个 key,这样通过 key 可以找到那个 value。

  • HashMap:基于哈希表,键值对无序,不允许键重复。LinkedHashMap:基于链表和哈希表,维护插入顺序,不允许键重复。
  • TreeMap:基于红黑树,键值对有序,不允许键重复。