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

Возможный дубликат:
Java: Обоснование класса Object не объявляется абстрактным

Почему класс Object, который является базовым классом "em" в Java, а не абстрактным?

У меня был этот вопрос на самом деле очень долгое время, и его попросили здесь исключительно из любопытства, что все. Ничто в коде кода или каком-либо коде не ломается, потому что оно не абстрактно, но мне было интересно, почему они сделали его конкретным?

Почему кому-то нужен "экземпляр" (а не его наличие a.k.a. Reference) этого класса Object? Один случай - плохой код синхронизации, который использует экземпляр объекта для блокировки (по крайней мере, я использовал его таким образом, когда-то.. мой плохой).

Есть ли практическое использование "экземпляра" класса Object? И как его инстанцирование вписывается в ООП? Что произошло бы, если бы они отметили его абстрактным (конечно, после предоставления реализаций его методам)?

Ответ 1

Без конструкторов java.lang.Object, рассказывающих нам, мы должны основывать наши ответы на мнениях. Есть несколько вопросов, которые можно задать, которые могут помочь в его устранении.

Может ли какой-либо из методов Object быть абстрактным?

Можно утверждать, что некоторые из методов выиграют от этого. Возьмите hashCode() и equals(), например, вероятно, было бы намного меньше разочарований вокруг сложностей этих двух, если бы они были сделаны абстрактными. Это потребует от разработчиков выяснить, как они должны их реализовывать, делая более очевидным, что они должны быть последовательными (см. Эффективная Java). Однако я больше придерживаюсь мнения, что hashCode(), equals() и clone() относятся к отдельным абстракциям opt-in (т.е. интерфейсам). Другие методы wait(), notify(), finalize() и т.д. Достаточно сложны и/или являются родными, поэтому лучше всего они уже реализованы и не будут извлекаться из абстракции.

Итак, я бы догадался, что ответ будет отрицательным, ни один из методов Object не станет абстрактным.

Было бы полезно отметить класс Object как абстрактный?

Предполагая, что все методы реализованы, единственным эффектом маркировки абстрактного объекта является то, что он не может быть сконструирован (т.е. new Object() является ошибкой компиляции). Это принесет пользу? Я считаю, что термин "объект" сам по себе абстрактный (можете ли вы найти что-нибудь вокруг вас, которое может быть полностью описано как "объект"?), Поэтому оно будет соответствовать объектно-ориентированной парадигме. Это, однако, на стороне пуриста. Можно утверждать, что заставить разработчиков выбрать имя для любого конкретного подкласса, даже пустые, приведет к коду, который лучше выражает их намерение. Я думаю, что, будучи полностью правильным с точки зрения парадигмы, Object должен быть отмечен abstract, но когда дело доходит до него, нет никакой реальной выгоды, это вопрос предпочтений дизайна (прагматизм против чистоты).

Является ли практика использования простого объекта для синхронизации достаточной достаточной причиной для его конкретной?

Многие другие ответы говорят о построении простого объекта для использования в операции synchronized(). Хотя это, возможно, была распространенной и общепринятой практикой, я не считаю, что было бы достаточно хорошей причиной, чтобы объект был абстрактным, если дизайнеры хотели, чтобы это было. В других ответах мы упоминали о том, как мы должны были бы объявить один, пустой подкласс объекта в любое время, когда мы хотели бы синхронизировать определенный объект, но это не выдерживает - в SDK может быть предоставлен пустой подкласс (java.lang.Lock или что-то еще), которые могут быть построены в любое время, когда мы хотели синхронизировать. Это будет иметь дополнительное преимущество для создания более сильного заявления о намерениях.

Есть ли какие-либо другие факторы, которые могли бы пострадать от создания абстрактного объекта Object?

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

  • Производительность
  • Безопасность
  • Простота реализации JVM

Могут ли быть другие причины?

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

Там также незабываемый момент, что java.lang.Object был разработан людьми: они, возможно, допустили ошибку, они, возможно, не рассмотрели вопрос. Нет языка без недостатков, и это может быть один из них, но если он есть, он вряд ли большой. И я думаю, что могу без смело сказать, что вряд ли буду участвовать в разработке ключевой части такой широко используемой технологии, особенно той, которая длилась 15 (?) Лет и все еще сильна, поэтому это не следует рассматривать как критику.

Сказав это, я бы сделал его абстрактным; -p

Резюме
В принципе, насколько я вижу, ответ на оба вопроса "Почему java.lang.Object бетонный?" или (если бы это было так) "Почему java.lang.Object abstract?" это... "Почему бы и нет?".

Ответ 2

Обычные экземпляры java.lang.Object обычно используются в сценариях блокировки/синхронизации и что принятая практика.

