comprimento e comprimento () em Java

88

Por que temos o comprimento de uma matriz como um atributo array.length, e para String temos um método str.length(),?

Existe algum motivo?

Nitish Upreti
fonte
3
Já foi discutido antes no CodeRanch. Veja a discussão aqui.
missingfaktor

Respostas:

98

Deixe-me primeiro destacar três maneiras diferentes para fins semelhantes.

length- matrizes ( int[], double[], String[]) - para saber o comprimento das matrizes

length()- Cadeia objecto relacionado ( String, StringBuilder, etc.) - a saber o comprimento da corda

size()- Objeto Coleção ( ArrayList, Set, etc.) - para saber o tamanho da coleção

Agora esqueça de length()considerar apenas lengthe size().

lengthnão é um método, portanto, faz todo o sentido que não funcione em objetos. Ele só funciona em matrizes.
size()seu nome o descreve melhor e por ser um método, ele será usado no caso daqueles objetos que trabalham com coleção (frameworks de coleção) como eu disse lá em cima.

Agora vamos para length():
String não é um array primitivo (então não podemos usar .length) e também não é uma Collection (então não podemos usar .size()), por isso também precisamos de um diferente que é length()(mantenha as diferenças e atenda ao propósito).

Como resposta a por quê?
Acho que é útil, fácil de lembrar e usar e amigável.

Saif
fonte
6
solução incrível!
Jeff Hu
27

Um pouco simplificado, você pode pensar nisso como arrays sendo um caso especial e não classes comuns (um pouco como primitivas, mas não). String e todas as coleções são classes, daí os métodos para obter tamanho, comprimento ou coisas semelhantes.

Eu acho que a razão na época do design era o desempenho. Se eles o criaram hoje, provavelmente teriam criado algo como classes de coleção baseadas em array.

Se alguém estiver interessado, aqui está um pequeno trecho de código para ilustrar a diferença entre os dois no código gerado, primeiro a fonte:

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

Cortar uma parte não tão importante do código de bytes, rodando javap -cna classe resulta no seguinte para as duas últimas linhas:

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

No primeiro caso (20-25), o código apenas pergunta ao JVM o tamanho do array (em JNI, isso seria uma chamada para GetArrayLength ()), enquanto no caso de String (28-35) ele precisa fazer um chamada de método para obter o comprimento.

Em meados dos anos 1990, sem bons JITs e outras coisas, teria matado totalmente o desempenho ter apenas o java.util.Vector (ou algo semelhante) e não uma construção de linguagem que realmente não se comportasse como uma classe, mas fosse rápida. Eles poderiam, é claro, ter mascarado a propriedade como uma chamada de método e manipulado no compilador, mas acho que seria ainda mais confuso ter um método em algo que não é uma classe real.

Fredrik
fonte
1
Java trata array como objetos e strings como objetos imutáveis ​​!! : |
Nitish Upreti
@Myth: Não vejo seu ponto ... A propriedade length dos arrays não é um campo público nem nada, é uma construção do jvm (arraylength é até uma operação no bytecode). É muito óbvio quando você faz JNI ou se você apenas desmonta o código de onde ele vem.
Fredrik
Não acho que o raciocínio do design original fosse apenas desempenho. Como você implementaria Vectorquando a linguagem Java não tivesse suporte a array?
Holger
8

.lengthé uma propriedade única de Java. É usado para encontrar o tamanho de uma única matriz dimensional .

.length()é um método. É usado para encontrar o comprimento de a String. Evita duplicar o valor.

Prabandha
fonte
8

Considerar:

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

É muito provável que strings e arrays tenham sido projetados em momentos diferentes e, portanto, acabaram usando convenções diferentes. Uma justificativa é que, como Strings usam arrays internamente, um método,, length()foi usado para evitar a duplicação das mesmas informações. Outra é que usar um método length()ajuda a enfatizar a imutabilidade das strings, embora o tamanho de uma matriz também seja imutável.

