Должна ли Java обрабатывать массивы как объекты? - PullRequest
7 голосов
/ 18 февраля 2009

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

Например:

ints.sort();                 // Arrays.sort(ints);
int[] onemore = ints.add(8); // int[] onemore = ArrayUtils.add(ints, 8);

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

Это считается хорошей или плохой идеей и почему?

Насколько легко это реализовать?

Некоторые другие примеры могут включать (но не зацикливайтесь на них, они не имеют отношения к самому вопросу):

int[] ints = {5,4,3,2,1};

// Arrays.sort (ints);
ints.sort();

// int pos = Arrays.asList(ints).indexOf (5);
// int pos = ArraysUtils.indexOf (ints, 5);
int pos = ints.indexOf (5);

// Arrays.reverse (ints);
ints.reverse();

Array<Integer> array = ints; // cast to super class.

// int length = Array.getLength (array);
int length = array.getLength();

// Object n = Array.get (array, 3);
Object n = array.get (3);

// Array.set (array, 3, 7);
array.set (3, 7);

Object obj = array;
// if (obj instanceof int[])
//     System.out.println(Array.toString((int[]) obj));
// else if (....)
System.out.println (obj);

Ответы [ 10 ]

7 голосов
/ 18 февраля 2009

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

Если вы хотите использовать объекты, вы должны просто использовать коллекцию (ArrayList является примером коллекции). Это может быть неуклюжим, но Коллекции предоставляют типичный методологический доступ, который вам, кажется, нужен.

5 голосов
/ 18 февраля 2009

Эти методы очень похожи на идиомы ruby ​​или python. К сожалению, вы не можете сделать это в Java (хотелось бы).

Во-первых, как уже отмечали другие, классы коллекций делают это за вас. С другой стороны, myarray.sort () не так хорош, потому что вы можете создавать массивы объектов, для которых сортировка не была определена. Предположим, у меня есть

 Foo[] foos; 

И Фу не сопоставим. Что происходит с foos.sort ()? Мы определенно не хотели бы, чтобы это работало только для примитивов

int[] ints; 
ints.sort(); //legal
Object[] objects;
objects.sort(); //illegal

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

 myarray.add(new Foo());

это бессмысленно, так как массивы в java не растут.

Было бы было бы хорошо, если бы распечатка массива не давала вам такой бесполезной

