Em Java especificamente, mas provavelmente em outras linguagens: quando seria útil ter duas referências ao mesmo objeto?
Exemplo:
Dog a = new Dog();
Dob b = a;
Existe uma situação em que isso seria útil? Por que essa seria uma solução preferida para usar a
sempre que você quiser interagir com o objeto representado por a
?
object-oriented
object-oriented-design
object
Bassinator
fonte
fonte
a
eb
sempre fizer referência ao mesmoDog
, então não faz sentido. Se às vezes podem, então é bastante útil.Respostas:
Um exemplo é quando você deseja ter o mesmo objeto em duas listas separadas :
Outro uso é quando você tem o mesmo objeto desempenhando várias funções :
fonte
Persona batman = new Persona("Batman"); Persona bruce = new Persona("Bruce Wayne"); Persona currentPersona = batman;
- onde você tem vários valores possíveis (ou uma lista de valores disponíveis) e uma referência ao atualmente ativo / selecionado.currentPersona
aponta para um objeto ou outro, mas nunca para ambos. Em particular, pode ser possível que nuncacurrentPersona
esteja definido como , nesse caso, certamente não é uma referência a dois objetos. Eu diria que, no meu exemplo, ambos e são referências à mesma instância, mas servem um significado semântico diferente dentro do programa.bruce
batman
currentPersona
Essa é realmente uma pergunta surpreendentemente profunda! A experiência do C ++ moderno (e linguagens que tiram do C ++ moderno, como o Rust) sugere que muitas vezes você não quer isso! Para a maioria dos dados, você deseja uma referência única ou exclusiva ("proprietária"). Essa idéia também é a principal razão para sistemas do tipo linear .
No entanto, mesmo assim, você normalmente deseja algumas referências "emprestadas" de curta duração que são usadas para acessar brevemente a memória, mas não duram uma fração significativa do tempo em que os dados existem. Geralmente, quando você passa um objeto como argumento para uma função diferente (os parâmetros também são variáveis!):
Um caso menos comum quando você usa um dos dois objetos, dependendo de uma condição, fazendo essencialmente a mesma coisa, independentemente da sua escolha:
Voltando aos usos mais comuns, mas deixando as variáveis locais para trás, passamos aos campos: por exemplo, widgets em estruturas de GUI geralmente têm widgets pai, portanto, seu grande quadro contendo dez botões teria pelo menos dez referências apontando para ele (além de mais algumas de seus pais e talvez de ouvintes de eventos e assim por diante). Qualquer tipo de gráfico de objetos e alguns tipos de árvores de objetos (aqueles com referências de pai / irmão) têm vários objetos, cada um com o mesmo objeto. E praticamente todo conjunto de dados é na verdade um gráfico ;-)
fonte
Variáveis temporárias: considere o seguinte pseudocódigo.
As variáveis
max
ecandidate
podem apontar para o mesmo objeto, mas a atribuição de variáveis muda usando regras diferentes e em momentos diferentes.fonte
Para complementar as outras respostas, você também pode querer percorrer uma estrutura de dados de maneira diferente, começando no mesmo local. Por exemplo, se você tivesse um
BinaryTree a = new BinaryTree(...); BinaryTree b = a
, poderá percorrer o caminho mais à esquerda da árvorea
e o caminho mais à direitab
, usando algo como:Já faz um tempo desde que escrevi Java, para que o código não seja correto ou sensato. Tome-o mais como pseudocódigo.
fonte
Esse método é ótimo quando você tem vários objetos que todos chamam de volta para outro objeto que pode ser usado incontextualmente.
Por exemplo, se você tiver uma interface com guias, poderá ter as Tab1, Tab2 e Tab3. Você também pode usar uma variável comum, independentemente da guia em que o usuário está, para simplificar seu código e reduzir a necessidade de descobrir rapidamente sobre a guia do usuário.
Em cada uma das guias numeradas do Click, você pode alterar o CurrentTab para fazer referência a essa guia.
Agora, no seu código, você pode chamar "CurrentTab" com impunidade, sem precisar saber em qual guia está realmente. Você também pode atualizar as propriedades do CurrentTab e elas fluirão automaticamente para a guia referenciada.
fonte
Existem muitos cenários em que
b
deve ser uma referência a um "a
" desconhecido para ser útil. Em particular:b
aponta no tempo de compilação.Por exemplo:
Parâmetros
t
é uma referência a uma variável de um escopo externo.Retornar valores e outros valores condicionais
biggerThing
ez
são cada uma referências aa
oub
. Não sabemos qual em tempo de compilação.Lambdas e seus valores de retorno
x
é um parâmetro (exemplo 1 acima) et
é um valor de retorno (exemplo 2 acima)Colecções
index["some name"]
é, em grande parte, uma aparência mais sofisticadab
. É um alias para um objeto que foi criado e empacotado na coleção.rotações
t
é uma referência a um item retornado (exemplo 2) por um iterador (exemplo anterior).fonte
É 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, chamarfoo(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:
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.
Sugiro que o "rover"
dl
seja o efetuadosetOwner
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:
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.
fonte
Obviamente, outro cenário em que você pode acabar:
é quando você mantém o código e
b
costumava ser um cão diferente ou uma classe diferente, mas agora é atendido pora
.Geralmente, a médio prazo, você deve refazer todo o código para se referir
a
diretamente, mas isso pode não acontecer imediatamente.fonte
Você deseja isso sempre que seu programa tiver a chance de puxar uma entidade para a memória em mais de um ponto, possivelmente porque diferentes componentes o estejam usando.
O Identity Maps forneceu um repositório local definitivo de entidades para que possamos evitar duas ou mais representações separadas. Quando representamos o mesmo objeto duas vezes, nosso cliente corre o risco de causar um problema de simultaneidade se uma referência do objeto persistir e seu estado mudar antes que a outra outra instância. A idéia é que queremos garantir que nosso cliente esteja sempre negociando a referência definitiva à nossa entidade / objeto.
fonte
Eu usei isso ao escrever um solucionador de Sudoku. Quando eu sei o número de uma célula ao processar linhas, quero que a coluna que contém saiba também o número dessa célula ao processar colunas. Portanto, colunas e linhas são matrizes de objetos Cell que se sobrepõem. Exatamente como a resposta aceita mostrou.
fonte
Em aplicativos da Web, os Mapeadores Relacionais de Objetos podem usar carregamento lento, para que todas as referências ao mesmo objeto de banco de dados (pelo menos no mesmo encadeamento) aponte para a mesma coisa.
Por exemplo, se você tivesse duas tabelas:
Cães:
Os Proprietários:
Existem várias abordagens que seu ORM pode fazer se as seguintes chamadas forem feitas:
Na estratégia ingênua, todas as chamadas para os modelos e as referências relacionadas recuperam objetos separados.
Dog.find()
,Owner.find()
,owner.dogs
, Edog.owner
resultado em um banco de dados atingiu a primeira vez, após o que são salvos na memória. E entao:Sem uma referência, você tem mais buscas, usa mais memória e apresenta a possibilidade de substituir atualizações anteriores.
Suponha que seu ORM saiba que todas as referências à linha 1 da tabela cães devem apontar para a mesma coisa. Então:
Em outras palavras, o uso de referências ajuda a codificar o princípio de um único ponto de verdade (pelo menos nesse segmento) sendo a linha no banco de dados.
fonte