Pergunta

Esta questão é especificamente relacionado com substituindo as método equals () para objetos com um grande número de campos. Primeiro, deixe-me dizer que este objeto grande não pode ser dividido em vários componentes sem violar princípios OO, então me dizendo "nenhuma classe deve ter mais do que os campos x" não vai ajudar.

Seguindo em frente, o problema tornou-se realidade quando eu esqueci de verificar um dos campos para a igualdade. Portanto, o meu método equals estava incorreta. Então eu pensei usar a reflexão:

--code removed because it was too distracting--

O objetivo deste post não é necessariamente para refatorar o código (este não é ainda o código que estou usando), mas em vez para obter a entrada sobre se este é ou não uma boa idéia.

Pros:

  • Se um novo campo é adicionado, ele é automaticamente incluído
  • O método é muito mais concisa do que 30 if

Contras:

  • Se um novo campo é adicionado, ele é automaticamente incluído, por vezes, isso é indesejável
  • Performance: Isso tem que ser mais lento, eu não sinto a necessidade de romper com um profiler
  • whitelisting certos campos de ignorar na comparação é um pouco feio

Qualquer pensamento?

Foi útil?

Solução

Se você queria whitelist por motivos de desempenho, considere usar uma anotação para indicar quais os campos para comparar. Além disso, esta aplicação não vai funcionar se os seus campos não tem boas implementações para equals().

P.S. Se você percorrer esse caminho para equals(), não se esqueça de fazer algo semelhante para hashCode().

P.P.S. Eu confio em você já considerado HashCodeBuilder e EqualsBuilder .

Outras dicas

Use Eclipse, FFS!

Excluir o hashCode e igual métodos que você tem.

Botão direito do mouse sobre o arquivo.

Selecionar Source-> Gerar hashCode e igual ...

Feito! Não mais se preocupa com reflexão.

Repita para cada campo adicionado, basta usar a visualização de tópicos para eliminar seus dois métodos, e depois deixar Eclipse gerar automaticamente-los.

Se você vai fazer a abordagem reflexão, EqualsBuilder ainda é seu amigo:

 public boolean equals(Object obj) {
    return EqualsBuilder.reflectionEquals(this, obj);
 }

Aqui está um pensamento, se você está preocupado com:

1 / Forgetting atualizar seus grandes série de instruções if para verificar a igualdade quando você adicionar / remover um campo.

2 / O desempenho de fazer isso no método equals ().

Tente o seguinte:

a Revert para trás / para usando a longa sequência de caso-declarações em seus equals () método.

b / ter uma única função que contém uma lista de campos (em uma matriz String) e que vai verificar que lista contra realidade (isto é, os campos reflectidos). Ele vai lançar uma exceção se eles não corresponderem.

c / Em seu construtor para este objeto, têm uma sincronizada execução única chamada para esta função (semelhante a um padrão Singleton). Em outras palavras, se este é o primeiro objecto construído por esta classe, chamada de função de verificação descrito em (b) acima.

A exceção irá torná-lo imediatamente óbvio quando você executar seu programa se você não tiver atualizado o seu de uma instrução if para combinar os campos refletidas; então você corrigir os se-afirmações e actualizar a lista de campo a partir de (b) acima.

construção subsequente de objetos não vai fazer essa verificação e seus iguais () método irá funcionar em sua velocidade máxima possível.

Por mais que tentasse, eu não tenho sido capaz de encontrar quaisquer problemas reais com essa abordagem (mentes maiores podem existir em StackOverflow) - há uma verificação de condição extra em cada construção de objeto para a execução única comportamento, mas que parece bastante menor.

Se você tentar duro o suficiente, você poderia ainda ter o seu se-declarações fora de sintonia com o seu campo de lista e campos refletidas mas a exceção irá garantir a sua lista de campos coincide com os campos refletidos e você apenas certifique-se de atualizar o se- declarações e lista de campos ao mesmo tempo.

Você sempre pode anotar os campos que fazer / não quer em seu método equals, que deve ser um simples e simples mudança para ele.

O desempenho é, obviamente, relacionado à forma como muitas vezes o objeto é realmente comparação, mas um monte de estruturas de usar mapas hash, para que seus iguais podem estar sendo usados ??mais do que você pensa.

Além disso, falando de mapas hash, você tem o mesmo problema com o método hashCode.

Finalmente, você realmente precisa para comparar todos os campos para a igualdade?

Você tem alguns bugs em seu código.

  1. Você não pode assumir que this e obj são da mesma classe. Na verdade, é explicitamente permitido para obj ser qualquer outra classe. Você poderia começar com if ( ! obj instanceof myClass ) return false; porém este é ainda não correta , porque obj poderia ser uma subclasse de this com campos adicionais que podem importa.
  2. Você tem que suportar valores null para obj com um simples if ( obj == null ) return false;
  3. Você não pode tratar null e string vazia como iguais. Em vez null deleite especial. maneira mais simples aqui é começar comparando Field.get(obj) == Field.get(this). Se eles são ambos iguais ou ambos acontecer para apontar para o mesmo objeto, este é rápido. (Nota:. Esta é também uma otimização, o que você precisa uma vez que esta é uma rotina lenta) Se isto falhar, você pode usar o if ( Field.get(obj) == null || Field.get(this) == null ) return false; rápido para lidar com casos onde exatamente é null. Finalmente, você pode usar o equals() habitual.
  4. Você não está usando foundMismatch

Eu concordo com Hank que [HashCodeBuilder][1] e [EqualsBuilder][2] é a melhor maneira de ir. É fácil de manter, não um monte de código clichê, e você evita todas estas questões.

Você pode usar anotações para excluir campos do cheque

por exemplo.

@IgnoreEquals
String fieldThatShouldNotBeCompared;

E então é claro que você verificar a presença da anotação em seu método equals genérico.

Se você tem acesso aos nomes dos campos, por que não torná-lo um padrão que campos que você não deseja incluir sempre começar com "local" ou "nochk" ou algo parecido.

Em seguida, você lista negra todos os campos que começam com isto (código não é tão feio então).

Eu não tenho dúvida de que é um pouco mais lento. Você precisa decidir se você quiser trocar a facilidade de atualizações contra a velocidade de execução.

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