Skip to content

Latest commit

 

History

History
147 lines (96 loc) · 12.2 KB

intro.md

File metadata and controls

147 lines (96 loc) · 12.2 KB

java.lang.Object и все-все-все

Введение

Java - это объектно-ориентированный язык программирования. В ООП мы в основном оперируем понятиями класса и объекта.

Подробнее про ООП можно прочесть здесь.

Ну а если вы ознакомились с основными понятиями, то давайте обсудим главный класс в Java. И этим классом является: java.lang.Object - это корень иерархии классов в Java.

Это значит, что каждый класс, включая массивы, является потомком java.lang.Object.

Именно поэтому писать что-то в духе:

public class Test extends Object {
    // some code
}

Абсолютно лишено смысла - Java автоматически добавит ваш класс в иерархию с родителем java.lang.Object.

При этом, даже если вы не создали ни одного конструктора для вашего класса, то Java создаст конструктор по умолчанию. И, с учетом того, что у нас есть родительский класс, этот конструктор будет выглядеть в виде:

public class Test {
    public Test() {
        super();
    }
}

Теперь давайте посмотрим какое влияние на поведение классов оказывает java.lang.Object, являясь родительским классом. Поведение класса - это его интерфейс, методы, которые он предоставляет.

Методы java.lang.Object

Всего в java.lang.Object представлено 11 public-методов, 6 из которых имеют нативную реализацию.

Нативная реализация означает, что метод реализован в платформенно-зависимом коде, чаще всего на C/C++, и скомпонован в виде динамической библиотеки. А значит, это реализация зависит от JVM.

Возможно, вас сейчас это напугало, но на самом деле достаточно просто понимать, что native означает лишь то, что мы вызываем код, который реализован не на Java.

Почему java.lang.Object не является абстрактным классом

После того, как мы ознакомились с методами java.lang.Object, прочли про ООП, то давайте зададимся вопросом - а почему это не абстрактный класс?

Про абстрактные классы прочитать можно тут // todo

В целом, на первый взгляд было бы логичным ожидать, что такой класс должен быть абстрактным. Это кажется логичным даже из названия - Object, которое является довольно обобщенным - "объект".

Однако, модификатора abstract у java.lang.Object нет и мы постараемся ответить на вопрос - почему?

Все это - только мое мнение, так как почему именно так сделано - могут объяснить только разработчики JDK.

Для ответа на этот вопрос давайте разберемся, а какие плюсы принес бы нам модификатор asbtract?

Что нам дает то, что один или несколько методов java.lang.Object были бы абстрактными

Представим себе ситуацию, когда у java.lang.Object существует один или несколько абстрактных методов. Что это дает?

Пометив какие-то методы abstract мы явно потребуем от разработчиков реализации этих методов. Еще раз взглянем на методы класса java.lang.Object и подумаем - насколько упростит жизнь разработчика, если хоть один из методов будет необходимо каждый раз реализовывать при написании класса.

Методы wait, notify, finalize, notifyAll и getClass довольно сложны(часть из этих методов являются native-методами) и требовать каждый раз от разработчика их реализации - это дополнительные проблемы и большое количество подводных камней, на которые можно натолкнуться.

Методы equals, hashCode, clone и toString в целом можно было бы сделать абстрактными, но мне кажется эти методы относятся к отдельным абстракциям. Ведь не каждому классу нужно(и можно) иметь строковое представление, возможности клонирования, сравнения и предоставления hash-кода.

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

Но делать эти методы абстрактными - это уже опять шаг в сторону усложнения написания кода, ведь требовать от класса, которому не нужно уметь представлять себя в строковом виде определение toString - неразумно и не глупо. В таком случае разработчик будет писать какой-то "фейковый" toString и у каждого он будет свой.

Поэтому, на мой взгляд, оптимальное решение было то, какое выбрали в текущей реализации.

В итоге, как мы сейчас увидели, делать методы класса java.lang.Object абстрактными неразумно, так как это только усложнит написание кода и не дает никаких преимуществ.

Что нам дает то, что java.lang.Object будет абстрактным классом

Теперь предположим, что класс java.lang.Object является абстрактным, но не имеет абстрактных методов.

С точки зрения наименований - довольно логично было бы, чтобы такой класс был абстрактным. Ведь сложно найти что-то, что полностью подходило под описание "объект". Объектов много - но это всегда что-то абстрактное. Объектами являются и лампа, и машина, и дом.

Поэтому с точки зрения дизайна языка, мне кажется, было бы правильней чтобы java.lang.Object был абстрактным.

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

Разберем теперь пользу от возможности создания экземпляра класса java.lang.Object.

Экземпляр класса java.lang.Object часто используется для synchronized операций. Так как в Java можно занять монитор объекта - сделать синхронизацию на нем.

И часто для таких целей пишут что-то в виде:

public class Example {
    private final Object lock = new Object();

    public void doSomething() {
        synchronized (lock) {
            // do possibly dangerous stuff
        }
    }
}

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

С другой стороны, для возможности использовать synchronized можно было бы сделать специальный объект, например, java.lang.Lock или что-то подобное. Чтобы тип поля явно говорил нам - для чего это поле будет использоваться, ведь когда вы видите поле с типом Object - это по началу вводит в ступор, особенно, если название переменной не слишком понятно.

Иногда бывает также удобно иметь возможность создать объект-пустышку, так называемый Placeholder, без состояния, например, как реализован HashSet. Это реализация Map, где ключами являются элементы множества, а значениями будут объекты-пустышки.

И опять же, можно было бы ожидать, что для таких целей будет именно так и названный класс, что-то типа java.lang.Placeholder, являющийся наследником нашего абстрактного java.lang.Object.

Подробнее про Map //todo

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

Также, возможно, есть еще какие-то примения java.lang.Object, например в механизме Reflection, в безопасности и так далее. Поэтому, я считаю, что java.lang.Object может быть не абстрактным, почему нет? И я не отношу это к минусам дизайна языка.

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

Более того, я считаю, что методы equals, hashCode, clone и toString должны быть в отдельных интерфейсах, так, чтобы это поведение я мог бы подмешивать к своему классу тогда, когда мне это было бы надо.

Но что сделано - то сделано.