Java SE面试题集合(一)

简介: 笔记

(1)Java基础


1.JDK 和 JRE 有什么区别?


JDK:Java 开发工具包, 提供了 Java 的开发环境和运行环境。

JRE:Java 运行环境, 为 Java 的运行提供了所需环境。

2.== 和 equals 的区别是什么?


==运算符比较的是两个引用是否指向相同的对象(即同一内存空间),也就是说在内存空间中的存储位置是否一致。

equals是判断两个变量或者实例指向同一个内存空间的值是不是相同

3. 两个对象的 hashCode() 相同,则 equals() 也一定为 true,对吗?

不对, 两个对象的 hashCode() 相同, equals() 不一定 true。

4. final 在 Java 中有什么作用?


final 修饰的类叫最终类, 该类不能被继承。

final 修饰的方法不能被重写。

final 修饰的变量叫常量, 常量必须初始化,初始化之后值就不能被 修改。

5. Java 中的 Math. round(-1. 5) 等于多少?

等于 -1。round()是四舍五入,注意负数5是舍的,
例如:Math.round(1.5)值是2,Math.round(-1.5)值是-1。

6. String 属于基础的数据类型吗?


String 不 属 于 基 础 类 型 , 基 础 类 型 有 8 种 : byte 、 boolean 、 char 、 short 、 int 、 float 、 long 、 double , 而 String 属于对象。


7. Java 中操作字符串都有哪些类?它们之间有什么区别?

操作字符串的类有:String、StringBuffer、StringBuilder。


区别一:


String是不可变字符串

StringBuffer和StringBuilder是可变字符串。

区别二:


StringBuffer是线程安全的,它的方法是支持线程同步,线程同步会操作串行顺序执行,在单线程环境 下会影响效率。

StringBuilder是StringBuffer单线程版本,它不是线程安全的,但它 的执行效率很高。

运行速度快慢为:StringBuilder > StringBuffer > String


8. String str="i"与 String str=new String(“i”)一样吗?

不一样, 因为内存的分配方式不一样。 String str=" i" 的方式, Java 虚拟 机会将其分配到常量池中;而 String str=new String(" i" ) 则会被分到堆 内存中。


9. 如何将字符串反转?

使用 StringBuilder 或者 stringBuffer 的 reverse() 方法。


10. String 类的常用方法都有那些?


indexOf():返回指定字符的索引。

charAt():返回指定索引处的字符。

replace():字符串替换。

trim():去除字符串两端空白。

split():分割字符串, 返回一个分割后的字符串数组。

getBytes():返回字符串的 byte 类型数组。

length():返回字符串长度。

toLowerCase():将字符串转成小写字母。

toUpperCase():将字符串转成大写字符。

substring():截取字符串。

equals():字符串比较。

11. 抽象类必须要有抽象方法吗?

不需要,抽象类不一定非要有抽象方法;但是包含一个抽象方法的类一定是抽象类。


12. 普通类和抽象类有哪些区别?


普通类不能包含抽象方法, 抽象类可以包含抽象方法。

抽象类不能直接实例化, 普通类可以直接实例化。

如果一个类继承于抽象类,则该子类必须实现父类的抽象方法。如果子类没有实现父类的抽象方法,则必须将子类也定义为abstract类。

13. 抽象类能使用 final 修饰吗?

不能, 定义抽象类就是让其他类继承的, 如果定义为 final 该类就不能被 继承, 这样彼此就会产生矛盾, 所以 final 不能修饰抽象类。


14. 接口和抽象类有什么区别?


实 现 : 抽 象 类 的 子 类 使 用 extends 来 继 承 ; 接 口 必 须 使 用 implements 来实现接口。

构造函数:抽象类可以有构造函数;接口不能有。

实现数量:接口支持多继承,而抽象类(包括具体类)只能继承一个父类。

成员变量:接口中不能有实例成员变量,接口所声明的成员变量全部是静态常量,抽象类与普通类一样各种形式的成员变量都可以声明。

