0、堆、栈、方法区
堆:
- 所有线程共享
- 存储的是对象实例(Object)
- 是垃圾回收(GC)的主要区域
- 生命周期与对象一致,GC管理
- 可以通过
-Xms和-Xmx设置初始大小和最大大小
栈:
- 每个线程私有
- 生命周期与方法调用一致
- 方法调用产生栈帧,调用结束释放栈帧
- 存储基本类型变量(如
int,double)和对象引用(reference)
方法区:
类结构、常量池、静态变量等
类的加载顺序:
父类静态变量,父类静态代码块,子类静态变量,子类静态代码块,父类实例变量赋值和实例代码块,父类构造函数,子类实例变量赋值和实例代码块,子类构造函数。
1、静态方法为什么不能调用非静态成员?
静态方法是属于类的,在类加载的时候就会分配内存,可以通过类名直接访问。而非静态成员属于实例对象,只有在对象实例化之后才存在,需要通过类的实例对象去访问。
在类的非静态成员不存在的时候静态方法就已经存在了,此时调用在内存中还不存在的非静态成员,属于非法操作。
2、接口和抽象类有什么共同点和区别?
接口和抽象类的共同点
实例化:接口和抽象类都不能直接实例化,只能被实现(接口)或继承(抽象类)后才能创建具体的对象。
抽象方法:接口和抽象类都可以包含抽象方法。抽象方法没有方法体,必须在子类或实现类中实现。
接口和抽象类的区别
接口主要用于对类的行为进行约束,你实现了某个接口就具有了对应的行为。抽象类主要用于代码复用,强调的是所属关系。
一个类只能继承一个类(包括抽象类),因为 Java 不支持多继承。但一个类可以实现多个接口,一个接口也可以继承多个其他接口。
抽象类可以包含抽象方法和非抽象方法。抽象方法没有方法体,必须在子类中实现。非抽象方法有具体实现,可以直接在抽象类中使用或在子类中重写。
3、深拷贝和浅拷贝和引用拷贝
浅拷贝,对于对象内部的引用类型的对象不拷贝,跟原对象使用同一个引用类型的对象。
BeanUtils.copyProperties
深拷贝,完全拷贝成新的对象。
手动重新赋值
json序列化 重新转成新对象
引用拷贝,两个不同的引用指向同一个对象。
Person p1 = new Person("Tom", 20);
Person p2 = p1; // 引用拷贝
4、String StringBuffer StringBuilder
String 中的对象是不可变的,也就可以理解为常量,线程安全。
- 保存字符串的数组被
final修饰且为私有的,并且String类没有提供/暴露修改这个字符串的方法。 String类被final修饰导致其不能被继承,进而避免了子类破坏String不可变。
StringBuffer 对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的。StringBuilder 并没有对方法进行加同步锁,所以是非线程安全的。
5、try-catch-finally 如何使用?
try块:用于捕获异常。其后可接零个或多个 catch 块,如果没有 catch 块,则必须跟一个 finally 块。
catch块:用于处理 try 捕获到的异常。
finally 块:无论是否捕获或处理异常,finally 块里的语句都会被执行。当在 try 块或 catch 块中遇到 return 语句时,finally 语句块将在方法返回之前被执行。 finally里如果有return,则直接return了。不会执行 try 或 catch里的return了。
finally 之前虚拟机被终止运行,程序所在线程死亡,关闭cpu,finally 中的代码不会被执行。
6、Java反射
反射允许程序在运行时动态地加载类、创建对象、调用方法和访问字段。
许多现代 Java 框架(如 Spring、Hibernate、MyBatis)都大量使用反射来实现依赖注入(DI)、面向切面编程(AOP)、对象关系映射(ORM)、注解处理等核心功能。反射是实现这些“魔法”功能不可或缺的基础工具。控制反转IOC,注解@Service @Controller @Mapper 等都依赖反射。
通过反射,可以编写更通用、可重用和高度解耦的代码,降低模块之间的依赖。例如,可以通过反射实现通用的对象拷贝、序列化、Bean 工具等。
7、BIO NIO AIO
BIO 同步阻塞型IO模型。
NIO 同步非阻塞 IO 模型。 Netty框架
AIO 异步 IO 是基于事件和回调机制实现的
8、集合
List
ArrayList 数组
LinkedList 双向链表
Set
HashSet (无序,唯一): 基于 HashMap 实现的,底层采用 HashMap 来保存元素。
LinkedHashSet LinkedHashSet 是 HashSet 的子类,内部是通过 LinkedHashMap 来实现的。
TreeSet (有序,唯一): 红黑树(自平衡的排序二叉树)。
Map
HashMap 1.8以前是数组+链表 1.8以后是红黑树 初始大小是16,每次扩容都是2倍。不保证任何顺序。
当链表长度大于等于阈值(默认为 8)(将链表转换成红黑树前会判断,如果当前数组的长度小于 64,那么会选择先进行数组扩容,而不是转换为红黑树)时,将链表转化为红黑树,以减少搜索时间。
LinkedHashMap 继承自 HashMap,双向链表,保证有序。
TreeMap 红黑树 有序
Hashtable:这是 HashMap 的一个线程安全版本,所有方法都是同步的。与 HashMap 不同的是,Hashtable 不允许键或值为 null。
ConcurrentHashMap:提供了一种高效且线程安全的哈希表实现。
map遍历
0、Lambda
map.forEach((key, value) -> {
System.out.println(key);
System.out.println(value);
});
1、for each
for (Map.Entry<Integer, String> entry : map.entrySet()) {
System.out.println(entry.getKey());
System.out.println(entry.getValue());
}
2、迭代器
Iterator<Map.Entry<Integer, String>> iterator = map.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<Integer, String> entry = iterator.next();
System.out.println(entry.getKey());
System.out.println(entry.getValue());
}
9、多线程
传统方式 继承 Thread 类和实现 Runnable 接口 重写run()
现在 使用 Executors 工具类来创建不同类型的线程池,如固定大小的线程池、缓存线程池等。
还可以使用线程池。通过 ThreadPoolExecutor 构造函数直接创建 (推荐)
Thread#sleep() 方法和 Object#wait()
sleep()方法没有释放锁,而wait()方法释放了锁 。
wait() 方法被调用后,线程不会自动苏醒,需要别的线程调用同一个对象上的 notify()或 者 notifyAll() 方法。
直接调用run()不会启动多线程,要调用start()才启动。
死锁:线程互相等待。 避免死锁:破坏循环等待条件
乐观锁和悲观锁
乐观锁 基于CAS算法实现。 悲观锁:每次访问都要上锁,synchronized
数据库
ACID 原子性 一致性 隔离性 持久性
事务级别 读未提交 读已提交 可重复读(默认的隔离级别) 可串行化
mysql
创建数据库、表 删除数据库、表,索引、视图 create drop
-- 添加字段
ALTER TABLE users ADD COLUMN age INT AFTER name;
-- 删除字段
ALTER TABLE users DROP COLUMN age;
-- 修改字段类型或位置
ALTER TABLE users MODIFY COLUMN age VARCHAR(3);
当前默认的存储引擎是 InnoDB。并且,所有的存储引擎中只有 InnoDB 是事务性存储引擎,也就是说只有 InnoDB 支持事务。
三大范式
第一范式(1NF): 数据库表中的字段都是单一值。
第二范式(2NF):非主键字段需完全依赖于主键。
第三范式(3NF):一个非主键字段不能依赖另一个非主键字段。
索引
单表索引最好不超过5个。对于频繁的查询,优先考虑使用覆盖索引就是包含了所有查询字段 (where、select、order by、group by 包含的字段) 的索引
聚簇索引:索引和数据一起存放的索引,如主键索引。聚簇索引默认使用的是 B+Tree 索引。
非聚簇索引:索引结构和数据分开存放的索引,普通、唯一、复合、覆盖。
索引失效
- 创建了组合索引,但查询条件未遵守最左匹配原则;
- 在索引列上进行计算、函数、类型转换等操作;
- 以 % 开头的 LIKE 查询比如
LIKE '%abc';; - 查询条件中使用 OR,且 OR 的前后条件中有一个列没有索引,涉及的索引都不会被使用到;
- IN 的取值范围较大时会导致索引失效,走全表扫描(NOT IN 和 IN 的失效场景相同);
最左索引
联合索引的最左匹配原则,在遇到范围查询(如 >、<)的时候,就会停止匹配,也就是范围查询的字段可以用到联合索引,但是在范围查询字段后面的字段无法用到联合索引。注意,对于 >=、<=、BETWEEN、like 前缀匹配的范围查询,并不会停止匹配。
Redis
缓存击穿:热点key失效,短时间大量请求数据库。 热点key提前预热或不过期
缓存穿透:无效的key 访问数据库。 缓存无效的key或者使用布隆过滤器
缓存雪崩:大量key集中失效。 redis集群或设置随机失效时间或提前预热
常见的缓存预热方式有两种:使用定时任务,比如 xxl-job,来定时触发缓存预热的逻辑,将数据库中的热点数据查询出来并存入缓存中。使用消息队列,比如 Kafka,来异步地进行缓存预热,将数据库中的热点数据的主键或者 ID 发送到消息队列中,然后由缓存服务消费消息队列中的数据,根据主键或者 ID 查询数据库并更新缓存。
Redis 中比较常见的数据类型有下面这些:
- 5 种基础数据类型:String(字符串)、List(列表)、Set(集合)、Hash(散列)、Zset(有序集合)。
- 3 种特殊数据类型:HyperLogLog(基数统计)、Bitmap (位图)、Geospatial (地理位置)。
Redis 采用的是那种删除策略呢
Redis 采用的是 定期删除+惰性/懒汉式删除 结合的策略。

被折叠的 条评论
为什么被折叠?



