最新2024/2025快手Java后端实习面试题(一面)

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;
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值