Você está na página 1de 71

Programao por Objectos

Java
Parte 8: Tipos genricos

LEEC@IST

Java 1/68

Tipos genricos reviso


Um tipo genrico um tipo que recebe
como argumento outros tipos (no
primitivos). Os tipos genricos so ainda
conhecidos como tipos parametrizados.
Os tipos genricos so muito utilizadas na
definio de coleces (conjuntos, listas,
pilhas, rvores, etc).

LEEC@IST

Java 2/68

Tipos genricos (1)


Conjunto

+ adicionar(elem: T)
+ remover(elem: T)

public class Conjunto<T> {


public void adicionar(T elem) {...}
public void remover(T elem) {...}
}

LEEC@IST

Java 3/68

Tipos genricos (2)


public class Elemento<T> {
protected T elemento;
protected Elemento<T> prximoElemento;
public Elemento(T elemento) {
this.elemento = elemento;
}
public Elemento(T elemento, Elemento<T> prximoElemento) {
this.elemento = elemento;
this.prximoElemento = prximoElemento;
}
}

Para criar um objecto do tipo Elemento necessrio dizer ao compilador


que tipo substituir por T. Por exemplo, um elemento que contm uma
String construdo da seguinte forma:
Elemento<String> strElem = new Elemento<String>("Hello");
LEEC@IST

Java 4/68

Tipos genricos (3)


public class Conjunto<T> {
protected int numElementos;
protected Elemento<T> primeiroElemento;
public void adicionar(T elem) {
//verificar se elemento j existe no conjunto
for (Elemento<T> aux=primeiroElemento;
aux!=null;
aux=aux.prximoElemento)
if (elem.equals(aux.elemento)) return;
//se no existir adicionar no incio do conjunto
primeiroElemento =
new Elemento<T>(elem,primeiroElemento);
numElementos++;
}
public void remover(T elem) {...}
}

LEEC@IST

Java 5/68

Tipos genricos (4)


Mais uma vez, para criar um objecto do tipo Conjunto
necessrio dizer ao compilador que tipo substituir
por T. Por exemplo, um conjunto de Strings
construdo da seguinte forma:
Conjunto<String> cj = new Conjunto<String>();

Adicionar Strings ao conjunto seria:


cj.adicionar(Hello);
cj.adicionar(World);
cj.adicionar(!);
cj.adicionar(34); //Invlido

LEEC@IST

Java 6/68

Tipos genricos (5)


Declarar a varivel cj de tipo Conjunto<String>
informa o compilador que cj uma referncia para
um objecto do tipo Conjunto<T> onde T String.
No criada uma classe Conjunto<String>.
Os tipos Conjunto<String> e Conjunto<Number> no so
duas classes distintas.

Tal como para os mtodos, nos tipos genricos


tambm existe o conceito de parmetro/argumento:
No contexto de Conjunto<T>, T dito parmetro (tipo).
No contexto de Conjunto<String>, String dito
argumento (tipo).
LEEC@IST

Java 7/68

Tipos genricos (6)


public class Conjunto<T> {
protected int numElementos;
protected Elemento<T> primeiroElemento;
private static int numProxConjunto=0;
private int numConjunto;
public Conjunto() {
numConjunto = numProxConjunto++;
}
public int numConjunto() {
return numConjunto;
}
public static int numProxConjunto() {
return numProxConjunto;
}
public void adicionar(T elem) {...}
public void remover(T elem) {...}
}
LEEC@IST

Java 8/68

Tipos genricos (7)


Conjunto<String> cj_s = new Conjunto<String>();
System.out.println(cj_s o conjunto nmero
+ cj_s.numConjunto());
Conjunto<Integer> cj_i = new Conjunto<Integer>();
System.out.println(cj_i o conjunto nmero
+ cj_i.numConjunto());

No terminal impresso cj_s o conjunto nmero 0


cj_i o conjunto nmero 1

LEEC@IST

Java 9/68

Tipos genricos (8)


Consequncias:
O parmetro tipo T no pode ser usado num contexto
esttico.
O acesso a membros estticos das classes parametrizadas
no podem ser feitos atravs do nome da classe
parametrizada:
Conjunto<String>.numProxConjunto(); //INVLIDO!!!
Conjunto.numProxConjunto();

LEEC@IST

Java 10/68

Tipos genricos (9)


No possvel usar o parmetro tipo T para criar
objectos nem para criar tabelas.
public class Conjunto<T> {
// ...
public T[] converterConjuntoParaTabela() {
T[] res = new T[numElementos]; //INVLIDO!!!
//... copiar elementos do conjunto para a tabela
}
}

