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
представлено 11 public
-методов, 6 из которых имеют нативную реализацию.
Нативная реализация означает, что метод реализован в платформенно-зависимом коде, чаще всего на
C/C++
, и скомпонован в виде динамической библиотеки. А значит, это реализация зависит отJVM
.Возможно, вас сейчас это напугало, но на самом деле достаточно просто понимать, что
native
означает лишь то, что мы вызываем код, который реализован не наJava
.
После того, как мы ознакомились с методами java.lang.Object
, прочли про ООП
, то давайте зададимся вопросом - а почему это не абстрактный класс?
Про абстрактные классы прочитать можно тут // todo
В целом, на первый взгляд было бы логичным ожидать, что такой класс должен быть абстрактным.
Это кажется логичным даже из названия - Object
, которое является довольно обобщенным - "объект".
Однако, модификатора abstract
у java.lang.Object
нет и мы постараемся ответить на вопрос - почему?
Все это - только мое мнение, так как почему именно так сделано - могут объяснить только разработчики
JDK
.
Для ответа на этот вопрос давайте разберемся, а какие плюсы принес бы нам модификатор asbtract
?
Представим себе ситуацию, когда у 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
часто используется для 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
должны быть в отдельных интерфейсах, так, чтобы это поведение я мог бы подмешивать к своему классу тогда, когда мне это было бы надо.
Но что сделано - то сделано.