15. Java 中 IO 流分为几种?

按功能来分:输入流(input)、输出流(output)。

按类型来分:字节流和字符流。


字节流和字符流的区别是:字节流按 8 位传输以字节为单位输入输出数据, 字符流按 16 位传输以字符为单位输入输出数据。


16. BIO、NIO、AIO 有什么区别?


BIO:Block IO 同步阻塞式 IO, 就是我们平常使用的传统 IO, 它 的特点是模式简单使用方便, 并发处理能力低。

NIO:Non IO 同步非阻塞 IO, 是传统 IO 的升级, 客户端和服务 器端通过 Channel(通道)通讯, 实现了多路复用。

AIO:Asynchronous IO 是 NIO 的升级, 也叫 NIO2, 实现了异 步非堵塞 IO , 异步 IO 的操作基于事件和回调机制。

17. Files 的常用方法都有哪些?


Files. exists():检测文件路径是否存在。

Files. createFile():创建文件。

Files. createDirectory():创建文件夹。

Files. delete():删除一个文件或目录。

Files. copy():复制文件。

Files. move():移动文件。

Files. size():查看文件个数。

Files. read():读取文件。

Files. write():写入文件。


(2)容器


18. Java 容器都有哪些?

Java 容器分为 Collection 和 Map 两大类, 其下又有很多子类, 如下所 示:


Collection

List

ArrayList

LinkedList

Vector

Stack

Set

HashSet

LinkedHashSet

TreeSet

Map

HashMap

LinkedHashMap

TreeMap

ConcurrentHashMap

Hashtable

19. Collection 和 Collections 有什么区别?


Collection 是一个集合接口, 它提供了对集合对象进行基本操作的 通用接口方法, 所有集合都是它的子类, 比如 List、Set 等。

Collections 是一个包装类, 包含了很多静态方法, 不能被实例化, 就像一个工具类, 比如提供的排序方法: Collections. sort(list)。

20. List、Set、Map 之间的区别是什么?


List:有序、允许重复

Set:无序、不允许重复

Map:key是set类型,不允许重复、value是Collection类型,可以重复

21. HashMap 和 Hashtable 有什么区别?


HashMap是继承自AbstractMap类,而HashTable是继承自Dictionary类

存储:HashMap的key-value支持key-value,null-null,key-null,null-value四种。而Hashtable只支持key-value一种

线程安全:Hashtable 是线程安全的, 而 HashMap 是非线程安全 的。

Hashtable比HashMap多提供了elments() 和contains() 两个方法。

22. 如何决定使用 HashMap 还是 TreeMap?


对于在 Map 中插入、删除、定位一个元素这类操作,选HashMap

要对一个 key 集合进行有序的遍历,选TreeMap

23. 说一下 HashMap 的实现原理?

HashMap 基 于 Hash 算 法 实 现 的 , 我 们 通 过 put(key,value) 存 储 , get(key)来获取。 当传入 key 时, HashMap 会根据 key. hashCode() 计算出 hash 值, 根据 hash 值将 value 保存在 bucket 里。 当计算出的 hash 值相同时, 我们称之为 hash 冲突, HashMap 的做法是用链表和 红黑树存储相同 hash 值的 value。 当 hash 冲突的个数比较少时, 使用 链表否则使用红黑树。


24. 说一下 HashSet 的实现原理?

HashSet 是基于 HashMap 实现的, HashSet 底层使用 HashMap 来 保存所有元素, 因此 HashSet 的实现比较简单, 相关 HashSet 的操作, 基本上都是直接调用底层 HashMap 的相关方法来完成, HashSet 不允 许重复的值。


25. ArrayList 和 LinkedList 的区别是什么?


数 据 结 构 实 现 : ArrayList 是 动 态 数 组 的 数 据 结 构 实 现 , 而 LinkedList是双向链表的数据结构实现。

随机访问效率:ArrayList 比 LinkedList 在随机访问的时候效率要 高, 因为LinkedList 是线性的数据存储方式, 所以需要移动指针从 前往后依次查找。

