Java基础面试题

Java基础

1、== 和 equals() 的区别

== 对于基本类型和引用类型的作用效果是不同的: 对于基本数据类型来说,== 比较的是值。 对于引用数据类型来说,== 比较的是对象的内存地址。

equals() 不能用于判断基本数据类型的变量,只能用来判断两个对象是否相等。equals()方法存在于Object类中,而Object类是所有类的直接或间接父类,因此所有的类都有equals()方法。

ini 复制代码
String a = new String("ab"); // a 为一个引用
String b = new String("ab"); // b为另一个引用,对象的内容一样
String aa = "ab"; // 放在常量池中
String bb = "ab"; // 从常量池中查找
System.out.println(aa == bb);// true
System.out.println(a == b);// false
System.out.println(a.equals(b));// true
System.out.println(42 == 42.0);// true

String 中的 equals 方法是被重写过的,因为 Objectequals 方法是比较的对象的内存地址,而 Stringequals 方法比较的是对象的值。

当创建 String 类型的对象时,虚拟机会在常量池中查找有没有已经存在的值和要创建的值相同的对象,如果有就把它赋给当前引用。如果没有就在常量池中重新创建一个 String 对象。

2、String s1 = new String("abc");这句话创建了几个字符串对象?

会创建 1 或 2 个字符串对象。

1.字符串常量池中不存在 "abc":会创建 2 个 字符串对象。一个在字符串常量池中,由 ldc 指令触发创建。一个在堆中,由 new String() 创建,并使用常量池中的 "abc" 进行初始化。

2.字符串常量池中已存在 "abc":会创建 1 个 字符串对象。该对象在堆中,由 new String() 创建,并使用常量池中的 "abc" 进行初始化。

字符串常量池的作用:是 JVM 为了提升性能和减少内存消耗针对字符串(String 类)专门开辟的一块区域,主要目的是为了避免字符串的重复创建。

3、抽象类和接口的区别

抽象类:包含抽象方法的类,可以包含成员变量和方法,包含静态方法,静态变量以及常量,构造器。

接口:抽象类更高层次的抽象,是一种标准,一种规范,只允许有静态常量,抽象方法,java8引入default方法和静态方法,java9引入private方法。

java 复制代码
/**
 * 消息处理抽象类
 *
 * @param <T>
 */
public interface BerryMqService<T> {

    /**
     * 保存消息
     */
    public abstract void save(String message);

    /**
     * 数据转换
     */
    default MqData<T> transformation(String message, Class<?> dataClass) {
        Type tp = TypeToken.getParameterized(MqData.class, dataClass).getType();
        return GsonUtil.gson().fromJson(message, tp);
    }
}

如何选择:如果有状态,有成员变量的情况下选择抽象类,或者需要控制构造器入参时。其他情况选用接口。

4、引用拷贝,浅拷贝,深拷贝的区别
  • 引用拷贝:两个变量指向同一个对象。
  • 浅拷贝:新对象独立,但子对象共享。
  • 深拷贝:新对象完全独立,包括所有子对象。
5、为什么重写 equals() 时必须重写 hashCode() 方法?

因为两个相等的对象的 hashCode 值必须是相等。也就是说如果 equals 方法判断两个对象是相等的,那这两个对象的 hashCode 值也要相等。

如果重写 equals() 时没有重写 hashCode() 方法的话就可能会导致 equals 方法判断是相等的两个对象,hashCode 值却不相等。

6、重写 equals() 时没有重写 hashCode() 方法的话,使用 HashMap 可能会出现什么问题?

HashMap不能正常工作

HashMap 依赖于 hashCode()equals() 方法来存储和检索键值对:

  • 存储时HashMap 使用 hashCode() 确定键的存储位置(桶)。
  • 检索时HashMap 先通过 hashCode() 找到桶,再用 equals() 比较键是否相等。 如果没有重写 hashCode(),即使两个对象通过 equals() 判断相等,它们的 hashCode() 可能不同,导致:
  • 存储问题:相同的键可能被存储到不同的桶中。
  • 检索问题:无法通过键正确检索到对应的值。
arduino 复制代码
class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (obj == null || getClass() != obj.getClass()) return false;
        Person person = (Person) obj;
        return age == person.age && name.equals(person.name);
    }

    // 没有重写 hashCode()
}

