É um ponto crucial, mas vale a pena entender o IMHO.
Todas as linguagens OO sempre fazem cópias de referências e nunca copiam um objeto 'invisivelmente'. Seria muito mais difícil escrever programas se as linguagens OO funcionassem de outra maneira. Por exemplo, funções e métodos, nunca poderiam atualizar um objeto. Java e a maioria das linguagens OO seria quase impossível de usar sem uma complexidade adicional significativa.
Um objeto em um programa deve ter algum significado. Por exemplo, representa algo específico no mundo físico real. Geralmente, faz sentido ter muitas referências à mesma coisa. Por exemplo, meu endereço residencial pode ser fornecido a muitas pessoas e organizações, e esse endereço sempre se refere ao mesmo local físico. Portanto, o primeiro ponto é que os objetos geralmente representam algo específico, real ou concreto; e, portanto, poder ter muitas referências à mesma coisa é extremamente útil. Caso contrário, seria mais difícil escrever programas.
Sempre que você passa a
como argumento / parâmetro para outra função, por exemplo, chamar
foo(Dog aDoggy);
ou aplicar um método a
, o código do programa subjacente faz uma cópia da referência, para produzir uma segunda referência para o mesmo objeto.
Além disso, se o código com uma referência copiada estiver em um encadeamento diferente, ambos poderão ser usados simultaneamente para acessar o mesmo objeto.
Portanto, na maioria dos programas úteis, haverá várias referências ao mesmo objeto, porque essa é a semântica da maioria das linguagens de programação OO.
Agora, se pensarmos sobre isso, porque a passagem por referência é o único mecanismo disponível em muitas linguagens OO (o C ++ suporta os dois), podemos esperar que seja o comportamento padrão "certo" .
IMHO, usar referências é o padrão certo , por algumas razões:
- Garante que o valor de um objeto usado em dois locais diferentes seja o mesmo. Imagine colocar um objeto em duas estruturas de dados diferentes (matrizes, listas etc.) e executar algumas operações em um objeto que o altera. Isso pode ser um pesadelo para depurar. Mais importante, é o mesmo objeto em ambas as estruturas de dados ou o programa possui um bug.
- Felizmente, você pode refatorar o código em várias funções ou mesclar o código de várias funções em uma, e a semântica não muda. Se o idioma não fornecesse semântica de referência, seria ainda mais complexo modificar o código.
Há também um argumento de eficiência; fazer cópias de objetos inteiros é menos eficiente do que copiar uma referência. No entanto, acho que isso é errado. Várias referências ao mesmo objeto fazem mais sentido e são mais fáceis de usar, pois correspondem à semântica do mundo físico real.
Então, IMHO, geralmente faz sentido ter várias referências ao mesmo objeto. Nos casos incomuns em que isso não faz sentido no contexto de um algoritmo, a maioria das linguagens fornece a capacidade de criar um 'clone' ou cópia detalhada. No entanto, esse não é o padrão.
Acho que as pessoas que argumentam que esse não deve ser o padrão estão usando uma linguagem que não fornece coleta automática de lixo. Por exemplo, C ++ à moda antiga. O problema é que eles precisam encontrar uma maneira de coletar objetos "mortos" e não recuperar objetos que ainda possam ser necessários; ter várias referências ao mesmo objeto dificulta isso.
Penso que, se o C ++ tivesse uma coleta de lixo suficientemente barata, para que todos os objetos referenciados sejam coletados, então grande parte da objeção desaparece. Ainda haverá alguns casos em que a semântica de referência não é o que é necessário. No entanto, na minha experiência, as pessoas que conseguem identificar essas situações também costumam ser capazes de escolher a semântica apropriada.
Acredito que há alguma evidência de que uma grande quantidade de código em um programa C ++ existe para manipular ou mitigar a coleta de lixo. No entanto, escrever e manter esse tipo de código "infra-estrutural" adiciona custo; existe para tornar o idioma mais fácil de usar ou mais robusto. Assim, por exemplo, a linguagem Go foi projetada com o objetivo de corrigir alguns dos pontos fracos do C ++ e não tem escolha, exceto a coleta de lixo.
É claro que isso é irrelevante no contexto de Java. Também foi projetado para ser fácil de usar, e também possui coleta de lixo. Portanto, ter várias referências é a semântica padrão e é relativamente segura no sentido de que os objetos não são recuperados enquanto houver uma referência a eles. É claro que eles podem ser mantidos por uma estrutura de dados porque o programa não é organizado corretamente quando realmente termina com um objeto.
Então, voltando à sua pergunta (com um pouco de generalização), quando você deseja mais de uma referência ao mesmo objeto? Praticamente em todas as situações em que consigo pensar. Eles são a semântica padrão do mecanismo de passagem de parâmetros da maioria dos idiomas. Sugiro que isso ocorre porque a semântica padrão de manipulação de objetos que existe no mundo real praticamente tem que ser por referência (porque os objetos reais estão lá fora).
Qualquer outra semântica seria mais difícil de lidar.
Dog a = new Dog("rover"); // initialise with name
DogList dl = new DogList()
dl.add(a)
...
a.setOwner("Mr Been")
Sugiro que o "rover" dl
seja o efetuado setOwner
ou que os programas sejam difíceis de escrever, entender, depurar ou modificar. Eu acho que a maioria dos programadores ficaria confusa ou consternada caso contrário.
depois, o cachorro é vendido:
soldDog = dl.lookupOwner("rover", "Mr Been")
soldDog.setOwner("Mr Mcgoo")
Esse tipo de processamento é comum e normal. Portanto, a semântica de referência é o padrão, porque geralmente faz mais sentido.
Resumo: sempre faz sentido ter várias referências ao mesmo objeto.