длина и длина () в Java

Почему у нас есть длина массива как атрибут, array.length, и для Строки у нас есть метод, str.length()?

Есть ли некоторая причина?

85
задан Peter Mortensen 8 February 2018 в 18:21
поделиться

3 ответа

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

1
ответ дан 24 November 2019 в 08:20
поделиться

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

Длина Строки случайна; это не атрибут Строки, а побочный продукт. Хотя Java-строки на самом деле незыблемы, если бы можно было изменить их содержимое, то можно было бы изменить их длину. Отсечение последнего символа (если бы это было возможно) уменьшило бы длину.

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

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

.
2
ответ дан 24 November 2019 в 08:20
поделиться

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

Наверное, причиной в момент проектирования было исполнение. Если бы они создали ее сегодня, то, наверное, придумали что-то вроде классов коллекций, поддерживаемых массивами.

Если кому-то интересно, то вот небольшой фрагмент кода, иллюстрирующий разницу между ними в сгенерированном коде, сначала исходный текст:

public class LengthTest {
  public static void main(String[] args) {
    int[] array = {12,1,4};
    String string = "Hoo";
    System.out.println(array.length);
    System.out.println(string.length());
  }
}

Вырезая не очень важную часть байтового кода, запустив javap -c по классу, вы получите следующие результаты для двух последних строк:

20: getstatic   #3; //Field java/lang/System.out:Ljava/io/PrintStream;
23: aload_1
24: arraylength
25: invokevirtual   #4; //Method java/io/PrintStream.println:(I)V
28: getstatic   #3; //Field java/lang/System.out:Ljava/io/PrintStream;
31: aload_2
32: invokevirtual   #5; //Method java/lang/String.length:()I
35: invokevirtual   #4; //Method java/io/PrintStream.println:(I)V

В первом случае (20-25) код просто запрашивает у JVM размер массива (в JNI это был бы вызов GetArrayLength()), в то время как в случае String (28-35) для получения длины необходимо выполнить вызов метода.

В середине 1990-х, без хороших JIT и прочего, это полностью убило бы производительность, если бы у него был только java.util.Vector (или что-то подобное), а не языковая конструкция, которая на самом деле вела себя не как класс, а была бы быстрой. Конечно, они могли бы замаскировать это свойство под вызов метода и обработать его в компиляторе, но я думаю, что было бы еще более запутанным иметь метод на чем-то, что не является настоящим классом

.
25
ответ дан 24 November 2019 в 08:20
поделиться
Другие вопросы по тегам:

Похожие вопросы: