1.Int和nteger的区别
- 数据类型:Int是基本数据类型,用于存储整数值;Integer是Int的包装类,属于引用数据类型;
- 内存分配:Int直接存储在栈中;integer作文对象,在堆内存中分配空间,栈中存储的是其引用。
- 默认值:Int的默认值是0;integer的默认值是null;
2.==和equals()的区别
- ==:对于基本数据类型,比较的是值是否相等;对于引用数据类型,比较的是对象的内存地址是否相同。
- equals():Object类中的equals()方法默认也是比较内存地址,与==效果相同。但是很多类重写了该方法,比如String类,重写后比较的是对象的内容是否相等。
3.重写equals()为什么也得重写hashCode()
- 在Java中,hashCode()和equals()是关联的。如果两个对象通过equals()方法比较相等,那么它们的hashiCode()方法返回值也应该相等,这样能保证在哈希表等数据结构中,相等的对象能正确存储和检索。如果只重写equals(),不重写hashCode(),可能·会·导致在使用哈希表等数据结构时出现逻辑错误。
4.Object有哪些方法
- equals(Object obj):比较两个对象是否相等。
- hashCode():返回对象的哈希码值。
- toString():返回对象的哈希码值。
- clone():创建并返回此对象的一个副本。
- wait():使当前线程等待,直到其他线程调用此对象的notify()或notifyAll()方法。
- notify():唤醒在此对象监视器上等待的所有线程。
- notifyAll():唤醒在此对象监视器上等待的所有线程。
- finalize():当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法。
5.wait()和sleep()的区别
- 所属类:wait()是Object类的方法;sleep()是Thread类的方法。
- 释放锁:wait()方法会释放对象的锁,进入等待状态;sleep()方法不会释放锁,线程只是暂时休眠。
- 使用场景:wait()通常用于线程间的通信和协作;sleep()用于让线程暂停执行一段时间,通常用于控制线程的执行节奏。
6. notify () 能指定唤醒某个线程吗?
- notify() 方法不能指定唤醒某个线程,它会随机唤醒一个在该对象监视器上等待的线程。如果需要唤醒特定线程,可使用 Condition 接口的 signal() 方法(配合 Lock 接口),它可以实现更灵活的线程唤醒控制。
7.int i = 1000; Integer j = new Integer (1000); i == j 的结果,并解释结果为 true。
- 因为 Integer 会自动拆箱为 int,然后进行值的比较,1000 和 1000 是相等的。
8.介绍 ConcurrentHashMap,为什么它的并发能力强
- ConcurrentHashMap 是 Java 中的一个线程安全的哈希表。它采用分段锁技术,将数据分成多个段(Segment),每个段有自己独立的锁。在多线程环境下,不同线程可以同时访问不同的段,从而减少锁竞争,提高并发访问性能。
9.手写单例模式,volatile 有什么作用,内存可见性指的是什么意思
- 单例模式(双重检查锁定)
public class Singleton {
private volatile static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
- volatile 的作用是保证变量的内存可见性和禁止指令重排序。内存可见性是指当一个线程修改了 volatile 修饰的变量,其他线程能立即看到最新的值,避免读取到过期的数据。
10.手写两条简单的 sql 语句
- 查询表中所有数据
SELECT * FROM table_name;
- 插入一条数据
INSERT INTO table_name (column1, column2) VALUES ('value1', 'value2');
11. MySQL 中什么情况下索引会失效
- 对索引字段使用函数。例如 SELECT * FROM table WHERE YEAR(create_time) = 2023; ,create_time 上的索引会失效。
- 字符串不使用引号。比如 SELECT * FROM table WHERE name = 123; (name 为字符串类型),可能导致索引失效。
- 使用 OR 连接条件,且 OR 两边字段没有全部建立索引。例如 SELECT * FROM table WHERE id = 1 OR name = 'test'; ,若 name 没有索引,id 索引可能失效。
- 模糊查询以通配符开头。如 SELECT * FROM table WHERE name LIKE '%test'; 索引失效。
12. @RequestBody 的作用
- @RequestBody 是 Spring 框架中的一个注解,用于将 HTTP 请求体中的数据绑定到方法的参数上。通常用于处理 Content-Type 为 application/json、application/xml 等类型的请求,将请求体中的 JSON 或 XML 数据转换为对应的 Java 对象。
13. 分布式锁,Redis 怎么实现分布式锁,怎么避免释放别人的锁,怎么实现可重入锁
Redis 实现分布式锁
- 可以使用 SET 命令的 NX(not exist)选项和 EX(expire)选项。例如 SET lock_key unique_value NX EX 10 ,lock_key 是锁的键,unique_value 是每个客户端生成的唯一标识,NX 表示只有键不存在时才设置,EX 10 表示设置过期时间为 10 秒。
避免释放别人的锁
- 在释放锁时,通过判断锁的唯一标识是否与自己设置的一致。即先获取锁的值,与自己设置的值比较,一致才删除锁。
实现可重入锁
- 可以在 Redis 中为每个锁记录一个持有锁的线程标识和重入次数,每次获取锁时,判断线程标识是否为自己,是则重入次数加 1;释放锁时,重入次数减 1,减到 0 时才真正删除锁。
14. Redis 中的跳表
- 跳表是 Redis 中用于实现有序集合(Sorted Set)的数据结构。它是一种分层的数据结构,每一层都是一个有序链表,上层链表节点是下层链表节点的子集。通过多层链表,可以快速定位和查询元素,其查找时间复杂度接近平衡树的 O(log n),实现相对平衡树更简单,便于维护和扩展。
15.算法题:反转链表中的第 m 个节点到第 n 个节点,要求一次扫描。acm 模式
import java.util.Scanner;
class ListNode {
int val;
ListNode next;
ListNode(int val) {
this.val = val;
}
}
public class ReverseBetween {
public static ListNode reverseBetween(ListNode head, int m, int n) {
if (head == null) {
return null;
}
ListNode dummy = new ListNode(0);
dummy.next = head;
ListNode pre = dummy;
for (int i = 1; i < m; i++) {
pre = pre.next;
}
ListNode cur = pre.next;
for (int i = m; i < n; i++) {
ListNode next = cur.next;
cur.next = next.next;
next.next = pre.next;
pre.next = next;
}
return dummy.next;
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int m = scanner.nextInt();
int n = scanner.nextInt();
int num = scanner.nextInt();
ListNode head = new ListNode(num);
ListNode cur = head;
for (int i = 1; i < n; i++) {
num = scanner.nextInt();
cur.next = new ListNode(num);
cur = cur.next;
}
ListNode result = reverseBetween(head, m, n);
while (result != null) {
System.out.print(result.val + " ");
result = result.next;
}
}
}