2009-12-27 2 views
70

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

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

+3

Ранее обсуждался в CodeRanch. См. Обсуждение [здесь.] (Http://www.coderanch.com/t/383558/Java-General/java/String-length-vs-Arrays-length) – missingfaktor

ответ

23

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

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

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

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()), тогда как в th e Строковый регистр (28-35) необходимо выполнить вызов метода для получения длины.

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

+1

Java обрабатывает массив как объекты и строки как неизменные объекты !! : | –

+0

@Myth: я не вижу вашей точки ... Свойство length массивов не является публичным полем или чем-то еще, это конструкция jvm (arraylength - это даже операция в байт-коде). Это очень очевидно, когда вы делаете JNI или просто разбираете код, из которого он поступает. – Fredrik

2

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

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

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

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

1

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

+0

Хорошая точка ..... – Zaki

+10

Длина массива не может меняться во время цикла. – Fredrik

+2

вы не можете изменить длину этого конкретного массива, но вы можете назначить новую одну ту же переменную – Bozho

5

Рассмотрим:

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 

Это очень вероятно, что строки и массивы были разработаны в разное время и, следовательно, в конечном итоге, используя различные соглашения. Одно из обоснований состоит в том, что, поскольку строки используют внутренние массивы, метод, length(), использовался для предотвращения дублирования одной и той же информации. Другое заключается в том, что использование метода length() помогает подчеркнуть неизменность строк, даже если размер массива также неизменен.

В конечном счете это просто несогласованность, которая возникла бы, что определенно было бы исправлено, если бы язык был перепроектирован с нуля. Насколько я знаю, никакие другие языки (C#, Python, Scala и т. Д.) Не делают то же самое, так что это, вероятно, просто небольшой недостаток, который оказался частью языка.

Вы получите сообщение об ошибке, если используете какой-либо другой вариант.

+0

Это более оправданный и непредвзятый ответ. –

0

Всякий раз, когда создается массив, его размер указан. Таким образом, длину можно рассматривать как атрибут конструкции. Для String это по существу массив символов. Длина - это свойство массива char. Нет необходимости ставить длину как поле, потому что не все нуждается в этом поле. http://www.programcreek.com/2013/11/start-from-length-length-in-java/

72

Позвольте мне вначале выделить три разных способа для аналогичной цели.

length - массивы (int[], double[], String[]) - знать длину массивов

length() - строковых объектов (String, StringBuilder и т.д.) - знать длина строки

size() - Коллекция объектов (ArrayList, Set и т.д.) - знать размер коллекции

Сейчас забудьте о length() рассмотрите только length и size().

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

Теперь пришел length():
Строка не примитивный массив (поэтому мы не можем использовать .length), а также не коллекция (так что мы не можем использовать .size()), поэтому мы также нужен другой тот, который length() (соблюдайте различия и выполняйте эту задачу).

Как ответ на вопрос Почему?
Я считаю это полезным, легко запоминающимся и используемым и дружественным.

+2

Удивительное решение! –

6

.length - одноразовая собственность Java.Он используется для определения размера одномерного массива .

.length() - это метод. Он используется для определения длины String. Это позволяет избежать дублирования значения.

-1

Я просто хочу добавить несколько замечаний к замечательному answer по Fredrik.

В Java Language Specification in Section 4.3.1 состоянии

An объект является экземпляром класса или массива.

Так что массив действительно играет особую роль в Java. Я действительно удивляюсь, почему.

Можно утверждать, что текущий массив реализации является важным для лучшей производительности. Но это внутренняя структура, которую не следует раскрывать.

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

Я согласен с Фредриком в том, что оптимальный выбор оптимального компилятора был бы лучшим выбором. Это также решит проблему: даже если вы используете свойство для массивов, вы не решили проблему для строк и других (неизменяемых) типов коллекций, потому что, например, string основан на массиве char, как вы можете видеть на класс определение String:

public final class String implements java.io.Serializable, Comparable<String>, CharSequence {   
    private final char value[]; // ... 

И я не согласен с тем, что было бы еще более запутанным, поскольку массив имеет наследовать all methods from java.lang.Object.

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

Т.Л., д-р

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

Смежные вопросы