Aula 11 - manipulação de ref, polimorfismo e lig. din
-
Upload
marcelo-vale-rio -
Category
Documents
-
view
30 -
download
4
Transcript of Aula 11 - manipulação de ref, polimorfismo e lig. din
1
Aula 11 – Manipulação de Referências,
Polimorfismo e Ligação Dinâmica
Programação
Orientada a Objetos
Rafael Braga
2
• De maneira geral, o tratamento dado em Java para
conversões de tipo para referências a objetos é análogo
ao que acontece nas conversões de tipos primitivos.
• Conversões de tipo (classe) para referências a objetos
podem ocorrer:
– implicitamente, em atribuições e passagem de parâmetros, ou
– através de casting explícito.
• Conversões de tipos mais específicos para tipos mais
gerais (upcasting) são permitidas.
• O contrário, conversões de tipos mais gerais para tipos
mais específicos (downcasting) exigem casting
explícito. Isto vale para a hierarquia completa de
herança, incluindo classes e interfaces.
Manipulando Referências
3
• Regras de Conversão para Operações com
Variáveis de Referência
1. Operação de Atribuição:
TipoDeOrigem origRef;
TipoDeDestino destRef = origRef;
2. Operação de Passagem de Parâmetro:
TipoDeOrigem origRef;
enviarParam( origRef );
...
void enviarParam( TipoDeDestino destRef )
{ ... }
Manipulando Referências
4
• Como já foi visto em seções anteriores, a
passagem de parâmetros de tipos primitivos
em Java é feita por valor, ou seja, uma cópia do
valor original é feita.
• Isso significa que modificações no parâmetro
formal não são refletidas no parâmetro real.
• Para arrays, uma cópia da referência para o
array é passada.
• Para objetos, uma cópia da referência ao
objeto é passada, e não uma cópia do objeto.
Passagem de Parâmetros
5
• Para arrays, uma cópia da referência para o array é passada, assim, as mudanças no seus elementos dentro de um método, se refletem no lugar onde o método foi chamado. public static void somar(int[] x)
{
x[2] = x[1] + x[0];
}
public static void main (String args[]) {
int[] a = new int[3];
a[0] = 1;
a[1] = 10;
a[2] = 20;
System.out.println(“antes >”+ a[2]);
somar(a);
System.out.println(“depois >”+ a[2]);
}
antes >20
depois >11
Passagem de Parâmetros com Arrays
6
• Graficamente...
public static void somar(int[] x)
{
x[2] = x[1] + x[0];
}
...
somar(a);
Passagem de Parâmetros com Arrays
1 10 20
a
x
7
hoje 0x852ef8b
dia = 11;
mes = 05; ano = 2004;
Passagem de Parâmetros com Referências
• Relembrando funcionamento das referências... Data hoje;
hoje = new Data();
hoje.setDia(11);
hoje.setMes(02);
hoje.setAno(2004);
Data outroDia = hoje;
outroDia.setMes(05);
outroDia
referências objeto
8
• Esse “fenômeno” é conhecido como aliasing.
• Apesar da passagem por parâmetros em Java ser
por valor, pode-se ter aliasing quando um objeto é
passado como parâmetro, assim como acontece
na atribuição de referências.
• É sempre a referência (ponteiro) de um objeto que
é passada como parâmetro e não o objeto em si.
• O parâmetro formal passa a ser uma referência
para a mesma instância do objeto passado, logo,
qualquer mudança nos valores do objeto se reflete
no lugar onde o método foi chamado.
Passagem de Parâmetros com Referências
9
• Exemplo public static void main( String args[] ) {
Data hoje;
hoje = new Data();
funcao(hoje);
System.out.println( hoje.getMes() ); // 10
}
static void funcao( Data umaData ) {
umaData.setMes( 10 );
}
Passagem de Parâmetros com Referências
hoje
0x852ef8b
dia = 0; mes = 10; ano = 0;
umaData
10
• Perceba que os valores dos campos do objeto
podem ser alterados dentro do método chamado,
porém, mudanças na própria referência dentro do método não afetam a referência externa. public static void main( String args[] ) {
Data hoje;
hoje = new Data();
funcao(hoje);
System.out.println( hoje.getMes() );
}
void funcao( Data umaData ) {
umaData.setMes( 10 );
umaData = new Data();
umaData.setDia( 22 );
}
Passagem de Parâmetros com Referências
11
• Graficamente...
Passagem de Parâmetros com Referências
hoje
0x1402bc84
dia = 22; mes = 0; ano = 0;
0x852ef8b
dia = 0; mes = 10; ano = 0;
umaData
12
• Casting de Referências Object
Estundante
EstudanteMonitor
Upcasting
Casting implícito
Ex:
EstudanteMonitor em = new EstudanteMonitor();
Estudante e = em;
Manipulando Referências
13
• Exemplos public class Programa {
EstudanteMonitor em = new EstudanteMonitor();
// situação 1
Estudante e = em;
// situação 2
Turma t = new Turma();
t.matricular( em );
}
public class Turma {
...
public void matricular( Estudante e ) {...}
...
}
Origem
Manipulando Referências
Destino
14
• O operador binário instanceof tem a seguinte sintaxe:
variavelDeReferencia instanceof TipoDeDestino
• O operador instanceof retorna true se o objeto denotado pela variavelDeReferencia, em tempo de execução é – uma instância da classe TipoDeDestino
– ou uma instância de uma subclasse dela.
• Perceba que esse teste é feito em tempo de execução.
Operador instanceof
15
• Em tempo de compilação, porém, é verificado se o tipo da variavelDeReferencia e o TipoDeDestino estão no mesmo ramo da hierarquia de classes.
• Do contrário, acontecerá um erro de compilação.
Operador instanceof
C c = new C();
c instanceof C
c instanceof B
c instanceof A
c instanceof E
c instanceof D
c instanceof Object
A
D
B
C
E
c
true
true
true
false
ERRO COMP.
true
16
• Para fazer casting (conversão) da variavelDeReferencia do TipoDeOrigem para o TipoDeDestino, usa-se a seguinte sintaxe:
( TipoDeDestino ) variavelDeReferencia
• O casting acima é possível se o objeto denotado pela variavelDeReferencia, em tempo de execução é: – uma instância da classe TipoDeDestino,
– ou uma instância de uma subclasse dela.
Casting de Referências
17
• Quando usar o casting: public class Turma {
...
public Estudante obterEstudante(int mat)
{...}
}
...
EstudanteMonitor em;
em = new EstudanteMonitor(111, “Pedro”, „M‟);
Turma t = new Turma()
t.matricular( em );
EstudanteMonitor em2 = t.obterEstudante( 111 );
Casting de Referências
ERRO DE COMPILAÇÃO, pois o método obterEstudante() retorna um Estudante e
não um EstudanteMonitor.
18
• Solução → casting: public class Turma {
...
public Estudante obterEstudante(int mat) {...}
}
...
EstudanteMonitor em;
em = new EstudanteMonitor(111, “Pedro”, „M‟);
Turma t = new Turma()
t.matricular( em );
EstudanteMonitor em2 =
((EstudanteMonitor)t.obterEstudante( 111 ));
Casting de Referências
É necessário dizer ao compilador que o método obterEstudante() vai retornar em tempo de execução,
nesse caso, um objeto da subclasse EstudanteMonitor.
19
• Quando usar o casting: ...
EstudanteMonitor em = new EstudanteMonitor();
Turma t = new Turma()
t.matricular( em );
Estudante e = t.obterEstudante( 111 );
e.tirarDuvidas();
...
Casting de Referências
ERRO DE COMPILAÇÃO,
pois a classe Estudante não
possui um método chamado tirarDuvidas().
20
• Solução → casting: ...
EstudanteMonitor em = new EstudanteMonitor();
Turma t = new Turma()
t.matricular( em );
Estudante e = t.obterEstudante( 111 );
((EstudanteMonitor) e ).tirarDuvidas();
...
Casting de Referências
É necessário dizer ao compilador que a referência „e‟ denotará, em tempo de
execução, um objeto que possui um método chamado tirarDuvidas().
21
Object
Estudante
EstudanteMonitor
Downcasting
É necessário fazer o
casting explícito
Upcasting
Casting implícito
Ex:
EstudanteMonitor em =
new EstudanteMonitor ();
Estudante e = em;
Ex:
Estudante e = new
EstudanteMonitor();
EstudanteMonitor em =
(EstudanteMonitor)e;
Casting de Referências
22
• Escrevendo código seguro: combinando Casting e instanceof ...
EstudanteMonitor em = new EstudanteMonitor();
Turma t = new Turma()
t.matricular( em );
Estudante e = t.obterEstudante( 111 );
if ( e instanceof EstudanteMonitor )
{
( (EstudanteMonitor) e ).tirarDuvidas();
}
...
Casting e instanceof
23
• Tanto o casting quanto o operador instanceof requerem verificação: – em tempo de compilação, que avalia somente as
referências, e
– em tempo de execução, que avalia o objeto propriamente dito.
• Atenção para a situação abaixo:
// o trecho abaixo passa na compilação,
// mas vai gerar erro de execução
Estudante e = new Estudante();
EstudanteMonitor em = (EstudanteMonitor)e;
Casting e instanceof
O objeto referenciado por „e‟ é, de fato, um Estudante, e não um EstudanteMonitor.
24
• Comportamento dos métodos com Casting class Estudante {
public void exibir() { ...
System.out.println("metodo exibir de Estudante");
}
public double lerNota(int prova) {
System.out.println("metodo lerNota de Estudante");
return notas[prova-1];
}...}
class EstudanteMonitor extends Estudante {
public void exibir() {
System.out.println("metodo exibir de
EstudanteMonitor");
}
public void tirarDuvidas() {
System.out.println("metodo tirarDuvidas de
EstudanteMonitor");
}...}
Casting – Usando Métodos
25
• Comportamento dos métodos com Casting public class Programa {
public static void main( String args[] ) {
EstudanteMonitor em = new EstudanteMonitor();
em.exibir(); // executa o exibir() redefinido em
// EstudanteMonitor
em.lerNota(1); // executa o lerNota() de Estudante
em.tirarDuvidas(); // executa o tirarDuvidas() de
// EstudanteMonitor
Estudante e = em;
e.exibir(); // executa o exibir() redefinido em
// EstudanteMonitor
// e.tirarDuvidas(); // não existe tirarDuvidas() na
// classe Estudante -> ERRO!!!
((EstudanteMonitor)e).tirarDuvidas(); // Ok
((Estudante)e).exibir(); // executa o exibir()
// do objeto, portanto,
// de EstudanteMonitor
}
}
Casting – Usando Métodos
26
• Qual objeto uma referência realmente denotará
em tempo de execução nem sempre se pode
determinar em tempo de compilação.
• Polimorfismo é a capacidade de uma referência
denotar diferentes objetos na hierarquia de
herança em diferentes momentos durante a
execução. Tal referência é uma referência de
supertipo.
• Quando um método é invocado usando uma
referência, a definição do método que será
realmente executada é determinada:
– pela classe denotada pela referência em tempo de
execução, e
– pela assinatura do método.
Polimorfismo
27
• Entendendo o Polimorfismo...
(1) EstudanteMonitor em = new EstudanteMonitor();
(2) Estudante e = em;
(3) e.atribuirNota(1, 7.5);
(4) e = new EstudanteEstagiario();
(5) e.atribuirNota(1, 8.5);
Estudante
EstudanteMonitor
e
em
EstudanteEstagiario (1)
(2) (4)
Polimorfismo
28
• Usando o Polimorfismo... public class Turma {
...
public Estudante obterEstudante(int mat) {...}
public void matricular (Estudante e) {...}
}
...
EstudanteMonitor em;
em = new EstudanteMonitor(111, “Pedro”, „M‟);
Turma t = new Turma()
t.matricular( em );
EstudanteMonitor em2 =
((EstudanteMonitor)t.obterEstudante( 111 ));
Polimorfismo
29
• Numa hierarquia de herança de classes, dois
métodos podem ter o mesmo nome e tipo:
– Definição e redefinição, qual usar?
• O código é escolhido dinamicamente (em tempo
de execução), não estaticamente (em tempo de
compilação).
• Escolha é feita com base na classe do objeto
associado à variável destino do método.
• O mecanismo de ligação dinâmica (dynamic
binding) é responsável por associar uma
solicitação (de um método) a um objeto em tempo
de execução.
Ligação Dinâmica
30
• Observando o emprego do Polimorfismo e da Ligação Dinâmica
public class Programa {
public static void main( String args[] ) {
Estudante e = new Estudante(“Pedro”);
e.exibir(); // executa o exibir() de Estudante
e = new EstudanteMonitor(“Maria”);
e.exibir(); // executa o exibir() redefinido em
// EstudanteMonitor
e = new EstudanteEstagiario(“Fernanda”);
e.exibir(); // executa o exibir() redefinido em
// EstudanteEstagiario
}
}
Ligação Dinâmica
31
Questionário
1. O que é upcasting e downcasting?
2. Em que situação ou situações é necessário fazer casting explicíto?
3. Em que situação ou situações não é necessário fazer casting explicíto?
4. Quando o operador instanceof retorna verdadeiro?
5. Que validação é feita em tempo de compilação quando se usa o operador instanceof?
6. Que validação é feita em tempo de execução quando se usa o operador instanceof?
7. Qual a relação do casting com o operador instanceof?
8. Por que conversões usando casting são ditas inseguras?
9. O que é polimorfismo?
10. Na herança de classes, quando há redefinição de métodos, o que se pode dizer sobre a execução do método?
11. Explique o mecanismo de ligação dinâmica.
32
Prática de Laboratório
1. Implementar o programa do slide 27 para testar o emprego do casting.
2. Implementar o programa do slide 33 para testar o emprego do polimorfismo e da ligação dinâmica.
3. Criar uma classe chamada „Apresentador‟ que possui um único método chamado apresentar(Estudante e), que recebe como argumento um Estudante e exibe seus dados, ou seja, chama o método exibir do objeto passado.
4. Codifique um programa para criar um apresentador e três estudantes (comum, monitor e estagiário) e passá-los ao apresentador para exibir seus dados. Observe o emprego do polimorfismo e da ligação dinâmica.