Eu estava trabalhando com um HashSet
outro dia, que tem isso escrito na especificação:
[add ()] adiciona o elemento especificado e a este conjunto se este conjunto não contiver nenhum elemento e2 tal que (e == null? e2 == null: e.equals (e2))
Eu estava usando char[]
no HashSet
até que percebi que, com base neste contrato, não era melhor do que um ArrayList
! Como ele está usando o não substituído .equals()
, minhas matrizes só serão verificadas quanto à igualdade de referência, o que não é particularmente útil. Eu sei que Arrays.equals()
existe, mas isso não ajuda quando alguém está usando coleções como HashSet
.
Então, minha pergunta é: por que as matrizes Java não substituem iguais?
java
language-design
array
Azar
fonte
fonte
n
slots de memória grandes o suficiente para cada um conter algum valor do tipoT
colado sequencialmente. Eles são os alicerces para coleções efêmeras mais sofisticadas. O que você queria eraList
.toString()
representação é praticamente inútil e quase não há vantagem em usar uma sobre umaArrayList
.Map<Key, int[]>
sempre pareceu natural. Mas eu sempre estou nervoso que há algo horrível esperando por mimRespostas:
Houve uma decisão de design a ser tomada desde o início em Java:
A resposta é: nem realmente ... ou ambos, se você olhar de outra maneira. Eles trabalham bastante próximos ao sistema em si e ao back-end da jvm.
Um exemplo disso é o método java.lang.System.arraycopy () que precisa ter uma matriz de qualquer tipo. Assim, a matriz precisa ser capaz de herdar algo e isso é um Objeto. E arraycopy é um método nativo.
Matrizes são também divertido em que eles podem segurar primitivas (
int
,char
,double
, etc ... enquanto as outras coleções só pode conter objetos. Olhe, por exemplo, na java.util.Arrays eo feio da iguala métodos. Este foi posto em como uma reflexão posterior deepEquals (Object [], Object []) não foi adicionado até 1,5, enquanto o restante da classe Arrays foi adicionado no 1.2.Porque esses objetos são matrizes , eles permitem que você faça algumas coisas que estão na memória ou quase no nível da memória - algo que o Java geralmente oculta do codificador. Isso permite que certas coisas sejam feitas mais rapidamente às custas de quebrar principalmente o modelo de objetos.
No início do sistema, houve uma troca entre flexibilidade e algum desempenho. O desempenho venceu e a falta de flexibilidade foi envolvida nas várias coleções. Matrizes em Java são um Objeto pouco implementado sobre um tipo primitivo (originalmente) destinado a trabalhar com o sistema quando você precisar.
Na maioria das vezes, matrizes brutas eram coisas que parece que os designers originais tentaram ignorar e esconder apenas no sistema. E eles queriam que fosse rápido (o Java inicial tinha alguns problemas com a velocidade). Era uma verruga no design de matrizes que não são boas matrizes, mas era necessária quando você queria expor algo o mais próximo possível do sistema. Aliás, as linguagens contemporâneas do Java inicial também têm essa verruga - não se pode fazer um
.equals()
no array do C ++.Java e C ++ seguiram o mesmo caminho para matrizes - uma biblioteca externa que executa as operações conforme necessário em matrizes em vez de matrizes ... e sugerindo que os codificadores usem tipos nativos melhores, a menos que realmente saibam o que estão fazendo e por que são. fazendo assim.
Portanto, a abordagem para implantar .equals em uma matriz está errada, mas é a mesma que os codificadores provenientes de C ++ conheciam. Portanto, escolha a coisa menos errada em termos de desempenho - deixe como a implementação de Objeto: dois Objetos são iguais se e somente se estiverem se referindo ao mesmo objeto.
Você precisa que a matriz seja uma estrutura primitiva para poder se comunicar com ligações nativas - algo o mais próximo possível da matriz C clássica. Mas, diferentemente das outras primitivas, você precisa que a matriz possa ser transmitida como referência e, portanto, como um Objeto. Portanto, é mais primitivo, com alguns hackers de objetos ao lado e algumas verificações de limites.
fonte
Em Java, matrizes são pseudo-objetos. As referências a objetos podem conter matrizes e eles têm os métodos Object padrão, mas são muito leves em comparação com uma coleção verdadeira. Arrays fazer apenas o suficiente para satisfazer o contrato de um objeto e usar as implementações padrão de
equals
,hashCode
etoString
deliberadamente.Considere um
Object[]
. Um elemento dessa matriz pode ser qualquer coisa que se encaixe em um objeto, que inclui outra matriz. Poderia ser um primitivo em caixa, um soquete, qualquer coisa. O que igualdade significa nesse caso? Bem, isso depende do que realmente está no array. Isso não é algo conhecido no caso geral quando o idioma estava sendo projetado. Igualdade é definida tanto pela própria matriz quanto pelo seu conteúdo .Essa é a razão pela qual existe uma
Arrays
classe auxiliar que possui métodos para calcular igualdade (incluindo valores profundos iguais), códigos de hash, etc. No entanto, esses métodos são bem definidos quanto ao que fazem. Se você precisar de uma funcionalidade diferente, escreva seu próprio método para comparar duas matrizes de igualdade com base nas necessidades do seu programa.Embora não seja uma resposta estrita à sua pergunta, acho relevante dizer que você realmente deve usar coleções em vez de matrizes. Apenas converta em uma matriz ao fazer interface com uma API que requer matrizes. Caso contrário, as coleções oferecem melhor segurança de tipo, contratos mais bem definidos e geralmente são mais fáceis de usar que as matrizes.
fonte
Arrays.equals()
profunda igualdade.A dificuldade fundamental com a substituição de matrizes
equals
é que uma variável de um tipo comoint[]
pode ser usada de pelo menos três maneiras fundamentalmente diferentes, e o significado deequals
deve variar dependendo do uso. Em particular, um campo do tipoint[]
...... pode encapsular uma sequência de valores em uma matriz que nunca será modificada, mas pode ser compartilhada livremente com o código que não a modifica.
... pode encapsular a propriedade exclusiva de um contêiner de retenção de número inteiro que pode ser alterado à vontade por seu proprietário.
... pode identificar um contêiner de retenção de número inteiro que alguma outra entidade está usando para encapsular seu estado e, assim, servir como uma conexão com o estado dessa outra entidade.
Se uma classe tiver um
int[]
campofoo
usado para qualquer um dos dois primeiros propósitos, instalex
ey
deverá considerarx.foo
ey.foo
como encapsular o mesmo estado se eles mantiverem a mesma sequência de números; se o campo for usado para a terceira finalidade, no entanto,x.foo
ey.foo
somente encapsulará o mesmo estado se eles identificarem a mesma matriz [isto é, são referência igual]. Se o Java incluísse tipos diferentes para os três usos acima e seequals
adotasse um parâmetro para identificar como a referência estava sendo usada, seria apropriadoint[]
usar a igualdade de sequência para os dois primeiros usos e a igualdade de referência para o terceiro. Contudo, não existe esse mecanismo.Observe também que o
int[]
caso era o tipo mais simples de matriz. Para matrizes que contêm referências a classes diferentesObject
ou tipos de matriz, haveria possibilidades adicionais.Uma referência a uma matriz imutável compartilhável que encapsula coisas que nunca mudarão.
Uma referência a uma matriz imutável compartilhável que identifica itens pertencentes a outras entidades.
Uma referência a uma matriz de propriedade exclusiva que encapsula referências a coisas que nunca mudarão.
Uma referência a uma matriz de propriedade exclusiva que encapsula referências a itens de propriedade exclusiva.
Uma referência a uma matriz de propriedade exclusiva que identifica itens pertencentes a outras entidades.
Uma referência que identifica uma matriz pertencente a alguma outra entidade.
Nos casos 1, 3 e 4, duas referências de matriz devem ser consideradas iguais se os itens correspondentes tiverem "valor igual". Nos casos 2 e 5, duas referências de matriz devem ser consideradas iguais se identificarem a mesma sequência de objetos. No caso 6, duas referências de matriz devem ser consideradas iguais apenas se identificarem a mesma matriz.
Para
equals
se comportar de maneira sensata com tipos agregados, eles precisam ter alguma maneira de saber como as referências serão usadas. Infelizmente, o sistema de tipos de Java não tem como indicar isso.fonte
Substituir array
equals()
ehashCode()
depender do conteúdo os tornaria semelhantes a coleções - tipos mutáveis com não constanteshashCode()
. Os tipos com alteraçãohashCode()
se comportam mal quando armazenados em tabelas de hash e outros aplicativos que dependem dehashCode()
valor fixo.Matrizes, por outro lado, têm hashCode trivial (), podem ser usadas como chaves de tabela de hash e ainda são mutáveis.
fonte
int[]
matriz de tipos.