[MÚSICA] [MÚSICA]
Esse é o curso de Desenvolvimento Ágil com Java Avançado.
Meu nome é Eduardo Guerra e hoje vamos continuar o que estávamos vendo sobre
tipos genéricos.
Hoje vamos falar aí sobre dois tipos de tipos,
que são os tipos invariantes e os covariantes.
Então a gente vai entender como é que a hierarquia da classe do tipo
genérico afeta a hierarquia da classe que tem o tipo genérico.
Outras palavras, se eu tenho lá, se eu estou passando como parâmetro genérico
uma classe e por exemplo eu tenho uma outra que é superclasse e uma outra como
subclasse, como é que funciona aí, uma herda outra, como é que é isso daí?
Então vamos ver aqui no nosso exemplo, como é que isso daí funciona.
Então vamos voltar aqui à nossa historinha aqui da minha classe cesta.
Agora, o que é que acontece?
Eu quero poder ter método que eu vou chamar ali de coloca tudo.
Então eu passo uma coleção para a minha cesta e ele vai colocar
todos os itens que estão naquela coleção na minha cesta.
Então vamos dar uma olhada como é que esse método aí vai funcionar.
Então, imagina que eu crio ali, vez de criar uma cesta de fruta,
eu crio uma cesta de vegetal, sendo que eu tenho ali a fruta
como uma subclasse da classe vegetal.
Vamos falar assim, bom a fruta é vegetal,
então eu consigo adicionar frutas na minha cesta.
Então se eu tiver uma collection de frutas, eu acho que se eu
chamar o coloca tudo, eu também vou conseguir adicionar na minha cesta.
Só que a minha surpresa é que quando eu tento passar
aquele collection de frutas para o método coloca tudo,
ele dá erro de compilação falando que é o tipo errado,
que ele não aceita uma coleção de frutas ali.
Vamos tentar entender por quê?
Eu tenho os tipos covariantes e os tipos invariantes.
O array, que é uma coisa que a gente já está acostumado,
ele é exemplo de tipo covariante, por quê?
Porque se eu tenho uma classe A que é subclasse de B,
então o array de A é subclasse do array de B.
Então como exemplo, se a gente pegar array de string,
ele vai ser uma subclasse de array de object.
Já os tipos genéricos, assim, muito de a gente ter
confundido essa questão no slide anterior,
é porque a gente está acostumado com esse jeitão nos arrays,
que não é o mesmo modelo que os tipos genéricos adotam.
Os tipos genéricos adotam o modelo invariante.
Significa que para qualquer A e B uma lista de A e uma lista B
nunca vão estender ao outro.
Então, por exemplo, uma lista de string, ela não estende uma lista de object.
Então se eu tenho método que aceita uma lista de object como parâmetro,
ele não vai aceitar que eu passe uma lista de string para ele.
Então é por isso que no caso aqui do slide anterior,
se eu tento passar uma collection de fruta no lugar que ele
espera uma collection de vegetal, ele não aceita, por quê?
Porque o tipo genérico é invariante.
Então nunca eu vou ter essa relação de herança quando eu tenho tipos diferentes.
Então, só para a gente entender pouco mais, o tipo covariante pode ser perigoso,
porque ele pode gerar erros tempo de compilação.
Tempo de execução, certo?
Então, por exemplo, se eu pegar aqui array de objetos e
atribuir para ele array de string, o tipo de variável,
o tipo da variável array ali no caso, ele vai ser array de objetos,
mas ele vai estar apontando memória para array de strings.
Significa que tempo de compilação,
ele aceita que eu pegue por exemplo 10 e atribua para
elemento desse array, porque o tipo é de objeto.
Mas no momento que eu tento fazer isso tempo de execução, ele vai gerar erro.
Por quê?
Porque o tipo ali que está memória só vai aceitar strings.
Então a gente vê que com o tipo covariante,
a gente pode ter esse tipo de erro acontecendo tempo de execução.
Então por isso que os tipos genéricos decidiram seguir modelo diferente.
Então se a gente olhar,
nem sempre é adequado a gente aceitar só as subclasses.
Então se a gente colocar ali, se a gente for pensar, se eu tenho
método colocaTudo, como é que eu vou estar colocando dentro da minha classe?
Poderia ser de uma subclasse?
Faria sentido eu estar aceitando coleções
não só da classe, mas também de subclasses.
Por outro lado, se eu tivesse outro método chamado tiraTudo,
que eu tiro tudo da minha cesta e coloco numa coleção, essa coleção pode
ser do meu tipo da cesta e pode ser também de uma superclasse do meu tipo da cesta.
Então a gente vê que nem sempre que você aceita parâmetro genérico,
parâmetro que tem o tipo genérico, você quer que ele seja
exatamente só de subclasses ou só de superclasses, depende do caso.
Com esses métodos colocaTudo e tiraTudo a gente vê isso daí.
E aí a gente tem umas palavrinhas-chave, que é por exemplo,
a gente pode colocar a interrogação, que seria ali o Curinga extends,
para quando a gente quer que seja uma subclasse,
quando a gente quer que aceite uma coleção de uma subclasse,
ou a gente pode colocar uma interrogação junto com o super,
quando a gente quer que ele aceite a própria classe ou uma superclasse.
Então, na verdade, a gente não pode,
digamos assim, o tipo genérico é invariante.
Então eu não consigo quando eu digo: eu vou aceitar uma collection de E.
Eu não posso aceitar nem da superclasse nem de subclasse, tem de ser exatamente de
E, mas eu consigo colocar o Curinga mais o extends
ou o Curinga mais o super para respectivamente aceitar a classe
mais a sua subclasse, ou para aceitar a classe mais a sua superclasse.
Então, apesar de eu ter essa invariância dentro dos tipos genéricos,
eu tenho aí o Curinga que eu posso estar utilizando nesse caso.
Então, com isso, eu espero que você tenha entendido essa questão dos tipos genéricos
serem invariantes, do porquê que ele, se você aceita por exemplo uma lista de E,
ele não vai aceitar uma lista de qualquer outra coisa,
mas a gente viu também como configurar o
parâmetro ali com o Curinga mais o extends ou o super,
para que ele realmente aceite os tipos que a gente quer que ele aceite, certo?
Então muito obrigado, a gente continua vendo genéricos na próxima aula!
[MÚSICA] [MÚSICA]