LEEC@IST

Java 11/68

Tipos genricos (10)


Soluo 1: passar a tabela por parmetro e o mtodo
converterConjuntoParaTabela preenche a tabela
com os elementos do respectivo conjunto.
public class Conjunto<T> {
// ...
public T[] converterConjuntoParaTabela(T[] tabela) {
int i = 0;
for (Elemento<T> aux=primeiroElemento;
aux!=null;
aux=aux.prximoElemento)
tabela[i++] = aux.elemento;
return tabela;
}
}

LEEC@IST

Java 12/68

Tipos genricos (11)


Na definio de tipos genricos possvel restringir
o tipo do argumento passado ao parmetro tipo T:
interface ColecoOrdenada<T extends Comparable<T>> {...}

O tipo do argumento passado ao parmetro tipo T


implementa os mtodos da interface Comparable<T>.
interface ColecoOrdenadaSequnciaCaracteres<
T extends Comparable<T> & CharSequence> {...}

O tipo do argumento passado ao parmetro tipo T


implementa os mtodos da interface Comparable<T> e
implementa os mtodos da interface CharSequence.
LEEC@IST

Java 13/68

Tipos genricos (12)


A palavra chave extends usada nos parmetros tipo
dos tipos genricos de uma forma muito geral:
Significando extends se o tipo que se segue uma classe.
Significando implements se o tipo que se segue uma
interface.
Um tipo genrico apenad pode estender uma classe e um
conjunto de interfaces, ou seja s podemos ter declaraes da
forma:
Conjunto<T estends [class | interface] & interfacelist>

LEEC@IST

Java 14/68

Tipos genricos aninhados (1)


Um tipo aninhado pode ser um tipo genrico.
Se um tipo genrico for aninhado noutro tipo
genrico:
Se o tipo genrico aninhado for esttico, o parmetro tipo do
tipo aninhado independente do parmetro tipo do tipo
genrico que o engloba, mesmo que tenham o mesmo
nome.
Se o tipo genrico aninhado no for esttico, ento o
parmetro tipo do tipo genrico que o engloba acessvel
no tipo aninhado, portanto pode ser usado directamente
(sempre que tal fizer sentido).

LEEC@IST

Java 15/68

Tipos genricos aninhados (2)


public class Conjunto<T> {
static class Elemento<E> {
protected E elemento;
protected Elemento<E> prximoElemento;
public Elemento(E elemento) {
this.elemento = elemento;
}
public Elemento(E elemento, Elemento<E> prximoElemento) {
this.elemento = elemento;
this.prximoElemento = prximoElemento;
}
}
protected int numElementos;
protected Elemento<T> primeiroElemento;
// ...
}
LEEC@IST

Java 16/68

Tipos genricos aninhados (3)


Poderamos ter parmetros tipo com o mesmo
nome, por exemplo, T, sendo na mesma ambos
distintos:
public class Conjunto<T> {
static class Elemento<T> {
protected T elemento;
protected Elemento<T> prximoElemento;
// ...
}
protected Elemento<T> primeiroElemento;
// ...
}

LEEC@IST

Java 17/68

Tipos genricos aninhados (4)


public class Conjunto<T> {
class Elemento {
protected T elemento;
protected Elemento<T> prximoElemento;
public Elemento(T elemento) {
this.elemento = elemento;
}
public Elemento(T elemento, Elemento<T> prximoElemento) {
this.elemento = elemento;
this.prximoElemento = prximoElemento;
}
}
protected int numElementos;
protected Elemento<T> primeiroElemento;
// ...
}
LEEC@IST

Java 18/68

Utilizao de tipos genricos (1)


Os tipos genricos podem ser utilizados no contexto
de declarao/instanciao de tipos:

tipo de atributos;
tipo de variveis locais;
tipo dos parmetros de mtodos;
tipo de retorno de mtodos.

LEEC@IST

Java 19/68

Utilizao de tipos genricos (2)


Considere um mtodo que soma os elementos em
Conjunto<Number>:
static double soma(Conjunto<Number> cj) {
double res = 0.0;
for (Elemento<Number> aux=cj.primeiroElemento;
aux!=null;
aux=aux.prximoElemento)
res+=aux.elemento.doubleValue();
return res;
}

LEEC@IST

Java 20/68

Utilizao de tipos genricos (3)


Se tentarmos chamar o mtodo soma com um
Conjunto<Integer>, o cdigo no compila:
Conjunto<Integer> cj = new Conjunto<Integer>();
cj.adicionar(1);
cj.adicionar(2);
double soma = soma(cj); //INVLIDO!!!

