61. Java中的Hashtable和HashMap有何区别?它们适用于哪些场景?
-
区别:
- HashMap:
- 非线程安全,可以存储null键和null值。
- 迭代顺序不确定,性能比Hashtable高。
- Hashtable:
- 线程安全,不允许存储null键和null值(会抛出NullPointerException)。
- 迭代顺序不确定,性能比HashMap低。
- HashMap:
-
适用场景:
- HashMap:适合单线程环境或者通过Collections工具类实现线程安全的场景,需要高性能且不需要同步的情况。
- Hashtable:适合多线程环境下需要线程安全的场景,性能相对较低但提供了同步机制。
62. Java中的EnumSet和BitSet有何异同?它们分别适用于哪些场景?
-
异同:
- EnumSet:
- 专门用于枚举类型,只能存储枚举值。
- 内部使用位向量实现,性能高效。
- 提供了枚举集合特有的操作方法,如按位操作等。
- BitSet:
- 通用的位集合,可以存储任意的位序列。
- 内部使用位向量实现,非常紧凑和高效。
- 主要用于存储大量布尔类型数据或者进行位运算。
- EnumSet:
-
适用场景:
- EnumSet:适合存储和操作枚举类型的集合,提供了与枚举相关的高效位操作。
- BitSet:适合存储大量布尔类型数据,进行位运算或者实现位图算法。
63. Java中的CopyOnWriteArrayList和ArrayList有何区别?它们分别适用于哪些场景?
-
区别:
- ArrayList:
- 线程不安全,适合单线程环境或者通过Collections工具类实现线程安全的场景。
- 修改操作时可能会抛出ConcurrentModificationException异常。
- CopyOnWriteArrayList:
- 线程安全,通过写时复制(copy-on-write)机制实现。
- 迭代器遍历时不会抛出ConcurrentModificationException异常。
- ArrayList:
-
适用场景:
- ArrayList:适合单线程或者多线程环境中读操作远多于写操作的场景,性能较高。
- CopyOnWriteArrayList:适合读写操作频率相当的场景,如事件监听器列表,其中读操作比写操作频繁。
64. Java中的Stack和Deque有何区别?它们分别适用于哪些场景?
-
区别:
- Stack:
- 继承自Vector,底层基于数组实现,线程安全。
- 提供了后进先出(LIFO)的栈操作,如push和pop。
- Deque(双端队列):
- 提供了在两端添加和移除元素的操作,支持队列和栈的混合操作。
- LinkedList和ArrayDeque都实现了Deque接口,前者基于双向链表,后者基于数组。
- Stack:
-
适用场景:
- Stack:适合需要后进先出操作的场景,如表达式求值、深度优先搜索等。
- Deque:适合需要在两端进行元素操作的场景,如双端队列、循环队列等。
65. Java中的HashMap如何工作?它的内部实现原理是什么?
- 工作原理:
- HashMap基于数组和链表(或红黑树)实现。
- 使用键的hashCode()确定存储位置(索引),如果位置上已经存在元素,则以链表或树形结构存储冲突的元素。
- 在JDK8及之后,还引入了红黑树来优化链表,提高查找效率。
- 当链表长度超过一定阈值(默认为8),链表会转换为红黑树。
66. Java中的线程池是什么?如何创建和使用线程池?
-
线程池:
- 线程池是管理和复用线程的机制,用于执行异步任务。
- 通过预先创建一组线程,避免了频繁创建和销毁线程的开销,提高了性能和资源利用率。
-
创建和使用:
- 使用
Executors
类的工厂方法创建线程池,如newFixedThreadPool
、newCachedThreadPool
等。 - 提交任务给线程池执行,可以通过
submit
方法提交Callable
或Runnable
任务。 - 线程池执行任务后会返回
Future
对象,可以用于获取任务执行结果或取消任务。
- 使用
67. Java中的反射(Reflection)是什么?如何使用反射机制?
-
反射:
- 反射是在运行时动态获取类信息以及操作类成员(字段、方法、构造方法等)的能力。
- 主要通过
Class
类及其方法实现,如getClass()
、getFields()
、getMethods()
等。
-
使用:
- 获取类的Class对象:
Class clazz = MyClass.class;
或者通过对象获取:Class clazz = obj.getClass();
- 获取类的字段、方法等信息:通过
clazz.getField("fieldName")
、clazz.getMethod("methodName", parameterTypes)
等方法获取。 - 动态创建对象、调用方法、访问和修改字段等。
- 获取类的Class对象:
68. Java中的序列化(Serialization)和反序列化是什么?如何实现?
-
序列化:
- 将对象转换为字节序列的过程称为序列化,可以将对象保存到文件或者通过网络传输。
- 实现
Serializable
接口并定义serialVersionUID
字段。
-
反序列化:
- 将字节序列恢复为对象的过程称为反序列化。
- 通过
ObjectInputStream
读取字节流,调用readObject()
方法。
69. Java中的多线程同步机制有哪些?如何实现?
- 同步机制:
- 使用
synchronized
关键字:对代码块或方法加锁,保证同一时刻只有一个线程访问。 - 使用
ReentrantLock
:显式锁,提供了更多的灵活性和扩展功能。 - 使用
volatile
关键字:保证可见性,但不保证原子性,适用于状态标志等简单的同步需求。
- 使用
70. Java中的异常处理机制是怎样的?常见的异常类有哪些?
-
异常处理:
- 使用
try-catch-finally
块捕获和处理异常。 throws
关键字用于声明方法可能抛出的异常。- 异常分为受检异常(checked exception)和非受检异常(unchecked exception)。
- 使用
-
常见异常类:
NullPointerException
ArrayIndexOutOfBoundsException
ClassNotFoundException
IOException
RuntimeException
及其子类,如IllegalArgumentException
、IllegalStateException
等。