21、3*0.1 == 0.3返回值是什么?
✅ false
有些浮点数在计算的时候不能完整的表示出来。
22、a=a+b与a+=b有什么区别吗?
a += b 会隐式的将结果类型转换为持有结果的类型,而 a = a + b 不会。
例如:
byte a = 127;
byte b = 127;
b = a + b; // 报编译错误:cannot convert from int to byte
b += a; // 编译通过
23、try catch finally,try里有return,finally还执行么?
答案肯定是 finally 还执行,无论 try 里边是否有 return , finally 最终都会执行,如果有 return ,finally 中的程序会在 try 中的 return 语句执行后,但是结果还没有返回的时候执行,此时无论 finally 中执行什么,try 中的 return 返回的值不会改变。需要注意的是 finally 中最好不要包含 return , 否则程序会提前退出,返回值不是 try 和catch 中的值了。
24、Exception 与 Error 包结构
Java 可抛出(Throwable)的结构分为三种,被检测的异常(CheckedException)、运行时异常(RuntimeException)、错误(Error)
- 运行时异常
运行时异常就是 RuntimeException 及其子类。
其特点就是 Java 编译器在运行时不会检测它,这类异常我们在编码的时候无法预测,所以不会使用 throws 抛出,或者使用 try catch 进行捕获,还是会编译通过的。
常见的运行时异常如下:
ArithmeticException 除数为零时产生的异常
IndexOutOfBoundsException 数组越界产生的异常
ClassCastException 类转换异常
NullPointerException 空指针异常
ArrayStoreException 数组存储异常,操纵数据类型不一致导致的
✅ ConcurrentModificationException 并发修改异常
这个异常是 fail-fast 机制产生的,它是 Java 集合的一种错误机制检测,当多个线程同时对一个集合进行结构上的操作时,有可能会产生 fail-fast 机制,但不一定会产生。
假设存在两个线 程(线程1、线程2),线程1通过Iterator在遍历集合A中的元素,在某个时候线程2修改了集合A的结构(是结构上面的修改,而不是简单的修改集合元素的内容),那么这个时候程序就会抛出 ConcurrentModificationException 异常,从而产生fail-fast机制,这个异常叫并发修改异常。
Fail- safe,java.util.concurrent 包下面的所有的类都是安全失败的,在遍历过程中,如果已经遍历的数组上的内容变化了,迭代器不会抛出 ConcurrentModificationException 异常。如果未遍历的数组上的内容发生了变化,则有可能反映到迭代过程中。这就是ConcurrentHashMap迭代器弱一致的表现。ConcurrentHashMap的弱一致性主要是为了提升效率,是一致性与效率之间的一种权衡。 要成为强一致性,就得到处使用锁,甚至是全局锁,这就与Hashtable和同步的HashMap一样 了。)等,都属于运行时异常。
- 被检测异常
Exception类本身,以及Exception的子类中除了"运行时异常"之外的其它子类都属于被检查异常。
特点 : Java编译器会检查它。 此类异常,要么通过throws进行声明抛出,要么通过try-catch进行捕 获处理,否则不能通过编译。
常见的被检测异常有如下几种:
IOException
FileNotFoundException
SQLException
被检查的异常适用于那些不是因程序引起的错误情况
- Error 错误
它包括 Error 类和机器子类,编译器是不会对其进行检测的,当资源不足、约束失败、或是其它程序无法继续运行的条件发生时,就产生错误。程序本身无法修 复这些错误的。
25、OOM 和 SOF 你遇到过哪些情况?
除了程序计数器外,虚拟机内存的其他几个运行时区域都有发生 OutOfMemoryError(OOM) 异常的 可能。
SOF (StackOverflow)堆栈溢出:当应用程序出现死循环或者大量的递归调用的时候,会导致栈容量超过 1MB 限制导致溢出。
26、简述线程、进程、程序之间的基本概念,以及他们之间的关系是什么?
线程与进程相似,但是一个进程中可以有多个线程,同一个进程中的线程可以共享同一块内存空间和系统资源,所以同一个进程中的线程在切换时,负担要比进程小很多,所以线程又被称为轻量级进程。
程序是由含有指令和数据的文件,被存储在磁盘或者其他的存储设备中,也就是静态的代码。
进程是程序执行一次的过程,是系统运行程序的基本单位,因此进程是动态的,系统运行程序时就是一个进程被创建到消亡的过程。同时,每个进程还占用一定的系统资源,比如 cpu 时间、内存空间、文件的输入或输出、以及物理设备的使用。和线程不同的是,各个进程之间是相互独立的。从另一个角度来说,进程是系统运行的范畴,在同一段时间内,可以执行一个以上的程序,而线程则是在同一个程序内执行一个以上的程序段。
27、Java 中如果有些字段不想序列化怎么处理?
Java 中的序列化简而言之就是为了保存内存中的各种对象的状态(也就是实例变量,不是方法),并且可以把保存的对象状态再读出来。
✅ 序列化和反序列化:
- 把对象转换为字节序列的过程称为对象的序列化
- 把字节序列恢复为对象的过程称为对象的反序列化
✅ Java 实现序列化的两个点:
- 本类或者父类实现了 java.io.Serializable 接口
- 该类中的所有成员变量必须是可序列化的。
✅ 什么时候需要序列化?
当我们需要将一个对象的数据保存到文件或者数据库中,需要序列化,比如 mybatis 中的通用 mapper 中我们使用 insert 插入数据的时候就会需用序列化,有时候可能会因为传入的数据类型不一致时出现序列化失败的报错。
✅ 如果一个字段不想被序列应该需要如何处理?
只需要在相应字段前使用 transient 标注即可。它的作用是:阻止实例中那些用此关键字修饰的的变量序列化;当对象被反序列化 时,被 transient 修饰的变量值不会被持久化和恢复。transient 只能修饰变量,不能修饰类和方 法。
28、说说 Java 中的 io 流
Java中的 io 流涉及 40 多个类,但是他们彼此之间联系紧密,是非常有规律的。
按照流的方向分类,我们可以将流分为输入流和输出流。
按照流的单元分类,我们可以将流分为字节流和字符流。
按照流的角色可以划分为节点流和处理流。
29、Java 中 IO 和 NIO 的区别
NIO 即 New IO ,这个库是在 JDK1.4 中才引入的。NIO 和 IO 有相同的作用和目的,但实现方式不同, NIO 主要用到的是块,所以NIO的效率要比IO高很多。在Java API中提供了两套NIO,一套是针对标 准输入输出NIO,另一套就是网络编程NIO。
30、Java的反射作用原理
✅ 什么是Java的反射机制
反射机制是运行时对任意一个类,都能够获取这个类的所有属性和方法的。这种动态获取信息以及动态调用对象方法或属性的功能称为 Java 语言的反射机制。
✅ 哪里会用到反射机制?
JDBC 就是典型的反射。
Class.forName('com.mysql.jdbc.Driver.class');//加载MySQL的驱动类
✅ 反射的实现方式
第一步:获取Class对象,有4中方法:
1)Class.forName(“类的路径”);
2)类名.Class
3)对象 名.getClass()
第二步:使用获取的类名 newInstance() 一个实例。
✅ 实现Java反射的类
1)Class:表示正在运行的Java应用程序中的类和接口 注意: 所有获取对象的信息都需要Class类 来实现。
2)Field:提供有关类和接口的属性信息,以及对它的动态访问权限。
3)Constructor: 提供关于类的单个构造方法的信息以及它的访问权限
4)Method:提供类或接口中某个方法的信息
✅ 反射的优缺点
优点:
1、和动态编译相结合
2、能够在运行时获取类的实例,比较灵活。
缺点:
使用反射时性能较低,需要读取字节码文件,效率比价低。
解决办法如下:
- 通过 setAccessible(true) 关闭 JDK 中的安全扫描
- 多次创建对象,有缓存会快很多
31、说说 List、Set、Map 三者的区别
- List: List接口存储一组不唯一(可以有多个元素引用相同的对象),有序
的对象 - Set: 不允许重复的集合。不会有多个元素引用相同的对象。
- Map: 使用键值对存储。Map会维护与Key有关联的值。两个Key可以引
用相同的对象,但Key不能重复,典型的Key是String类型,但也可以是任何对象。
32、Object 有哪些常用方法?大致说一下每个方法的含义?
✅ clone()
保护方法,实现对象的浅复制,只有实现了 Cloneable 接口才可以调用该方法,否则抛出 CloneNotSupportedException 异常,深拷贝也需要实现 Cloneable,同时其成员变量为引用类型 的也需要实现 Cloneable,然后重写 clone 方法。
✅ equals()
该方法使用频率非常高。一般 equals 和 == 是不一样的,但是在 Object 中两者是一样的。子类一 般都要重写这个方法。
✅ hashCode 方法
该方法用于哈希查找,重写了 equals 方法一般都要重写 hashCode 方法,这个方法在一些具有哈希功能的 Collection 中用到。
✅ finalize()
该方法和垃圾收集器有关系,判断一个对象是否可以被回收的最后一步就是判断是否重写了此方法。
✅ wait(long timeout) wait()
配合 synchronized 使用,wait 方法就是使当前线程等待该对象的锁,当前线程必须是该对象的拥有者,也就是具有该对象的锁。wait() 方法一直等待,直到获得锁或者被中断。wait(long timeout) 设定一个超时间隔,如果在规定时间内没有获得锁就返回。
✅ notify()
配合 synchronized 使用,该方法唤醒在该对象上等待队列中的某个线程(同步队列中的线程是给抢占 CPU 的线程,等待队列中的线程指的是等待唤醒的线程)。
<aside>
✅ notifyAll()
</aside>
配合 synchronized 使用,该方法唤醒在该对象上等待队列中的所有线程。
<aside>
✅ toString()
</aside>
按照自定义规则对对象进行输出,一般都需要重写该方法。
33、HashMap 中的 key 我们可以使用任何类作为key 吗?
平时可能最多的就是使用 String 作为 HashMap 的 key,但是现在我们想使用某个自定义类作为 HashMap 的 key,那就需要注意以下几点:
- 如果类重写了 equals 方法,它也应该重写 hashCode 方法。
- 我们自定义的 key 最好是不可变的,这样可以使hashCode 值可以被缓存起来,拥有更好的能。不可变的类也可以确保 hashCode 和 equals 在未来不会改变,这样就会解决与可变相关的问题了。
34、HashMap 与 ConcurrentHashMap 的异同
✅ 相同点
他们的都是 key-value 的存储形式
✅ 不同点
- HashMap 是线程不安全的,ConcurrentHashMap 是 JUC 下线程安全的。
- HashMap 底层数据结构是数组 + 链表(JDK 1.8 之前)。JDK 1.8 之后是数组 + 链表 + 红黑树。当链表中元素个数达到 8 的时候,链表的查询速度不如红黑树快,链表会转为红黑树,红黑树查询速度快; ConcurrentHashMap 的数据结构是分段数组 + 链表 + 红黑树
35、红黑树有哪几个特征?
- 每个节点是黑色或红色
- 根节点是黑色
- 每个叶子节点都是黑色(指向空的叶子节点)
- 如果一个叶子节点是红色,那么其子节点必须都是黑色的
- 从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑节点