([I'm an array(*&(*

мусор, хотя.

3 голосов
/ 18 февраля 2009

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

До автобокса работа с примитивами и объектами была очень громоздкой.

Если бы массивы были объектами и могли быть автоматически упакованы (и обобщены!), Мы могли бы иметь что-то вроде

Array<Integer> myArray = new Integer[];
myArray.add(8);
int x = myArray[0];
....

или

Array<Class<? extends MyBaseObject>> myArray = {ExtendedObject.class}
ExtendedObject object = myArray[0].newInstance();
....
2 голосов
/ 18 февраля 2009

Да, я считаю, что для массивов должен быть определен API, отличный от того, который указан в самом языке. В частности, досадно, что Foo[] не реализует Iterable<Foo>. Да, я знаю, что это легко обернуть - но это раздражает, что ты должен.

.NET понимает это в основном правильно, с типом Array, который в основном предназначен для неуниверсального доступа, и различными универсальными интерфейсами, которые, как считается, реализуются фактическими массивами. Например:

IList<int> intList = new int[10];

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

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

Кроме того, разные люди называли массивы примитивами в этой теме. Хотя они, конечно, имеют особую обработку, они не определены как примитивы. Из спецификации языка , раздел 4.2 :

Тип примитива предопределен языком программирования Java и назван его зарезервированное ключевое слово (§3.9):

PrimitiveType:
        NumericType
        boolean

NumericType:
        IntegralType
        FloatingPointType

IntegralType: one of
        byte short int long char

FloatingPointType: one of
        float double
2 голосов
/ 18 февраля 2009

Прежде чем я отвечу за ДОЛЖНО, я расскажу вам о состоянии этой проблемы.

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

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

Единственный реальный интерфейс для массивов - это статический метод System.arrayCopy или статические методы Array. *, Которые наиболее эффективно копируют в / из массивов.

В ответ НАДО; это было решено, хотя стандарт был бы лучше, чем ответ: используйте ArrayList.

1 голос
/ 18 февраля 2009

Лично мне нравится идея, что все является объектом, и это уже было сделано, например, в Smalltalk. Однако последствия превращения всего, даже методов / функций в объект, очень далеко идущие (взгляните на smalltalk, чтобы понять, что я имею в виду). Быть последовательным в применении принципа «все является объектом» приводит к тому, что язык больше не похож на C (или Java).

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

Так что, чтобы ответить на вопрос СЛЕДУЕТ, я бы сказал нет, потому что Java с этим изменением больше не будет Java. Как уже отмечали другие, есть и другие классы, которые позволяют вам обрабатывать задачи, которые могли бы быть выполнены с массивом в C с использованием объектов в Java, но полностью избавиться от примитивных типов данных и массивов - задача, которую лучше оставить другому языку ИМХО.

1 голос
/ 18 февраля 2009

Я считаю, что это очень трудно реализовать без нарушения совместимости на многих уровнях.

  • JVM обрабатывает массивы немного иначе, чем другие объекты. Создание / инициализация отличается: конструктор не вызывается для одной вещи. Как бы вы хотели добавить новые методы? Если, добавив суперкласс, вы бы назвали его конструктором?
  • Массивы знают тип элемента во время выполнения, а обобщенные - нет. Если вы хотите добавить новый суперкласс для всех массивов (как вы предложили в оригинальном вопросе), вы бы сделали его универсальным? Также имейте в виду, что массивы в Java ковариантны, а дженерики - нет.
  • Массивы имеют фиксированный набор методов / полей, указанных в Спецификации языка Java (все методы из Объектов с явным именем в JLS, поле длины). Добавление новых участников может привести к поломке существующих клиентов в зависимости от этого. (то есть массивы не случайный класс)
  • Сериализация массива, вероятно, тоже будет затронута
  • Я уверен, что есть еще детали реализации, которые чрезвычайно усложнили бы это: - (
  • Программы, скомпилированные для работы с новыми методами, не будут работать на старых JVM. Что еще хуже, в зависимости от реализации программы, скомпилированные для старых JVM, могут не работать с измененными массивами на новых JVM.

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

1 голос
/ 18 февраля 2009

Это не ПЛОХАЯ идея. Дело в том, что это уже сделано на коллекциях. Попробуйте расширить ArrayList, если хотите сойти с ума.

0 голосов
/ 19 февраля 2009

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

int[] ints = {5, 4, 3, 2, 1};
System.out.println("ints= "+ints);
ints.sort();
System.out.println("after sort() ints= "+ints);
ints = ints.add(6);
System.out.println("after add(6) ints= "+ints);

Печать

ints= [5, 4, 3, 2, 1]
after sort() ints= [1, 2, 3, 4, 5]
after add(6) ints= [1, 2, 3, 4, 5, 6]

Это работает с Java 5 & 6, и компилятор и IDE справились с этим, как я и ожидал.

0 голосов
/ 18 февраля 2009

Для тех, кто пропустил предыдущий пост, который был закрыт. Некоторые другие примеры включают

int[] ints = {5,4,3,2,1};
ints.sort(); // instead of Arrays.sort(ints);
int pos = ints.indexOf(5); // instead of Arrays.asList(ints).indexOf(5); or ArraysUtils.indexOf(ints, 5);
ints.reverse(); // instead of Arrays.reverse(ints);
Array<Integer> array = ints; // cast to super class.
int length = array.getLength(); // instead of Array.getLength(array);
Object n = array.get(3); // instead of Array.get(array, 3);
array.set(3, 7); // instead of Array.set(array, 3, 7);
Object obj = array;
System.out.println(obj); // prints [5,4,7,2,1] instead of having to
// if (obj instanceof int[]) System.out.println(Array.toString((int[]) obj)); else if (....)

int[] ints2 = ints.copyOf(2);
int[] ints3 = ints.subArray(2,4);
ints.sort(myComparator);
List<Integer> list = ints.asList();
Set<Integer> set = ints.asSet();
long total = ints.sum();
double avg = int.average();
int max = ints.max();
int max2 = ints.max(myComparator);
http://commons.apache.org/lang/api/org/apache/commons/lang/ArrayUtils.html
int[] onemore = ints.add(8); // instead of ArrayUtils.add(ints, 8);
int[] moreInts = ints.addAll(ints2); // instead of ArraysUtils.addAll(ints, ints2);
int[] oneless = int.remove(3); // instead of ArrayUtils.remove(ints, 3);
Integer[] integers = int.toObject();
int[] intsAgain = integers.toPrimitive();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...