← Назад к вопросам
Будет ли выдаваться один и тот же экземпляр объекта в памяти, если создать объект два раза с одним идентификатором?
2.0 Middle🔥 151 комментариев
#ORM и Hibernate#Кэширование и NoSQL
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
# Один и тот же экземпляр объекта при одном идентификаторе
Ответ: НЕТ, по умолчанию
Если вы создадите объект два раза с одинаковым идентификатором, это будут ДВА РАЗНЫХ экземпляра в памяти. Каждый вызов new создаёт новый объект.
Базовый пример
public class User {
private int id;
private String name;
public User(int id, String name) {
this.id = id;
this.name = name;
}
}
// Использование
User user1 = new User(1, "Alice"); // Объект #1 в памяти
User user2 = new User(1, "Bob"); // Объект #2 в памяти (ДРУГОЙ!)
System.out.println(user1 == user2); // false (разные объекты)
System.out.println(user1.equals(user2)); // false (разные объекты)
Хотя у user1 и user2 одинаковый id, это РАЗНЫЕ экземпляры в памяти:
Локальные переменные (Stack):
user1 -> адрес 0x1234
user2 -> адрес 0x5678
Память (Heap):
0x1234: User { id=1, name="Alice" }
0x5678: User { id=1, name="Bob" }
Чтобы получить ОДИН экземпляр, нужны специальные механизмы:
1. Паттерн Singleton
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
// Использование
Singleton s1 = Singleton.getInstance();
Singleton s2 = Singleton.getInstance();
System.out.println(s1 == s2); // true (ОДИН объект!)
2. Lazy Initialization с потокобезопасностью
public class ThreadSafeSingleton {
private static volatile ThreadSafeSingleton instance;
private ThreadSafeSingleton() {}
public static ThreadSafeSingleton getInstance() {
if (instance == null) {
synchronized (ThreadSafeSingleton.class) {
if (instance == null) {
instance = new ThreadSafeSingleton();
}
}
}
return instance;
}
}
3. Enum Singleton (самый безопасный)
public enum EnumSingleton {
INSTANCE;
private String data;
public void setData(String data) {
this.data = data;
}
public String getData() {
return data;
}
}
// Использование
EnumSingleton s1 = EnumSingleton.INSTANCE;
EnumSingleton s2 = EnumSingleton.INSTANCE;
System.out.println(s1 == s2); // true (ОДИН объект!)
4. Статические переменные класса
public class UserRegistry {
private static final Map<Integer, User> users = new HashMap<>();
public static void register(User user) {
users.put(user.getId(), user);
}
public static User getUser(int id) {
return users.get(id);
}
}
// Использование
User user1 = UserRegistry.getUser(1); // null первый раз
UserRegistry.register(new User(1, "Alice"));
User user2 = UserRegistry.getUser(1); // Теперь вернёт тот же объект
User user3 = UserRegistry.getUser(1); // Снова тот же объект
System.out.println(user2 == user3); // true
Spring Beans (наиболее распространённо)
@Service
public class UserService {
// Spring создаёт ОДИН экземпляр этого сервиса
}
@RestController
public class UserController {
private final UserService userService1;
private final UserService userService2;
public UserController(UserService userService1, UserService userService2) {
this.userService1 = userService1;
this.userService2 = userService2;
}
@GetMapping("/test")
public String test() {
// userService1 и userService2 указывают на ОДИН объект в памяти
return "Same? " + (userService1 == userService2); // true
}
}
Паттерн Object Pool (пулинг объектов)
public class ConnectionPool {
private static final List<Connection> availableConnections = new LinkedList<>();
private static final int POOL_SIZE = 10;
static {
for (int i = 0; i < POOL_SIZE; i++) {
availableConnections.add(new Connection(i));
}
}
public static Connection getConnection(int id) {
// Возвращает существующий объект из пула
return availableConnections.stream()
.filter(conn -> conn.getId() == id)
.findFirst()
.orElse(null);
}
}
WeakHashMap и кеширование
public class UserCache {
private static final Map<Integer, User> cache = new WeakHashMap<>();
public static User getOrCreate(int id, String name) {
User user = cache.get(id);
if (user == null) {
user = new User(id, name);
cache.put(id, user);
}
return user;
}
}
// Использование
User user1 = UserCache.getOrCreate(1, "Alice");
User user2 = UserCache.getOrCreate(1, "Alice");
System.out.println(user1 == user2); // true (один и тот же объект)
Flyweight паттерн (облегчённые объекты)
public class Character {
private char c;
public Character(char c) {
this.c = c;
}
}
public class CharacterFactory {
private static final Map<Character, Character> cache = new HashMap<>();
public static Character getCharacter(char c) {
Character character = cache.get(c);
if (character == null) {
character = new Character(c);
cache.put(c, character);
}
return character;
}
}
// Использование
Character char1 = CharacterFactory.getCharacter('A');
Character char2 = CharacterFactory.getCharacter('A');
Character char3 = CharacterFactory.getCharacter('B');
System.out.println(char1 == char2); // true
System.out.println(char1 == char3); // false
Сравнение разных подходов
| Механизм | Один экземпляр | Потокобезопасность | Использование |
|---|---|---|---|
| new каждый раз | НЕТ | Да | Обычные объекты |
| Singleton | ДА | Зависит | Конфиг, логгер |
| Spring Bean | ДА (по умолчанию) | Да | Enterprise приложения |
| Object Pool | ДА (из пула) | Можно | Дорогие ресурсы |
| Кеширование | ДА (если в кеше) | Зависит | Часто используемые объекты |
| WeakHashMap | ДА (пока на них ссылка) | Нет | Кеши, памятьчувствительные |
Важный момент: Identity vs Equality
// Вы можете переопределить equals, чтобы объекты считались равными
public class User {
private int id;
@Override
public boolean equals(Object obj) {
if (!(obj instanceof User)) return false;
return this.id == ((User)obj).id;
}
}
User user1 = new User(1);
User user2 = new User(1);
System.out.println(user1 == user2); // false (разные объекты)
System.out.println(user1.equals(user2)); // true (одинаковые данные)
Итоговый ответ
Нет, при простом создании объекта два раза это будут разные экземпляры:
User u1 = new User(1, "Alice"); // Объект #1
User u2 = new User(1, "Bob"); // Объект #2 (ДРУГОЙ!)
u1 == u2 // false
Да, если использовать специальные паттерны (Singleton, кеширование, Spring, пулинг):
User u1 = cache.getUser(1); // Объект из кеша
User u2 = cache.getUser(1); // ТОТ ЖЕ объект
u1 == u2 // true
Выбор зависит от вашей архитектуры и требований приложения.