Apesar de Integer ser um subtipo de Number,


Conjunto<Integer> no um subtipo de
Conjunto<Number>.
Por exemplo Conjunto<Integer> no contm o mtodo
cj.adicionar(Number x) de Conjunto<Number>
LEEC@IST

Java 21/68

Utilizao de tipos genricos (4)


A soluo definir o parmetro do mtodo soma
como um conjunto de Number ou de um qualquer
subtipo deste:
static double soma(Conjunto<? extends Number> cj) {
double res = 0.0;
for (Elemento<? extends Number> aux=cj.primeiroElemento;
aux!=null;
aux=aux.prximoElemento)
res+=aux.elemento.doubleValue();
return res;
}

O ? extends no parmetro tipo refere-se a um


Number ou a uma subclasse de Number.
? referido como um wildcard
LEEC@IST

Java 22/68

Utilizao de tipos genricos (5)


Tambm possvel definir o parmetro tipo de tal
forma que seja de um determinado tipo ou de um
qualquer supertipo deste.
Conjunto<? super Integer> denota um conjunto de
Integer, ou de um supertipo de Integer:

Conjunto<Integer>
Conjunto<Number>
Conjunto<Object>

O extends e o super no podem ser usados em


simultneo.
Extends implementa um uper bound wildcard
enquanto que super implementa um lower bound
wildcard.
LEEC@IST

Java 23/68

Utilizao de tipos genricos

Utilizao do super
Suponha que pretende implementar uma interface de uma lista
ordenada genrica, para tal necessita de um tipo para o qual esteja
definida uma ordem, ou seja implemente o interface
Comparable<E>
Ex: interface SortedCollection<E extends
Comparable<E>>
No entanto suficiente que E implemente Comparable para
qualquer supertipo de E, por exemplo basta que exista E.
compareTo(Object), pelo que mais correctamente devemos
fazer:
Ex: interface SortedCollection<E extends
Comparable<? Super E>>

LEEC@IST

Java 24/68

Utilizao de tipos genricos (6)


Tambm possvel definir o parmetro tipo de tal
forma que seja de um qualquer tipo.
O Conjunto<?> denota um conjunto de qualquer tipo.
Implicitamente, Conjunto<?> refere-se a um qualquer
tipo desde que seja um Object ou uma subclasse deste.

LEEC@IST

O Conjunto<?> outra forma de dizer Conjunto<?


extends Object> (e no Conjunto<Object>).

Java 25/68

Utilizao de tipos genricos (7)


Conjunto<?>
Object

Number

Conjunto<Object>

Conjunto<? extends Number>

Integer
Conjunto<Number>

Conjunto<? extends Integer>

Conjunto<Integer>
LEEC@IST

Java 26/68

Utilizao de tipos genricos (8)

Como o ? representa um tipo desconhecido, no possvel


chamar nenhum mtodo da classe parametrizada que receba o
parmetro tipo como parmetro:
Conjunto<?> cj = new Conjunto<Integer>();
cj.adicionar(new Integer(2)); //INVLIDO!!!
Conjunto<? extends Integer> cj = new Conjunto<Integer>();
cj.adicionar(new Integer(2)); //INVLIDO!!!
Conjunto<? super Integer> cj = new Conjunto<Integer>();
cj.adicionar(new Integer(2));
Conjunto<? super Integer> cj = new Conjunto<Integer>();
cj.adicionar(1.0); // INVLIDO!!!
cj.adicionar(new Object()); //INVLIDO!!!

LEEC@IST

Java 27/68

Utilizao de tipos genricos


void method(Conjunto<? extends Number> cj);
cj pode ser instanciada como
new Conjunto<Number>()
Aceita: cj.adicionar(new Integer(2));
Aceita: cj.adicionar(new Long(2));
Aceita: cj.adicionar(new Float(2));

new Conjunto<Integer>()
Aceita: cj.adicionar(new Integer(2));

new Conjunto<Long>()
Aceita: cj.adicionar(new Long(2));
new Conjunto<Float>()
Aceita: cj.adicionar(new Float(2));
no h mtodos comuns a todas as instancias pelo que a chamada a
cj.adicionar(T x) invlida.
No entanto posso chamar qualquer mtodo de Number.

LEEC@IST

Java 28/68

Utilizao de tipos genricos


void method(Conjunto<? super Integer> cj);
cj pode ser instanciada como
new Conjunto<Integer>()
Aceita: cj.adicionar(new Integer(2));

new Conjunto<Number>()
Aceita: cj.adicionar(new Integer(2));
Aceita: cj.adicionar(new Long(2));
Aceita: cj.adicionar(new Float(2));

