Класс Object и его методы

Последнее обновление: 25.09.2025

Хотя мы можем создать обычный класс, который не является наследником, но фактически все классы наследуются от класса Object. Все остальные классы, даже те, которые мы добавляем в свой проект, являются неявно производными от класса Object.

Мы можем использовать переменную типа Object для ссылки на объекты любого типа:

public class Program{
      
    public static void main(String[] args) {
             
        Object obj = "Some Object";
        System.out.println(obj);    // Some Object

        obj = 41;
        System.out.println(obj);    // 41

        obj = new Person("Tom");
        System.out.println(obj);    // Person@1dbd16a6
    }
}
class Person{
    private String name;

    Person(String name) { this.name = name; }

    void print(){  System.out.println("Person " + name); }
}

Поскольку все классы неявно наследуются от Object, то все эти классы также наследуют методы класса Object. Рассмотрим эти методы.

toString

Метод toString служит для получения представления данного объекта в виде строки. При попытке вывести строковое представления какого-нибудь объекта, как правило, будет выводиться полное имя класса. Например:

public class Program{
     
	public static void main(String[] args) {
			
		Person tom = new Person("Tom");
		System.out.println(tom.toString()); // Будет выводить что-то наподобие Person@7960847b
	}
}
class Person {
    
    private String name;
	
    public Person(String name){
    
        this.name=name;
    }
}

Полученное мной значение (в данном случае Person@7960847b) вряд ли может служить хорошим строковым описанием объекта. Поэтому метод toString() нередко переопределяют. Например:

public class Program{
     
	public static void main(String[] args) {
			
		Person tom = new Person("Tom");
		System.out.println(tom.toString()); // Person Tom
	}
}
class Person {
    
    private String name;
   
    public Person(String name){
    
        this.name=name;
    }
	
	@Override
	public String toString(){
         
        return "Person " + name;
    }
}

Метод hashCode

Метод hashCode позволяет задать некоторое числовое значение, которое будет соответствовать данному объекту или его хэш-код. По данному числу, например, можно сравнивать объекты. Так, если x и y — два разных объекта, то существует высокая вероятность того, что вызовы x.hashCode() и y.hashCode() дадут различные результаты.

Например, выведем представление вышеопределенного объекта:

public class Program{
      
    public static void main(String[] args) {
             
        Person tom = new Person("Tom");
        System.out.println(tom.hashCode()); // 498931366
    }
}
class Person{
    private String name;
    Person(String name) {  this.name = name; }
}

Но мы можем задать свой алгоритм определения хэш-кода объекта. Существует много готовых алгоритмов хеширования. Например, класс String применяет следующий алгоритм:

int hash = 0;
for (int i = 0; i < length(); i++)
   hash = 31 * hash + charAt(i);

Мы можем определить и свой алгоритм, главное надо учитывать, что алгоритм желательно подобрать такой, чтобы при вычислении кода для разных объектов их код также различался. Например:

public class Program{
      
    public static void main(String[] args) {
             
        Person tom = new Person("Tom");
        System.out.println(tom.hashCode()); // 842740


        Person tomas = new Person("Tom");
        System.out.println(tomas.hashCode()); // 842740

        Person tim = new Person("Tim");
        System.out.println(tim.hashCode()); // 840880
    }
}
class Person{
    private String name;

    Person(String name) {  this.name = name; }
    @Override
    public int hashCode(){
 
        return 10 * name.hashCode();
    }
}

В данном случае алгоритм хеширования взят от балды просто для демонстрациионных целей. При этом он зависит от хеш-кода поля name. Но тем не менее по консольному выводу мы видим, что объекты с одинаковым полем name совпадают, а с разными различаются.

Объединение хешей

Обычно хеши вычисляются на основе полей объекта, как, например, в примере выше для вычисления хеша применялось поле name. Если класс содержит несколько полей, то, возможно, мы захотим использовать все эти поля для вычисления общего хеша объекта. Например:

class Person{
    private String name;
    private int age;

