Зарегистрируйтесь, чтобы продолжить обучение

Класс Объект Java: Классы

Тема классов в Java плотно связана с понятием наследования. Для хорошего понимания этой темы нужно иметь больше практического опыта, чем у нас есть на момент этого курса, поэтому плотно наследование изучается в последующих курсах. Сейчас же, мы пройдемся только по самым базовым понятиям, без которых не получится двигаться вперед.

Если в двух словах, наследование это механизм связи между классами, когда один класс, называемый наследуемым (дочерним, подклассом), как бы расширяет другой класс, называемый базовым (родительским, суперклассом). Выглядит это так:

class Expert extends User {

}

Наследование никак не влияет на родительский класс, но значительно влияет на класс наследник. Он наследует все, что реализовано в родительском классе. Внешне, при использовании класса наследника все выглядит так, как будто этот код находится внутри самого класса, а не где-то еще. В примере выше Expert без добавления своего кода, ведет себя так же как и User.

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

Object

Если мы создадим объект любого класса, в котором не определен ни один метод, то увидим, что у него уже доступны какие-то методы, например, toString(). Откуда берутся эти методы если мы ничего не определили? Дело в том, что любой класс в Java неявно наследует класс Object. Это делает его суперклассом для всех Java-классов. Зачем это нужно?

Часть механизмов в Java должны работать универсально для всех объектов с возможностью это поведение изменить для конкретных классов. Возьмем для примера текстовое представление любого объекта. Если попытаться распечатать любой объект, то это будет сделано без ошибок. Такое происходит потому, что механизм печати ожидает наличие метода toString() у любого объекта. И он действительно есть у всех объектов, так как определен в Object.

var name = "hexlet";
System.out.println(name); // => hexlet
System.out.println(name.toString()); // => hexlet

var user = new User();
System.out.println(user); // => io.hexlet.User@25618e91
System.out.println(user.toString()); // => io.hexlet.User@25618e91

var obj = new Object();
System.out.println(obj); // => java.lang.Object@7a92922

Для строк этот метод возвращает саму строку, что логично. А вот для других объектов toString() возвращает стандартное представление, состоящее из имени класса и хеша. Но если мы хотим, то можем легко изменить это поведение, реализовав метод toString() внутри нашего класса. Таким образом мы переопределим метод родительского класса.

class User {
    private String name;

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

    // Если метод переопределяется, то добавляют аннотацию @Override
    @Override
    public String toString() {
        return "User [name=" + name + "]";
    }
}

Теперь вывод объекта на экран поменяет свой вид.

var user = new User("Mike");
System.out.println(user); // => User [name=Mike]

В этом примере метод отмечен аннотацией @Override. Она явно указывает, что метод переопределяет метод родительского класса. Эта аннотация помогает улучшить читаемость, позволяя разработчикам быстро увидеть переопределенные методы. Кроме того, редактор кода и компилятор используют эту аннотацию для проверки корректности переопределения. Если метод не соответствует сигнатуре родительского метода, компилятор выдаст ошибку. Редактор кода также подсветит это место, что поможет разработчику быстро обнаружить и исправить проблему.

Приведение типов

Другая важная деталь в наличии Object связана с приведением типов. Любой объект можно представить как объект типа Object.

// Будут работать только методы описанные в Object
Object obj = new User("Nina");

Такое поведение полезно в следующих сценариях:

  • Когда мы хотим иметь возможность обрабатывать объекты всех типов каким-то одинаковым способом. Например, метод System.out.println() работает именно так. Его параметр имеет тип Object: println(Object x).
  • Для хранения объектов разных типов в рамках одной структуры. С этим примером мы познакомимся ближе в курсе по дженерикам, где реализуем свою коллекцию элементов, работающую со всеми типами.

Аватары экспертов Хекслета

Остались вопросы? Задайте их в разделе «Обсуждение»

Вам ответят команда поддержки Хекслета или другие студенты

Для полного доступа к курсу нужен базовый план

Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.

Получить доступ
1000
упражнений
2000+
часов теории
3200
тестов

Открыть доступ

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно

  • 130 курсов, 2000+ часов теории
  • 1000 практических заданий в браузере
  • 360 000 студентов
Отправляя форму, вы принимаете «Соглашение об обработке персональных данных» и условия «Оферты», а также соглашаетесь с «Условиями использования»

Наши выпускники работают в компаниях:

Логотип компании Альфа Банк
Логотип компании Aviasales
Логотип компании Yandex
Логотип компании Tinkoff
Рекомендуемые программы
профессия
от 25 000 ₸ в месяц
Разработка приложений на языке Java
10 месяцев
с нуля
Старт 26 декабря

Используйте Хекслет по-максимуму!

  • Задавайте вопросы по уроку
  • Проверяйте знания в квизах
  • Проходите практику прямо в браузере
  • Отслеживайте свой прогресс

Зарегистрируйтесь или войдите в свой аккаунт

Отправляя форму, вы принимаете «Соглашение об обработке персональных данных» и условия «Оферты», а также соглашаетесь с «Условиями использования»