Кроме того - что было бы причиной для его абстрактного? Потому что он не полностью функционирует сам по себе как экземпляр? Может ли это действительно с некоторыми абстрактными членами? Не думайте так. Таким образом, аргумент для его абстрактного в первую очередь не существует. Так что это не так.

Возьмем классическую иерархию животных, где у вас есть абстрактный класс Animal, рассуждение сделать абстракцию класса Animal связано с тем, что экземпляр Animal фактически является "недопустимым" - из-за отсутствия лучшего слова- (даже если все его методы обеспечивают базовую реализацию). С Object это просто не так. Нет никакого подавляющего случая, чтобы сделать его абстрактным в первую очередь.

Ответ 3

Я могу вспомнить несколько случаев, когда полезно использовать примеры Object:

  • Блокировка и синхронизация, как вы и другие комментаторы, упоминаете. Вероятно, это запах кода, но я видел, что экземпляры Object всегда использовали этот путь.
  • Как Null Objects, потому что equals всегда будет возвращать false, кроме самого экземпляра.
  • В тестовом коде, особенно при тестировании классов коллекции. Иногда проще всего заполнить коллекцию или массив фиктивными объектами, а не null s.
  • В качестве базового экземпляра для анонимных классов. Например:
    Object o = new Object() {...code here...}

Ответ 4

Из всего, что я прочитал, кажется, что Object не обязательно должен быть конкретным, и на самом деле должен был быть абстрактным.

Не обязательно, чтобы это было конкретным, но после некоторого больше чтения Я убежден, что Object не, будучи абстрактным, противоречит базовой модели наследования - мы не должны допускать абстрактные подклассы конкретного класса, так как подклассы должны только добавлять функциональность.
Очевидно, что это не так в Java, где у нас есть абстрактные подклассы Object.

Ответ 5

Я думаю, что он, вероятно, должен был быть объявлен абстрактным, но как только он будет сделан и выпущен, его очень сложно отменить, не причинив много боли - см. Java Language Spec 13.4.1:

"Если класс, который не был абстрактным, был изменен, чтобы быть объявленным абстрактом, тогда существовавшие ранее двоичные файлы, которые пытаются создать новые экземпляры этого класса, будут бросать либо время InstantiationError во время ссылки, либо (если используется рефлексивный метод) исключение InstantiationException во время выполнения, поэтому такое изменение не рекомендуется для широко распространенных классов.

Ответ 6

Время от времени вам нужен простой объект, который не имеет собственного состояния. Хотя такие объекты кажутся бесполезными с первого взгляда, у них все еще есть полезность, поскольку каждый из них имеет различную идентичность. Tnis полезен в нескольких сценариях, наиболее важным из которых является блокировка: вы хотите координировать два потока. В Java это делается с помощью объекта, который будет использоваться как блокировка. Объекту не обязательно должно быть никакого состояния, для которого достаточно его существования, чтобы он стал блокировкой:

class MyThread extends Thread {
   private Object lock;
   public MyThread(Object l) { lock = l; }

   public void run() { 

      doSomething();
      synchronized(lock) {
          doSomethingElse();
      } 
   }
}

Object lock = new Object();
new MyThread(lock).start();
new MyThread(lock).start();

В этом примере мы использовали блокировку для предотвращения одновременного выполнения двух потоков doSomethingElse()

Если объект был абстрактным, и нам понадобилась блокировка, нам пришлось бы подклассифицировать его, не добавляя ни один метод, ни поля, чтобы мы могли создавать экземпляр блокировки.

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

Ответ 7

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

public class UseableObject extends AbstractObject{}

UseableObject наследует от абстрактного объекта и удивляет, что он может быть реализован, он не добавляет каких-либо функциональных возможностей и единственной причиной существования является доступ к методам, открытым объектом. Также я должен не согласиться с использованием в "плохой" синхронизации. Использование закрытых объектов для синхронизации доступа безопаснее, чем использование синхронизации (это) и более безопасно, а также проще в использовании, чем классы Lock из java util.

Ответ 8

Мне кажется, здесь есть простой вопрос практичности. Создание абстрактного класса отвлекает способность программиста что-то делать, а именно, создавать его. Вы ничего не можете сделать с абстрактным классом, который вы не можете сделать с конкретным классом. (Ну, вы можете объявить в нем абстрактные функции, но в этом случае нам не нужно иметь абстрактные функции.) Таким образом, делая это конкретным, вы делаете его более гибким.

Конечно, если бы был какой-то активный вред, который был сделан, сделав его конкретным, эта "гибкость" была бы недостатком. Но я не могу думать о каком-либо активном вреде, создаваемом объектом. (Является ли "реальным" слово? Что бы ни было.) Мы могли бы обсуждать, является ли любое использование, которое кто-то сделал из необработанного экземпляра объекта, хорошая идея. Но даже если бы вы могли убедить меня в том, что любое использование, которое я когда-либо видел для экземпляра необработанного объекта, было плохой идеей, которая все равно не докажет, что там могут быть неэффективные варианты использования. Так что, если это ничего не повредит, и это может помочь, даже если мы не можем думать о том, как это действительно поможет в данный момент, зачем его запрещать?

