2010-01-22 3 views
120

Можно создать дубликат:
Java: Rationale of the Object class not being declared abstractПочему java.lang.Object не абстрактный?

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

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

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

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

+5

+1, это сразу заставило меня подумать об одном и том же вопросе, но в отношении языков на основе .NET –

+9

Кажется, что возникает много путаницы в вопросе; абстрактным классам не нужны абстрактные методы. Скорее, вопрос задает вопрос: «Есть ли какая-то настоящая причина, по которой мы нуждаемся, чтобы иметь возможность« new Object();?? » Если нет, 'Object' должен быть абстрактным. –

+5

Флипсайд, а ИМО - лучший вопрос, который нужно задать: «Есть ли настоящая необходимость? Объект должен быть абстрактным?» Нет. Так что это должно быть конкретным. –

ответ

61

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

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

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

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

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

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

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

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

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

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

  • Performance
  • безопасности
  • простота реализации JVM

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

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

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

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

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

+1

Сами методы не должны быть абстрактными - точка создания абстрактного класса состоит в том, что вы не можете вызывать 'new Object()' в коде. Вопрос в том, есть ли необходимость в каждом экземпляре объекта Object? Хотя я согласен с вами в том, что 'hashCode' /' clone' не лучший, это не связано с вопросом. –

+0

Упоминание hashCode/clone должно помочь понять, какие методы выиграют от абстрактности, а ответ IMO оказывается никем, поэтому я думаю, что это связано.Хорошая мысль о том, что вы не можете обновить объект, добавила некоторую информацию об этом. – Grundlefleck

+1

+1 за то, что они были интересными вещами, если ничего другого. –

24

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

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

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

+8

Звучит как хак для меня –

+1

@BlueRaja, пожалуйста, объясните, почему синхронизация на старом старом закрытом конечном объекте может быть взломом? – Jerome

+0

Nit-picking здесь, но я считаю, что есть немного более низкие накладные расходы, если вы используете байт [0] вместо Object в качестве вашей блокировки. – Adamski

5

Время от времени вам нужен простой объект, который не имеет собственного состояния. Хотя такие объекты кажутся бесполезными с первого взгляда, они все еще имеют полезность, поскольку каждый из них имеет различный идентификатор . 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()

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

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

+3

Хм ... Разве вам не было бы лучше использовать новый материал java.util.concurrent в наши дни –

+2

Знаете ли вы какие-либо доказательства, являющиеся причиной ** ** Объект не абстрактный? Конечно, это было полезно, но вызвало ли это первоначальное решение сделать его конкретным? – Grundlefleck

+1

«Если объект был абстрактным, и нам нужна была блокировка, которую мы должны были бы подклассифицировать без добавления какого-либо метода или полей, чтобы мы могли создавать экземпляр блокировки». - Да, но это можно сделать один раз, в SDK, поэтому вы используете объект java.lang.Lock (или что-то еще), и вы лучше выражаете свои намерения. Это не похоже, что каждый должен будет создать новый пустой класс каждый раз, когда захочет синхронизировать блокировку. – Grundlefleck

11

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

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

«В качестве базового экземпляра для анонимных классов». -> это также можно сделать, когда Object является абстрактным. – Fortega

+6

Все очень достоверные точки, но все это можно сделать другими хорошими способами, когда объект является абстрактным. – BalusC

-9

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

+5

Вам нужно только переопределить абстрактные методы, а не каждый метод. – pgb

+8

Хм .... этот вопрос выявил некоторые очень простые недоразумения в том, что такое абстрактный класс .... – skaffman

+0

Только абстрактные методы должны быть переопределены/реализованы, а не все методы абстрактного класса. – Lucero

0

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

+3

Вы можете иметь, скажем, общий массив типа 'Object []', даже если 'Object' были абстрактными - вам просто нужно заполнить его подтекстами' Object'. –

-4

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

  1. отражения
    см object.getClass()

  2. общего использования (до Java 5)

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

  4. syncronization
    см. Object.wait(), Object .notify() и т.д.

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

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

