Java后端开发面试被问到的“冷门”知识点集锦(一)

写在前面

本集锦预计持续更新,分享笔者面试时被一些平时不太关注的知识点拷打的经验。。。

大家引以为戒,知识图谱一定要全面且结合工程实践啊。

平时多看看和自己技术栈相关的开源项目,很有用。


1. 为什么要用List,不直接用ArrayList?

List<Integer> l = new ArrayList<>();

形如以上代码,为什么接口要用List,不直接用ArrayList? List中实现了ArrayList的各种方法吗?为什么不用更大的接口Collection呢?

这道题本质上在考察Java中接口的运用和面向接口编程的理念

(1)为什么接口要用List,不直接用ArrayList?

        首先要明确,List是接口,接口中的大部分方法只有定义,没有实现,高度依赖于实现类;而ArrayList是实现类,负责实现接口中定义的各种方法。注意,Java 8 及以后:允许接口包含默认实现/静态实现,使用default/static关键字修饰即可。Java 9 及以后,接口也支持实现私有方法。

        答:

        A. 为了遵循面向接口编程原则。通过依赖抽象(接口)而不是具体实现(类),可以降低代码之间的耦合性,提高模块化程度。这使得代码更容易维护和测试。

        B. 通过将变量声明为 List 类型,你可以将代码与具体的实现解耦,提高灵便性和可拓展性。如果将来需要将 ArrayList 替换为其他 List 的实现,只需要更改实例化的部分,而不需要修改使用该变量的所有代码。因为 List 中定义的方法对于所有 List 的实现类来说都是存在的。

// 面向接口:后续可轻松切换实现
List<String> list = new ArrayList<>();
list = new LinkedList<>(); // 无需修改其他代码

// 直接依赖实现类:更换实现需修改多处
ArrayList<String> list = new ArrayList<>();
// 若改为 LinkedList,需修改所有声明为 ArrayList 的地方

        注意,以上代码切换类型的时候并不会自动保存原类型的数据,如果要保存,参考如下:

List<String> arrayList = new ArrayList<>();
arrayList.add("A");
arrayList.add("B");

// 创建 LinkedList 并复制数据
List<String> linkedList = new LinkedList<>(arrayList)
// 或者使用 addAll 方法
List<String> linkedList2 = new LinkedList<>();
linkedList2.addAll(arrayList);

        C. 便于与Java工具类和方法协作。Java的许多工具类和方法(如 Collections 类中的方法)通常返回接口类型,而不是具体实现类型。如果你的代码使用 List 类型声明变量,可以更自然地与这些方法配合使用。

(2) List中实现了ArrayList的各种方法吗?

        答:

        大部分常用的方法在 List 中定义,例如 get 、add、remove 等,但一般没有实现,接口方法的实现通常依赖于具体的实现类。 当然也有例外,基本上每一个实现类都有自己独特的方法,例如 ArrayList 的 trimtoSize ,如果确有必要使用这些独特的方法,则不能使用接口 List 。

(3)为什么不用更大的接口Collection呢?

        答:

        这个答案很简单,因为很多属于列表的方法在Collection里面没定义,用不了。在面向接口编程的时候,我们通常优先考虑最小的那个接口。


2. try () ... catch 语句中的try后的圆括号代表什么?

        答:

        在 Java 的 try () ... catch 语句中,try 后面的圆括号代表的是 try-with-resources 语法的一部分。这种语法是 Java 7 引入的,相对于传统的 try-catch-finally 语法, 它简化了资源管理,尤其是那些需要显式关闭的资源(例如文件流、数据库连接等)。圆括号内的内容是资源声明,用于定义需要自动关闭的对象。

        圆括号内的内容在 try 块执行结束后会自动调用其 close 方法,例如 BufferedReader 、FileReader, 无需手动在 finally 中关闭资源。这种机制确保了资源的正确释放,避免了资源泄漏。

 try (FileOutputStream fileOutputStream = new FileOutputStream(new File(filePath));
         FileInputStream fileInputStream = new FileInputStream(new File(filePath))) {
   // ...
}
   // ...

        Java 9 之后,再次优化了 try-with-resources 语法。

// Java9可以这样写        
FileOutputStream fileOutputStream = new FileOutputStream(new File(filePath));
FileInputStream fileInputStream = new FileInputStream(new File(filePath));
try (fileOutputStream;fileInputStream) {
     // ...
}

3. MySQL除了主键之外还能增加唯一性约束吗?

这题我其实一开始答对了,但是没底气,面试官一反问就回答说不敢确定了。

答:

        是的,在 MySQL 中,除了主键(PRIMARY KEY)之外,还可以增加唯一性约束(UNIQUE CONSTRAINT),以确保某个列或一组列的值在表中是唯一的。它和外键约束一样,同属于MySQL约束(CONSTRAINT)的一种。MySQL 允许一个表拥有多个 UNIQUE 约束,这与 PRIMARY KEY 的限制不同(一个表只能有一个主键)。

// 创建表时添加唯一性约束
CREATE TABLE users (
    id INT AUTO_INCREMENT PRIMARY KEY, -- 主键
    email VARCHAR(100) UNIQUE,        -- 单列上的唯一性约束
    username VARCHAR(50),
    CONSTRAINT unique_name UNIQUE (username) -- 命名约束
);

// 修改添加唯一性约束
ALTER TABLE users
ADD UNIQUE (email); -- 添加单列唯一性约束

ALTER TABLE users
ADD CONSTRAINT unique_name UNIQUE (username); -- 添加命名约束

// 多列组合成唯一性约束
CREATE TABLE orders (
    order_id INT AUTO_INCREMENT PRIMARY KEY,
    user_id INT,
    product_id INT,
    UNIQUE (user_id, product_id) -- 确保用户和产品的组合唯一
);


关注一下,持续更新哦~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值