Почему у нас есть длина массива в качестве атрибута. array.length
, а для String - метод str.length()
?
Просто я пришел в голову, есть ли какая-то причина?
Почему у нас есть длина массива в качестве атрибута. array.length
, а для String - метод str.length()
?
Просто я пришел в голову, есть ли какая-то причина?
Позвольте мне вначале выделить три разных способа для аналогичной цели.
length
- массивы (int[]
, double[]
, String[]
) - знать длину массивов
length()
- Связанный с строкой объект (String
, StringBuilder
и т.д.) - знать длину строки
size()
- Объект коллекции (ArrayList
, Set
и т.д.) - знать размер коллекции
Теперь забудьте о length()
рассмотреть только length
и size()
.
length
не является методом, поэтому вполне понятно, что он не будет работать на объектах. Он работает только на массивах. size()
его имя описывает его лучше, и поскольку это метод, он будет использоваться в случае тех объектов, которые работают с коллекцией (фреймворками коллекции), как я уже сказал там.
Теперь переходите к length()
:
Строка не является примитивным массивом (поэтому мы не можем использовать .length
), а также не коллекцию (поэтому мы не можем использовать .size()
), поэтому нам также нужен другой, который является length()
(сохраняйте различия и подавайте цель).
Как ответ на Почему?
Я считаю, что это полезно, легко запомнить и использовать и дружелюбно.
Немного упрощенная, вы можете думать об этом как о массивах, которые являются особым случаем, а не обычными классами (немного похожими на примитивы, но нет). Строка и все коллекции являются классами, поэтому методы получения размера, длины или аналогичных вещей.
Я предполагаю, что причиной на момент разработки была производительность, если они создали ее сегодня, они, вероятно, придумали что-то вроде массивов, основанных на массивах.
Если кому-то интересно, вот небольшой фрагмент кода, иллюстрирующий разницу между двумя в сгенерированном коде, сначала источник:
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) ему нужно для вызова метода для получения длины.
В середине 90-х годов, без хороших JIT и т.д., он бы полностью уничтожил производительность, чтобы иметь только java.util.Vector(или что-то подобное), а не конструкцию языка, которая на самом деле не вела себя как класс, но была быстро. Разумеется, они могли маскировать свойство как вызов метода и обрабатывать его в компиляторе, но я думаю, что было бы еще более запутанным иметь метод для чего-то, что не является реальным классом.
.length
- одноразовое свойство Java. Он использовал для определения размера одномерного массива .
.length()
- это метод. Он использовал для нахождения длины String
. Это позволяет избежать дублирования значения.
int[] myArray = new int[10];
String myString = "hello world!";
List<int> myList = new ArrayList<int>();
myArray.length //gives the length of the array
myString.length() //gives the length of the string
myList.size() //gives the length of the list
Скорее всего, строки и массивы были спроектированы в разное время и, следовательно, были использованы в разных соглашениях. Одно из обоснований заключается в том, что, поскольку в Strings используются внутренние массивы, метод length()
использовался во избежание дублирования одной и той же информации. Другим является то, что использование метода length()
помогает подчеркнуть неизменность строк, даже если размер массива также неизменен.
В конечном счете это просто непоследовательно, что эволюционировало, что определенно было бы исправлено, если бы язык был перепроектирован с нуля. Насколько я знаю, никакие другие языки (С#, python, scala и т.д.) Не делают то же самое, так что это скорее всего небольшой недостаток, который оказался частью языка.
Вы получите сообщение об ошибке, если в любом случае вы используете неверный.: P: D
В Java массив хранит свою длину отдельно от структуры, которая фактически хранит данные. Когда вы создаете массив, вы указываете его длину и становится определяющим атрибутом массива. Независимо от того, что вы делаете с массивом длины N (значения изменения, нулевые значения и т.д.), Он всегда будет массивом длины N.
Длина строки является случайной; это не атрибут String, а побочный продукт. Хотя Java-строки на самом деле неизменяемы, если бы можно было изменить их содержимое, вы могли бы изменить их длину. Сбрасывание последнего символа (если это было возможно) уменьшило бы длину.
Я понимаю, что это прекрасное различие, и я могу проголосовать за него, но это правда. Если я делаю массив длиной 4, эта длина 4 является определяющей характеристикой массива и истинна независимо от того, что удерживается внутри. Если я создаю строку, содержащую "собак", эта строка имеет длину 4, потому что она содержит четыре символа.
Я рассматриваю это как оправдание для того, чтобы сделать одно с атрибутом, а другое - с помощью метода. По правде говоря, это может быть непреднамеренная несогласованность, но это всегда имело смысл для меня, и это всегда так, как я думал об этом.
Мне научили, что для массивов длина не извлекается методом из-за следующего страха: программисты просто назначили длину локальной переменной перед входом в цикл (подумайте о цикле for, где условное использует длину массива. ) Программист предположительно сделает это, чтобы обрезать вызовы функций (и тем самым повысить производительность). Проблема в том, что длина может измениться во время цикла, а переменная не будет.
Всякий раз, когда создается массив, его размер задается. Таким образом, длину можно рассматривать как атрибут конструкции. Для String это по существу массив char. Длина является свойством массива char. Нет необходимости ставить длину как поле, потому что не все нуждается в этом поле. http://www.programcreek.com/2013/11/start-from-length-length-in-java/
Я просто хочу добавить несколько замечаний к замечанию Фредрик.
Спецификация языка Java в разделе 4.3.1 утверждает
Объект - это экземпляр класса или массив.
Итак, массив действительно играет особую роль в Java. Я действительно удивляюсь, почему.
Можно утверждать, что текущий массив реализации является/имеет важное значение для лучшей производительности. Но это внутренняя структура, которую не следует раскрывать.
Они могли бы, конечно, замаскировать свойство как вызов метода и обработать его в компиляторе, но я думаю, что было бы еще более запутанным иметь метод для чего-то, что не является реальным классом.
Я согласен с Fredrik, что лучший выбор для оптимизатора компилятора. Это также решит проблему: даже если вы используете свойство для массивов, вы не решили проблему для строк и других (неизменяемых) типов коллекций, потому что, например, string
основывается на массиве char
, поскольку вы можно увидеть в определении класса string
:
public final class String implements java.io.Serializable, Comparable<String>, CharSequence {
private final char value[]; // ...
И я не согласен с тем, что это будет еще более запутанным, потому что массив наследует все методы из java.lang.Object
.
Как инженер, мне действительно не нравится ответ "Потому что это всегда было так". и пожелал бы лучшего ответа. Но в этом случае это похоже.
TL;DR
По-моему, это дизайнерский недостаток Java и не должен реализовываться таким образом.