增加和删除效率:在非首尾的增加和删除操作,

LinkedList 要比 ArrayList 效率要高, 因为 ArrayList 增删操作要影响数组内的其他 数据的下标。

26. 如何实现数组和 List 之间的转换?


数组转 List:使用 Arrays. asList(array) 进行转换。

List 转数组:使用 List 自带的toArray() 方法。

27. ArrayList 和 Vector 的区别是什么?


线程安全:Vector 使用了 Synchronized 来实现线程同步, 是线 程安全的, 而 ArrayList 是非线程安全的。

性能:ArrayList 在性能方面要优于 Vector。

扩容:ArrayList 和 Vector 都会根据实际的需要动态的调整容量,只不过在 Vector 扩容每次会增加 1 倍, 而 ArrayList 只会增加 50%。

28. Array 和 ArrayList 有何区别?


Array 可以存储基本数据类型和对象, ArrayList 只能存储对象。

Array 是指定固定大小的, 而 ArrayList大小是自动扩展的。

Array 内 置 方 法 没 有 ArrayList 多 , 比如addAll、removeAll、iteration 等方法只有 ArrayList 有。

29. 在 Queue 中 poll()和 remove()有什么区别?


相同点:都是返回第一个元素, 并在队列中删除返回的对象。

不同点:如果没有元素 poll()会返回 null, 而

remove()会直接抛 出 NoSuchElementException 异常。

30. 哪些集合类是线程安全的?

Vector、Hashtable、Stack 都是线程安全的


31. 迭代器 Iterator 是什么?

Iterator 接 口 提 供 遍 历 任 何 Collection 的 接 口 。 我 们 可 以 从 一 个 Collection 中使用迭代器方法来获取迭代器实例。 迭代器取代了 Java 集 合框架中的 Enumeration, 迭代器允许调用者在迭代过程中移除元素。


32. Iterator 怎么使用?有什么特点?

Iterator 使用代码如下:

List<String> list = new ArrayList<>(); 
Iterator<String> it = list. iterator();
while(it. hasNext()){ 
  String obj = it. next(); 
  System. out.println(obj); 
}

Iterator 的特点是更加安全, 因为它可以确保, 在当前遍历的集合元素被 更改的时候, 就会抛出 ConcurrentModificationException 异常。


33. Iterator 和 ListIterator 有什么区别?


Iterator 可以遍历 Set 和 List 集合, 而 ListIterator 只能遍历 List。

Iterator 只能单向遍历, 而 ListIterator 可以双向遍历(向前/后 遍历)。

ListIterator 从 Iterator 接口继承, 然后添加了一些额外的功能, 比如添加一个元素、替换一个元素、获取前面或后面元素的索引位置。

34. 怎么确保一个集合不能被修改?

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


(3)多线程


35. 并行和并发有什么区别?


并行:多个处理器或多核处理器同时处理多个任务。

并发:多个任务在同一个 CPU 核上, 按细分的时间片轮流(交替)执 行, 从逻辑上来看那些任务是同时执行。

并发 = 两个队列和一台咖啡机。

并行 = 两个队列和两台咖啡机。


36. 线程和进程的区别?

一个程序下至少有一个进程, 一个进程下至少有一个线程, 一个进程下也 可以有多个线程来增加程序的执行速度。


37. 守护线程是什么?

守护线程是运行在后台的一种特殊进程。 它独立于控制终端并且周期性地 执行某种任务或等待处理某些发生的事件。 在 Java 中垃圾回收线程就是 特殊的守护线程。


38. 创建线程有哪几种方式?


继承Thread类

实现Runnable接口

实现Callable接口通过FutureTask包装器来创建Thread线程

通过线程池创建线程,使用线程池接口ExecutorService结合Callable、Future实现有返回结果的多线程。

39. 说一下 runnable 和 callable 有什么区别?

runnable 没有返回值, callable 可以拿到有返回值, callable 可以看作 是 runnable 的补充。