new Conjunto<Object>()
Aceita: cj.adicionar(new Integer(2));
Aceita: cj.adicionar(new Long(2));
Aceita: cj.adicionar(new Float(2));
Aceita: cj.adicionar(new String(2));

O nico mtodo comum :


cj.adicionar(new Integer(2));

LEEC@IST

Java 29/68

Utilizao de tipos genricos (9)


Uma instancia de
Conjunto<Integer>
Pode ser atribuda a diferente declaraes de variveis:
Conjunto<?> cj = new Conjunto<Integer>();
System.out.println(cj.numConjunto());
Conjunto<? extends Integer> cj = new Conjunto<Integer>();
System.out.println(cj.numConjunto());
Conjunto<? super Integer> cj = new Conjunto<Integer>();
System.out.println(cj.numConjunto());

LEEC@IST

Java 30/68

Utilizao de tipos genricos (10)


O ? s pode ser utilizados no contexto de
declarao de tipos de variveis:

tipo de atributos;
tipo de variveis locais;
tipo dos parmetros de mtodos;
tipo de retorno de mtodos.

LEEC@IST

Java 31/68

Mtodos e construtores
genricos (1)
public class Conjunto<T> {
// ...
public T[] converterConjuntoParaTabela(T[] tabela) {
//... copiar elementos do conjunto para a tabela
return tabela;
}
}

O mtodo converterConjuntoParaTabela tal como


est definido demasiado restritivo (ver slide 11 e 12):
Num objecto de tipo Conjunto<Integer> temos de passar
como argumento uma tabela Integer[].
Num objecto de tipo Conjunto<Integer> nunca poderiamos
passar uma tabela Object[], mesmo sendo vlido guardar
objectos do tipo Integer numa tal tabela.
LEEC@IST

Java 32/68

Mtodos e construtores
genricos (2)
Um mtodo genrico declarado definindo o
parmetro tipo entre os qualificadores e o tipo de
retorno do mtodo:
public class Conjunto<T> {
//...
public <E> E[] converterConjuntoParaTabela(E[] tabela) {
Object[] tmp = tabela;
int i = 0;
for (Elemento<T> aux=primeiroElemento;
aux!=null;
aux=aux.prximoElemento)
tmp[i++] = aux.elemento;
return tabela;
}
}
LEEC@IST

Java 33/68

Mtodos e construtores
genricos (3)
Conjunto<Integer> cj = new Conjunto<Integer>();
Object[] tocj = new Object[cj.numElementos];
tocj = cj.converterConjuntoParaTabela(tocj);

Conjunto<Integer> cj = new Conjunto<Integer>();


Integer[] ticj = new Integer[cj.numElementos];
ticj = cj.converterConjuntoParaTabela(ticj);

LEEC@IST

Java 34/68

Mtodos e construtores
genricos (4)
Um mtodo ou construtor genrico no precisa de
ser declarado dentro duma classe genrica, mas se
o for os parmetros tipo so distintos.

LEEC@IST

Java 35/68

Mtodos e construtores
genricos (5)
O mtodo converterConjuntoParaTabela pode ser
chamado da seguinte forma:
Conjunto<Integer> cj = new Conjunto<Integer>();
Integer[] tcj = new Integer[cj.numElementos];
tcj = cj.<Integer>converterConjuntoParaTabela(tcj);

Esta chamada parametrizada informa o compilador que


o parmetro tipo E do mtodo
converterConjuntoParaTabela deve ser tratado
com um Integer, e que os argumentos e o retorno
devem estar de acordo com tal.
LEEC@IST

Java 36/68

Mtodos e construtores
genricos (6)
A chamada parametrizada s muito raramente
necessria. O compilador consegue, de uma maneira
geral, fazer a inferncia do tipo em causa:
Conjunto<Integer> cj = new Conjunto<Integer>();
Integer[] tcj = new Integer[cj.numElementos];
tcj = cj.converterConjuntoParaTabela(tcj);

A inferncia do tipo baseada no tipo esttico do


argumento passado ao mtodo ou construtor
genrico (no nos seus tipos dinmicos).
Tipo declarado ou cast explcito.
LEEC@IST

Java 37/68

Mtodos e construtores
genricos (7)
<T> T passarObjecto(T obj) {
return obj;
}
String s1 = Hello;
String s2 = this.<String>passarObjecto(s1);
String
String
Object
Object

s1
s2
o1
o2

=
=
=
=

Hello;
passarObjecto(s1);
passarObjecto(s1);
passarObjecto((Object)s1);

// T -> String
// T -> String
// T -> Object