public class Main {
    public static void main(String[] args) {
        Person p1 = new Person("Alice", 25);
        Person p2 = new Person("Alice", 25);

        System.out.println(p1.equals(p2)); // true

        HashMap<Person, String> map = new HashMap<>();
        map.put(p1, "Alice's Data");

        System.out.println(map.get(p2)); // 输出: null
    }
}
7、finally一定会执行么,在finally里return会发什么?

1.finally不一定会执行,比如finally之前虚拟机终止的话finally就不会被执行

csharp 复制代码
try {
    System.out.println("Try to do something");
    throw new RuntimeException("RuntimeException");
} catch (Exception e) {
    System.out.println("Catch Exception -> " + e.getMessage());
    // 终止当前正在运行的Java虚拟机
    System.exit(1);
} finally {
    System.out.println("Finally");
}

输出:

vbnet 复制代码
Try to do something
Catch Exception -> RuntimeException

另外,在以下 2 种特殊情况下,finally 块的代码也不会被执行:程序所在的线程死亡。或者关闭 CPU。

2.不要在 finally 语句块中使用 return! 当 try 语句和 finally 语句中都有 return 语句时,try 语句块中的 return 语句会被忽略。这是因为 try 语句中的 return 返回值会先被暂存在一个本地变量中,当执行到 finally 语句中的 return 之后,这个本地变量的值就变为了 finally 语句中的 return 返回值。

csharp 复制代码
public static void main(String[] args) {
    System.out.println(f(2));
}

public static int f(int value) {
    try {
        return value * value;
    } finally {
        if (value == 2) {
            return 0;
        }
    }
}
//输出
0

集合

1.HashMap

HashMap和HashSet的区别
  1. 作用上就不一样,HashSet存储的是无需的元素。HashMap存放的是键值对。
  2. HashSet是基于HashMap实现的,HashSet的元素就是HashMap中的Key
HashMap和TreeMap的区别
  1. 首先TreeMap有序``HashMap无序的,二者同样继承了AbstractMap类但TreeMap同样实现了NavigableMap接口,这个接口提供了很多搜索和操作键值对的方法,基于`红黑树实现。
HashMap的底层实现
  1. JDK1.8之前:数组+链表的方式组合,当一个元素putHashMap通过Key的 hashcode经过扰动函数处理过后得到hash值,然后通过二进制运算 数组长度-1 & hash得到数组位置,如果该位置没有元素,直接插入,如果有元素,判断该元素与存入元素得hash(调用hashCode())值和key相不相同(调用equals()),相同则替换,不相同则使用头插法将元素加入链表中(头插法目的:开发者认为后插入得元素使用概率会更大)。

  2. JDK1.8 之后在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为 8)时,判断数组长度是否小于64如果小于优先扩容,否则将链表转化为红黑树,以减少搜索时间。

为什么hashMap总以2的幂作为hash表的大小
  1. 优化哈希函数 :均匀分布键值对,减少哈希冲突,如果不取2的幂作为表大小,有些索引将永远不会得到利用,因为索引位置的计算公式是hash(key) & (length - 1) 这个(length - 1)在计算中起到掩码的作用,如果出现0将会导致0这位永远的得不到运算,位置只取决于非0位掩码的值。
  2. 提高计算效率:用与运算替代取模运算,提升性能,效率更高,只需要取hash值的低几位就可以了。
  3. 扩容优化:扩容时重新哈希的计算更加高效,因为扩容后的位置总是原来的位置,或者是原来的位置+原来表的大小。
相关推荐
互联网全栈架构40 分钟前
遨游Spring AI:第一盘菜Hello World
java·人工智能·后端·spring
优秀的颜2 小时前
计算机基础知识(第五篇)
java·开发语言·分布式
BillKu2 小时前
Java严格模式withResolverStyle解析日期错误及解决方案
java
网安INF2 小时前
ElGamal加密算法:离散对数难题的安全基石
java·网络安全·密码学
AWS官方合作商3 小时前
在CSDN发布AWS Proton解决方案:实现云原生应用的标准化部署
java·云原生·aws
gadiaola4 小时前
【JVM】Java虚拟机(二)——垃圾回收
java·jvm
coderSong25686 小时前
Java高级 |【实验八】springboot 使用Websocket
java·spring boot·后端·websocket
Mr_Air_Boy7 小时前
SpringBoot使用dynamic配置多数据源时使用@Transactional事务在非primary的数据源上遇到的问题
java·spring boot·后端
豆沙沙包?8 小时前
2025年- H77-Lc185--45.跳跃游戏II(贪心)--Java版
java·开发语言·游戏
年老体衰按不动键盘8 小时前
快速部署和启动Vue3项目
java·javascript·vue