Java基础面试题突击系列6

本文介绍了Java编程中的一些核心概念和技术,包括为何重写equals方法时需同时重写hashCode,Java泛型的好处和擦除机制,静态变量与实例变量的区别,死锁的概念,线程的sleep()和yield()方法的差异,事务的ACID特性,线程局部变量的作用,JDBC操作数据库的步骤,以及集合的不可变性和排序方式。此外,还探讨了Statement和PreparedStatement的区别及其性能考量。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

👩🏻 作者:一只IT攻城狮 ,关注我不迷路
❤️《java面试核心知识》突击系列,持续更新…
💐 面试必知必会学习路线:Java技术栈面试系列+SpringCloud项目实战学习路线
📝再小的收获x365天都会成就不一样的自己,一起学习,一起进步。

一、为什么重写equals方法必须要重写hashCode方法

因为有强制的规范指定需要同时重写 hashcode 与 equal 是方法。

如果只重写了equals方法而没有重写hashCode方法的话,则会违反约定,因为相等的对象必须具有相等的散列码(hashCode)。许多容器类,如 HashMap、HashSet 都依赖于此规定,比较对象相等首先要比较hashCode是否相等,如果hashCode相等才会去比较equals。

二、Java泛型与泛型擦除

Java泛型是J2 SE1.5中引入的一个新特性,其本质是参数化类型,也就是说所操作的数据类型被指定为一个参数(type parameter)这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。

1、Java泛型好处:

  • 第一是泛化。可以用T代表任意类型Java语言中引入泛型是一个较大的功能增强不仅语言、类型系统和编译器有了较大的变化,以支持泛型,而且类库也进行了大翻修,所以许多重要的类,比如集合框架,都已经成为泛型化的了,这带来了很多好处。
  • 第二是类型安全。泛型的一个主要目标就是提高Java程序的类型安全,使用泛型可以使编译器知道变量的类型限制,进而可以在更高程度上验证类型假设。如果不用泛型,则必须使用强制类型转换,而强制类型转换不安全,在运行期可能发生ClassCast Exception异常,如果使用泛型,则会在编译期就能发现该错误。
  • 第三是消除强制类型转换。泛型可以消除源代码中的许多强制类型转换,这样可以使代码更加可读,并减少出错的机会。
  • 第四是向后兼容。支持泛型的Java编译器(例如JDK1.5中的Javac)可以用来编译经过泛型扩充的Java程序(Generics Java程序),但是现有的没有使用泛型扩充的Java程序仍然可以用这些编译器来编译。

2、泛型擦除:

泛型信息只存在于代码编译阶段,但是在java的运行期(已经生成字节码文件后)与泛型相关的信息会被擦除掉,专业术语叫做类型擦除。
Java 泛型擦除是 Java 泛型中的一个重要特性,其目的是避免过多的创建类而造成的运行时的过度消耗,及兼容问题。

三、静态变量和实例变量的区别

静态变量是被 static 修饰符修饰的变量,也称为类变量,它属于类,不属于类的任何一个对象,一个类不管创建多少个对象,静态变量在内存中有且仅有一个拷贝;

实例变量必须依存于某一实例,需要先创建对象然后通过对象才能访问到它。
静态变量可以实现让多个对象共享内存。

补充:在 Java 开发中,上下文类和工具类中通常会有大量的静态成员。

四、什么是死锁?

当线程 A 持有独占锁a,并尝试去获取独占锁 b 的同时,线程 B 持有独占锁 b,并尝试获取独占锁 a 的情况下,就会发生 AB 两个线程由于互相持有对方需要的锁,而发生的阻塞现象,我们称为死锁。

五、线程的 sleep()方法和 yield()方法有什么区别?

1、sleep()方法给其他线程运行机会时不考虑线程的优先级,因此会给低优先级的线程以运行的机会;yield()方法只会给相同优先级或更高优先级的线程以运行的机会;
2、 线程执行 sleep()方法后转入阻塞(blocked)状态,而执行 yield()方法后转入就绪(ready)状态;
3、 sleep()方法声明抛出 InterruptedException,而 yield()方法没有声明任何异常;
4、 sleep()方法比 yield()方法(跟操作系统 CPU 调度相关)具有更好的可移植性。

六、事务的 ACID 是指什么?

1、原子性(Atomic):事务中各项操作,要么全做要么全不做,任何一项操作
的失败都会导致整个事务的失败;
2、一致性(Consistent):事务结束后系统状态是一致的;
3、隔离性(Isolated):并发执行的事务彼此无法看到对方的中间状态;
4、持久性(Durable):事务完成后所做的改动都会被持久化,即使发生灾难
性的失败。通过日志和同步备份可以在故障发生后重建数据。