Ответ 9

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

Ответ 10

Я думаю, что все ответы до сих пор забывают, как это было с Java 1.0. В Java 1.0 вы не можете сделать анонимный класс, поэтому, если вам просто нужен объект для какой-либо цели (синхронизация или нулевой заполнитель), вам нужно будет объявить класс для этой цели, а затем целая куча кода будет иметь эти дополнительные классы для этой цели. Гораздо более прямолинейно, чтобы просто позволить прямое создание объекта Object.

Конечно, если бы вы разрабатывали Java сегодня, вы могли бы сказать, что каждый должен делать:

 Object NULL_OBJECT = new Object(){};

Но это не вариант в 1.0.

Ответ 11

Это также означает, что он может быть создан в массиве. В течение до 1,5 дней это позволит вам иметь общие структуры данных. Это может быть справедливо на некоторых платформах (я думаю, J2ME, но я не уверен)

Ответ 12

Причины, по которым объект должен быть конкретным.

  • отражение
    см. Object.getClass()

  • общее использование (pre Java 5)

  • Сравнение/выход
    см. Object.toString(), Object.equals(), Object.hashCode() и т.д.


  • синхронизация см. Object.wait(), Object.notify() и т.д.

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

Класс Object используется в отражении, поэтому код может вызывать методы для экземпляров неопределенного типа, то есть "Object.class.getDeclaredMethods()". Если Object должен был быть абстрактным, тогда код, который хотел участвовать, должен был реализовать все абстрактные методы, прежде чем клиентский код мог бы использовать отражение на них.

Согласно Sun, Абстрактный класс - это класс, объявленный abstract - он может включать или не включать абстрактные методы. Абстрактные классы не могут быть созданы, но они могут быть подклассифицированы. Это также означает, что вы не можете вызывать методы или обращаться к общедоступным полям абстрактного класса.

Пример абстрактного корневого класса:

abstract public class AbstractBaseClass
{
    public Class clazz;

    public AbstractBaseClass(Class clazz)
   {
       super();
       this.clazz = clazz;
   }
}

Ребенок нашего AbstractBaseClass:

public class ReflectedClass extends AbstractBaseClass  
{
    public ReflectedClass() 
    {
       super(this);
    }

    public static void main(String[] args)  
    {
        ReflectedClass me = new ReflectedClass();
    }
}

Это не будет компилироваться, потому что оно недействительно ссылаться на 'this' в конструкторе, если только его не вызывает другой конструктор в том же классе. Я могу заставить его скомпилировать, если я его изменил на:

   public ReflectedClass()
   {
       super(ReflectedClass.class);
   }  

но это работает только потому, что у ReflectedClass есть родительский объект (Object), который является 1) конкретным, и 2) имеет поле для хранения типа для своих детей.

Пример, более типичный для отражения, был бы в нестатической функции-члене:

public void foo()
{
    Class localClass = AbstractBaseClass.clazz;  
}

Это не удастся, если вы не измените поле "clazz" как статическое. Для класса класса Object это не сработает, потому что предполагается, что он специфичен для экземпляра. Для Object не имеет смысла иметь статическое поле класса.

Теперь я попробовал следующее изменение, и оно работает, но немного вводит в заблуждение. Он по-прежнему требует расширения базового класса для работы.

public void genericPrint(AbstractBaseClass c)
{
    Class localClass = c.clazz;
    System.out.println("Class is: " + localClass);
}

public static void main(String[] args)
{
    ReflectedClass me = new ReflectedClass();
    ReflectedClass meTwo = new ReflectedClass();

    me.genericPrint(meTwo);
}

Генералы Pre-Java5 (например, с массивами) были бы невозможны

Object[] array = new Object[100];
array[0] = me;
array[1] = meTwo;

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

Ответ 13

Я подозреваю, что короткий ответ заключается в том, что классы коллекций потеряли информацию о типе в дни перед Java-дженериками. Если коллекция не является общей, то она должна возвращать конкретный объект (и быть отключенным во время выполнения до того, что было ранее).

Поскольку создание конкретного класса в абстрактном классе нарушило бы двоичную совместимость (как указано выше), был сохранен конкретный класс Object. Я хотел бы указать, что ни в коем случае он не был создан с единственной целью синхронизации; фиктивные классы работают так же хорошо.

Неисправность дизайна не включает в себя дженерики с самого начала. Много критики дизайна нацелено на это решение и его последствия. [oh и правило подтипирования массива.]

Ответ 14

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