1.Java中‘==’和‘equals()’的区别是什么?

‘==’是在代码中用来比较两个变量的值的,如果比较的是基本数据类型变量(比如整数,浮点数,布尔值,字符),那么它比较的就是储存的具体数值;如果比较的是引用类型数据变量(比如对象,数组),那么它比较的就是储存对象在内存中的地址。

‘equals()’是Object类里的一个实列方法,因为所有的类都直接或间接继承自Object,所以所有对象都有equals()方法,使用这个方法时所有的对象类都要重写equals(),然后根据自己的属性需要来写这个比较方法,如果想通过name就能比较成功就只写上并判断name,如果想要比较对象所有属性都一样就把属性全部加上并判断。

具体实例:在比较字符串的时候,‘==’比较的是字符串的地址,而‘equals()’是将字符串里的每个字符都拿出来逐个比较。

2.‘hashCode()’的作用是什么?

Object类的一个方法,所有的类都有继承,通常在使用时也需要重写。用于帮助对象计算哈希值,为对象生成一个“快速定位码”,让基于散列的集合(如HashMap)能够高效查找,它必须与equals()保持一致:相等的对象必须有相等的哈希码。

注:在哈希算法中,如果两个对象的哈希值不一样,那么这两个对象是一定不一样的,只有哈希值一样才需要继续比较。因此一般情况下会先用hashCode()直接判断这两个对象的哈希值是否相同,如果不同就没必要再进行比较,如果相同再使用equals()方法进行比较。

3.以下代码的输出是什么并解释原因。(字符串常量池   JVM   

堆内存)

String s1 = "hello";
String s2 = "hello";
String s3 = new String("hello"); // false
System.out.println(s1 == s2);  // true or false? // true
System.out.println(s1 == s3);  // true or false?

String n1 = "hello";
String n2 = "World";
String n3 = new String(n1+n2);// +

System.out.println(s1 == s2);这一行输出的是true;System.out.println(s1 == s3);这一行输出的是false。

在JVM内存中,有一块专门存放字符串的区域“字符串常量池”,每一个字符串在创建之后就是一个常量,像String s1 = "hello"和String s2 = "hello"中由于“hello”在字符串常量池中只有一个对象,所以s1和s2拿到的是同一个对象的地址。而String s3 = new String("hello")中由于new String()始终创建新对象,所以它会在常量池之外的堆内存中创建对象,s3拿到的对象的地址就和s1、s2不一样,最后输出的结果才会是true和false。

如果没有“String s1 = "hello"”;和“String s2 = "hello";”这两行代码,只有“String s3 = new String("hello");”这一行,在内存中会创建两个对象,一个在字符串常量池中,一个在堆内存中。

注:

String n1 = "hello";
String n2 = "World";
String n3 = new String(n1+n2);

这三行代码中,因为拼接操作‘+’的原理是调用StringBuilder类中的append方法,而最后还会调用一下toString方法,把StringBuilder对象转换成一个字符串对象,所以会多创建一个新的对象,最终这三行代码总共会创建4个对象。(函数调用部分过程如下图)

拓展:hash表经常用字符串作为“key”,不仅是因为字符串信息丰富便于表达,而且字符串就存储在字符串常量池里面,具有不可变性,重复使用字符串也不会导致重复占用内存空间,所以才经常选择字符串作为键类型。

4. 解释 Java 中的四种引用类型:强引用、软引用、弱引用和虚引用。     (JVM      GC垃圾回收器)

如何理解“引用”:在内存中对象在堆里面,而代码在栈里面,需要在栈里面存储对象所在的堆内存地址才能够访问到对象数据,而“引用”是一个指向内存地址的值,它让你能够间接访问和操作内存中的数据,就好比遥控器(引用)和电视机(对象)。

GC垃圾回收器:它会判断你的程序中哪些数据是没有用的,然后清除没用的数据内存,保留有用的数据,对于以上四种引用,每一种都有对应的垃圾回收器的处理方案。

1. 强引用(Strong Reference)

最常见的引用类型,通过 new 创建的对象默认都是强引用。

特点:只要强引用存在,对象就不会被 GC 回收。

当内存不足时,JVM 会抛出 OutOfMemoryError 而不是回收强引用对象。

java

Object obj = new Object();  // 强引用
obj = null;  // 切断强引用,对象变为可回收状态

2. 软引用(Soft Reference)

通过 java.lang.ref.SoftReference 类实现。

特点:

内存充足时软引用对象不会被回收,内存不足时,软引用对象会被 GC 回收。

适合用于实现内存敏感的缓存。

java

SoftReference<byte[]> softRef = new SoftReference<>(new byte[1024 * 1024]);
byte[] data = softRef.get();  // 获取对象,可能为 null(如果已被回收)

// 通常与 ReferenceQueue 配合使用
ReferenceQueue<byte[]> queue = new ReferenceQueue<>();
SoftReference<byte[]> ref = new SoftReference<>(new byte[1024], queue);

3. 弱引用(Weak Reference)

通过 java.lang.ref.WeakReference 类实现。

特点:

只要发生 GC无论内存是否充足,弱引用对象都会被回收。

适合用于实现弱缓存或监控对象生命周期;WeakHashMap 基于此实现。

java

WeakReference<Object> weakRef = new WeakReference<>(new Object());
Object obj = weakRef.get();  // 可能为 null(如果已被回收)