40. 线程有哪些状态?


NEW 尚未启动

RUNNABLE 正在执行中

BLOCKED 阻塞的(被同步锁或者 IO 锁阻塞)

WAITING 永久等待状态

TIMED_WAITING 等待指定的时间重新被唤醒的状态

TERMINATED 执行完成

41. sleep() 和 wait() 有什么区别?


类的不同:sleep() 来自 Thread, wait() 来自 Object。

释放锁:sleep() 不释放锁;wait() 释放锁。

用法不同:sleep() 时间到会自动恢复;wait() 可以使用 notify()/ notifyAll()直接唤醒。

42. notify()和 notifyAll()有什么区别?

notifyAll()会唤醒所有的线程, notify()之后唤醒一个线程。 notifyAll() 调用后, 会将全部线程由等待池移到锁池, 然后参与锁的竞争, 竞争成功 则继续执行, 如果不成功则留在锁池等待锁被释放后再次参与竞争。 而 notify()只会唤醒一个线程, 具体唤醒哪一个线程由虚拟机控制。


43. 线程的 run() 和 start() 有什么区别?

start() 方法用于启动线程, run() 方法用于执行线程的运行时代码。 run() 可以重复调用, 而 start() 只能调用一次。


44. 创建线程池有哪几种方式?


线程池创建有七种方式, 最核心的是最后一种:


newSingleThreadExecutor():它的特点在于工作线程数目被限制 为 1, 操作一个无界的工作队列, 所以它保证了所有任务的都是被顺 序执行, 最多会有一个任务处于活动状态, 并且不允许使用者改动线 程池实例, 因此可以避免其改变线程数目;

newCachedThreadPool():它是一种用来处理大量短时间工作任 务的线程池, 具有几个鲜明特点:它会试图缓存线程并重用, 当无缓 存线程可用时, 就会创建新的工作线程;如果线程闲置的时间超过 60 秒, 则被终止并移出缓存;长时间闲置时, 这种线程池, 不会消 耗什么资源。 其内部使用 SynchronousQueue 作为工作队列;

newFixedThreadPool(int nThreads) : 重 用 指 定 数 目 (nThreads)的线程, 其背后使用的是无界的工作队列, 任何时候 最多有 nThreads 个工作线程是活动的。 这意味着, 如果任务数量 超过了活动队列数目, 将在工作队列中等待空闲线程出现;如果有工 作线程退出,将会有新的工作线程被创建,以补足指定的数目 nThreads;

newSingleThreadScheduledExecutor() : 创建 单 线 程 池 , 返回 ScheduledExecutorService, 可以进行定时或周期性的工作调度;

newScheduledThreadPool(int corePoolSize) : 和 newSingleThreadScheduledExecutor() 类 似 , 创 建 的 是 个 ScheduledExecutorService, 可以进行定时或周期性的工作调度, 区别在于单一工作线程还是多个工作线程;

newWorkStealingPool(int parallelism) :这是一个经常被人忽 略 的 线 程 池 , Java 8 才 加 入 这 个 创 建 方 法 , 其 内 部 会 构 建 ForkJoinPool, 利用 Work-Stealing 算法, 并行地处理任务, 不保 证处理顺序;

ThreadPoolExecutor():是最原始的线程池创建, 上面 1-3 创建 方式都是对 ThreadPoolExecutor 的封装。

45. 线程池都有哪些状态?


RUNNING:这是最正常的状态, 接受新的任务, 处理等待队列中 的任务。

SHUTDOWN:不接受新的任务提交, 但是会继续处理等待队列中 的任务。

STOP:不接受新的任务提交, 不再处理等待队列中的任务, 中断正 在执行任务的线程。

TIDYING:所有的任务都销毁了, workCount 为 0, 线程池的状 态在转换为 TIDYING 状态时, 会执行钩子方法 terminated()。

TERMINATED:terminated()方法结束后, 线程池的状态就会变 成这个。

46. 线程池中 submit() 和 execute() 方法有什么区别?


