Java面试题-35题

1.Java 的 8 大基本数据类型及其对应的包装类(引用类型)如下
  • 基本类型 byte → 包装类 Byte
  • 基本类型 short → 包装类 Short
  • 基本类型 int → 包装类 Integer
  • 基本类型 long → 包装类 Long
  • 基本类型 float → 包装类 Float
  • 基本类型 double → 包装类 Double(注意拼写是 Double,不是 Doubel)
  • 基本类型 boolean → 包装类 Boolean
  • 基本类型 char → 包装类 Character(对应的包装类不是 Char,而是 Character)

String 是引用类型,但它并不是任何基本数据类型的包装类,它是 Java 中专门用于表示字符串的类。

2.JDK 和 JRE 有什么区别?


JDK:Java Development Kit 的简称,Java 开发工具包,提供了 Java 的开发环境和运行环境。
JRE:Java Runtime Environment 的简称,Java 运行环境,为 Java 的运行提供了所需环境。
具体来说 JDK 其实包含了 JRE,同时还包含了编译 Java 源码的编译器 Javac,还包含了很多 Java 程序调试和分析的工具。

简单来说:

如果你需要运行 Java 程序,只需安装 JRE 就可以了。

如果你需要编写 Java 程序,需要安装 JDK。

3.== 和equals的区别

==:

        对于基本数据类型,==比较的是值。

        对于引用数据类型,==比较的是引用。

举例:

String x = "string";
String y = "string";
String z = new String("string");
System.out.println(x==y); // true
System.out.println(x==z); // false

因为 x 和 y 指向的是同一个引用,所以 == 也是 true,而 new String()方法则重写开辟了内存空间,所以 == 结果为 false

equals:

String x = "string";
String y = "string";
String z = new String("string");
System.out.println(x.equals(y)); // true
System.out.println(x.equals(z)); // true

由于string重写了equals的方法,导致此处equals比较的是值。x ,y,z的值全部一样,所以结果为true.

public boolean equals(Object anObject){
    if (this == anObject) {
        return true;
    }
    if (anObject instanceof String) {
        String anotherString = (String)anObject;
        int n = value.length;
        if (n == anotherString.value.length) {
            char v1[] = value;
            char v2[] = anotherString.value;
            int i = 0;
            while (n-- != 0) {
                if (v1[i] != v2[i])
                    return false;
                i++;
            }
            return true;
        }
    }
    return false;
}

但对于其他引用类型,如果没有重写equals方法,则使用equals还是对比的是他们的引用,而不是值。

classCat{
    public Cat(String name){
        this.name = name;
    }

    private String name;

    public String getName(){
        return name;
    }

    public void set Name(String name){
        this.name = name;
    }
}

Cat c1 = new Cat("王磊");
Cat c2 = new Cat("王磊");
System.out.println(c1.equals(c2)); // false

来看equal源码:是比较的引用,而不是直接比较值。

public boolean equals(Object obj){
        return (this == obj);
}

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

3.基本数据类型可以使用equals吗?

        不能

  1. equals() 是 Object 类的方法

  equals() 是 Java 中所有引用类型(对象)继承自 Object 类的方法,用于比较两个对象的 “内容” 是否相等。而基本数据类型(如 intdoubleboolean 等)不是对象,它们没有方法,因此无法直接调用 equals()

  1. 基本数据类型的比较方式:基本数据类型的比较需要使用比较运算符 ==,直接比较它们的值:

    java运行

    int a = 5;
    int b = 5;
    System.out.println(a == b); // true(比较值是否相等)
    
  2. 包装类可以使用 equals()如果需要用 equals() 比较基本数据类型的值,可以先将其装箱为对应的包装类(引用类型),再调用 equals()

    java运行

    Integer a = 5; // 自动装箱(int → Integer)
    Integer b = 5;
    System.out.println(a.equals(b)); // true(包装类的 equals() 比较值)
    

    注意:包装类的 equals() 会先判断类型是否一致,再比较值。例如 Integer.equals(Double) 会直接返回 false

  3. 常见误区若试图对基本数据类型调用 equals(),编译器会直接报错:

    java运行

    int a = 5;
    a.equals(5); // 编译错误:int 不是对象,没有 equals() 方法
    

总结:

  • 基本数据类型:用 == 比较值。
  • 引用类型(包括包装类):用 equals() 比较内容(需注意非空判断),用 == 比较地址是否相同。
4.两个对象的 hashCode() 相同,则 equals() 也一定为 true,对吗?

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

代码示例:

String str1 = "通话";
String str2 = "重地";
System. out. println(String. format("str1:%d | str2:%d",  str1. hashCode(),str2. hashCode()));
System. out. println(str1. equals(str2));
执行的结果:

