You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何修改Student类使new Student()生成的s1==s2返回true?

解决方案:让两次new Student()返回同一引用

在Java中,==对于对象引用的比较逻辑非常明确:判断两个引用是否指向内存中的同一个对象实例。所以要让s1 == s2返回true,核心目标就是让两次new Student()操作得到的引用指向同一个内存地址。

面试官提到不能用传统单例(比如私有构造+静态实例),但我们可以通过类级别的修改实现这个效果,以下是两种可行思路:


1. 利用枚举类(特殊的单例实现)

虽然枚举本质上属于单例范畴,但它是Java语言原生支持的合法实现,可能面试官对“单例”的定义不包含这种语言层面的特殊实现:

public enum Student {
    INSTANCE;
    
    // 可以添加Student类需要的字段和方法
    private String name;
    
    public void setName(String name) {
        this.name = name;
    }
    
    public String getName() {
        return name;
    }
}

说明:

枚举类的构造方法是隐式私有,客户端无法用new Student()创建实例,需要改为s1 = Student.INSTANCE; s2 = Student.INSTANCE;。如果必须严格保留new Student()的调用方式,这个方案不适用。


2. 利用Unsafe类实现对象引用复用(黑科技)

如果必须保留new Student()的调用方式,我们可以借助sun.misc.Unsafe类(JDK内部非标准API)来修改对象的引用指向,让每次new操作最终都指向同一个实例:

import sun.misc.Unsafe;
import java.lang.reflect.Field;

public class Student {
    // 存储唯一的Student实例
    private static Student singleton;
    // Unsafe实例和静态字段的内存偏移量
    private static final Unsafe unsafe;
    private static final long singletonOffset;

    static {
        try {
            // 通过反射获取Unsafe实例
            Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
            unsafeField.setAccessible(true);
            unsafe = (Unsafe) unsafeField.get(null);
            // 获取singleton字段的内存偏移量
            singletonOffset = unsafe.objectFieldOffset(Student.class.getDeclaredField("singleton"));
        } catch (NoSuchFieldException | IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

    public Student() {
        synchronized (Student.class) {
            if (singleton == null) {
                // 第一次创建时,将当前对象赋值给singleton
                singleton = this;
            } else {
                // 后续创建时,利用Unsafe将当前对象的引用替换为singleton
                unsafe.putObject(this, singletonOffset, singleton);
            }
        }
    }
}

注意事项:

  • 这个方案依赖sun.misc.Unsafe,属于JDK内部API,在不同JVM版本可能存在兼容性问题,生产环境不建议使用。
  • 同步块是为了保证线程安全,避免多线程并发创建时出现多个实例。

为什么其他思路不可行?

  • 重写equals/hashCode:这只会改变equals()方法的比较结果,完全不影响==的引用比较逻辑。
  • 对象池/缓存:new关键字会强制分配新内存空间,构造方法无法阻止这一行为,只能修改对象状态,但引用仍然是不同的。
  • 普通单例:私有构造方法会导致new Student()编译报错,不符合客户端代码的调用要求。

内容的提问来源于stack exchange,提问作者Deepu--Java

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:56:21