    Person(String name, int age) { 

        this.name = name;
        this.age = age;
    }
    @Override
    public int hashCode(){
 
        return 31* name.hashCode() + age;
    }
}

В данном случае для вычисления хеша применяются поля name и age. Но объединение нескольких хэш-значений может быть утомительным. Во многих случаях можно просто вызвать Objects.hash, передав в него все необходимые поля. Этот метод на выходе объединит хэш-коды своих аргументов:

import java.util.Objects;  // для Objects.hash
..................................
class Person{
    private String name;
    private int age;

    Person(String name, int age) { 

        this.name = name;
        this.age = age;
    }
    @Override
    public int hashCode(){
 
        return Objects.hash(name, age);
    }
}

Получение типа объекта и метод getClass

Метод getClass позволяет получить тип данного объекта:

Person tom = new Person("Tom");
System.out.println(tom.getClass()); // class Person

Метод equals

Метод equals сравнивает два объекта на равенство. В качестве параметра метод принимает объект, с который надо сравнить текущий, и возвращает true, если объекты равны, и false, если не равны:

boolean equals(Object otherObject)

Стоит отметить, что определения equals и hashCode должны быть совместимы: если x.equals(y) возвращает true, то x.hashCode() должен возвращать то же значение, что и y.hashCode().

По умолчанию метод equals определяет идентичность двух ссылок на объекты:

public class Program{
      
    public static void main(String[] args) {
             
        Point a = new Point(10, 15);
        Point b = a;
        Point c = new Point(10, 15);

        boolean result = a.equals(b);
        System.out.println(result);    // true

        result = a.equals(c);
        System.out.println(result);    // false
    }
}
class Point{

    private int x;
    private int y;

    Point(int x, int y){ 

        this.x = x;
        this.y = y;
    }

    void print(){  System.out.printf("(%d, %d)", x, y); }
}

Здесь в программе переменные a и b хранять ссылку на один и тот же объект Point, который представляет точку с двумя координатами:

Point a = new Point(10, 15);
Point b = a;

boolean result = a.equals(b);    // true

Поэтому они равны.

А вот переменная c хранит ссылку на другой объект, поэтому переменные a/b и c не равны.

Point a = new Point(10, 15);
Point c = new Point(10, 15);

boolean result = a.equals(b);
result = a.equals(c);   // false

Однако в реальности мы видим, что оба объекта (a т c), даже несмотря на то, что они не равны, они имеют одинаковые значения. То есть мы имеем две точки с одинаковыми значениями. И было бы более разумно, если бы они были равны в силу равности их координат. В этом случае мы можем переопределить метод equals:

public class Program{
      
    public static void main(String[] args) {
             
        Point point1 = new Point(10, 15);
        Point point2 = point1;

        boolean result = point1.equals(point2);
        System.out.println(result);    // true

        result = point1.equals(new Point(10, 15));
        System.out.println(result);    // true


        result = point1 .equals("hello");
        System.out.println(result);    // false

        result = point1 .equals(null);
        System.out.println(result);    // false
    }
}
class Point{

    private int x;
    private int y;

    Point(int x, int y){ 

        this.x = x;
        this.y = y;
    }

    void print(){  System.out.printf("(%d, %d)", x, y); }

    // переопределяем метод equals
    @Override
    public boolean equals(Object otherObject){
         
        // проверяем объекты на идентичноть - равенство их ссылок
        if (this == otherObject) return true;

        // проверяем, что второй объект не равен null
        if (otherObject == null) return false;

        // если классы объектов не совпадают, то они не равны
        if (getClass() != otherObject.getClass()) return false;
 
        // иначе преобразуем объект к типу Point
        Point p = (Point)otherObject;
        // и проверяем равенство их координат
        return this.x == p.x  && this.y == p.y;
    }
}

Метод equals принимает в качестве параметра объект любого типа, соответственно это может быть абсолютно любой объект или даже значение null. И в методе equals сначала проверяем, что текущий и второй экземпляр хранят ссылки на один и тот же объект:

if (this == otherObject) return true;

Если же две переменных представляют хранят ссылку на один и тот же объект, то они равны.