String s1 = Hello;
s1 = passarObjecto((Object)s1); //INVLIDO(s com cast)!!!
String s1 = Hello;
s1 = (String) passarObjecto((Object)s1);
LEEC@IST

// T -> Object
Java 38/68

Mtodos e construtores
genricos (8)
A chamada parametrizada tem de ser sempre feita
sempre atravs do nome qualificado:

this.<Tipo>mtodo(params);
super.<Tipo>mtodo(params);
ref.<Tipo>mtodo(params);
IdentC.<Tipo>mtodos(params);
para mtodos estticos, onde IdentC o identificador da
respectiva classe.
String s1 = Hello;
String s2 = <String>passarObjecto(s1); //INVLIDO!!!

LEEC@IST

Java 39/68

Subtipos e tipos genricos (1)


possvel:
Definir um subtipo (genrico ou no) a partir de um
supertipo no genrico.
Definir uma subtipo (genrico ou no) a partir de um
supertipo genrico.
class
class
class
class
...

ListaGeral<E> implements List<E> {...}


ListaStrings implements List<Strings> {...}
ConjuntoNmeros<T extends Number> extends Conjunto<T> {...}
ConjuntoInteiros extends Conjunto<Integer> {...}

LEEC@IST

Java 40/68

Subtipos e tipos genricos (2)


Uma classe no pode implementar duas interfaces
que sejam diferentes parametrizaes da mesma
interface.
class Valor implements Comparable<Valor> {...}
class ValorEstendido extends Valor
implements Comparable<ValorEstendido> {...} //INVLIDO!!!

Nesse caso, a classe ValorEstendido teria de


implementar ambas as interfaces
Comparable<Valor> e
Comparable<ValorEstendido> (o que no
permitido).
LEEC@IST

Java 41/68

Apagamento (1)
Para cada tipo genrico h apenas um tipo.
Que tipo esse?
Dada a classe Conjunto<T>, que tipo
Conjunto<Integer> e Conjunto<Number> partilham?

Na realidade o compilador apaga toda a informao


do parmetro tipo na classe compilada:
O Conjunto<T> na classe compilada apenas
Conjunto.
O parmetro tipo T na classe compilada:
Object, quando se encontra num contexto <T> (Object
a superclasse implcita de T).
Number, quando se encontra num contexto <T extends
Number> (Number a superclasse explcita de T).
LEEC@IST

Java 42/68

Apagamento (2)
A informao que apagada do tipo parametrizado
denominada o apagamento (erasure).
Conjunto o apagamento de Conjunto<T>.
Object o apagamento de T num contexto <T>.
Number o apagamento de T num contexto <T extends
Number>.

O apagamento de um tipo genrico tambm


denominado o tipo cr (raw type).
Conjunto o tipo cr de Conjunto<T>.

O compilador gera a definio de um tipo para o


apagamento do tipo genrico substituindo todas as
utilizaes do parmetro tipo pelo correspondente
apagamento.
LEEC@IST

Java 43/68

Apagamento (3)
public class PassarObjecto<T> {
T passarObjecto(T t) { return t; }
}
public class PassarObjecto {
Object passarObjecto(Object t) { return t; }
}

Quando o tipo parametrizado usado e a informao sobre o tipo


resultante do apagamento insuficiente, o compilador insere um
cast.
PassarObjecto<String> pos = new PassarObjecto<String>();
String s1 = Hello;
s1 = pos.passarObjecto(s1);
PassarObjecto pos = new PassarObjecto();
String s1 = Hello;
s1 = (String) pos.passarObjecto(s1);

LEEC@IST

Java 44/68

Apagamento (4)
public class Elemento<T> {
protected T elemento;
protected Elemento<T> prximoElemento;
public Elemento(T elemento) {...}
public Elemento(T elemento, Elemento<T> prximoElemento) {...}
}
public class Elemento {
protected Object elemento;
protected Elemento prximoElemento;
public Elemento(Object elemento) {...}
public Elemento(Object elemento, Elemento prximoElemento) {...}
}

LEEC@IST

Java 45/68

Apagamento (5)
public class Conjunto<T> {
protected int numElementos;
protected Elemento<T> primeiroElemento;
public void adicionar(T elem) {...}
public void remover(T elem) {...}
public T escolher() {
return primeiroElemento.elemento;
}
public class Conjunto {
}
protected int numElementos;
protected Elemento primeiroElemento;
public void adicionar(Object elem) {...}
public void remover(Object elem) {...}
public Object escolher() {
return primeiroElemento.elemento;
}
}
LEEC@IST

Java 46/68

Apagamento (6)