str1:1179395 | str2:1179395

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

原因:

在 Java 中,hashCode() 和 equals() 是两个密切相关的方法,它们的设计遵循以下规范:如果两个对象 equals() 返回 true,则它们的 hashCode() 必须相等;但如果两个对象 hashCode() 相等,equals() 不一定返回 true

这种特性的核心原因与 哈希算法的 “哈希冲突” 有关,具体可从以下角度理解:

1. hashCode() 的作用

hashCode() 用于计算对象的哈希值(一个整数),主要服务于哈希表(如 HashMapHashSet 等)。哈希表通过哈希值快速定位对象的存储位置,从而提高查询效率。

哈希算法的目标是让不同对象尽量生成不同的哈希值,但由于 哈希值是有限的整数(32 位或 64 位),而对象的可能性是无限的,必然会出现 “不同对象计算出相同哈希值” 的情况,这就是 哈希冲突(Hash Collision)。

2. equals() 的作用

equals() 用于判断两个对象的 “内容” 是否真正相等(逻辑相等)。例如,两个 String 对象 "abc" 和 "abc"equals() 返回 true;而 "abc" 和 "abd" 则返回 false

3. 为什么 hashCode() 相同,equals() 可能不同?

因为 哈希冲突是不可避免的。即使两个对象的内容不同(equals() 返回 false),哈希算法也可能计算出相同的哈希值。

举例说明:

java

运行

public class HashDemo {
    private int num;

    public HashDemo(int num) {
        this.num = num;
    }

    // 重写 hashCode(),仅返回 num % 2(哈希值只有 0 或 1)
    @Override
    public int hashCode() {
        return num % 2;
    }

    // 重写 equals(),仅当 num 完全相同时才相等
    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (obj == null || getClass() != obj.getClass()) return false;
        HashDemo other = (HashDemo) obj;
        return num == other.num;
    }

    public static void main(String[] args) {
        HashDemo a = new HashDemo(2);
        HashDemo b = new HashDemo(4);

        System.out.println(a.hashCode()); // 0(2%2=0)
        System.out.println(b.hashCode()); // 0(4%2=0)→ 哈希值相同
        System.out.println(a.equals(b));  // false(2≠4,内容不同)
    }
}

在这个例子中,a 和 b 的 hashCode() 相同(都是 0),但 equals() 返回 false,因为它们的实际内容(num 的值)不同。这正是哈希冲突导致的结果。

4. 设计规范的意义

  • 若 equals() 为 true 则 hashCode() 必须相同:确保哈希表中 “逻辑相等” 的对象能被正确定位到同一个桶中,避免查找错误。
  • 若 hashCode() 相同 equals() 可不同:允许哈希冲突存在(无法避免),此时哈希表会通过 equals() 进一步判断对象是否真正相等,从而处理冲突(如链表或红黑树存储)。

总结:hashCode() 相同仅表示两个对象可能相等(哈希表中会被分到同一桶中),但最终是否相等必须通过 equals() 验证。哈希冲突的必然性决定了 “hashCode() 相同但 equals() 不同” 是合理且常见的情况。

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


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

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


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

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

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

8. Java 中操作字符串都有哪些类?它们之间有什么区别?
操作字符串的类有:String、StringBuffer、StringBuilder。

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

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

9. String str="i"与 String str=new String("i")一样吗?

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

10.如何将字符串反转?


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

// 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
11. String 类的常用方法都有那些?


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

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


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

示例代码:

abstract class Cat{
    public static void sayHi(){
        System. out. println("hi~");
    }
}


上面代码,抽象类并没有抽象方法但完全可以正常运行。

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


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

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


不能,定义抽象类就是让其他类继承的,如果定义为 final 该类就不能被继承,这样彼此就会产生矛盾,所以 final 不能修饰抽象类,如下图所示,编辑器也会提示错误信息:

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


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

16. Java 中 IO 流分为几种?


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

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

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

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


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

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 的区别主要体现在两个方面:元素是否有序、是否允许元素重复。

1. 存储结构(核心区别)

  • List线性表结构,存储单个元素的有序集合(元素可重复),通过索引(下标) 访问元素(类似数组)。例如:[1, 2, 2, 3](允许重复,有下标 0、1、2、3)。

  • Set集合结构,存储2. 核心特性对比个元素的无序集合(元素不可重复),无索引,不能通过下标访问。例如:{1, 2, 3}(不允许重复,元素顺序不固定)。

  • Map键值对结构,存储键(Key)和值(Value)的映射关系(键不可重复,值可重复),通过访问值。例如:{ "name": "Alice", "age": 20 }(键 name 唯一,对应值 Alice)。

