如何修改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
相关产品推荐
相关产品推荐

