Java是一门面向对象的编程语言,不仅吸收了C++语言的各种优点,还摒弃了C++里难以理解的多继承指针等概念,因此Java语言具有功能强大和简单易用两个特征。Java语言作为静态面向对象编程语言的代表,极好地实现了面向对象理论,允许程序员以优雅的思维方式进行复杂的编程。Java具有简单性、面向对象、分布式健壮性安全性、平台独立与可移植性、多线程、动态性等特点。 Java可以编写桌面应用程序、Web应用程序、分布式系统嵌入式系统应用程序等

常见问题

== 和 equals 的区别

  • == 解读

    基本类型:比较的是值是否相同; 引用类型:比较的是引用是否相同;

    若指向同一个引用,== 为 true,而 new String() 方法重新开辟了内存空间, == 结果为 false,而 equals 比较的是值,结果为 true

  • equals 解读:equals 本质上就是 ==,只不过 String 和 Integer 等重写了 equals 方法,把它变成了值比较

  • 总结: == 对于基本类型来说是值比较,对于引用类型来说是比较的是引用;而 equals 默认情况下是引用比较,String、Integer 等类重写了equals,把它变成了值比较,所以一般情况下 equals 比较的是值是否相等。

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

不对,两个对象的 hashCode() 相同,equals() 不一定 true。代码解读:显然“通话”和“重地”的 hashCode() 相同,然而 equals()为 false,因为在散列表中,hashCode() 相等即两个键值对的哈希值相等,然而哈希值相等,并不一定能得出键值对相等。

1
2
3
4
5
6
7
8
String str1 = “通话”;
String str2 = "重地”;
System. out.printIn(string. format("str1:%d|str2:%d", str1. hashcode(),str2. hashcode()));
System. out.println(str1. equals(str2));

# 打印结果
str1:1179395 | str2:1179395
false

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

等于 -1,因为在数轴上取值时,中间值(0.5)向右取整,所以正 0.5 是往上取整,负 0.5 是直接舍弃。

final 在 Java 中有什么作用

  • final 修饰的类叫最终类,该类不能被继承。
  • final 修饰的方法不能被重写。
  • final 修饰的变量叫常量,常量必须初始化,初始化之后值就不能被修改。

基础的数据类型

基础类型有 8 种:bytebooleancharshortintfloatlongdouble

String 不属于基础类型, String 属于对象

Files的常用方法都有哪些?

1
2
3
4
5
6
7
8
9
Files.exists():检测文件路径是否存在。
Files.createFile():创建文件。
Files.createDirectory():创建文件夹。
Files.delete():删除一个文件或目录。
Files.copy():复制文件。
Files.move():移动文件。
Files.size():查看文件个数。
Files.read():读取文件。
Files.write():写入文件。

字符串String

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

操作字符串的类有:StringStringBufferStringBuilder

String 和 StringBuffer、StringBuilder 的区别在于 String 声明的是不可变的对象,每次操作都会生成新的 String 对象,然后将指针指向新的 String 对象,而 StringBufferStringBuilder 可以在原有对象的基础上进行操作,所以在经常改变字符串内容的情况下最好不要使用 String。

StringBuffer 和 StringBuilder 最大的区别在于,**StringBuffer 线程安全,而 StringBuilder 非线程安全**,但 StringBuilder 性能高于 StringBuffer,所以在单线程环境下推荐使用 StringBuilder,多线程环境下推荐使用 StringBuffer

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

不一样,因为内存的分配方式不一样。

String str = ”i” 的方式,Java 虚拟机会将其分配到常量池中;

String str = new String(“i”) 则会被分到堆内存中。

如何将字符串反转?

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

1
2
3
4
5
6
7
// stringBuffer reverse
StringBuffer stringBuffer = new stringBuffer();
stringBuffer. append("abcdefg");
System. out. println(stringBuffer. reverse()); // gfedcba
// stringBuilder reverse
stringBuilder stringBuilder =new stringBuilder();
stringBuilder. append("abcdefg");System. out. println(stringBuilder. reverse()); // gfedcba

String 类的常用方法

1
2
3
4
5
6
7
8
9
10
11
indexOf():返回指定字符的索引。
charAt():返回指定索引处的字符。
replace():字符串替换。
trim():去除字符串两端空白。
split():分割字符串,返回一个分割后的字符串数组。
getBytes():返回字符串的 byte 类型数组。
length():返回字符串长度。
toLowerCase():将字符串转成小写字母。
toUpperCase():将字符串转成大写字符。
substring():截取字符串。
equals():字符串比较。

抽象类问题

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

不需要,抽象类不一定非要有抽象方法。

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

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

