Estaba trabajando con otro HashSet
el otro día, que tiene esto escrito en la especificación:
[add ()] agrega el elemento e especificado a este conjunto si este conjunto no contiene ningún elemento e2 tal que (e == null? e2 == null: e.equals (e2))
Yo estaba usando char[]
en el HashSet
hasta que me di cuenta de que, sobre la base de este contrato, no era mejor que una ArrayList
! Dado que está utilizando los no anulados .equals()
, mis matrices solo se verificarán para la igualdad de referencia, lo que no es particularmente útil. Sé que Arrays.equals()
existe, pero eso no ayuda cuando uno está usando colecciones como HashSet
.
Entonces mi pregunta es, ¿por qué las matrices Java no anulan iguales?
java
language-design
array
Azar
fuente
fuente
n
ranuras de memoria lo suficientemente grandes como para que cada una tenga algún valor de tipoT
pegado secuencialmente. Son los bloques de construcción para colecciones efímeras más sofisticadas. Lo que querías era unList
.toString()
representación es en su mayoría inútil, y casi no hay ninguna ventaja en usar una sobre unaArrayList
.Map<Key, int[]>
siempre se ha sentido natural. Pero siempre estoy nervioso de que haya algo horrible esperándomeRespuestas:
Hubo una decisión de diseño que tomar desde el principio en Java:
La respuesta es, tampoco realmente ... o ambas si lo miras de otra manera. Trabajan bastante estrechamente con el sistema en sí y el backend de la jvm.
Un ejemplo de esto es el método java.lang.System.arraycopy () que necesita tomar una matriz de cualquier tipo. Por lo tanto, la matriz necesita poder heredar algo y eso es un Objeto. Y arraycopy es un método nativo.
Las matrices son también divertido, ya que pueden contener primitivas (
int
,char
,double
, etc ... mientras que las otras colecciones sólo pueden contener objetos. Mira, por ejemplo, en java.util.Arrays y lo feo de los Iguales métodos. Este se puso en como un pensamiento posterior, deepEquals (Object [], Object []) no se agregó hasta 1.5 mientras que el resto de la clase Arrays se agregó en 1.2.Debido a que estos objetos son matrices , le permiten hacer algunas cosas en la memoria o cerca del nivel de memoria, algo que Java a menudo oculta del codificador. Esto permite que ciertas cosas se hagan más rápido a expensas de romper principalmente el modelo de objetos.
Al principio del sistema hubo una compensación entre flexibilidad y cierto rendimiento. El rendimiento ganó y la falta de flexibilidad se vio envuelta en varias colecciones. Las matrices en Java son un objeto poco implementado sobre un tipo primitivo (originalmente) destinado a trabajar con el sistema cuando lo necesita.
En su mayor parte, los arreglos en bruto fueron cosas que parece que los diseñadores originales intentaron ignorar y guardar solo en el sistema. Y querían que fuera rápido (los primeros Java tenían algunos problemas con la velocidad). Fue una verruga en el diseño que las matrices no son matrices agradables, pero era necesaria cuando se quería exponer algo lo más cerca posible del sistema. Para el caso, los lenguajes contemporáneos de los primeros Java también tienen esta verruga: no se puede hacer nada
.equals()
en la matriz de C ++.Java y C ++ tomaron la misma ruta para las matrices: una biblioteca externa que realiza las operaciones según sea necesario en las matrices en lugar de las matrices ... y sugiere a los codificadores que usen tipos nativos mejores a menos que realmente sepan lo que están haciendo y por qué lo hacen. haciéndolo de esa manera.
Por lo tanto, el enfoque de implantación de .equals en una matriz es incorrecto, pero es el mismo error que los codificadores procedentes de C ++ conocían. Por lo tanto, elija la cosa menos incorrecta en términos de rendimiento: déjelo como la implementación de Object: dos objetos son iguales si y solo se refieren al mismo objeto.
Necesita que la matriz sea una estructura primitiva como para poder comunicarse con enlaces nativos, algo lo más cercano posible a la matriz C clásica. Pero a diferencia de las otras primitivas, necesita que la matriz se pueda pasar como referencia y, por lo tanto, como un Objeto. Por lo tanto, es más primitivo con algunos hacks de objetos en el lateral y algunas comprobaciones de límites.
fuente
En Java, las matrices son pseudoobjetos. Las referencias a objetos pueden contener matrices, y tienen los métodos Object estándar, pero son muy livianos en comparación con una verdadera colección. Las matrices hacen lo suficiente para cumplir con el contrato de un elemento y utilizar las implementaciones por defecto de
equals
,hashCode
ytoString
deliberadamente.Considera una
Object[]
. Un elemento de esta matriz puede ser cualquier cosa que encaje en un objeto, que incluye otra matriz. Podría ser un primitivo en caja, un enchufe, cualquier cosa. ¿Qué significa igualdad en ese caso? Bueno, depende de lo que esté realmente en la matriz. Eso no es algo conocido en el caso general cuando se estaba diseñando el lenguaje. La igualdad se define tanto por la matriz en sí como por sus contenidos .Esta es la razón por la cual hay una
Arrays
clase auxiliar que tiene métodos para calcular la igualdad (incluyendo iguales profundos), códigos hash, etc. Sin embargo, esos métodos están bien definidos en cuanto a lo que hacen. Si necesita una funcionalidad diferente, escriba su propio método para comparar dos matrices de igualdad en función de las necesidades de su programa.Si bien no es estrictamente una respuesta a su pregunta, creo que es relevante decir que realmente debería usar colecciones en lugar de matrices. Solo convierta a una matriz cuando interactúe con una API que requiera matrices. De lo contrario, las colecciones ofrecen una mejor seguridad de tipos, contratos más bien definidos y, en general, son más fáciles de usar que las matrices.
fuente
Arrays.equals()
una igualdad profunda.La dificultad fundamental con la anulación de matrices
equals
es que una variable de un tipo comoint[]
se puede usar en al menos tres formas fundamentalmente diferentes, y el significado deequals
debe variar según el uso. En particular, un campo de tipoint[]
...... puede encapsular una secuencia de valores en una matriz que nunca se modificará, pero se puede compartir libremente con un código que no lo modificará.
... puede encapsular la propiedad exclusiva de un contenedor de números enteros que su propietario puede mutar a voluntad.
... puede identificar un contenedor de retención de enteros que otra entidad está utilizando para encapsular su estado y, por lo tanto, servir como una conexión con el estado de esa otra entidad.
Si una clase tiene un
int[]
campofoo
que se utiliza para cualquiera de los dos primeros propósitos, entonces instanciasx
yy
deben considerarx.foo
yy.foo
como encapsular el mismo estado si tienen la misma secuencia de números; si el campo se usa para el tercer propósito, entonces,x.foo
yy.foo
solo encapsularía el mismo estado si identificaran la misma matriz [es decir, son iguales de referencia]. Si Java hubiera incluido diferentes tipos para los tres usos anteriores, y si hubieraequals
tomado un parámetro que identificara cómo se estaba utilizando la referencia, entonces hubiera sido apropiadoint[]
usar la secuencia de igualdad para los dos primeros usos y la igualdad de referencia para el tercero. No existe tal mecanismo, sin embargo.Tenga en cuenta también que el
int[]
caso era el tipo más simple de matriz. Para las matrices que contienen referencias a clases distintasObject
o tipos de matriz, habría posibilidades adicionales.Una referencia a una matriz inmutable que se puede compartir que encapsula cosas que nunca cambiarán.
Una referencia a una matriz inmutable que se puede compartir que identifica cosas que pertenecen a otras entidades.
Una referencia a una matriz de propiedad exclusiva que encapsula referencias a cosas que nunca cambiarán.
Una referencia a una matriz de propiedad exclusiva que encapsula referencias a elementos de propiedad exclusiva.
Una referencia a una matriz de propiedad exclusiva que identifica cosas pertenecientes a otras entidades.
Una referencia que identifica una matriz propiedad de otra entidad.
En los casos 1, 3 y 4, dos referencias de matriz deben considerarse iguales si los elementos correspondientes son "iguales en valor". En los casos 2 y 5, dos referencias de matriz deben considerarse iguales si identifican la misma secuencia de objetos. En el caso 6, dos referencias de matriz deben considerarse iguales solo si identifican la misma matriz.
Para
equals
comportarse con sensatez con los tipos agregados, necesitan tener alguna forma de saber cómo se utilizarán las referencias. Desafortunadamente, el sistema de tipos de Java no tiene forma de indicar eso.fuente
Anular la matriz
equals()
yhashCode()
depender del contenido los haría similares a las colecciones, tipos mutables con no constantehashCode()
. Los tipos con cambios sehashCode()
comportan mal cuando se almacenan en tablas hash y otras aplicaciones que dependen dehashCode()
un valor fijo.Las matrices, por otro lado, tienen trivial hashCode (), se pueden usar como claves de tabla hash y aún son mutables.
fuente
int[]
tipo de matriz.