Método get() de Map

Olá,

só pra saber… Alguém mais além de mim já se perguntou porquê os métodos containsValue(), containsKey() e get() da interface Map recebem parâmetros Object ao invés de receber o generic correspondente? Questãozinha boba mas é algo que vem me atiçando a curiosidade heheh.

[]'s,

Não é exatamente a resposta de sua pergunta, mas apenas um comentário.

Não é só em Map que acontece isso. Por exemplo, o método contains de List também recebe Object. Se for passado um objeto que não seja do tipo dos elementos, simplesmente retornaria false. Os métodos containsValue, containsKey seguem o mesmo padrão. A restrição de tipo fica mesmo para colocar os valores no mapa.

A razão é que o contrato desses métodos é aberto. O contrato especifica que para que esses métodos retornem true (ou um valor do mapa, no caso do get), eles precisam de um objeto que passe no teste do equals e não sejam nulos. Não dizem que precisam ser exatamente do mesmo tipo da chave.

Isso permite, por exemplo, que objetos proxies sejam usados como valores no get. Vamos supor que você tenha um proxy (ClienteReadOnly) que seja simplesmente uma versão imutável de um outro objeto da sua aplicação (digamos, da classe Cliente), mutável. E esse proxy foi usado como chave do seu map. Você poderia usar o equals para testar contra objetos do tipo cliente.

Outra opção seria testar se um List está entre os valores do map, mesmo que seja um list de uma implementação diferente da que esteja num map. Por exemplo, dentro do map vc ter um linkedList, mas quer saber num containsValue se existe uma lista com os mesmos elementos de um ArrayList.

Agora, eu concordo com você. Eu também faria esses métodos com o tipo correspondente. Acho que o benefício de se ter verificação em compile time é muito maior do que o benefício do recurso que citei acima, principalmente porque o equals geralmente retorna false quando usado com tipos diferentes, e também porque quando é o caso de retornar true, ele geralmente vai ser com uma classe que implementa uma superclasse ou interface comum (caso da List).

Imagino eu que toda classe é um Object.

Com isso, basta ele chamar o método equals que ele irá ver se o objeto está lá dentro ou não.

[quote=ViniGodoy]A razão é que o contrato desses métodos é aberto. O contrato especifica que para que esses métodos retornem true (ou um valor do mapa, no caso do get), eles precisam de um objeto que passe no teste do equals e não sejam nulos. Não dizem que precisam ser exatamente do mesmo tipo da chave.

Isso permite, por exemplo, que objetos proxies sejam usados como valores no get. Vamos supor que você tenha um proxy (ClienteReadOnly) que seja simplesmente uma versão imutável de um outro objeto da sua aplicação (digamos, da classe Cliente), mutável. E esse proxy foi usado como chave do seu map. Você poderia usar o equals para testar contra objetos do tipo cliente.

Outra opção seria testar se um List está entre os valores do map, mesmo que seja um list de uma implementação diferente da que esteja num map. Por exemplo, dentro do map vc ter um linkedList, mas quer saber num containsValue se existe uma lista com os mesmos elementos de um ArrayList.

Agora, eu concordo com você. Eu também faria esses métodos com o tipo correspondente. Acho que o benefício de se ter verificação em compile time é muito maior do que o benefício do recurso que citei acima, principalmente porque o equals geralmente retorna false quando usado com tipos diferentes, e também porque quando é o caso de retornar true, ele geralmente vai ser com uma classe que implementa uma superclasse ou interface comum (caso da List).

[/quote]
Boa explicação a sua Vini. Mas o grande questionamento, para mim, surgiu quando ocorreu um pequeno problema no projeto em que eu estava trabalhando e um colega acabou por colocar a mesma enumeração duas vezes no projeto, só que em pacotes diferentes. Aí, o mapa ficou retornando null - só que eu demorei pra perceber que era porque meu mapa usava a enumeração que estava no pacote x e o objeto que eu passava no get() era da enumeração do pacote y (classes com mesmo nome em pacotes diferentes).
Óbvio que isso que ocorreu comigo foi um erro de refatoração, mas quando me dei conta de que era esse o problema fiquei pensando porquê não tinha ocorrido nenhum erro em runtime (ClassCastExceptions ou algo do tipo). Aí foi que verifiquei na especificação do Map que o get() realmente recebia Object.

Sempre bom discutir coisas desse tipo com outras pessoas - dá pra entender por quê algumas coisas são como são. :smiley:

[quote=jakefrog]Imagino eu que toda classe é um Object.

Com isso, basta ele chamar o método equals que ele irá ver se o objeto está lá dentro ou não.[/quote]
Isso sim, toda classe herda de Object.
Mas meu questionamento diz(ia) mais respeito ao conceito de type safety. Lembro de ter lido em algum lugar que os Generics foram introduzidos no Java por questões de type safety. Por isso concluí que não fazia muito sentido o get(Object) - ainda mais considerando que o get() retorna um tipo genérico (V).

[quote=Stormqueen1990]Boa explicação a sua Vini. Mas o grande questionamento, para mim, surgiu quando ocorreu um pequeno problema no projeto em que eu estava trabalhando e um colega acabou por colocar a mesma enumeração duas vezes no projeto, só que em pacotes diferentes. Aí, o mapa ficou retornando null - só que eu demorei pra perceber que era porque meu mapa usava a enumeração que estava no pacote x e o objeto que eu passava no get() era da enumeração do pacote y (classes com mesmo nome em pacotes diferentes).
Óbvio que isso que ocorreu comigo foi um erro de refatoração, mas quando me dei conta de que era esse o problema fiquei pensando porquê não tinha ocorrido nenhum erro em runtime (ClassCastExceptions ou algo do tipo). Aí foi que verifiquei na especificação do Map que o get() realmente recebia Object.

Sempre bom discutir coisas desse tipo com outras pessoas - dá pra entender por quê algumas coisas são como são. :D[/quote]

Sim. E eu concordo com você. Também já tive problemas como esse.
Acho que o inconveniente que o método geraria é muito pequeno, comparado com a vantagem de evitar enganos desse tipo.