Conjunto<String> cjs = new Conjunto<String>();


String s1 = Hello;
cjs.adicionar(s1);
s1 = cjs.escolher();
Conjunto cjs = new Conjunto();
String s1 = Hello;
cjs.adicionar(s1);
s1 = (String) cjs.escolher();

LEEC@IST

Java 47/68

Apagamento (7)
O apagamento faz com que, em tempo de execuo,
no seja permitido nada que necessite do
conhecimento do argumento tipo:
1. No possvel usar o parmetro tipo T para
criar objectos nem para criar tabelas.
public class Conjunto<T> {
// ...
public T[] converterConjuntoParaTabela() {
T[] res = new T[numElementos]; //INVLIDO!!!
//... copiar elementos do conjunto para a tabela
}
}

LEEC@IST

Java 48/68

Apagamento (8)
2. No possvel criar tabelas cujos elementos
sejam tipos parametrizados, com a excepo de
tipos parametrizados com ?.
Conjunto<String>[] tcjs = new Conjunto<String>[2]; //INVLIDO!!!
Conjunto<?>[] tabela = new Conjunto<?>[2];
tabela[0] = new Conjunto<String>();
tabela[1] = new Conjunto<Integer>();
((Conjunto<String>)tabela[0]).adicionar("Hello");
((Conjunto<Integer>)tabela[1]).adicionar(1);
System.out.println(tabela[0].escolher());
System.out.println(tabela[1].escolher());

LEEC@IST

Java 49/68

Apagamento (9)
3. No possvel usar o instanceof para verificar
se um objecto uma instncia dum tipo
parametrizado, com a exepo de tipos
parametrizados com ?.
Conjunto<String> strings = new Conjunto<String>();
boolean b = strings instanceof Conjunto<?>;
boolean b = strings instanceof Conjunto<String>; //INVLIDO!!!

Conjunto<?> strings = new Conjunto<String>();


System.out.println(strings instanceof Conjunto<?>);
System.out.println(strings instanceof Conjunto<String>); //INVLIDO!!!

LEEC@IST

Java 50/68

Apagamento (10)
4. Os casts envolvendo tipos parametrizados ou
parmetros tipo so substitudos por casts para
os correspondentes apagamentos.
Usualmente, tal faz com que o compilador gere
unchecked warnings: o cast no pode ser verificado
em tempo de execuo, nem tem garantia de ser
seguro em tempo de compilao.

LEEC@IST

Java 51/68

Apagamento (11)
void adicionarStringHello(Conjunto<?> cj) {
Conjunto<String> strings = (Conjunto<String>) cj; //unchecked
strings.adicionar(Hello);
}
void adicionarStringHello(Conjunto cj) {
O erro em tempo de
Conjunto strings = (Conjunto) cj;
strings.adicionar(Hello);
execuo surgir
}
numa linha diferente

de onde est o erro.


Conjunto<Integer> integers = new Conjunto<Integer>();
adicionarStringHello(integers);
//ok
Integer nb = integers.escolher(); //erro em tempo de execuo!!!
Conjunto integers = new Conjunto();
adicionarStringHello(integers);
Integer nb = (Integer) integers.escolher();
LEEC@IST

Java 52/68

Apagamento (12)
Object passarObjecto(Objecto obj) {
return obj;
}
Conjunto<String> strings = new Conjunto<String>();
Object obj = passarObjecto(strings);
Conjunto<String> cj1 = (Conjunto<String>) obj; // unckecked
Conjunto<String> cj2 = (Conjunto) obj;
// unckecked e tipo cr
Conjunto<?> cj3 = (Conjunto) obj;
// ok mas tipo cr
Conjunto<?> cj4 = (Conjunto<?>) obj;
// ok

Os tipos crs existem por razes de cdigo legado,


por isso devem ser evitados.

LEEC@IST

Java 53/68

Limites de parmetros e
argumentos tipo (1)
Parmetro (tipo)
(na definio de mtodos ou tipos parametrizados)
void foo(int n, char c) {...} //n e c so parmetros
class Conjunto<T> {...}
//T um parmetro tipo
<T> T escolher() {...}
//T um parmetro tipo

Argumento (tipo)
(na chamada de mtodos ou declarao/instanciao
de tipos parametrizados)
foo(5,a);
Conjunto<?> cj1;
cj1 = new Conjunto<String>;
this.<String>escolher();
LEEC@IST

//5 e a so argumentos
//? um argumento tipo
//String um argumento tipo
//String um argumento tipo
Java 54/68