Далее проверяем, что второй объект не равен null, иначе дальше сравнивать смысла нет, и объекты будут уже не равны:

if (otherObject == null) return false;

Поскольку второй объект может представлять в реальности объект любого типа, то смотрим, представляют ли объекты один и тот же класс. Если НЕ представляют, то объекты не равны:

if (getClass() != otherObject.getClass()) return false;

И если объекты представляют один и тот же класс, то преобразуем второй объект к целевому типу Point и сравниваем из координаты.

Оператор instanceof позволяет упростить код. Он позволяет выяснить, является ли переданный в качестве параметра объект объектом определенного класса, в данном случае класса Person. Если объекты принадлежат к разным классам, или второй объект представляет null, то их сравнение не имеет смысла, и возвращается значение false:

public class Program{
      
    public static void main(String[] args) {
             
        Point point1 = new Point(10, 15);
        Point point2 = point1;

        boolean result = point1.equals(point2);
        System.out.println(result);    // true

        result = point1.equals(new Point(10, 15));
        System.out.println(result);    // true


        result = point1 .equals("hello");
        System.out.println(result);    // false

        result = point1 .equals(null);
        System.out.println(result);    // false
    }
}
class Point{

    private int x;
    private int y;

    Point(int x, int y){ 

        this.x = x;
        this.y = y;
    }

    void print(){  System.out.printf("(%d, %d)", x, y); }

    // переопределяем метод equals
    @Override
    public boolean equals(Object otherObject){
         
        // проверяем объекты на идентичноть - равенство их ссылок
        if (this == otherObject) return true;

        // проверяем, что второй объект - это объект типа Point
        if (!(otherObject instanceof Point)) return false;
 
        // иначе преобразуем объект к типу Point
        Point p = (Point)otherObject;
        // и проверяем равенство их координат
        return this.x == p.x  && this.y == p.y;
    }
}

Наследование и метод equals

При определении метода equals для подкласса имеет смысл сначала вызовать метода equals для суперкласса. Если проверка не пройдена, объекты не могут быть равны. Если поля суперкласса равны, можно сравнивать поля объекта подкласса:

class Person{
    private String name;

    Person(String name) {  this.name = name; }

    @Override
    public boolean equals(Object otherObject){
         
        if (this == otherObject) return true;
        if (otherObject == null) return false;
        if (getClass() != otherObject.getClass()) return false;
 
        Person p = (Person)otherObject;
        return this.name == p.name;
    }
}

class Employee extends Person{
    private String company;

    Employee(String name, String company) {  

        super(name);
        this.company = company; 
    }

    @Override
    public boolean equals(Object otherObject){
         
        if (!super.equals(otherObject)) return false;
        // super.equals уже проверяет, что this и otherObject представляют один и тот же класс
        Employee empl = (Employee)otherObject;
        // и проверяем равенство их координат
        return this.company.equals(empl.company);
    }
}

В данном случае в классе Employee в реализации метода equals() сначала вызываем его реализацию у базового класса Person через super.equals(otherObject). Если этот вызов возвращает true, то это значит, что оба объекта как минимум представляют один и тот же класс и значения их полей name равны. И далее мы можем сравнивать уже те поля, которые определены непосредственно в классе Employee. Применение метода:

public class Program{
      
    public static void main(String[] args) {
             
        Employee empl1 = new Employee("Tom", "Yandex");
        Employee empl2 = empl1;

        boolean result = empl1.equals(empl2);
        System.out.println(result);    // true

        result = empl1 .equals(new Employee("Tom", "Yandex"));
        System.out.println(result);    // true

        result = empl1 .equals(new Employee("Bob", "Google"));
        System.out.println(result);    // false

        result = empl1.equals(new Person("Tom"));
        System.out.println(result);    // false

        result = empl1 .equals(null);
        System.out.println(result);    // false
    }
}
Помощь сайту
Юмани:
410011174743222
Номер карты:
4048415020898850
Morty Proxy This is a proxified and sanitized view of the page, visit original site.