2. 核心特性对比

ListSetMap
存储内容单个元素(值)单个元素(值)键值对(Key-Value)
元素唯一性允许重复元素不允许重复元素(依赖 equals() 和 hashCode()键(Key)不可重复,值(Value)可重复
有序性有序(插入顺序与存储顺序一致)无序(默认);部分实现类有序(如 LinkedHashSet无序(默认);部分实现类有序(如 LinkedHashMapTreeMap
索引访问支持(通过下标 get(index)不支持(无索引)不支持(通过键 get(key) 访问值)
主要实现类ArrayListLinkedListVectorHashSetLinkedHashSetTreeSetHashMapLinkedHashMapTreeMapHashtable

3. 典型使用场景

  • List:适合需要按顺序存储、允许重复元素、频繁通过下标访问或修改的场景。例如:存储用户列表(可能有重名)、数组的动态扩容(ArrayList)、频繁插入删除(LinkedList)。

  • Set:适合需要保证元素唯一性、无需按顺序访问的场景。例如:存储不重复的 ID 集合、去重操作(HashSet)、按自然顺序排序的唯一元素(TreeSet)。

  • Map:适合需要通过 “键” 快速查找 “值” 的场景,本质是 “映射关系” 存储。例如:存储配置信息(键为配置项,值为配置值)、缓存数据(键为唯一标识,值为数据)、统计频次(键为元素,值为次数)。

21. HashMap 和 Hashtable 有什么区别?


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

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


对于在 Map 中插入、删除、定位一个元素这类操作,HashMap 是最好的选择,因为相对而言 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 增删操作要影响数组内的其他数据的下标。
综合来说,在需要频繁读取集合中的元素时,更推荐使用 ArrayList,而在插入和删除操作较多时,更推荐使用 LinkedList。

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


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

// list to array
List<String> list = new ArrayList<String>();
list. add("王磊");
list. add("的博客");
list. toArray();
// array to list
String[] array = new String[]{"王磊","的博客"};
Arrays. asList(array);

27. Array 和 ArrayList 有何区别?


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

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


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

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

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

29. 线程和进程的区别?


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

30. OSI 的七层模型都有哪些?


物理层:利用传输介质为数据链路层提供物理连接,实现比特流的透明传输。
数据链路层:负责建立和管理节点间的链路。
网络层:通过路由选择算法,为报文或分组通过通信子网选择最适当的路径。
传输层:向用户提供可靠的端到端的差错和流量控制,保证报文的正确传输。
会话层:向两个实体的表示层提供建立和使用连接的方法。
表示层:处理用户信息的表示问题,如编码、数据格式转换和加密解密等。
应用层:直接向用户提供服务,完成用户希望在网络上完成的各种工作。

OSI 模型是自下而上(从硬件到软件)设计的,先记住 7 层的排列顺序,这是记忆的基础:物理层 → 数据链路层 → 网络层 → 传输层 → 会话层 → 表示层 → 应用层

口诀 “物联网传会表应”

默念 “物(物理层,传信号)→ 联(数据链路层,MAC)→ 网(网络层,IP)→ 传(传输层,TCP/UDP)→ 会(会话层,建连接)→ 表(表示层,转格式)→ 应(应用层,用户用)”

31. get 和 post 请求有哪些区别?


get 请求会被浏览器主动缓存,而 post 不会。
get 传递参数有大小限制,而 post 没有。
post 参数传输更安全,get 的参数会明文限制在 url 上,post 不会。

MySQL
32. 数据库的三范式是什么?


第一范式:强调的是列的原子性,即数据库表的每一列都是不可分割的原子数据项。
第二范式:要求实体的属性完全依赖于主关键字。所谓完全依赖是指不能存在仅依赖主关键字一部分的属性。
第三范式:任何非主属性不依赖于其它非主属性。

33. 说一下 ACID 是什么?


Atomicity(原子性):一个事务(transaction)中的所有操作,或者全部完成,或者全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被恢复(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。即,事务不可分割、不可约简。
Consistency(一致性):在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设约束、触发器、级联回滚等。
Isolation(隔离性):数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable)。
Durability(持久性):事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。

34. MySQL 的内连接、左连接、右连接有什么区别?


内连接关键字:inner join;左连接:left join;右连接:right join。

内连接是把匹配的关联数据显示出来;左连接是左边的表全部显示出来,右边的表显示出符合条件的数据;右连接正好相反。

35. 如何做 MySQL 的性能优化?


为搜索字段创建索引。
避免使用 select *,列出需要查询的字段。
垂直分割分表。
选择正确的存储引擎。
Redis

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值