Где определено свойство длины массива?

263

Мы можем определить продолжительность ArrayList<E>использования его открытого метода size(), например

ArrayList<Integer> arr = new ArrayList(10);
int size = arr.size();

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

String[] str = new String[10];
int size =  str.length;

Тогда как size()метод класса ArrayListопределен внутри ArrayListкласса, где определено это lengthсвойство Array?

простофиля
источник
С точки зрения организации вопросов, я бы предложил поставить ваш вопрос "где определено свойство длины массива?" перед всеми объяснениями, чтобы ваш пост не звучал как учебник для начинающих.
NoName

Ответы:

250

Массивы - это специальные объекты в Java, у них есть простой атрибут, lengthкоторый называетсяfinal .

Не существует «определения класса» массива (вы не можете найти его ни в одном файле .class), они являются частью самого языка.

10,7. Члены массива

Членами типа массива являются все следующие:

  • public finalПоле length, которое содержит число компонентов массива. lengthможет быть положительным или нулевым.
  • Не publicметод clone, который переопределяет метод того же имени в классе Objectи броски не проверяемые исключения. Тип возвращаемого значения cloneметода типа массива T[]являетсяT[] .

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

  • Все члены унаследованы от класса Object; единственный метод, Objectкоторый не наследуется, это его cloneметод.

Ресурсы:

Колин Хеберт
источник
84
Также обратите внимание, что в нем ArrayList.size()указывается номер объекта, фактически сохраненного в массиве, а myArray.length( []) - «емкость». То есть, если для myArray = new int[10];, он возвращает 10. Это не количество объектов, которые вы поместили в массив.
wmorrison365
1
@Colin Как объекты массива настолько особенные, я имею в виду, почему дизайнеры должны сделать его особенным, и почему бы не предоставить файл класса массива?
Викас Верма
5
@VikasVerma Почему массивы не похожи на объекты? Из-за истории. Когда разрабатывался Java, большинство попыток языковых инноваций проваливались, если не были похожи на C по синтаксису и стилю. Таким образом, C ++, Objective-C и Java были одними из немногих языков, которые избежали мрака в ту эпоху. Java была сознательно разработана для включения фигурных скобок, примитивов и простых массивов, чтобы они казались знакомыми обычным программистам того времени. Смотрите интервью с Джеймсом Гослингом и другими людьми из Sun. Некоторые люди придерживаются Коллекций для чистого ООП и избегают простых массивов.
Базилик Бурк
1
@VikasVerma, в какой-то момент, Java должна быть построена на технологии более низкого уровня. Если Java не существует, вы не можете построить его с помощью Java. Вы должны использовать C ++ (или что-то еще, кроме C ++ в этом случае), чтобы построить некоторую примитивную компиляцию, чтобы остальная часть java имела контекст для своего собственного существования. Вы не можете иметь классы для всего, не в конечном итоге достигнув предела, где вы кодируете его на C ++. Как именно вы построите массив в Java? Если вы не можете использовать, Listпотому что он использует массивы в своих реализациях.
Александр Берд
если вы хотите ответить на него как есть , то stackoverflow.com/a/50506451/1059372
Евгений
114

Это «специальный» в основном, со своей инструкцией байткода: arraylength. Итак, этот метод:

public static void main(String[] args) {
    int x = args.length;
}

компилируется в байт-код следующим образом:

public static void main(java.lang.String[]);
  Code:
   0:   aload_0
   1:   arraylength
   2:   istore_1
   3:   return

Так что это не так, как если бы это было нормальное поле. В самом деле, если вы попытаетесь получить его так, как если бы оно было нормальным полем, например, это не сработает:

// Fails...
Field field = args.getClass().getField("length");
System.out.println(field.get(args));

Так что, к сожалению, описание JLS каждого типа массива, имеющего открытое конечное поле length, несколько вводит в заблуждение :(

Джон Скит
источник
1
Я точно не помню цитату Альберта Эйнштейна, но то, что она говорит, это то, что «люди понимают что-то очень хорошо, могут объяснить вещи только очень простым способом», я думаю, что это вас очень устраивает :)
JAVA
@Jon Skeet Как объект массива особенный Я имею в виду, почему дизайнеры должны сделать его особенным, и почему бы не предоставить файл класса массива?
Викас Верма
2
@VikasVerma: подумайте о размере объекта массива. Все другие типы имеют фиксированный размер - каждый экземпляр имеет одинаковый размер, тогда как массивы варьируются в зависимости от их длины. Это только один пример. Если вы думаете, что могли бы достичь тех же результатов, не используя ничего особенного, как вы думаете, как будут выглядеть поля класса массива? Как бы вы представляли, int[]когда дженерики не применяются к примитивным типам? (И, черт возьми, дженерики в любом случае долгое время не существовали.) Вы можете обойтись без массивов, используя связанные списки для всех коллекций, но это было бы ужасно для эффективности.
Джон Скит
@JonSkeet Но как насчет типа класса StringBuffer, который также имеет фиксированный размер? Да, действительно, я думал о дженериках, но вы указали, прежде чем я спросил спасибо за это.
Викас Верма
@VikasVerma: StringBufferДа, сам класс - да, потому что он содержит ссылку на a char[](или, по крайней мере, сделал; я не знаю, сохранил ли он до сих пор). Таким образом, хотя a StringBuilderотвечает за больший объем памяти, ее непосредственный размер и расположение фиксированы.
Джон Скит
18

