Pergunta

Você vê algum problema com o uso de uma matriz de bytes como chave do Mapa? Eu também poderia fazer new String(byte[]) e haxixe por String mas é mais simples de usar byte[].

Foi útil?

Solução

O problema é que a identidade usos byte[] objeto para equals e hashCode, de modo que

byte[] b1 = {1, 2, 3}
byte[] b2 = {1, 2, 3}

não irá corresponder em uma HashMap. Vejo três opções:

  1. Embrulho em um String, mas então você tem que ter cuidado sobre a codificação problemas (você precisa ter certeza de que o byte -> String -> byte dá-lhe os mesmos bytes).
  2. Use List<Byte> (pode ser caro na memória).
  3. Faça a sua própria classe de embrulho, escrevendo hashCode e equals de usar o conteúdo da matriz de bytes.

Outras dicas

Está tudo bem, desde que você só deseja igualdade de referência para a sua chave - matrizes não implementar "valor igualdade" na maneira que você provavelmente gostaria. Por exemplo:

byte[] array1 = new byte[1];
byte[] array2 = new byte[1];

System.out.println(array1.equals(array2));
System.out.println(array1.hashCode());
System.out.println(array2.hashCode());

imprime algo como:

false
1671711
11394033

(Os números reais são irrelevantes;. O fato de que eles são diferentes é importante)

Assumindo que você realmente quer a igualdade, eu sugiro que você criar o seu próprio invólucro que contém um byte[] e implementos igualdade e código hash geração apropriadamente:

public final class ByteArrayWrapper
{
    private final byte[] data;

    public ByteArrayWrapper(byte[] data)
    {
        if (data == null)
        {
            throw new NullPointerException();
        }
        this.data = data;
    }

    @Override
    public boolean equals(Object other)
    {
        if (!(other instanceof ByteArrayWrapper))
        {
            return false;
        }
        return Arrays.equals(data, ((ByteArrayWrapper)other).data);
    }

    @Override
    public int hashCode()
    {
        return Arrays.hashCode(data);
    }
}

Note que se você alterar os valores dentro da matriz de bytes depois de usar o ByteArrayWrapper, como uma chave em um HashMap (etc) você terá problemas olhando para cima a tecla novamente ... você poderia tirar uma cópia dos dados em o construtor ByteArrayWrapper se quiser, mas obviamente que vai ser um desperdício de desempenho se você sabe que você não estar mudando o conteúdo da matriz de bytes.

EDIT: Como mencionado nos comentários, você também pode usar ByteBuffer para este (em particular, a sua ByteBuffer#wrap(byte[]) método). Eu não sei se é realmente a coisa certa, dadas todas as habilidades extras que ByteBuffers têm que você não precisa, mas é uma opção.

Podemos utilizar para este ByteBuffer (Isto é, basicamente, o invólucro byte [] com um comparador)

HashMap<ByteBuffer, byte[]> kvs = new HashMap<ByteBuffer, byte[]>();
byte[] k1 = new byte[]{1,2 ,3};
byte[] k2 = new byte[]{1,2 ,3};
byte[] val = new byte[]{12,23,43,4};

kvs.put(ByteBuffer.wrap(k1), val);
System.out.println(kvs.containsKey(ByteBuffer.wrap(k2)));

irá imprimir

true

Você pode usar java.math.BigInteger. Tem um construtor BigInteger(byte[] val). É um tipo de referência, de modo que poderia ser usado como uma chave para hashtable. E .equals() e .hashCode() são definidos como para os respectivos números inteiros, o que significa que tem BigInteger equals semântica consistentes como byte [] matriz.

Estou muito surpreso que as respostas não estão apontando a alternativa mais simples.

Sim, não é possível usar um HashMap, mas ninguém o impede de usar um SortedMap como alternativa. A única coisa é escrever um comparador que precisa para comparar as matrizes. Não é tão alto desempenho como um HashMap, mas se você quiser uma alternativa simples, aqui vai (você pode substituir SortedMap com o mapa se você quiser esconder a implementação):

 private SortedMap<int[], String>  testMap = new TreeMap<>(new ArrayComparator());

 private class ArrayComparator implements Comparator<int[]> {
    @Override
    public int compare(int[] o1, int[] o2) {
      int result = 0;
      int maxLength = Math.max(o1.length, o2.length);
      for (int index = 0; index < maxLength; index++) {
        int o1Value = index < o1.length ? o1[index] : 0;
        int o2Value = index < o2.length ? o2[index] : 0;
        int cmp     = Integer.compare(o1Value, o2Value);
        if (cmp != 0) {
          result = cmp;
          break;
        }
      }
      return result;
    }
  }

Esta implementação pode ser ajustado para outras matrizes, a única coisa que você deve estar ciente de que as matrizes de igual (= comprimento igual com os membros iguais) deve retornar 0 e que você tem uma ordem DETERMISTIC

Eu acredito que os arrays em Java não necessariamente implementar os métodos hashCode() e equals(Object) intuitivamente. Ou seja, duas matrizes de bytes idênticos não necessariamente compartilham o mesmo código hash e eles não serão necessariamente afirmam ser iguais. Sem essas duas características, o seu HashMap irá se comportar de forma inesperada.

Portanto, eu recomendo contra usando byte[] como chaves em um HashMap.

Você deve usar criar um somthing classe como ByteArrKey e hashcode sobrecarga e métodos iguais, lembre-se o contrato entre eles.

Isso irá dar-lhe uma maior flexibilidade no que pode saltar 0 entradas que estão apensas no final da matriz de bytes, especialmente se copiar apenas alguma parte formar o outro tampão de byte.

Desta forma, você vai decidir como ambos os objetos devem ser iguais.

Eu vejo problemas, pois você deve usar Arrays.equals e Array.hashCode, no lugar de implementações de matriz padrão

Arrays.toString (bytes)

Você também pode converter o byte [] para uma string 'seguro' usando Base32 ou Base64, por exemplo:

byte[] keyValue = new byte[] {…};
String key = javax.xml.bind.DatatypeConverter.printBase64Binary(keyValue);

é claro que existem muitas variantes do acima, como:

String key = org.apache.commons.codec.binary.Base64.encodeBase64(keyValue);

Aqui é uma solução utilizando a interface e método Java java.util.Arrays.equals TreeMap, comparadores (byte [], byte []);

NOTA: A ordenação no mapa não é relevante com este método

SortedMap<byte[], String> testMap = new TreeMap<>(new ArrayComparator());

static class ArrayComparator implements Comparator<byte[]> {
    @Override
    public int compare(byte[] byteArray1, byte[] byteArray2) {

        int result = 0;

        boolean areEquals = Arrays.equals(byteArray1, byteArray2);

        if (!areEquals) {
            result = -1;
        }

        return result;
    }
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top