Limites de parmetros e
argumentos tipo (2)
Na definio de tipos/mtodos genricos, um
parmetro tipo da forma:
<T> diz-se um parmetro tipo simples.
<T extends Number> diz-se um parmetro tipo com limite
superior (neste caso Number).

Na declarao de tipos genricos, um argumento tipo


da forma:
<T> diz-se um argumento tipo simples.
<T extends Number> ou <? extends Number> diz-se um
argumento tipo com limite superior (neste caso Number).
<T super Number> ou <? super Number> diz-se um
argumento tipo com limite inferior (neste caso Number).
<?> diz-se um argumento tipo ilimitado.

LEEC@IST

Java 55/68

Sobreposio em
tipos genricos (1)

No Java, a assinatura de um mtodo definida por:


Identificador do mtodo.
Nmero e tipo dos parmetros do mtodo.
A assinatura de um mtodo genrico definida por:
Identificador do mtodo.
Nmero e tipo de parmetros (incluindo parmetros e limites
tipo do mtodo).
Dois mtodos tm assinaturas equivalentes (overrideequivalente signature) se tm a mesma assinatura, ou se aps o
apagamento tm a mesma assinatura.
Um mtodo uma sobreposio de outro se ambos tm o
mesmo identificador mas no tm assinaturas equivalentes.

LEEC@IST

Java 56/68

Sobreposio em
tipos genricos (2)
class SuperClasse<T> {
void m(int x) {}
void m(T t) {}
void m(String s) {}
<N extends Number> void m(N n) {}
void m(Conjunto<?> cj) {}
}

A classe SuperClasse define cinco sobreposies do mtodo m:

void
void
void
void
void

LEEC@IST

m(int x) {}
m(Object t) {}
m(String s) {}
m(Number n) {}
m(Conjunto cj) {}
Java 57/68

Sobreposio em
tipos genricos (3)

um erro uma classe ou interface declarar dois mtodos com o


mesmo identificador e a mesma assinatura aps apagamento.
Definir qualquer dos seguintes mtodos na classe SuperClasse
daria erro:

void m(Object o) {}
void m(Number n) {}
<G extends String> void m(G g) {}
void m(Conjunto<Object> cj) {}
class SuperClasse<T> {
void m(int x) {}
void m(T t) {}
void m(String s) {}
<N extends Number> void m(N n) {}
void m(Conjunto<?> cj) {}
}

LEEC@IST

Java 58/68

Redefinio em
tipos genricos (1)

Um mtodo num subtipo uma redefinio dum mtodo do


supertipo se:
1. Ambos os mtodos tm assinaturas equivalentes.
2. O retorno dos mtodos tem de ser covariante (antes do
apagamento)
Temos ainda que:

Um mtodo genrico no pode redefinir um mtodo no genrico.


Um mtodo genrico pode redefinir um mtodo genrico.
Um mtodo no genrico pode redefinir um mtodo genrico.

LEEC@IST

Java 59/68

Redefinio em
tipos genricos (2)
class SuperClasse<T> {
void m(int x) {}
void m(T t) {}
void m(String s) {}
<N extends Number> void m(N n) {}
void m(Conjunto<?> cj) {}
}

class SuperClasse {
void m(int x) {}
void m(Object t) {}
void m(String s) {}
void m(Number n) {}
void m(Conjunto cj) {}
}

class SubClasse<T> extends SuperClasse<T> {


void m(Integer i) {}
void m(Object t) {}
void m(Number s) {}
}

LEEC@IST

Java 60/68

Redefinio em
tipos genricos (3)
Em relao ao exemplo anterior:
O mtodo m(Integer i) uma sobreposio dos
mtodos m da SubClasse.
O mtodo m(Object t) da SubClasse uma redefinio
do mtodo m(T t) da SuperClasse.
O mtodo m(Number cj) da SubClasse uma
redefinio do mtodo m(N n) da SuperClasse.

LEEC@IST

Java 61/68

Redefinio em
tipos genricos (4)
class SuperClasse<T> {
void m(int x) {}
void m(T t) {}
void m(String s) {}
<N extends Number> void m(N n) {}
void m(Conjunto<?> cj) {}
}

class SuperClasse {
void m(int x) {}
void m(Object t) {}
void m(String s) {}
void m(Number n) {}
void m(Conjunto cj) {}
}

class SubClasse<T> extends SuperClasse<T> {


void m(Number n) {}
//ok
<S extends String> void m(S s) {} //INVLIDO!!!
}
class SubClasse extends SuperClasse {
void m(Number n) {}
void m(String s) {}
}
LEEC@IST

Java 62/68

