Java 的数据类型分两种:基本数据类型和引用数据类型。
二哥的 Java 进阶之路:Java数据类型
Java 基本数据类型范围和默认值:
数据类型 | 默认值 | 大小 |
---|---|---|
boolean | false | 1 比特 |
char | '\u0000' | 2 字节 |
byte | 0 | 1 字节 |
short | 0 | 2 字节 |
int | 0 | 4 字节 |
long | 0L | 8 字节 |
float | 0.0f | 4 字节 |
double | 0.0 | 8 字节 |
三分恶面渣逆袭:装箱和拆箱
举例:
Integer i = 10; //装箱
int n = i; //拆箱
二哥的 Java 进阶之路:Java集合主要关系
概览图说明:
①、Collection 接口:最基本的集合框架表示方式,提供了添加、删除、清空等基本操作,它主要有三个子接口:
List
:一个有序的集合,可以包含重复的元素。实现类包括 ArrayList、LinkedList 等。Set
:一个不包含重复元素的集合。实现类包括 HashSet、LinkedHashSet、TreeSet 等。Queue
:一个用于保持元素队列的集合。实现类包括 PriorityQueue、ArrayDeque 等。②、Map
接口:表示键值对的集合,一个键映射到一个值。键不能重复,每个键只能对应一个值。Map 接口的实现类包括 HashMap、LinkedHashMap、TreeMap 等。
一个类只能继承一个抽象类;但一个类可以实现多个接口。所以我们在新建线程类的时候一般推荐使用实现 Runnable 接口的方式,这样线程类还可以继承其他类,而不单单是 Thread 类。
抽象类符合 is-a 的关系,而接口更像是 has-a 的关系,比如说一个类可以序列化的时候,它只需要实现 Serializable 接口就可以了,不需要去继承一个序列化类。
可以,抽象类可以有构造方法。
abstract class Animal {
protected String name;
public Animal(String name) {
this.name = name;
}
public abstract void makeSound();
}
public class Dog extends Animal {
private int age;
public Dog(String name, int age) {
super(name); // 调用抽象类的构造函数
this.age = age;
}
@Override
public void makeSound() {
System.out.println(name + " says: Bark");
}
}
进程说简单点就是我们在电脑上启动的一个个应用,比如我们启动一个浏览器,就会启动了一个浏览器进程。进程是操作系统资源分配的最小单位,它包括了程序、数据和进程控制块等。
线程说简单点就是我们在 Java 程序中启动的一个 main 线程,一个进程至少会有一个线程。当然了,我们也可以启动多个线程,比如说一个线程进行 IO 读写,一个线程进行加减乘除计算,这样就可以充分发挥多核 CPU 的优势,因为 IO 读写相对 CPU 计算来说慢得多。线程是 CPU 分配资源的基本单位。
三分恶面渣逆袭:进程与线程关系
一个进程中可以有多个线程,多个线程共用进程的堆和方法区(Java 虚拟机规范中的一个定义,JDK 8 以后的实现为元空间)资源,但是每个线程都会有自己的程序计数器和栈。
MySQL 中的连接是通过两个或多个表之间的列进行关联,从而获取相关联的数据。连接分为内连接、外连接、交叉连接。
①、内连接(inner join):返回两个表中连接字段匹配的行。如果一个表中的行在另一个表中没有匹配的行,则这些行不会出现在查询结果中。
假设有两个表,Employees 和 Departments。
SELECT Employees.Name, Departments.DeptName
FROM Employees
INNER JOIN Departments ON Employees.DeptID = Departments.DeptID;
这个查询将返回所有员工及其所在部门的信息,但仅限于那些在 Departments 表中有对应部门的员工。
②、外连接(outer join):不仅返回两个表中匹配的行,还返回左表、右表或两者中未匹配的行。
SELECT Employees.Name, Departments.DeptName
FROM Employees
LEFT OUTER JOIN Departments ON Employees.DeptID = Departments.DeptID;
这个查询将返回所有员工的名字和他们部门的名字,即使某些员工没有分配到部门。
③、交叉连接(cross join):返回第一个表中的每一行与第二个表中的每一行的组合,这种类型的连接通常用于生成笛卡尔积。
SELECT Employees.Name, Departments.DeptName
FROM Employees
CROSS JOIN Departments;
这个查询将为 Employees 表中的每个员工与 Departments 表中的每个部门生成一个组合。
我在进行 SQL 优化的时候,主要通过以下几个方面进行优化:
沉默王二:SQL 优化
我重点说一下分页优化吧。
当数据量巨大时,传统的LIMIT
和OFFSET
可能会导致性能问题,因为数据库需要扫描OFFSET + LIMIT
数量的行。
延迟关联(Late Row Lookups)和书签(Seek Method)是两种优化分页查询的有效方法。
①、延迟关联
延迟关联适用于需要从多个表中获取数据且主表行数较多的情况。它首先从索引表中检索出需要的行 ID,然后再根据这些 ID 去关联其他的表获取详细信息。
SELECT e.id, e.name, d.details
FROM employees e
JOIN department d ON e.department_id = d.id
ORDER BY e.id
LIMIT 1000, 20;
延迟关联后:
SELECT e.id, e.name, d.details
FROM (
SELECT id
FROM employees
ORDER BY id
LIMIT 1000, 20
) AS sub
JOIN employees e ON sub.id = e.id
JOIN department d ON e.department_id = d.id;
首先对employees
表进行分页查询,仅获取需要的行的 ID,然后再根据这些 ID 关联获取其他信息,减少了不必要的 JOIN 操作。
②、书签(Seek Method)
书签方法通过记住上一次查询返回的最后一行的某个值,然后下一次查询从这个值开始,避免了扫描大量不需要的行。
假设需要对用户表进行分页,根据用户 ID 升序排列。
SELECT id, name
FROM users
ORDER BY id
LIMIT 1000, 20;
书签方式:
SELECT id, name
FROM users
WHERE id > last_max_id -- 假设last_max_id是上一页最后一行的ID
ORDER BY id
LIMIT 20;
优化后的查询不再使用OFFSET
,而是直接从上一页最后一个用户的 ID 开始查询。这里的last_max_id
是上一次查询返回的最后一行的用户 ID。这种方法有效避免了不必要的数据扫描,提高了分页查询的效率。
索引就好像书的目录,通过目录去查找对应的章节内容会比一页一页的翻书快很多。
三分恶面渣逆袭:索引加快查询远离
MySQL 的索引可以显著提高查询的性能,可以从三个不同的维度对索引进行分类(功能、数据结构、存储位置):
二哥的 Java 进阶之路:索引类型
我就从数据结构上来说明一下吧。
①、B+树索引:最常见的索引类型,一种将索引值按照一定的算法,存入一个树形的数据结构中(二叉树),每次查询都从树的根节点开始,一次遍历叶子节点,找到对应的值。查询效率是 O(logN)。
也是 InnoDB 存储引擎的默认索引类型。
B+ 树是 B 树的升级版,B+ 树中的非叶子节点都不存储数据,只存储索引。叶子节点中存储了所有的数据,并且构成了一个从小到大的有序双向链表,使得在完成一次树的遍历定位到范围查询的起点后,可以直接通过叶子节点间的指针顺序访问整个查询范围内的所有记录,而无需对树进行多次遍历。这在处理大范围的查询时特别高效。
一颗剽悍的种子:B+树的结构
因为 B+ 树是 InnoDB 的默认索引类型,所以创建 B+ 树的时候不需要指定索引类型。
CREATE TABLE example_btree (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255),
INDEX name_index (name)
) ENGINE=InnoDB;
②、Hash 索引:基于哈希表的索引,查询效率可以达到 O(1),但是只适合 = 和 in 查询,不适合范围查询。
Hash 索引在原理上和 Java 中的 HashMap 类似,当发生哈希冲突的时候也是通过拉链法来解决。
业余码农:哈希索引
可以通过下面的语句创建哈希索引:
CREATE TABLE example_hash (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255),
UNIQUE HASH (name)
) ENGINE=MEMORY;
注意,我们这里创建的是 MEMORY 存储引擎,InnoDB 并不提供直接创建哈希索引的选项,因为 B+ 树索引能够很好地支持范围查询和等值查询,满足了大多数数据库操作的需要。
不过,InnoDB 存储引擎内部使用了一种名为“自适应哈希索引”(Adaptive Hash Index, AHI)的技术。
自适应哈希索引并不是由用户显式创建的,而是 InnoDB 根据数据访问的模式自动建立和管理的。当 InnoDB 发现某个索引被频繁访问时,会在内存中创建一个哈希索引,以加速对这个索引的访问。
可以通过下面的语句查看自适应哈希索引的状态:
SHOW VARIABLES LIKE 'innodb_adaptive_hash_index';
如果返回的值是 ON,说明自适应哈希索引是开启的。
二哥的 Java 进阶之路
hash 不算是一种引擎,它是一种索引类型,InnoDB 和 memory 都支持 hash 索引。
MySQL 支持多种存储引擎,常见的有 MyISAM、InnoDB、MEMORY 等。MEMORY 并不常用。
存储引擎
我来做一个表格对比:
功能 | InnoDB | MyISAM | MEMORY |
---|---|---|---|
支持事务 | Yes | No | No |
支持全文索引 | Yes | Yes | No |
支持 B+树索引 | Yes | Yes | Yes |
支持哈希索引 | Yes | No | Yes |
支持外键 | Yes | No | No |
除此之外,我还了解到:
①、MySQL 5.5 之前,默认存储引擎是 MyISAM,5.5 之后是 InnoDB。
②、InnoDB 支持的哈希索引是自适应的,不能人为干预。
③、InnoDB 从 MySQL 5.6 开始,支持全文索引。
④、InnoDB 的最小表空间略小于 10M,最大表空间取决于页面大小(page size)。
MySQL 官网:innodb-limits.html