No final das contas, essa é apenas uma inconsistência que evoluiu e que definitivamente seria corrigida se a linguagem fosse redesenhada do zero. Até onde eu sei, nenhuma outra linguagem (C #, Python, Scala, etc.) faz a mesma coisa, então essa provavelmente é apenas uma pequena falha que acabou fazendo parte da linguagem.

Você obterá um erro se usar o errado de qualquer maneira.

Gordon Gustafson
fonte
Esta é uma resposta mais justificável e imparcial.
Zubair Alam
3

Em Java, um Array armazena seu comprimento separadamente da estrutura que realmente contém os dados. Ao criar um Array, você especifica seu comprimento, e isso se torna um atributo de definição do Array. Não importa o que você faça com um Array de comprimento N (alterar valores, anular coisas, etc.), sempre será um Array de comprimento N.

O comprimento de uma String é acidental; não é um atributo da String, mas um subproduto. Embora Java Strings sejam de fato imutáveis, se fosse possível alterar seu conteúdo, você poderia alterar seu comprimento. Eliminar o último caractere (se fosse possível) diminuiria o comprimento.

Eu entendo que esta é uma boa distinção e posso ser rejeitado a favor, mas é verdade. Se eu fizer um Array de comprimento 4, esse comprimento de quatro é uma característica definidora do Array, e é verdadeiro independentemente do que é mantido dentro. Se eu fizer uma String que contém "cachorros", essa String terá um comprimento 4 porque contém quatro caracteres.

Eu vejo isso como uma justificativa para fazer um com um atributo e outro com um método. Na verdade, pode ser apenas uma inconsistência não intencional, mas sempre fez sentido para mim e sempre foi assim que pensei sobre isso.

jakeboxer
fonte
2

Aprendi que, para arrays, o comprimento não é recuperado por meio de um método devido ao seguinte medo: os programadores apenas atribuem o comprimento a uma variável local antes de entrar em um loop (pense em um loop for em que a condicional usa o comprimento do array.) O programador supostamente faria isso para diminuir as chamadas de função (e assim melhorar o desempenho). O problema é que o comprimento pode mudar durante o loop, mas a variável não.

Mateus
fonte
10
O comprimento de uma matriz não pode mudar durante o loop.
Fredrik
2
você não pode alterar o comprimento dessa matriz específica, mas pode atribuir uma nova à mesma variável
Bozho
2
@Bozho: Verdadeiro, mas então é outro array e se você fizer isso intencionalmente e não atualizar o que quer que verifique seu loop, você tem um bug. Java nunca teve a intenção de impedir que você escrevesse bugs. Você pode fazer loops infinitos, recursão até morrer e todos os tipos de erros lógicos sem que o java tente impedi-lo. É uma boa razão para não armazenar o comprimento em uma variável, mas certamente não é a razão pela qual foi projetado dessa forma.
Fredrik
1

Sempre que uma matriz é criada, seu tamanho é especificado. Portanto, o comprimento pode ser considerado um atributo de construção. Para String, é essencialmente uma matriz char. O comprimento é uma propriedade da matriz char. Não há necessidade de colocar o comprimento como um campo, porque nem tudo precisa desse campo. http://www.programcreek.com/2013/11/start-from-length-length-in-java/

Ryan
fonte
0

Eu só quero acrescentar algumas observações à ótima resposta de Fredrik .

A especificação da linguagem Java na Seção 4.3.1 declara

Um objeto é uma instância de classe ou um array .

Portanto, array tem, de fato, um papel muito especial em Java. Eu me pergunto por quê.

Pode-se argumentar que o array de implementação atual é / foi importante para um melhor desempenho. Mas então é uma estrutura interna, que não deve ser exposta.

Eles poderiam, é claro, ter mascarado a propriedade como uma chamada de método e manipulado no compilador, mas acho que teria sido ainda mais confuso ter um método em algo que não é uma classe real.

Eu concordo com Fredrik, que uma otimização do compilador inteligente teria sido a melhor escolha. Isso também resolveria o problema, que mesmo se você usar uma propriedade para arrays, você não resolveu o problema para strings e outros tipos de coleção (imutáveis), porque, por exemplo, stringé baseado em um chararray como você pode ver na definição de classe de String:

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

E eu não concordo com isso seria ainda mais confuso, porque array herda todos os métodos dejava.lang.Object .

Como engenheiro, realmente não gosto da resposta "Porque sempre foi assim". e gostaria que houvesse uma resposta melhor. Mas, neste caso, parece que sim.

tl; dr

Na minha opinião, é uma falha de design do Java e não deveria ter sido implementado dessa forma.

Michael Dorner
fonte