execute():只能执行 Runnable 类型的任务。

submit():可以执行 Runnable 和 Callable 类型的任务。

Callable 类型的任务可以获取执行的返回值, 而 Runnable 执行无返回 值。


47. 在 Java 程序中怎么保证多线程的运行安全?


方法一:使用安全类, 比如 Java. util. concurrent 下的类。

方法二:使用自动锁 synchronized。

方法三:使用手动锁 Lock。

48. 多线程中 synchronized 锁升级的原理是什么?

synchronized 锁升级原理:在锁对象的对象头里面有一个 threadid 字 段, 在第一次访问的时候 threadid 为空, jvm 让其持有偏向锁, 并将 threadid 设置为其线程 id, 再次进入的时候会先判断 threadid 是否与 其线程 id 一致, 如果一致则可以直接使用此对象, 如果不一致, 则升级 偏向锁为轻量级锁, 通过自旋循环一定次数来获取锁, 执行一定次数之后, 如果还没有正常获取到要使用的对象, 此时就会把锁从轻量级升级为重量 级锁, 此过程就构成了 synchronized 锁的升级。


锁的升级的目的:锁升级是为了减低了锁带来的性能消耗。


49. 什么是死锁?

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


50. 怎么防止死锁?


尽 量 使 用 tryLock(long timeout, TimeUnit unit) 的 方 法 (ReentrantLock、ReentrantReadWriteLock) , 设置超时时间, 超时可以退出防止死锁。

尽量使用 Java. util. concurrent 并发类代替自己手写锁。

尽量降低锁的使用粒度, 尽量不要几个功能用同一把锁。

尽量减少同步的代码块。

51. ThreadLocal 是什么?有哪些使用场景?

ThreadLocal 为每个使用该变量的线程提供独立的变量副本, 所以每一个 线程都可以独立地改变自己的副本, 而不会影响其它线程所对应的副本。


ThreadLocal 的经典使用场景是数据库连接和 session 管理等。


52. 说一下 synchronized 底层实现原理?

synchronized 是 由 一 对 monitorenter/monitorexit 指 令 实 现 的 , monitor 对象是同步的基本实现单元。 在 Java 6 之前, monitor 的实现 完全是依靠操作系统内部的互斥锁, 因为需要进行用户态到内核态的切换, 所以同步操作是一个无差别的重量级操作, 性能也很低。 但在 Java 6 的 时 候 , Java 虚 拟 机 对 此 进 行 了 大 刀 阔 斧 地 改 进 , 提 供 了 三 种 不 同 的 monitor 实 现 , 也 就 是 常 说 的 三 种 不 同 的 锁 : 偏 向 锁 ( Biased Locking)、轻量级锁和重量级锁, 大大改进了其性能。


53. synchronized 和 volatile 的区别是什么?


volatile 是变量修饰符;synchronized 是修饰类、方法、代码段。

volatile 仅 能 实 现 变 量 的 修 改 可 见 性 , 不 能 保 证 原 子 性 ; 而 synchronized 则可以保证变量的修改可见性和原子性。

volatile 不会造成线程的阻塞;synchronized 可能会造成线程的 阻塞。

54. synchronized 和 Lock 有什么区别?


synchronized 可以给类、方法、代码块加锁;而 lock 只能给代码 块加锁。

synchronized 不需要手动获取锁和释放锁, 使用简单, 发生异常 会自动释放锁, 不会造成死锁;而 lock 需要自己加锁和释放锁, 如 果使用不当没有 unLock()去释放锁就会造成死锁。

通过 Lock 可以知道有没有成功获取锁, 而 synchronized 却无法 办到。

55. synchronized 和 ReentrantLock 区别是什么?


ReentrantLock 使用起来比较灵活, 但是必须有释放锁的配合动作;

ReentrantLock 必须手动获取与释放锁, 而 synchronized 不需 要手动释放和开启锁;

ReentrantLock 只适用于代码块锁, 而 synchronized 可用于修 饰方法、代码块等。

