Почему объекты массивов, но не могут использоваться в качестве базового класса?

Спецификация языка Java указывает, что

В языке программирования Java массивы являются объектами (§4.3.1), динамически создаются и могут быть назначены переменным типа Object (§ 4.3.3). Все методы класса Object могут быть вызваны в массиве.

Итак, учитывая, что массивы являются объектами - почему дизайнеры Java приняли решение не разрешать наследование и переопределение из него, например toString() или equals()?

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

Ответ 1

Java была компромиссом между не-предметными языками и очень медленными языками того времени, где все было объектом (подумайте о Smalltalk).

Даже на более поздних языках структура быстро на уровне языка для массивов (и обычно карт) считается стратегической целью. Большинству людей не понравится вес наследуемого объекта для массивов, и, конечно же, никто не хотел этого, прежде чем JVM будет продвигаться, как JIT.

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

Ответ 2

Я наткнулся на UNDER THE HOOD - Объекты и массивы, в котором объясняется почти все, что вам нужно знать о том, как JVM обрабатывает массивы. В JVM массивы обрабатываются специальными байткодами, а не как другие объекты, с которыми мы знакомы.

В наборе команд JVM все объекты создаются и доступны с тем же набором опкодов, за исключением массивов. В Java массивы полнофункциональные объекты и, как и любой другой объект в программе Java, создаются динамически. Ссылки на массивы можно использовать в любом месте требуется обращение к типу Object, и любой метод Object может вызывается в массиве. Тем не менее, в виртуальной машине Java массивы обрабатываются специальными байткодами.

Как и в случае любого другого объекта, массивы не могут быть объявлены как локальные переменные; только ссылки на массивы. Объекты массива всегда всегда содержат либо массив примитивных типов, либо массив объекта Рекомендации. Если вы объявляете массив объектов, вы получаете массив ссылки на объекты. Сами объекты должны быть явно созданы с новыми и назначенными элементам массива.

Массивы являются динамически создаваемыми объектами, и они служат в качестве контейнера, который содержит (постоянное) число объектов того же типа. Похоже, что массивы не похожи ни на какой другой объект, и почему с ними обращаются по-разному.

Ответ 3

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

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


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

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

Объект:

Object экземпляр следует за простым Opcode new, который представляет собой комбинацию из двух операндов - indexbyte1 и indexbyte2. После создания экземпляра JVM нажимает ссылку на этот объект на stack. Это происходит для всех объектов, независимо от их типов.


Массивы:

Array Opcodes (относительно создания экземпляра массива), однако, делятся на три разных кода.

newarray - длина всплывающих окон, выделяет новый массив примитивных типов типа, обозначенных atype, толкает objectref нового массива

newarray opcode используется при создании массивов, которые содержат примитивные типы данных (byte short char int long float double boolean), а не ссылки на объекты.

anewarray - длина попса, выделяет новый массив объектов класса, обозначенных indexbyte1 и indexbyte2, толкает objectref нового массива

anewarray opcode используется при создании массивов ссылок на объекты

multianewarray - размер попса числа длин массивов, выделяет новый многомерный массив класса, обозначенный indexbyte1 и indexbyte2, толкает objectref нового массива

multianewarray команда используется при распределении многомерных массивов


Объект может быть экземпляром класса или массивом.

Возьмите Документы Oracle

Экземпляр класса явно создается выражением создания экземпляра класса

НО

Массив явно создается выражением создания массива

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

Как мы видели, это не имеет никакого отношения к тому, что массивы могут содержать примитивные типы данных. Однако, немного подумав, не очень часто встречается ситуация, когда вы захотите toString() или equals(), но все же очень интересный вопрос, чтобы попытаться ответить.


Ресурсы:

Глава 4. Главы 4.3.1

глава Oracle-Docs 15.10.1

Artima - UnderTheHood

Ответ 4

В стандартной java-библиотеке есть много классов, которые нельзя подклассы, массивы - не единственный пример. Рассмотрим String или StringBuffer, или любую из "примитивных оберток", например Integer или Double. Есть оптимизация, которую JVM делает на основе знания точной структуры этих объектов, когда она имеет дело с ними (например, распаковывание примитивов или управление памятью массива на уровне байтов). Если бы вы могли переопределить что-либо, это было бы невозможно, и это повлияло бы на производительность программ очень плохо.