Согласно Sun, An abstract class is a class that is declared abstract—it may or may not include abstract methods. Abstract classes cannot be instantiated, but they can be subclassed. Это также означает, что вы не можете вызывать методы или получать доступ к общедоступным полям абстрактного класса.

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

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(); 
    } 
} 

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

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

но это работает только потому, что ReflectedClass имеет родителя («Объект»), который 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; 

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

+0

Разве они не должны были реализовать все абстрактные методы, прежде чем они даже скомпилировались? – Grundlefleck

+3

Еще раз, потому что сам класс является абстрактным, не означает, что методы должны быть. См. Комментарии к ответу girinie. –

+0

@BlueRaja. Дело не в том, что должно быть реализовано, а в том, что вы не сможете вызвать Object.class, если бы не были реализованы абстрактные методы. Выбор - Объект конкретный, или каждый класс, который хочет участвовать в размышлении, должен был бы обеспечить реализацию любых абстрактных методов. Другими словами, отражение является одной из причин, по которым Object не является абстрактным. –

9

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

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

+0

@BlueRaja Все хорошо и хорошо укладывается в я не совсем отвечаю на вопрос, но как ваш ответ дает ответ на вопрос: «Почему объект не абстрактный?», а вместе с ним и большинство других ответов здесь тоже. –

+0

@Wim: кажется, является реальным ответом на этот вопрос, кроме «Это была ошибка дизайна», поэтому «Объект * должен был быть абстрактным». –

+0

@Wim: Потому что я также ответил на ваш ответ, я предполагаю, что вы подумали Пожалуйста, обратите внимание, что я не заинтересован в том, чтобы лично нападать на людей, я просто хочу получить ответы на лучшие вопросы на сайте, и я делаю это, опросив ваш ответ. недоброжелательность или «закладывание». Я, очевидно, не могу говорить за BlueRaja, но мне кажется, он был только делая то же самое. – Grundlefleck

7

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

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

+0

Интересно. Было ли это добавление в отношении обсуждения вопроса об абстрактном объекте или общей точке? – Grundlefleck

+0

IIRC это только часть главы с общим советом по двоичной совместимости. – Tobu

1

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

-6

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

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

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

+3

* «Если коллекция не является общей, то она должна вернуть конкретный объект» * - я не понимаю этот комментарий.Коллекция может содержать/возвращать абстрактные типы, она просто не может - и не нуждается в их создании (таким образом, все «экземпляры» абстрактного типа являются фактически экземплярами подтипа). Так он всегда работал. –

+1

-1, классам коллекции не нужно возвращать конкретные объекты, они возвращают другие объекты (например, строки), переданные объекту. –

+3

Даже с дженериками, и из-за стирания типа не собирают ли сборники информации о типе? ??? –

1

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

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

Object NULL_OBJECT = new Object(){}; 

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

5

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

public class UseableObject extends AbstractObject{} 

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

+0

В ответ на вопрос «Зачем делать его абстрактным?» Я бы сказал, потому что это не означает, что * означает «объект». На самом деле слово «объект» является абстрактным термином. Я имею в виду, если вы посмотрите вокруг, вы не найдете ничего, что вы можете полностью описать как «объект», всегда будет конкретный термин для конкретной вещи. Я думаю, что это компромисс между прагматизмом, позволяющим что-то полезное, но на самом деле не имеет смысла в сравнении с точной идеей парадигмы. Это не имеет большого значения, но интересно подумать :) – Grundlefleck

+0

@Grundlefleck они могли бы назвать его MinimalJavaObject, тогда он описал бы минимальную реализацию любого объекта в java, что-то конкретное, но я должен согласиться что для прагматизма определенно была торговля, у меня есть реактивный самолет, чтобы увидеть безупречный язык программирования :). – josefx

+0

hmmmm, я полагаю, что это имеет смысл. – Grundlefleck

2

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

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

Смежные вопросы