// WeakHashMap 示例
WeakHashMap<Object, String> map = new WeakHashMap<>();
Object key = new Object();
map.put(key, "value");
key = null;  // 下次 GC 时,该 entry 会被自动移除

4. 虚引用(Phantom Reference)

通过 java.lang.ref.PhantomReference 类实现。

特点:

最弱的引用完全不会影响对象的生命周期。

无法通过 get() 方法获取对象(总是返回 null);必须与 ReferenceQueue 一起使用;主要用于对象被回收时收到系统通知,进行一些清理工作。

java

ReferenceQueue<Object> queue = new ReferenceQueue<>();
PhantomReference<Object> phantomRef = new PhantomReference<>(new Object(), queue);

// 监控回收通知
new Thread(() -> {
    while (true) {
        Reference<?> ref = queue.poll();
        if (ref != null) {
            System.out.println("对象已被回收,进行清理操作");
            break;
        }
    }
}).start();

对比总结

引用类型 回收时机 是否影响生命周期 常见用途
强引用 永不主动回收 普通对象引用
软引用 内存不足时回收 否(间接影响) 内存敏感缓存
弱引用 GC时立即回收 缓存、WeakHashMap
虚引用 GC时立即回收 对象回收监听、清理工作

5.final 、 finally  和  finalize  有什么区别?

1. final(关键字)

用于修饰类、方法和变量,表示"不可改变"。

final 类:不能被继承

java

final class FinalClass {
    // 不能被其他类继承
}
// class SubClass extends FinalClass {}  // 编译错误

 final 方法:不能被子类重写

 java

class Parent {
    final void show() {
        System.out.println("不能被子类重写");
    }
}
class Child extends Parent {
    // void show() {}  // 编译错误,不能重写final方法
}

 final 变量:一旦赋值就不能修改

java

final int MAX_VALUE = 100;
// MAX_VALUE = 200;  // 编译错误

final List<String> list = new ArrayList<>();
list.add("item");  // 可以,引用本身不变,内容可变
// list = new ArrayList<>();  // 编译错误,不能改变引用

2. finally(代码块)

异常处理的一部分,用于定义必须执行的代码块。

特点:无论是否发生异常,finally 块都会执行通常用于释放资源(如关闭文件、数据库连接等)

唯一不执行的情况:System.exit() 或 JVM 崩溃

java

try {
    // 可能抛出异常的代码
    int result = 10 / 0;
} catch (ArithmeticException e) {
    System.out.println("捕获异常");
    // return;  // 即使有return,finally仍会执行
} finally {
    System.out.println("总会执行 - 清理资源");
    // 关闭文件、数据库连接等
}
// 输出:捕获异常 → 总会执行 - 清理资源

特殊场景:

java

public int testFinally() {
    try {
        return 1;  // 先执行return表达式
    } finally {
        System.out.println("finally执行");
        // return 2;  // 如果finally中有return,会覆盖try中的return
    }
    // 返回1,但"finally执行"会先打印
}

3. finalize(方法)

Object 类的一个方法,用于垃圾回收前的清理。

特点:

在对象被垃圾回收器回收之前调用,不保证一定会执行(如果程序提前终止),执行时间不确定(由GC决定)

注:Java 9 开始已被弃用

java

class ResourceHolder {
    private String resource;
    
    public ResourceHolder(String resource) {
        this.resource = resource;
    }
    
    @Override
    protected void finalize() throws Throwable {
        try {
            System.out.println("清理资源: " + resource);
            // 清理操作
        } finally {
            super.finalize();  // 调用父类的finalize
        }
    }
}

// 使用
ResourceHolder obj = new ResourceHolder("DB Connection");
obj = null;  // 对象变为可回收
System.gc();  // 建议GC,但不保证立即执行finalize

对比表格

特性 final finally finalize
类型 关键字 代码块关键字 方法
作用域 类、方法、变量 try-catch 块 Object 类的方法
用途 定义不可变性 确保代码执行 对象回收前清理
执行时机 编译时/运行时定义 异常处理后 GC 回收对象前
是否强制 是(一旦定义) 是(总会执行) 否(不保证执行)
当前状态 常用 常用 已弃用(Java 9+)

6. Java 异常体系是怎样的? RuntimeException  和  Checked Exception  有何区别?

Java异常体系以Throwable为根类,分为两大分支:Error表示不可处理的严重错误,Exception表示可以处理的异常。Exception又进一步分为受检异常和非受检异常。

 RuntimeException表示程序员应修复的bug,通过代码质量避免

 CheckedException表示程序应处理的合理异常情况,通过编码应对

特性 RuntimeException CheckedException
编译检查 不检查 强制检查
处理要求 可处理可不处理 必须处理
设计理念 代码逻辑错误 外部环境问题
常见场景 空指针、数组越界 文件不存在、网络中断

如果要打比方的话:

 Error:房子塌了(系统级灾难,无法修复)

 RuntimeException:你被自己绊倒(代码写错了,可以避免)

 CheckedException:出门下雨了(外部环境问题,需带伞应对)

java

// RuntimeException - 不需要强制处理
String str = null;
str.length(); // 运行时才报NullPointerException

// Checked Exception - 必须处理
try {
    new FileReader("file.txt"); // 编译时强制检查
} catch (FileNotFoundException e) {
    // 必须处理
}

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