Java Generics: Descrição e Métodos
Desde o aparecimento da própria linguagem Javamuitas mudanças, que, sem dúvida, trouxeram momentos positivos à sua funcionalidade. Uma dessas mudanças significativas é a introdução do Java Generic ou generalização. Essa funcionalidade tornou a linguagem não apenas mais flexível e versátil, mas também muito mais segura em termos de redução de tipos de dados.
O fato é que, antes da introdução do genérico genéricocódigo em Java poderia ser criado apenas por referência ao tipo de objeto. Esses links podem ser atribuídos a qualquer objeto. Afinal, todas as classes em Java são descendentes implícitas da classe Object. No entanto, essa abordagem é uma fonte potencial de muitos erros de segurança de tipo quando você converte explicitamente um objeto de Object para o tipo de destino. Quando generalizações são usadas, todos os lançamentos são executados de forma implícita e automática, o que exclui até mesmo a possibilidade de ocorrência de erros.
Java Generics: descrição e exemplo
Vamos dar um exemplo simples de aplicar a generalização à classe usual na figura abaixo. E só então procederemos a um exame detalhado de todas as sutilezas e nuances do Java Generic.
Observe como odeclaração de classe Pair. Imediatamente após o nome de classe, os suportes de ângulo aberto, o que indicava a letra T. É um tipo de material de enchimento, que está no processo de criação de uma instância desta classe serão substituídos por um tipo específico. Parece como se segue: Par <Integer> obj = new Par <Integer> (). Deve-se notar que em vez de T pode especificar qualquer carta, mas, como regra, use T, V ou E.
Nota: começando com a oitava versão do Java, especificando o tipo de destino quando o link é declarado, você pode deixar os colchetes angulares no construtor vazio. Portanto, o exemplo acima pode ser reescrito da seguinte forma: Pair <Integer> obj = new Pair <> ().
Quando uma classe é declarada dessa maneira, entãoVocê pode usar essa letra em vez de tipos de campos específicos, referências e métodos retornados por métodos. Como T é substituído por um tipo específico ao criar um objeto de classe, o primeiro e o segundo campos nesse caso serão do tipo Integer.
Seguindo a lógica, os argumentos firstItem e secondItem,passado para o construtor correspondente, também deve ser do tipo Integer ou sua subclasse. Se você tentar passar um tipo de dados diferente do que foi especificado ao criar o objeto, o compilador não irá ignorar esse erro. Portanto, o construtor com argumentos ao criar o objeto terá o seguinte formato: Pair <Integer> obj = new Pair <> (novo Integer (1), new Integer (2)). O mesmo se aplica aos argumentos para os métodos setFirst e setSecond. E como você provavelmente já adivinhou, os métodos getFirst e getSecond retornarão valores do tipo Integer.
Uma classe genérica com vários parâmetros de tipo
Em classes genéricas, você também pode declarar vários parâmetros de tipo especificados em colchetes, separados por vírgulas. A classe Pair para este caso é apresentada na figura abaixo.
Como você pode ver, ao criar uma instância de tal classeNos parênteses angulares, você deve especificar o mesmo número de tipos que os parâmetros. Se você estiver familiarizado com um tipo de estrutura de dados como o Map, poderá notar que o mesmo princípio é usado lá. Lá, o primeiro argumento determina o tipo da chave e o segundo - o tipo do valor. Deve-se notar que os tipos de argumentos passados para a criação do objeto podem ser os mesmos. Portanto, a seguinte declaração de uma instância da classe Pair está absolutamente correta: Pair <String, String> obj.
Algumas características das generalizações
Antes de prosseguir, deve-se notar queO compilador Java não cria versões diferentes da classe Pair. Na verdade, durante o processo de compilação, todas as informações sobre o tipo genérico são excluídas. Em vez disso, os tipos correspondentes são convertidos, criando uma versão especial da classe Pair. No entanto, o próprio programa ainda tem uma única versão generalizada dessa classe. Esse processo é chamado na limpeza do tipo genérico Java.
Vamos notar um ponto importante. Referências a diferentes versões da mesma classe genérica java não podem apontar para o mesmo objeto. Ou seja, digamos que temos dois links: Pair <Integer> obj1 e Pair <Double> obj2. Portanto, um erro ocorre na linha obj1 = obj2. Embora ambas as variáveis sejam do tipo Pair <T>, os objetos aos quais eles se referem são diferentes. Este é um exemplo vívido da segurança de tipos no Java Generic.
Restrições impostas às classes generalizadas
É importante saber que as generalizações podem ser aplicadasapenas para tipos de referência, ou seja, para passar parâmetros argumento java classe genérica deve ser um tipo de classe. Estes tipos simples, tais como, por exemplo, duplas ou longas, não podem ser transferidos. Em outras palavras, a seguinte linha Par declaração de classe não é permitido: Par <int> obj. No entanto, essa limitação não é um problema grave, já que há uma classe de invólucro Java correspondente para cada tipo primitivo. Estritamente falando, se o par classe que você deseja encapsular um inteiro e booleano valor avtoupakovka faz tudo para você: Par <Integer, Boolean> obj = new Par <> (25, true).
Outra séria limitação é aimpossibilidade de criar uma instância de um parâmetro de tipo. Portanto, a linha a seguir causará um erro de compilação: T first = new T (). Isso é óbvio, já que você não sabe de antemão se uma classe completa ou uma interface abstrata será passada como um argumento. O mesmo vale para criar matrizes.
Tipos limitados
Muitas vezes há situações em queÉ necessário limitar a lista de tipos que podem ser passados como um argumento para a classe genérica java. Vamos supor que na nossa classe Pair, nós queremos encapsular valores exclusivamente numéricos para outras operações matemáticas neles. Para fazer isso, precisamos definir o limite superior do parâmetro type. Isso é implementado usando uma declaração de superclasse herdada por todos os argumentos passados em colchetes angulares. Será parecido com isto: class Pair <T extends Number>. Dessa maneira, o compilador aprende que, em vez do parâmetro T, você pode substituir a classe Number ou uma de suas subclasses.
Esta é uma técnica comum. Tais restrições são freqüentemente usadas para garantir a compatibilidade dos parâmetros de tipo na mesma classe. Considere um exemplo em nossa classe Pair: a classe Pair <T, V estende T>. Aqui dizemos ao compilador que o tipo T pode ser arbitrário, e o tipo V deve ser do tipo T ou uma de suas subclasses.
A restrição "de baixo" ocorre exatamente da mesmaimagem, mas em vez da palavra se estende, a palavra super é escrita. Ou seja, a declaração de classe Pair <T super ArrayList> indica que, em vez de T, uma ArrayList ou qualquer classe ou interface herdada pode ser substituída.
Métodos e construtores Java genéricos
Em Java, as generalizações podem ser aplicadas não apenas em relação às classes, mas também aos métodos. Então, o método generalizado pode ser declarado na classe ordinária.
Como você pode ver na figura acima, não há nada complicado na declaração do método generalizado. É suficiente colocar colchetes angulares antes do método de tipo de retorno e especificar parâmetros de tipo neles.
No caso do construtor, tudo é feito da mesma maneira:
Os colchetes de ângulo, neste caso, são colocados antes do nome do construtor, uma vez que ele não retorna nenhum valor. O resultado do trabalho de ambos os programas será:
Inteiro
String