Redefinio em
tipos genricos (5)
Em relao ao exemplo anterior:
O mtodo m(Number n) da SubClasse uma redefinio
do mtodo m(N n) da SuperClasse.
O mtodo m(S s) da SubClasse tenta fazer uma
redefinio do mtodo m(String s) da SuperClasse,
mas tal no permitido!

LEEC@IST

Java 63/68

Redefinio em
tipos genricos (6)
class SuperClasse {
protected Integer i;
<N extends Number> Number m1(N n) {return i;}
<N extends Number> N m2() {return (N) i;}
}
class SuperClasse {
protected Integer i;
Number m1(Number n) {return i;}
Number m2() {return (Number) i;}
}
class SubClasse extends SuperClasse {
<N extends Number> Integer m1(N n) {return i;}
<N extends Integer> N m2() {return (N) i;}
}
class SubClasse extends SuperClasse {
Integer m1(Number n) {return i;}
Integer m2() {return (Integer) i;}
}
LEEC@IST

Java 64/68

Redefinio em
tipos genricos (7)
O mtodo Integer m1(N n) da SubClasse uma
redefinio do mtodo Number m1(N n) da
SuperClasse.
O mtodo N m2() da SubClasse no uma redefinio
do mtodo N m2() da SuperClasse.
<N extends Number> != <? extends Number>
<N extends Number> N m2() pode implementar,
Integer <Integer>m2()
Long <Long>m2()
Float <Float>m2()

<N extends Integer> N m2() pode implementar,


Integer <Integer>m2()

Pelo que na classe derivada no seriam redefinidas todas as


implementaes do mtodo pois Integer no covariante com
Long ou Float
LEEC@IST

Java 65/68

Redefinio em
tipos genricos (8)
class SuperClasse {
protected Integer i;
<N extends Number> Number m1(N n) {return i;}
<N extends Number> N m2() {return (N) i;}
}
class SubClasse extends SuperClasse {
@Override //ok
<N extends Number> Integer m1(N n) {return i;}
Sobre-posio e chamada ambigua//!!!
<N extends Integer> N m2() {return (N) i;}
}

LEEC@IST

Java 66/68

Herana e sobreposio de
mtodos (revisitado) (1)

As mudanas ao algoritmo para escolha do mtodo


mais especfico para o caso de tipos genricos so:
1. Se a chamada do mtodo inclui argumentos tipo
explcitos:

So escolhidos como potencialmente aplicveis os mtodos


genricos com o mesmo nmero de parmetros tipo.

2. Se a chamada do mtodo no inclui argumentos tipo


explcitos:

feita a inferncia do tipo (baseada no tipo esttico dos


argumentos tipo passados na invocao do mtodo) e
escolhem-se os mtodos potencialmente aplicveis.
Este passo necessrio para mtodos em que por exemplo
o parmetro tipo aparece de repetido. Estes no sero
considerados se os argumentos tipo forem diferentes. Ex:

LEEC@IST

<T> foo(T x, T y)
Java 67/68

Herana e sobreposio de
mtodos (revisitado) (2)
3. De todos os mtodos aplicveis seleccionado
o mais especifico.
O mtodo A mais especifico do que o B se
qualquer chamada a A tambm pode ser feita a
B. A determinao do mtodo mais especifico
ser ento efectuada levando em conta os
limites aos parmetros tipo, e pode ser feita
determinando o mtodo mais especifico depois
do apagamento.

LEEC@IST

Java 68/68

Herana e sobreposio de
mtodos (revisitado) (3)
void m(String s, Object o) {...}
// 1 forma
<S, T extends Number> void m(S s, T t) {...} // 2 forma

As seguintes chamadas:
m(hello, world);
m(new Object(), 29);
m(hello, Integer.valueOf(29));
resultam na chamada de que forma do mtodo m?

LEEC@IST

Java 69/68

Herana e sobreposio de
mtodos (revisitado) (4)
Relativamente ao exemplo anterior:
m(hello, world);
resulta na chamada da 1 forma do mtodo xpto.
m(new Object(), 29);
resulta na chamada da 2 forma do mtodo xpto.
m(hello, Integer.valueOf(29));
invlida.

LEEC@IST

Java 70/68

Herana e sobreposio de
mtodos (revisitado) (5)
No exemplo anterior,
m(hello, Integer.valueOf(29));
uma chamada invlida, contudo:
Com o cast (Object)Hello a chamada
m((Object)Hello, Integer.valueOf(29));
resulta na chamada da 2 forma de m.
Com o cast (Object) Integer.valueOf(29) a
chamada
m(Hello, (Object) Integer.valueOf(29));
resulta na chamada da 1 forma de m.

LEEC@IST

Java 71/68