Это определено в спецификации языка Java :

Членами типа массива являются все следующие:

  • public finalПоле length, которое содержит число компонентов массива. lengthможет быть положительным или нулевым.

Поскольку существует неограниченное количество типов массивов (для каждого класса есть соответствующий тип массива, а затем существуют многомерные массивы), они не могут быть реализованы в файле класса; JVM должна делать это на лету.

Майкл Боргвардт
источник
15

Даже если это не прямой ответ на вопрос, это дополнение к аргументу .lengthпротив .size(). Я исследовал что-то, связанное с этим вопросом, поэтому, когда я столкнулся с этим, я заметил, что определение (я) предоставлено здесь

Публичная конечная длина поля, которая содержит количество компонентов массива .

не "точно" правильно.

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

Распределение памяти массива

Пример:

static class StuffClass {
    int stuff;
    StuffClass(int stuff) {
        this.stuff = stuff;
    }
}

public static void main(String[] args) {

    int[] test = new int[5];
    test[0] = 2;
    test[1] = 33;
    System.out.println("Length of int[]:\t" + test.length);

    String[] test2 = new String[5];
    test2[0] = "2";
    test2[1] = "33";    
    System.out.println("Length of String[]:\t" + test2.length);

    StuffClass[] test3 = new StuffClass[5];
    test3[0] = new StuffClass(2);
    test3[1] = new StuffClass(33);
    System.out.println("Length of StuffClass[]:\t" + test3.length);         
}

Вывод:

Length of int[]:        5
Length of String[]:     5
Length of StuffClass[]: 5

Тем не менее, .size()свойство ArrayListдействительно дает количество элементов в списке:

ArrayList<Integer> intsList = new ArrayList<Integer>();
System.out.println("List size:\t" + intsList.size());
intsList.add(2);
System.out.println("List size:\t" + intsList.size());
intsList.add(33);
System.out.println("List size:\t" + intsList.size());

Вывод:

List size:  0
List size:  1
List size:  2
nem035
источник
1
Это правильно, так как все элементы инициализируются нулями. Массивы не могут быть «пустыми»
Гвидо
Ну, это именно то, что я сказал. Это не совсем точно. Он по-прежнему имеет длину 5, хотя в массив ничего не добавлено. Таким образом, он не «точно» содержит количество элементов в массиве. Ваш комментарий является лишь дополнением к моему ответу, а не причиной, чтобы сделать его неправильным.
nem035
Это может быть «неправильно», если вы попытаетесь провести различие между nullненулевыми элементами. Но различие не работает. В конце концов, size()of (скажем) Listможет также включать nullзначения.
Стивен С
Да, по сути, моя точка зрения заключалась в том, что sizeведет себя динамически, в то время как lengthявляется статическим свойством ... тот факт, что оставшееся незаполненное пространство в массиве инициализируется как " Не значения " (в зависимости от типа), на самом деле не противоречит этой точке.
nem035
5

это открытое конечное поле, которое содержит количество компонентов массива (длина может быть положительной или нулевой)

Таким образом, массив имеет те же открытые поля и методы, что и следующий класс:

class A implements Cloneable, java.io.Serializable {
    public final int length = X;
    public Object clone() {
        try {
            return super.clone();
        } catch (CloneNotSupportedException e) {
            throw new InternalError(e.getMessage());
        }
    }
}

больше информации на

10.7 Члены массива

http://java.sun.com/docs/books/jls/second_edition/html/arrays.doc.html

Массимилиано Пелусо
источник
0

Чтобы ответить, как есть, где определено это свойство длины массива ? В специальномObject header .

Легко увидеть с помощью JOL

 int [] ints = new int[23];
 System.out.println(ClassLayout.parseInstance(ints).toPrintable());

Одна из строк этого вывода будет:

OFFSET  SIZE      TYPE DESCRIPTION
16       4        (object header)   17 00 00 00 (00010111 00000000 00000000 00000000) (23)

Обычно объекты имеют два заголовка (mark и klass), у массивов есть еще один, который всегда занимает 4 bytesдлину, как sizeи a int.

Евгений
источник
-1

Длина ключевого слова действует как определенная область данных. При использовании в массиве мы можем использовать его для доступа к количеству элементов в массиве. Что касается String [], мы можем вызвать метод length (), определенный в классе String. Что касается ArrayList, мы можем использовать метод size (), определенный в ArrayList. Обратите внимание, что при создании списка массивов с помощью ArrayList <> (acity) начальный размер () этого списка массивов равен нулю, так как элемента нет.

Сяоган
источник