能否确保JVM中不存在两个相同的对象?类比RDBMS主键机制
如何让Java确保JVM堆中不存在重复的Book对象?
先看数据库模型:
Book isbn primary key title
在RDBMS中,数据库会通过主键isbn的唯一约束,确保不会存在两条相同的记录。
对应的Java对象模型如下:
Book - isbn: int - title: String + Book(isbn)
当我们执行以下代码时:
Book b = new Book(123456); Book c = new Book(123456);
JVM堆中会生成两个独立的Book实例,即便它们的isbn完全相同。那能不能像RDBMS那样,让Java保证堆中不会存在重复的对象?
可行方案
1. 带缓存的工厂模式(推荐,彻底控制实例唯一性)
通过工厂类封装对象创建逻辑,用缓存容器存储已创建的实例,确保相同isbn的对象只被实例化一次:
import java.util.HashMap; import java.util.Map; public class BookFactory { private static final Map<Integer, Book> bookCache = new HashMap<>(); public static Book getBook(int isbn) { Book existingBook = bookCache.get(isbn); if (existingBook != null) { return existingBook; } Book newBook = new Book(isbn); bookCache.put(isbn, newBook); return newBook; } // 将Book设为内部类,构造方法私有,禁止外部直接实例化 private static class Book { private int isbn; private String title; private Book(int isbn) { this.isbn = isbn; } // 必要的getter/setter public int getIsbn() { return isbn; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } } }
使用方式:
Book b = BookFactory.getBook(123456); Book c = BookFactory.getBook(123456); // b和c指向同一个对象,b == c结果为true
2. 重写equals()+hashCode()(逻辑去重)
如果无法限制外部直接new对象,可以通过重写Book的equals()和hashCode()方法,让isbn相同的对象被视为逻辑相等,再配合HashSet等集合实现去重:
public class Book { private int isbn; private String title; public Book(int isbn) { this.isbn = isbn; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Book book = (Book) o; return isbn == book.isbn; } @Override public int hashCode() { return Integer.hashCode(isbn); } // getter/setter }
使用方式:
Set<Book> bookSet = new HashSet<>(); bookSet.add(new Book(123456)); bookSet.add(new Book(123456)); // bookSet的size为1,仅保留一个逻辑相同的对象
注意:这种方式只是逻辑层面的去重,如果外部直接创建两个isbn相同的实例,堆中依然会存在两个对象,只是集合会过滤掉重复项。如果要彻底确保堆中只有一个实例,优先选择工厂模式。
内容的提问来源于stack exchange,提问作者Faisal
相关产品推荐
相关产品推荐