七、什么是线程局部变量?

线程局部变量是局限于线程内部的变量,属于线程自身所有,不在多个线程间共享。

Java 提供 ThreadLocal 类来支持线程局部变量,是一种实现线程安全的方式。但是在管理环境下(如 web 服务器)使用线程局部变量的时候要特别小心,在这种情况下,工作线程的生命周期比任何应用变量的生命周期都要长。任何线程局部变量一旦在工作完成后没有释放,Java 应用就存在内存泄露的风险。

八、JDBC 操作数据库的步骤

1、加载驱动。

Class.forName("oracle.jdbc.driver.OracleDriver"); 

2、创建连接。

Connection con = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:orcl", "scott", "tiger"); 

3、创建语句。

PreparedStatement ps = con.prepareStatement("select * from emp where sal between ? and ?"); 
ps.setInt(1, 1000); 
ps.setInt(2, 3000); 

4、执行语句。

ResultSet rs = ps.executeQuery();

5、处理结果。

while(rs.next()) { 
System.out.println(rs.getInt("empno") + " - " + 
rs.getString("ename")); 
} 

6、关闭资源。

finally { 
if(con != null) { 
try { 
con.close(); 
} catch (SQLException e) { 
e.printStackTrace(); 
} 
} 
} 

提示:关闭外部资源的顺序应该和打开的顺序相反,也就是说先关闭 ResultSet、 再关闭 Statement、在关闭Connection。上面的代码只关闭了 Connection(连接),虽然通常情况下在关闭连接时,连接上创建的语句和打开的游标也会关闭,但不能保证总是如此,因此应该按照刚才说的顺序分别关闭。此外,第一步加载驱动在 JDBC 4.0 中是可以省略的(自动从类路径中加载驱动),但是我们建议保留。

九、怎么确保一个集合不能被修改?

可以使用 Collections. unmodifiableCollection(Collection c) 方法来创建一个只读集合,这样改变集合的任何操作都会抛出 Java. lang. UnsupportedOperationException 异常。
示例代码如下:

List<String> list = new ArrayList<>(); 
list. add("x"); 
Collection<String> clist = Collections. unmodifiableCollection(list); 
clist. add("y"); // 运行时此行报错 
System. out. println(list. size()); 

十、Statement 和 PreparedStatement 有什么区别?哪个性能更好?

与 Statement 相比,
1、PreparedStatement 接口代表预编译的语句,它主要的优势在于可以减少 SQL 的编译错误并增加 SQL 的安全性(减少 SQL 注射攻击的可能性);
2、PreparedStatement 中的 SQL 语句是可以带参数的,避免了用字符串连接拼接 SQL 语句的麻烦和不安全;
3、当批量处理 SQL 或频繁执行相同的查询时,PreparedStatement 有明显的性能上的优势,由于数据库可以将编译优化后的 SQL 语句缓存起来,下次执行相同结构的语句时就会很快(不用再次编译和生成执行计划)。

补充:为了提供对存储过程的调用,JDBC API 中还提供了 CallableStatement 接口。存储过程(Stored Procedure)是数据库中一组为了完成特定功能的 SQL 语句的集合,经编译后存储在数据库中,用户通过指定存储过程的名字并给出参数(如果该存储过程带有参数)来执行它。虽然调用存储过程会在网络开销、安全 性、性能上获得很多好处,但是存在如果底层数据库发生迁移时就会有很多麻烦, 因为每种数据库的存储过程在书写上存在不少的差别。

十一、用哪两种方式来实现集合的排序?

你可以使用有序集合,如 TreeSet 或 TreeMap,你也可以使用有顺序的的集合,如 list,然后通过Collections.sort() 来排序。

十二、poll() 方法和 remove() 方法的区别?

poll() 和 remove() 都是从队列中取出一个元素,但是 poll() 在获取元素失败的时候会返回空,但是 remove() 失败的时候会抛出异常。

十三、Java 中的 LinkedList 是单向链表还是双向链表?

是双向链表

十四、Java 中的 TreeMap 是采用什么实现的?

Java 中的 TreeMap 是使用红黑树实现的。

十五、Java 中Comparator 与 Comparable 有什么不同?

Comparable 接口用于定义对象的自然顺序,而 comparator 通常用于定义用户定制的顺序。Comparable 总是只有一个,但是可以有多个 comparator 来定义对象的顺序。

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一只IT攻城狮

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值