longitud y longitud () en Java

¿Por qué tenemos la longitud de una matriz como un atributo, array.length , y para String tenemos un método, str.length() ?

¿Hay alguna razón?

Permítanme primero resaltar tres maneras diferentes para un propósito similar.

lengtharrays ( int[] , double[] , String[] ) – para conocer la longitud de las matrices

length()String related Object ( String , StringBuilder , etc) – para conocer la longitud de la cadena

size()Objeto Collection ( ArrayList , Set , etc) – para conocer el tamaño de la Colección

Ahora olvídate de la length() considera solo la length y el size() .

length no es un método, por lo que tiene sentido que no funcione en los objetos. Solo funciona en arreglos.
size() su nombre lo describe mejor y como es un método, se usará en el caso de aquellos objetos que trabajan con colección (frameworks de colección) como dije allá arriba.

Ahora llega a la length() :
String no es una matriz primitiva (así que no podemos usar .length ) y tampoco una colección (así que no podemos usar .size() ) por eso también necesitamos una diferente que sea length() (mantener las diferencias y servir el propósito).

Como respuesta a ¿Por qué?
Me resulta útil, fácil de recordar y usar y amigable.

Un poco simplificado puedes pensar que las matrices son un caso especial y no clases ordinarias (un poco como primitivas, pero no). String y todas las colecciones son clases, de ahí los métodos para obtener tamaño, longitud o cosas similares.

Supongo que la razón en el momento del diseño fue el rendimiento. Si lo hubieran creado hoy, probablemente hayan encontrado algo así como clases de colección con respaldo de matriz.

Si alguien está interesado, aquí hay un pequeño fragmento de código para ilustrar la diferencia entre los dos en el código generado, primero la fuente:

 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()); } } 

Cortando de una manera la parte no tan importante del código de bytes, ejecutar javap -c en la clase da como resultado lo siguiente para las dos últimas líneas:

 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 

En el primer caso (20-25), el código solo pregunta a la JVM por el tamaño de la matriz (en JNI esto habría sido una llamada a GetArrayLength ()) mientras que en el caso String (28-35) necesita hacer una método de llamada para obtener la longitud.

A mediados de la década de 1990, sin buenos JIT y demás, hubiera matado por completo el rendimiento al tener solo el java.util.Vector (o algo similar) y no una construcción de lenguaje que realmente no se comportara como una clase, sino que fuera rápido. Por supuesto, pudieron haber enmascarado la propiedad como una llamada a método y manejarlo en el comstackdor, pero creo que habría sido aún más confuso tener un método en algo que no es una clase real.

Considerar:

 int[] myArray = new int[10]; String myString = "hello world!"; List myList = new ArrayList(); myArray.length // Gives the length of the array myString.length() // Gives the length of the string myList.size() // Gives the length of the list 

Es muy probable que las cadenas y matrices se diseñaron en diferentes momentos y, por lo tanto, terminaron usando diferentes convenciones. Una justificación es que, como Strings usa matrices internamente, se utilizó un método, length() , para evitar la duplicación de la misma información. Otra es que el uso de una length() método length() ayuda a enfatizar la inmutabilidad de las cadenas, aunque el tamaño de una matriz tampoco se puede modificar.

En última instancia, esta es solo una inconsistencia que evolucionó y que definitivamente se solucionaría si el lenguaje se rediseñara alguna vez desde cero. Hasta donde yo sé, no hay otros idiomas (C #, Python, Scala, etc.) que hagan lo mismo, por lo que es probable que se trate de un pequeño error que terminó como parte del lenguaje.

Obtendrá un error si utiliza el incorrecto de todos modos.

.length es una propiedad única de Java. Se usa para encontrar el tamaño de una matriz dimensional única.

.length() es un método. Se usa para encontrar la longitud de una String . Evita duplicar el valor.

En Java, una matriz almacena su longitud por separado de la estructura que contiene los datos. Cuando crea una matriz, especifica su longitud, y eso se convierte en un atributo definitorio de la matriz. No importa lo que le haga a una Matriz de longitud N (valores de cambio, cosas nulas, etc.), siempre será una Matriz de longitud N.

La longitud de una cadena es incidental; no es un atributo de la Cadena, sino un subproducto. Aunque las cadenas de Java son, de hecho, inmutables, si fuera posible cambiar su contenido, podría cambiar su longitud. Golpear el último carácter (si fuera posible) reduciría la longitud.

Entiendo que esta es una distinción excelente, y es posible que me voten a favor, pero es verdad. Si hago una Matriz de longitud 4, esa longitud de cuatro es una característica definitoria de la Matriz, y es verdadera independientemente de lo que contenga. Si hago una cadena que contenga “perros”, esa cadena tiene una longitud de 4 porque contiene cuatro caracteres.

Veo esto como una justificación para hacer uno con un atributo y el otro con un método. En verdad, puede ser una inconsistencia involuntaria, pero siempre tiene sentido para mí, y así es como lo he pensado.

Me enseñaron que para las matrices, la longitud no se recupera a través de un método debido al siguiente temor: los progtwigdores simplemente asignan la longitud a una variable local antes de ingresar un bucle (piense en un bucle donde el condicional usa la longitud de la matriz). supuestamente lo haría para recortar en las llamadas de función (y, por tanto, mejorar el rendimiento). El problema es que la longitud podría cambiar durante el ciclo, y la variable no lo haría.

Siempre que se crea una matriz, se especifica su tamaño. Entonces la longitud se puede considerar como un atributo de construcción. Para String, es esencialmente una matriz de caracteres. La longitud es una propiedad de la matriz de caracteres. No hay necesidad de poner longitud como un campo, porque no todo necesita este campo. http://www.programcreek.com/2013/11/start-from-length-length-in-java/

Solo quiero agregar algunas observaciones a la gran respuesta de Fredrik .

La especificación del lenguaje Java en la sección 4.3.1 indica

Un objeto es una instancia de clase o una matriz .

Así que la matriz tiene un papel muy especial en Java. Me pregunto por qué.

Se podría argumentar que el conjunto de implementación actual es / era importante para un mejor rendimiento. Pero que es una estructura interna, que no debe ser expuesta.

Por supuesto, pudieron haber enmascarado la propiedad como una llamada a método y manejarlo en el comstackdor, pero creo que habría sido aún más confuso tener un método en algo que no es una clase real.

Estoy de acuerdo con Fredrik en que una optimazación inteligente del comstackdor hubiera sido la mejor opción. Esto también resolvería el problema, que incluso si usa una propiedad para matrices, no ha resuelto el problema para cadenas y otros tipos de colecciones (inmutables), porque, por ejemplo, la string se basa en una matriz de caracteres como puede ver en el definición de clase de String :

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

Y no estoy de acuerdo con eso sería aún más confuso, porque array hereda todos los métodos de java.lang.Object .

Como ingeniero, realmente no me gusta la respuesta “Porque siempre ha sido así”. y deseó que hubiera una mejor respuesta. Pero en este caso parece ser.

tl; dr

En mi opinión, es un defecto de diseño de Java y no debería haberse implementado de esta manera.