← Назад к вопросам
Какие знаешь методы по умолчанию помимо toString?
1.0 Junior🔥 191 комментариев
#Основы Java
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
# Методы по умолчанию в Java Object (помимо toString)
Все методы класса Object
Все классы в Java наследуются от Object. Вот все методы Object кроме toString():
1. equals(Object obj)
Назначение: Сравнение объектов на равенство
public class User {
private int id;
private String name;
@Override
public boolean equals(Object obj) {
// Проверка типа
if (!(obj instanceof User)) {
return false;
}
User other = (User) obj;
// Сравнение по полям
return this.id == other.id &&
this.name.equals(other.name);
}
}
// Использование
User user1 = new User(1, "John");
User user2 = new User(1, "John");
user1.equals(user2); // true (по полям)
user1 == user2; // false (разные объекты в памяти)
По умолчанию (в Object):
// По умолчанию equals сравнивает ссылки (как ==)
return this == obj;
Правило: ВСЕГДА переопредели equals, если переопределил hashCode!
2. hashCode()
Назначение: Возврат хеш-кода объекта для использования в Hash структурах
public class Product {
private String code;
private String name;
@Override
public int hashCode() {
// ✅ Правильно — используй все поля из equals()
return Objects.hash(code, name);
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof Product)) return false;
Product other = (Product) obj;
return this.code.equals(other.code) &&
this.name.equals(other.name);
}
}
// Использование в HashSet, HashMap
Set<Product> products = new HashSet<>();
Product p1 = new Product("SKU123", "Laptop");
Product p2 = new Product("SKU123", "Laptop");
products.add(p1);
products.add(p2); // Не добавится, так как equals + hashCode одинаковые
System.out.println(products.size()); // 1
Контракт hashCode():
1. Если a.equals(b) == true, то a.hashCode() == b.hashCode()
2. Если a.hashCode() != b.hashCode(), то a.equals(b) == false
3. a.hashCode() == a.hashCode() для одного объекта (консистентность)
Плохо:
@Override
public int hashCode() {
return 42; // Все объекты имеют один хеш-код!
// Превращает HashMap в LinkedList — O(n)
}
3. getClass()
Назначение: Получить класс объекта (тип)
Object obj = "Hello";
// Получение класса
Class<?> clazz = obj.getClass();
System.out.println(clazz.getName()); // java.lang.String
System.out.println(clazz.getSimpleName()); // String
// Проверка типа
if (obj.getClass() == String.class) {
System.out.println("It's a String");
}
// Рефлексия
Class<?>[] methods = clazz.getMethods();
for (Method method : methods) {
System.out.println(method.getName());
}
Практическое применение:
public class TypeChecker {
public void process(Object obj) {
Class<?> type = obj.getClass();
// instanceof лучше, но getClass() тоже работает
if (type == String.class) {
String str = (String) obj;
System.out.println("String length: " + str.length());
} else if (type == Integer.class) {
Integer num = (Integer) obj;
System.out.println("Integer value: " + num);
}
}
}
4. clone()
Назначение: Создать копию объекта
// ❌ По умолчанию clone() выбрасывает исключение
try {
Object copy = obj.clone(); // CloneNotSupportedException
} catch (CloneNotSupportedException e) {
// ...
}
// ✅ Правильно — реализуй Cloneable
public class Document implements Cloneable {
private String title;
private String content;
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone(); // Shallow copy
}
// Или deep copy
@Override
public Document cloneDeep() throws CloneNotSupportedException {
Document cloned = (Document) super.clone();
// Глубокая копия для mutable полей
cloned.content = new String(this.content);
return cloned;
}
}
// Использование
Document doc1 = new Document("Title", "Content");
Document doc2 = (Document) doc1.clone(); // Поверхностная копия
Shallow vs Deep Copy:
public class Author {
private String name;
}
public class Book implements Cloneable {
private String title;
private Author author;
// Shallow copy — author ссылается на тот же объект
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
// Deep copy — копируем и автора
public Book cloneDeep() throws CloneNotSupportedException {
Book cloned = (Book) super.clone();
cloned.author = new Author(this.author.getName());
return cloned;
}
}
Альтернатива clone():
// Copy constructor (безопаснее)
public class User {
private int id;
private String name;
// Copy constructor
public User(User other) {
this.id = other.id;
this.name = other.name;
}
}
User user1 = new User(1, "John");
User user2 = new User(user1); // Явная копия
5. finalize()
Назначение: Вызывается перед удалением объекта сборщиком мусора
public class Resource implements AutoCloseable {
private FileInputStream fis;
public Resource(String filename) throws IOException {
fis = new FileInputStream(filename);
}
@Override
@Deprecated(since = "9")
protected void finalize() throws Throwable {
// ❌ УСТАРЕВШИЙ МЕТОД — не используй!
// Вызов не гарантирован
// Может быть отложен на неопределённое время
try {
if (fis != null) {
fis.close();
}
} finally {
super.finalize();
}
}
}
// ✅ ПРАВИЛЬНО — используй try-with-resources
public class Resource implements AutoCloseable {
private FileInputStream fis;
public Resource(String filename) throws IOException {
fis = new FileInputStream(filename);
}
@Override
public void close() throws IOException {
if (fis != null) {
fis.close();
}
}
}
// Использование
try (Resource resource = new Resource("file.txt")) {
// Работа с ресурсом
} // close() вызовется гарантированно
Почему finalize() плохой:
- Вызов не гарантирован
- Могут быть утечки ресурсов
- Замедляет сборку мусора
- Помечен как @Deprecated
6. wait(), notify(), notifyAll()
Назначение: Синхронизация потоков
public class SharedResource {
private String data;
private boolean isReady = false;
public synchronized void produce(String value) {
while (isReady) {
try {
wait(); // Ждёт, пока consumer прочитает
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
this.data = value;
this.isReady = true;
notifyAll(); // Пробуждает consumer
}
public synchronized String consume() {
while (!isReady) {
try {
wait(); // Ждёт, пока producer создаст данные
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
String result = this.data;
this.isReady = false;
notify(); // Пробуждает producer
return result;
}
}
// Пример использования
public class ProducerConsumer {
public static void main(String[] args) {
SharedResource resource = new SharedResource();
Thread producer = new Thread(() -> {
for (int i = 0; i < 5; i++) {
resource.produce("Item " + i);
}
});
Thread consumer = new Thread(() -> {
for (int i = 0; i < 5; i++) {
String data = resource.consume();
System.out.println("Consumed: " + data);
}
});
producer.start();
consumer.start();
}
}
notify() vs notifyAll():
notify(); // Пробуждает ОДИН поток
notifyAll(); // Пробуждает ВСЕ потоки
// Используй notifyAll() если несколько потоков ждут
// notify() может быть более эффективным, но опаснее
7. Полный список методов Object
public class Object {
// Сравнение и хеширование
public boolean equals(Object obj)
public int hashCode()
// Информация о типе
public Class<?> getClass()
// Копирование
protected Object clone() throws CloneNotSupportedException
// Строковое представление
public String toString()
// Синхронизация потоков
public final void wait() throws InterruptedException
public final void wait(long timeoutMillis) throws InterruptedException
public final void wait(long timeoutMillis, int nanos) throws InterruptedException
public final void notify()
public final void notifyAll()
// Управление жизненным циклом (DEPRECATED)
protected void finalize() throws Throwable
}
8. Практический пример: Правильная переопределение
public class Employee {
private int id;
private String name;
private double salary;
// Конструктор
public Employee(int id, String name, double salary) {
this.id = id;
this.name = name;
this.salary = salary;
}
// ✅ equals()
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (!(obj instanceof Employee)) return false;
Employee other = (Employee) obj;
return this.id == other.id &&
this.name.equals(other.name) &&
Double.compare(this.salary, other.salary) == 0;
}
// ✅ hashCode()
@Override
public int hashCode() {
return Objects.hash(id, name, salary);
}
// ✅ toString()
@Override
public String toString() {
return String.format("Employee{id=%d, name='%s', salary=%.2f}",
id, name, salary);
}
// ✅ Либо copy constructor, либо clone()
public Employee copy() {
return new Employee(this.id, this.name, this.salary);
}
}
// Использование
public class Main {
public static void main(String[] args) {
Employee emp1 = new Employee(1, "John", 50000);
Employee emp2 = new Employee(1, "John", 50000);
Employee emp3 = emp1.copy();
System.out.println(emp1.equals(emp2)); // true
System.out.println(emp1.hashCode() == emp2.hashCode()); // true
System.out.println(emp1.toString()); // Employee{id=1, name='John', salary=50000.00}
System.out.println(emp1.equals(emp3)); // true
Set<Employee> employees = new HashSet<>();
employees.add(emp1);
employees.add(emp2); // Не добавится
employees.add(emp3); // Не добавится
System.out.println(employees.size()); // 1
}
}
Заключение
Основные методы Object:
- equals() — сравнение объектов (по умолчанию ==)
- hashCode() — хеш для Hash структур (ВСЕГДА с equals)
- getClass() — получить класс объекта
- clone() — создать копию (редко используется)
- toString() — строковое представление
- wait(), notify(), notifyAll() — синхронизация потоков
- finalize() — DEPRECATED, не используй
Правила:
- Если переопределил equals() → переопредели hashCode()
- Используй Objects.hash() для hashCode()
- Используй Objects.equals() для сравнения null значений
- Используй try-with-resources вместо finalize()
- Copy constructor безопаснее clone()