抽象类能使用 final 修饰吗?

不能,定义抽象类就是让其他类继承的,定义为 final的类不能被继承,所以 final 不能修饰抽象类,编辑器也会提示错误信息:illegal combination of modifiers: 'abstract' and 'final

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

  • 实现:抽象类的子类使用 extends 来继承;接口必须使用 implements 来实现接口。
  • 构造函数:抽象类可以有构造函数;接口不能有。
  • 实现数量:类可以实现很多个接口;但是只能继承一个抽象类。
  • 访问修饰符:接口中的方法默认使用 public 修饰;抽象类中的方法可以是任意访问修饰符。

Java中的IO

Java 中 IO 流分为几种?

  • 按功能来分:输入流(input)、输出流(output)。
  • 按类型来分:字节流和字符流。字节流和字符流的区别是:字节流按 8 位传输以字节为单位输入输出数据,字符流按 16 位传输以字符为单位输入输出数据。

BIO、NIO、AIO 有什么区别?

  • BIO:Block IO,同步阻塞式 IO,就是我们平常使用的传统 IO,它的特点是模式简单使用方便,并发处理能力低。
  • NIO:Non IO,同步非阻塞 IO,是传统 IO 的升级,客户端和服务器端通过 Channel(通道)通讯,实现了多路复用。
  • AIO:Asynchronous IO,是 NIO 的升级,也叫 NIO2实现了异步非堵塞 IO ,异步 IO 的操作基于事件和回调机制。

Lambda表达式

Lambda表达式的语法

基本语法: (parameters) -> expression (parameters) ->{ statements; }

Lambda表达式由三部分组成:

  • paramaters:类似方法中的形参列表,这里的参数是函数式接口里的参数。这里的参数类型可以明确的声明也可不声明而由JVM隐含的推断。另外当只有一个推断类型时可以省略掉圆括号。
  • ->:可理解为“被用于”的意思
  • 方法体:可以是表达式也可以代码块,是函数式接口里方法的实现。代码块可返回一个值或者什么都不反回,这里的代码块块等同于方法的方法体。如果是表达式,也可以返回一个值或者什么都不反回。

优缺点:

  • 优点:代码简洁,开发迅速、方便函数式编程、容易进行并行计算、Java 引入 Lambda,改善了集合操作
  • 缺点:代码可读性变差、在非并行计算中,很多计算未必有传统的 for 性能要高、不易调试

应用举例

1
2
3
4
5
list.stream().filter(s -> s.length() > 3).forEach(System.out::println);
list.stream().map(StuffEntity::getCode).collect(Collectors.toList());
list.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(
() -> new TreeSet<>(Comparator.comparing(obj -> obj.getDealerPlan() ))), ArrayList::new));
Map<String, List<VpEntity>> map = stuffVp.stream().collect(Collectors.groupingBy(obj -> obj.getDealerPlan() ));

容器

Java 容器都有哪些?

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Collection
List
ArrayList
LinkedList
Vector
Stack
Set
HashSet
LinkedHashSet
TreeSet
Map
HashMap
LinkedHashMap
TreeMap
ConcurrentHashMap
Hashtable

Collection 和 Collections 有什么区别

Collection 是一个集合接口,它提供了对集合对象进行基本操作的通用接口方法,所有集合都是它的子类,比如 List、Set 等。Collections 是一个包装类,包含了很多静态方法,不能被实例化,就像一个工具类,比如提供的排序方法:Collections. sort(list)

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

List、Set、Map 的区别主要体现在两个方面:元素是否有序、是否允许元素重复。三者之间的区别,如下表:

20250618204117

List、Set 和 Map 的初始容量和加载因子

初始容量 加载因子 扩容增量
ArrayList 10 0.5 原容量的1.5倍
Vector 10 1 原容量的2倍
HashSet 16 0.75 原容量的2倍
HashMap 16 0.75 原容量的2倍
  • 初始容量‌:这是集合在创建时分配的存储空间大小。初始容量越大,集合在创建时分配的内存空间就越大,但这并不意味着它不会进行扩容。初始容量只是集合在创建时的一个预设值。
  • 加载因子‌:这是触发集合扩容的比例。当集合中的元素数量超过当前容量的加载因子时,集合会自动进行扩容操作。加载因子越小,集合的内存利用率越高,但可能会导致更多的内存开销;加载因子越大,内存利用率低,但可以减少扩容次数。

HashMap