volatile 标记的变量不会被编译器优化;synchronized 标记的变 量可以被编译器优化。

56. 说一下 atomic 的原理?

atomic 主要利用 CAS (Compare And Wwap) 和 volatile 和 native 方法来保证原子操作, 从而避免 synchronized 的高开销, 执行效率大为 提升。


(4)反射


57. 什么是反射?

反射是在运行状态中, 对于任意一个类, 都能够知道这个类的所有属性和 方法;对于任意一个对象, 都能够调用它的任意一个方法和属性;这种动 态获取的信息以及动态调用对象的方法的功能称为 Java 语言的反射机制。


58. 什么是 Java 序列化?什么情况下需要序列化?

Java 序列化是为了保存各种对象在内存中的状态, 并且可以把保存的对象 状态再读出来。


以下情况需要使用 Java 序列化:


想把的内存中的对象状态保存到一个文件中或者数据库中时候;

想用套接字在网络上传送对象的时候;

想通过 RMI(远程方法调用)传输对象的时候。

59. 为什么要使用克隆?

克隆的对象可能包含一些已经修改过的属性, 而 new 出来的对象的属性 都还是初始化时候的值, 所以当需要一个新的对象来保存当前对象的“状 态”就靠克隆方法了。


60. 如何实现对象克隆?


实现 Cloneable 接口并重写 Object 类中的 clone() 方法。

实现 Serializable 接口, 通过对象的序列化和反序列化实现克隆, 可以实现真正的深度克隆。




相关文章
|
11天前
|
安全 Java 开发者
【JAVA】哪些集合类是线程安全的
【JAVA】哪些集合类是线程安全的
|
11天前
|
Java
【JAVA】怎么确保一个集合不能被修改
【JAVA】怎么确保一个集合不能被修改
|
1天前
|
Java
三个可能的Java面试题
Java垃圾回收机制自动管理内存,回收无引用对象的内存,确保内存有效利用。多态性允许父类引用操作不同子类对象,如Animal引用可调用Dog的方法。异常处理机制通过try-catch块捕获和处理程序异常,例如尝试执行可能导致ArithmeticException的代码,catch块则负责处理异常。
19 9
|
5天前
|
存储 安全 Java
Java集合的分类有哪些?
Java中的集合就像一个容器,专门用来存储Java对象,这些对象可以是任意的数据类型,并且长度可变。这些集合类都位于java.util包中,在使用时一定要注意导包的问题,否则会出现异常。
33 10
|
8天前
|
安全 Java
循环的时候去删除集合中的元素 java.util.ConcurrentModificationException
循环的时候去删除集合中的元素 java.util.ConcurrentModificationException
|
11天前
|
存储 算法 Java
【JAVA】Java 中 Set集合常用方法
【JAVA】Java 中 Set集合常用方法
|
12天前
|
Java
【JAVA面试题】static的作用是什么?详细介绍
【JAVA面试题】static的作用是什么?详细介绍
|
12天前
|
Java
【JAVA面试题】final关键字的作用有哪些
【JAVA面试题】final关键字的作用有哪些
|
1天前
|
安全 Java 开发者
深入理解Java并发编程:线程安全与性能优化
【5月更文挑战第7天】在Java中,多线程编程是提高应用程序性能和响应能力的关键。本文将深入探讨Java并发编程的核心概念,包括线程安全、同步机制以及性能优化策略。我们将通过实例分析,了解如何避免常见的并发问题,如死锁、竞态条件和资源争用,并学习如何使用Java提供的并发工具来构建高效、可靠的多线程应用。
|
1天前
|
缓存 Java
Java并发编程:深入理解线程池
【5月更文挑战第7天】本文将深入探讨Java并发编程中的重要概念——线程池。我们将了解线程池的基本概念,以及如何使用Java的Executor框架来创建和管理线程池。此外,我们还将讨论线程池的优点和缺点,以及如何选择合适的线程池大小。最后,我们将通过一个示例来演示如何使用线程池来提高程序的性能。