Perché abbiamo la lunghezza di un array come attributo array.length, e per String abbiamo un metodo str.length(),?
C'è qualche motivo?
Perché abbiamo la lunghezza di un array come attributo array.length, e per String abbiamo un metodo str.length(),?
C'è qualche motivo?
Risposte:
Vorrei innanzitutto evidenziare tre modi diversi per uno scopo simile.
length- array ( int[], double[], String[]) - di conoscere la lunghezza degli array
length()- String oggetto correlato ( String, StringBuilder, ecc) - per conoscere la lunghezza della stringa
size()- Collezione Object ( ArrayList, Set, ecc) - per conoscere la dimensione della collezione
Ora dimentica di length()considerare solo lengthe size().
lengthnon è un metodo, quindi ha perfettamente senso che non funzioni sugli oggetti. Funziona solo su array.
size()il suo nome lo descrive meglio e poiché è un metodo, verrà utilizzato nel caso di quegli oggetti che lavorano con la raccolta (framework di raccolta) come ho detto sopra.
Ora vieni a length():
String non è un array primitivo (quindi non possiamo usarlo .length) e nemmeno una Collection (quindi non possiamo usarlo .size()) ecco perché ne abbiamo anche bisogno uno diverso che sia length()(mantieni le differenze e serve allo scopo).
Come risposta a Why?
Lo trovo utile, facile da ricordare e da usare e amichevole.
Un po 'semplificato puoi pensare che gli array siano un caso speciale e non classi ordinarie (un po' come le primitive, ma non). String e tutte le raccolte sono classi, da qui i metodi per ottenere dimensioni, lunghezza o cose simili.
Immagino che il motivo al momento del progetto fosse la performance. Se lo avessero creato oggi, probabilmente avrebbero inventato qualcosa come classi di raccolta supportate da array.
Se qualcuno è interessato, ecco un piccolo frammento di codice per illustrare la differenza tra i due nel codice generato, prima il sorgente:
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());
}
}
Tagliare un modo la parte non così importante del codice byte, eseguendo javap -cla classe risulta come segue per le ultime due righe:
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
Nel primo caso (20-25) il codice chiede semplicemente alla JVM la dimensione dell'array (in JNI questa sarebbe stata una chiamata a GetArrayLength ()) mentre nel caso String (28-35) deve fare un chiamata al metodo per ottenere la lunghezza.
A metà degli anni '90, senza un buon JIT e cose del genere, avrebbe ucciso totalmente le prestazioni avere solo java.util.Vector (o qualcosa di simile) e non un costrutto di linguaggio che non si comportava come una classe ma era veloce. Ovviamente avrebbero potuto mascherare la proprietà come una chiamata al metodo e gestirla nel compilatore, ma penso che sarebbe stato ancora più complicato avere un metodo su qualcosa che non è una vera classe.
Vectorse il linguaggio Java non avesse supporto per gli array?
Prendere in considerazione:
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
È molto probabile che stringhe e array siano stati progettati in tempi diversi e quindi abbiano finito per utilizzare convenzioni diverse. Una giustificazione è che, poiché le stringhe utilizzano gli array internamente length(), è stato utilizzato un metodo, per evitare la duplicazione delle stesse informazioni. Un altro è che l'uso di un metodo length()aiuta a enfatizzare l'immutabilità delle stringhe, anche se anche la dimensione di un array è immutabile.
In definitiva, questa è solo un'incoerenza che si è evoluta e che sarebbe sicuramente stata risolta se il linguaggio fosse mai stato ridisegnato da zero. Per quanto ne so, nessun altro linguaggio (C #, Python, Scala, ecc.) Fa la stessa cosa, quindi questo è probabilmente solo un piccolo difetto che è finito a far parte del linguaggio.
Riceverai comunque un errore se usi quello sbagliato.
In Java, un array memorizza la sua lunghezza separatamente dalla struttura che contiene effettivamente i dati. Quando crei un array, ne specifichi la lunghezza e questo diventa un attributo di definizione dell'array. Indipendentemente da ciò che fai a un array di lunghezza N (cambia i valori, annulla le cose, ecc.), Sarà sempre un array di lunghezza N.
La lunghezza di una stringa è casuale; non è un attributo della stringa, ma un sottoprodotto. Sebbene le stringhe Java siano di fatto immutabili, se fosse possibile cambiare il loro contenuto, potresti cambiare la loro lunghezza. Eliminare l'ultimo carattere (se possibile) ridurrebbe la lunghezza.
Capisco che questa sia una bella distinzione e potrei essere respinto per questo, ma è vero. Se creo un array di lunghezza 4, quella lunghezza di quattro è una caratteristica distintiva dell'array ed è vero indipendentemente da ciò che è contenuto all'interno. Se creo una stringa che contiene "cani", quella stringa è di lunghezza 4 perché contiene quattro caratteri.
Lo vedo come una giustificazione per fare uno con un attributo e l'altro con un metodo. In verità, potrebbe essere solo un'incoerenza involontaria, ma per me ha sempre senso, ed è sempre così che ci ho pensato.
Mi è stato insegnato che per gli array, la lunghezza non viene recuperata tramite un metodo a causa del seguente timore: i programmatori assegnerebbero semplicemente la lunghezza a una variabile locale prima di entrare in un ciclo (si pensi a un ciclo for in cui il condizionale utilizza la lunghezza dell'array). presumibilmente lo farebbe per ridurre le chiamate di funzione (e quindi migliorare le prestazioni). Il problema è che la lunghezza potrebbe cambiare durante il ciclo e la variabile no.
Ogni volta che viene creato un array, viene specificata la sua dimensione. Quindi la lunghezza può essere considerata un attributo di costruzione. Per String, è essenzialmente un array di caratteri. La lunghezza è una proprietà dell'array char. Non è necessario inserire la lunghezza come campo, perché non tutto ha bisogno di questo campo. http://www.programcreek.com/2013/11/start-from-length-length-in-java/
Voglio solo aggiungere alcune osservazioni alla grande risposta di Fredrik .
La specifica del linguaggio Java nella sezione 4.3.1 afferma
Un oggetto è un'istanza di classe o un array .
Quindi array ha davvero un ruolo molto speciale in Java. Mi chiedo perché.
Si potrebbe sostenere che l'attuale matrice di implementazione è / era importante per una migliore prestazione. Ma che è una struttura interna, che non dovrebbe essere esposta.
Ovviamente avrebbero potuto mascherare la proprietà come una chiamata al metodo e gestirla nel compilatore, ma penso che sarebbe stato ancora più complicato avere un metodo su qualcosa che non è una vera classe.
Sono d'accordo con Fredrik, che un'ottimizzazione intelligente del compilatore sarebbe stata la scelta migliore. Ciò risolverebbe anche il problema, che anche se usi una proprietà per gli array, non hai risolto il problema per le stringhe e altri tipi di raccolta (immutabili), perché, ad esempio, stringsi basa su un chararray come puoi vedere nella definizione della classe di String:
public final class String implements java.io.Serializable, Comparable<String>, CharSequence {
private final char value[]; // ...
E non sono d'accordo con il fatto che sarebbe ancora più confuso, perché array eredita tutti i metodi dajava.lang.Object .
Come ingegnere non mi piace davvero la risposta "Perché è sempre stato così". e desideravo che ci fosse una risposta migliore. Ma in questo caso sembra esserlo.
tl; dr
A mio parere, è un difetto di progettazione di Java e non avrebbe dovuto essere implementato in questo modo.