Estou pensando há algum tempo por que Java e C # (e tenho certeza de que outras linguagens) assumem como padrão a igualdade de referência ==
.
Na programação que faço (que certamente é apenas um pequeno subconjunto de problemas de programação), quase sempre quero igualdade lógica ao comparar objetos em vez de fazer referência à igualdade. Eu estava tentando pensar por que essas duas linguagens seguiram esse caminho, em vez de invertê-lo e ter ==
igualdade lógica e usar .ReferenceEquals()
como igualdade de referência.
Obviamente, o uso da igualdade de referência é muito simples de implementar e oferece um comportamento muito consistente, mas não parece se encaixar bem com a maioria das práticas de programação que eu vejo hoje.
Não desejo parecer ignorante sobre os problemas ao tentar implementar uma comparação lógica, e que ela deve ser implementada em todas as classes. Também percebo que essas linguagens foram projetadas há muito tempo, mas a questão geral permanece.
Existe algum benefício importante em deixar isso de lado, ou simplesmente parece que o comportamento padrão deve ser a igualdade lógica, e voltar a referenciar a igualdade, se não existir uma igualdade lógica para a classe?
Equals()
, ele não altera automaticamente o comportamento de==
?Respostas:
C # faz isso porque Java fez. O Java fez porque o Java não suporta sobrecarga do operador. Como a igualdade de valor deve ser redefinida para cada classe, ela não pode ser um operador, mas deve ser um método. A IMO foi uma péssima decisão. É muito mais fácil escrever e ler do
a == b
quea.equals(b)
e muito mais natural para programadores com experiência em C ou C ++, masa == b
quase sempre está errado. Os erros do uso de==
onde.equals
era necessário desperdiçavam milhares de horas de programadores.fonte
==
para muitas classes e, há alguns meses, descobri que alguns desenvolvedores não sabiam o que==
estava realmente fazendo. Sempre existe esse risco quando a semântica de alguma construção não é óbvia. Aequals()
notação me diz que estou usando um método personalizado e que preciso procurar em algum lugar. Conclusão: acho que a sobrecarga do operador é uma questão em aberto em geral.+
por exemplo, o que faz adição (de valores numéricos) e concatenação de cadeias ao mesmo tempo.a == b
ser mais natural para programadores com experiência em C, já que o C não suporta sobrecarga de operador definida pelo usuário? (Por exemplo, a forma C a comparar cadeias éstrcmp(a, b) == 0
, nãoa == b
.)char *
. Parece-me óbvio que comparar dois indicadores de igualdade não é o mesmo que uma comparação de cadeias.A resposta curta: Consistência
Para responder sua pergunta corretamente, sugiro que retrocedamos e analisemos a questão do que igualdade significa em uma linguagem de programação. Existem pelo menos TRÊS possibilidades diferentes, usadas em vários idiomas:
Esses três tipos de igualdade são frequentemente usados porque são convenientes de implementar: todas as três verificações de igualdade podem ser facilmente geradas por um compilador (no caso de profunda igualdade, o compilador pode precisar usar bits de tag para evitar loops infinitos se uma estrutura ser comparado tem referências circulares). Mas há outro problema: nada disso pode ser apropriado.
Em sistemas não triviais, a igualdade de objetos é frequentemente definida como algo entre igualdade profunda e de referência. Para verificar se queremos considerar dois objetos iguais em um determinado contexto, podemos exigir que alguns atributos sejam comparados com o local em que estão na memória e outros com profunda igualdade, enquanto alguns atributos podem ter algo completamente diferente. O que realmente gostaríamos é de um “quarto tipo de igualdade”, muito bom, muitas vezes chamado na literatura de igualdade semântica . As coisas são iguais se forem iguais, em nosso domínio. =)
Para que possamos voltar à sua pergunta:
O que queremos dizer quando escrevemos 'a == b' em qualquer idioma? Idealmente, deve ser sempre o mesmo: igualdade semântica. Mas isso não é possível.
Uma das principais considerações é que, pelo menos para tipos simples como números, esperamos que duas variáveis sejam iguais após a atribuição do mesmo valor. Ver abaixo:
Nesse caso, esperamos que 'a seja igual a b' nas duas declarações. Qualquer outra coisa seria insana. A maioria (se não todos) dos idiomas segue esta convenção. Portanto, com tipos simples (também conhecidos como valores), sabemos como alcançar a igualdade semântica. Com objetos, isso pode ser algo completamente diferente. Ver abaixo:
Esperamos que o primeiro 'se' seja sempre verdadeiro. Mas o que você espera no segundo 'se'? Isso realmente depende. Pode 'DoSomething' alterar a igualdade (semântica) de aeb?
O problema da igualdade semântica é que ele não pode ser gerado automaticamente pelo compilador para objetos, nem é óbvio pelas atribuições . Um mecanismo deve ser fornecido para o usuário definir igualdade semântica. Nas linguagens orientadas a objetos, esse mecanismo é um método herdado: igual . Lendo um pedaço de código OO, não esperamos que um método tenha a mesma implementação exata em todas as classes. Estamos acostumados a herança e sobrecarga.
Com os operadores, porém, esperamos o mesmo comportamento. Quando você vê 'a == b', deve esperar o mesmo tipo de igualdade (dos 4 acima) em todas as situações. Assim, visando à consistência, os designers de idiomas usaram igualdade de referência para todos os tipos. Não deve depender se um programador substituiu um método ou não.
PS: A linguagem Dee é um pouco diferente de Java e C #: o operador equals significa igualdade rasa para tipos simples e igualdade semântica para classes definidas pelo usuário (com a responsabilidade de implementar a operação = que fica com o usuário - nenhum padrão é fornecido). Como para tipos simples, a igualdade superficial é sempre semântica, a linguagem é consistente. O preço pago, no entanto, é que o operador igual é, por padrão, indefinido para os tipos definidos pelo usuário. Você tem que implementá-lo. E, às vezes, isso é apenas chato.
fonte
When you see ‘a == b’ you should expect the same type of equality (from the 4 above) in all situations.
Os designers de linguagem do Java usaram igualdade de referência para objetos e igualdade semântica para primitivas. Não é óbvio para mim que essa foi a decisão certa ou que essa decisão é mais "consistente" do que permitir==
sobrecarregar a igualdade semântica de objetos.a
eb
são do mesmo tipo, a expressãoa==b
testa sea
eb
mantém a mesma coisa. Se um deles possui uma referência ao objeto # 291 e o outro uma referência ao objeto # 572, eles não têm a mesma coisa. O conteúdo do objeto # 291 e # 572 pode ser equivalente, mas as próprias variáveis mantêm coisas diferentes.a == b
e saber o que faz. Da mesma forma, você pode vera.equals(b)
e presumir que uma sobrecargaequals
. Se asa == b
chamadasa.equals(b)
(se implementadas), são comparadas por referência ou por conteúdo? Não se lembra? Você deve verificar a classe A. O código não será mais tão rápido de ler se você não tiver certeza do que está sendo chamado. Seria como se métodos com a mesma assinatura fossem permitidos, e o método que está sendo chamado depende de qual é o escopo atual. Tais programas seriam impossíveis de ler.Porque a última abordagem seria confusa. Considerar:
Esse código
"ok"
deve ser impresso ou deve gerar umNullPointerException
?fonte
Para Java e C #, o benefício reside em serem orientados a objetos.
Do ponto de vista do desempenho - o código mais fácil de escrever também deve ser mais rápido: como o OOP pretende que elementos logicamente distintos sejam representados por objetos diferentes, a verificação da igualdade de referência seria mais rápida, levando em consideração que os objetos podem se tornar muito grandes.
Do ponto de vista lógico - a igualdade de um objeto para outro não precisa ser tão óbvia quanto comparar as propriedades do objeto para igualdade (por exemplo, como é nulo == nulo logicamente interpretado? Isso pode diferir de caso para caso).
Eu acho que o que se resume é a sua observação de que "você sempre quer igualdade lógica sobre igualdade de referência". O consenso entre os designers de idiomas foi provavelmente o oposto. Pessoalmente, acho difícil avaliar isso, pois não tenho o amplo espectro de experiência em programação. Grosso modo, utilizo mais a igualdade de referência nos algoritmos de otimização e a igualdade lógica no tratamento de conjuntos de dados.
fonte
.equals()
compara variáveis pelo seu conteúdo. em vez==
disso, compara os objetos pelo seu conteúdo ...usando objetos é mais preciso tu usar
.equals()
fonte