← Назад к вопросам

Будет ли выдаваться один и тот же экземпляр объекта в памяти, если создать объект два раза с одним идентификатором?

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

Выбор зависит от вашей архитектуры и требований приложения.