👩🏻 作者:一只IT攻城狮 ,关注我不迷路
❤️《java面试核心知识》突击系列,持续更新…
💐 面试必知必会学习路线:Java技术栈面试系列+SpringCloud项目实战学习路线
📝再小的收获x365天都会成就不一样的自己,一起学习,一起进步。
文章目录
- 一、为什么重写equals方法必须要重写hashCode方法
- 二、Java泛型与泛型擦除
- 1、Java泛型好处:
- 2、泛型擦除:
- 三、静态变量和实例变量的区别
- 四、什么是死锁?
- 五、线程的 sleep()方法和 yield()方法有什么区别?
- 六、事务的 ACID 是指什么?
- 七、什么是线程局部变量?
- 八、JDBC 操作数据库的步骤
- 九、怎么确保一个集合不能被修改?
- 十、Statement 和 PreparedStatement 有什么区别?哪个性能更好?
- 十一、用哪两种方式来实现集合的排序?
- 十二、poll() 方法和 remove() 方法的区别?
- 十三、Java 中的 LinkedList 是单向链表还是双向链表?
- 十四、Java 中的 TreeMap 是采用什么实现的?
- 十五、Java 中Comparator 与 Comparable 有什么不同?
一、为什么重写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 来定义对象的顺序。