HashMap 和 Hashtable 有什么区别?

  • 存储:HashMap 允许 key 和 value 为 null,而 Hashtable 不允许。
  • 线程安全:Hashtable 是线程安全的,而 HashMap 是非线程安全的。
  • 推荐使用:Hashtable 的类注释可以看到,Hashtable 是保留类不建议使用,推荐在单线程环境下使用 HashMap 替代,如果需要多线程使用则用 ConcurrentHashMap 替代。

HashMap 的实现原理?

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

HashMap为什么线程不安全?

主要原因在于其内部结构的非原子性操作和缺乏同步机制,导致多线程并发操作时可能引发数据不一致、死循环、数据覆盖等问题‌。

如何决定使用 HashMap 还是 TreeMap?

对于在 Map 中插入、删除、定位一个元素这类操作,HashMap 是最好的选择,因为相对而言 HashMap 的插入会更快,但是如果你要对一个 key 集合进行有序的遍历,那 TreeMap 是更好的选择。

HashSet 的实现原理?

HashSet 是基于 HashMap 实现的,HashSet 不允许重复的值。
HashSet 保证元素不重复是利用 HashMap 的 put 方法实现的,在存储之前先根据 key 的 hashCode 和 equals 判断是否已存在,如果存在就不在重复插入了,这样就保证了元素的不重复。

HashMap 和 ConcurrentHashMap 有什么区别?

ConcurrentHashMap的线程安全实现

  • Java7:分段锁(Segment)。将数据分成多个段,每段独立加锁,不同段的操作可并发。
  • Java 8+:CAS(无锁算法)+ synchronized(锁单个桶的头节点)。锁粒度更细,并发度更高。插入时,如果桶为空,用 CAS 添加;否则锁住头节点再操作。CAS(Compare And Swap(比较与交换))。读操作通常无锁(依赖 volatile 保证可见性)。

20250618205242

List

ArrayList 和 LinkedList 的区别是什么?

  • 数据结构实现:ArrayList 是动态数组的数据结构实现,而 LinkedList 是双向链表的数据结构实现。
  • 随机访问效率:ArrayListLinkedList 在随机访问的时候效率要高,因为 LinkedList 是线性的数据存储方式,所以需要移动指针从前往后依次查找。
  • 增加和删除效率:在非首尾的增加和删除操作,LinkedList 要比 ArrayList 效率要高,因为 ArrayList 增删操作要影响数组内的其他数据的下标。

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

  • 数组转 List:使用 Arrays. asList(array) 进行转换。
  • List 转数组:使用 List 自带的 toArray() 方法。

ArrayList 和 Vector 的区别是什么?

  • 线程安全:Vector 使用了 Synchronized 来实现线程同步,是线程安全的,而 ArrayList 是非线程安全的。
  • **性能:**ArrayList 在性能方面要优于 Vector
  • 扩容:ArrayList 和 Vector 都会根据实际需要动态调整容量,它们的初始容量都是10,不过 Vector 扩容每次会增加 1 倍,而 ArrayList 增加 50%

Array 和 ArrayList 有何区别?

Array 可以存储基本数据类型和对象,ArrayList 只能存储对象。
Array 是指定固定大小的,而 ArrayList 大小是自动扩展的。
Array 内置方法没有 ArrayList 多,比如 addAll、removeAll、iteration 等方法只有 ArrayList 有。

迭代器Iterator

迭代器 Iterator 是什么?

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

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

Iterator 使用代码如下所示:

1
2
3
4
5
6
List<string> list = new ArrayList<>();
Iterator<string>it = list.iterator();
while(it.hasNext()*){
String obj = it.next();
System.out.println(obj);
}

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

Iterator 和 ListIterator 有什么区别?

Iterator 可以遍历 Set 和 List 集合,而 ListIterator 只能遍历 List。
Iterator 只能单向遍历,而 ListIterator 可以双向遍历(向前/后遍历)。
ListIterator 从 Iterator 接口继承,添加了一些额外功能,如添加一个元素、替换一个元素、获取前面或后面元素的索引位置。


其他相关问题

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

相同点:都是返回第一个元素,并在队列中删除返回的对象。
不同点:如果没有元素 poll() 会返回 null,而 remove()会直接抛出 NoSuchElementException 异常。

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

Vector、Hashtable、Stack 都是线程安全的,而像 HashMap 则是非线程安全的,JDK 1.5 之后随着 Java. util. concurrent 并发包的出现,它们也有了自己对应的线程安全类,比如 HashMap 对应的线程安全类就是 ConcurrentHashMap

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

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

1
2
3
List<string> list = new ArrayList<>();list. add("x”);
Collection<string>clist = collections.unmodifiablecollection(list),clist. add("y”);// 运行时此行报错
System. out. println(list. size());