Arquivar

Archive for the ‘Programação’ Category

Flash CS4 e pontos de fuga?

Eu, sempre preocupado com o mundo Apple, acabo nunca postando nada no TI Developer, mas ontem fiz umas pesquisas interessantes com Flash e resolvi compartilhar com os nobres leitores deste nobre blog.

Esse é um exemplo de um workflow de duas horas de trabalho com Flash CS4. Não funciona em CS3, nem pense nisso!

Ontem me deparei com uma situação interessante: a empresa onde trabalho está fazendo um layout mais arrojado para um desses sites cheios de flash e um dos recursos do layout envolve um quadrado que gira em torno do próprio eixo. Um lado do quadrado mostra um conteúdo, e outro lado mostra outro conteúdo. Simples, não? Não.
Um programador que trabalha comigo resolveu usar o Papervision 3D. A princípio ele fez 18 cubos com lateral 0. Os cubos eram idênticos a quadrados. A face da frente e a de trás possuiam um movieclip diferente cada. O efeito funcionou. Mas… (sempre tem um “mas”) o flash precisa renderizar quadro-a-quadro 18 cubos girando. Isso significa que o SWF ficou deveras pesadíssimo.

Como contornar isso? A primeira resolução foi acabar com essa folia de cubos. Cada “quadrado” tinha 4 faces inúteis e duas faces com movieclips quando poderíamos usar só uma. Acabar com esse POG deixou o negócio mais leve, mas ainda estava pesado demais para a web.

Então eu entrei na jogada. Por que usar Papervision? O flash CS4 já dá suporte a 3 dimensões. E girar uma droga dum quadradinho não deveria ser tão difícil! Girar 18 quadradinhos deveria dar no mesmo.
Eu sou um programador de ActionScript 2. Embora saiba programar em AS3, não gosto muito porque acho o AS3 muito enrolado com coisas óbvias. Mas enfim, resolvi fuçar os arquivos de ajuda atrás de uma solução mais simples.

Eis minha idéia:
Pegamos o conteúdo de cada face.
Criamos um MovieClip.
O MovieClip terá 2 quadros. Cada um vai comportar um dos dois conteúdos.
Quadrados são bidimensionais. Então sempre que girarmos o quadrado, poderemos nos deparar com 2 situações:
ou haverá um quadro em que ele ficará invisível ou, de um quadro para outro veremos uma e outra face, sem intermédios.
Justamente nessa mudança mudaremos do quadro 1 para o 2, dando a impressão que estamos vendo o verso do quadro, quando na verdade só vemos outro quadro. Entendeu? =D

Ok.. Você leu até aqui e não entendeu picas? Então vamos pôr a mão na massa e irás entender.

Estou usando Windows XP aqui no trabalho, então os atalhos de teclado aqui não valem para quem usa Mac, beleza?

Na maioria das vezes, quem usa mac só precisa trocar o [Ctrl] por [Command] e [Enter] por [Return]. Mas vá, se vc que lê isso tem flash, saberá se virar sozinho, certo?

1. Criando o MovieClip

Abri meu flash e criei um novo documento em AS3. Apertei [Ctrl+F8]. Dei o name de “bola”, type “MovieClip”. [Enter].
Apertei a tecla [R] do meu teclado para fazer um quadrado. No painel procurei o “fill and stroke” e deixei sem linhas, só preenchimento. Criei um retângulo. Cliquei depois nesse retângulo e deixei com H em -100, Y em -100 também, W em 200 e H em 200 também. Pronto. Um quadrado. Um quadrado chamado “bola”. “Quadrado” tem 8 letras. “Bola” tem 4 letras. Muito mais econômico.
Deixei meu quadrado vermelho “#FF0000″.
Então apertei [F6]. Meu quadro na linha do tempo foi duplicado. No quadro 2 deixei esse quadrado verde “#006600″.
Criei um novo layer na linha do tempo. Cliquei no quadro 1 desse novo layer, apertei [F9] e escrevi isso:

stop();

Pronto. Simples.

2. Posicionando o MovieClip

Voltei para o “Scene 1″. Apertei [Ctrl+L] para ver minha biblioteca e arrastei o MovieClip “bola” para o palco. Segurei [Ctrl+K]. Deixei a opção “To stage” acionada. Cliquei no MovieClip, apertei [Ctrl+Alt+2] e depois [Ctrl+Alt+5]. Agora meu quadrado está centralizado. Na janela properties eu instanciei ele como “bola”.
Criei um novo layer na linha do tempo. Cliquei no frame em branco desse layer. Apertei [F9] de novo. Agora… ActionScript!

3. Criando a animação

Primeiro vamos fuçar o método “Tween”.

Copiei e colei um código de animação e troquei o nome do MovieClip ali. Ficou assim:

import fl.transitions.*;
import fl.transitions.easing.*;

var t1:Tween=new Tween(bola,”x”,Regular.easeIn,0,100,2,true);

Vamos por partes então. Linhas 1 e 2 importam bibliotecas que vou usar no tween.
A linha 4 cria um objeto Tween. Ele vai incrementar a coordenada x do MovieClip chamado “bola”, de 0 a 100, em 2 segundos, usando uma suavização conhecida como “easeIn”. Ou seja, vai começar lento e terminar rápido.
Não quero esse ritmo, então trocarei por “None.easeNone”. Se eu der [Ctrl+Enter] eu verei meu quadrado percorrendo um certo espaço. Parece uma lesma.
Enfim… sei que posso usar qualquer propriedade do meu MovieClip na classe Tween. Vou substituir o “x” por “rotationY”, porque quero girá-lo. A propriedade “rotationY” usa o princípio de graus. Quero que meu quadrado vire ao contrário. Isso serão 180 graus. Então meu código ficou assim:

import fl.transitions.*;
import fl.transitions.easing.*;

var t1:Tween=new Tween(bola,”rotationY”,None.easeNone,0,180,2,true);

Girou! Aêê! Quem precisa de PaperVision pra fazer isso?
Continuemos. Eu preciso mudar a face do bagulho quando chegar a 90 graus. Para isso vou construir um listener. Não quero usar “onEnterFrame” porque fica lerdo e ocupa memória. Então vou fazer o listener sobre o Tween.

t1.addEventListener(TweenEvent.MOTION_CHANGE, teste);

Simples né? Não funciona, pois não existe a função “teste” ainda. Então criei uma função “teste”:

function teste(e:Event):void {
trace(1);
}

Pronto. Agora quando o quadrado girar receberei o valor “1″ no output. Isso serve para eu ver se o listener funciona direitinho.
Vamos fazer isso ficar mais útil e me informar a posição do quadrado.
Ao invés de:

trace(1);

vou usar

trace(e.target.obj.rotationY);

Veja que interessante: e.target aponta para meu Tween. “obj” é o objeto que o Tween está alterando, no caso, “bola”; e “rotationY” é propriedade de “bola”.
Agora posso mudar o quadro quando chegar em 90 graus. Meu código ficou assim:

import fl.transitions.*;
import fl.transitions.easing.*;

var t1:Tween=new Tween(bola,”rotationY”,None.easeNone,0,180,2,true);

t1.addEventListener(TweenEvent.MOTION_CHANGE, teste);

function teste(e:Event):void {
if (e.target.obj.rotationY>90) {
e.target.obj.gotoAndStop(2);
}
}

4. Corrigindo o ponto de fuga

Maravilha! Parece que mudou mesmo. Tudo certo? Então pronto.
Pronto nada. Tem um porém nessa coisa toda. Vamos mudar a posição desse MovieClip.
Ponho meu X em 434 e meu Y em 284. Agora vejamos. Percebe o que aconteceu? Não? Então vamos deixar mais lento.
Mude a linha 4 para ficar assim (olha o 5 ali):

var t1:Tween=new Tween(bola,”rotationY”,None.easeNone,0,180,5,true);

Agora execute de novo. Viu agora? O quadrado ficou verde antes dos 90 graus! Mas como isso!?
Muita calma nessa hora.
Em primeiro lugar o flash não mudou o quadro nem antes nem depois da hora que foi definida. Passou de 90 graus, é instantâneo. A pergunta não é “porque ele mudou antes dos 90 graus”, mas “por que os 90 graus não estão perpendiculares à ‘câmera’?”.
Simples: o Flash possui um ponto de fuga. Quando o MovieClip estava centralizado, o ponto de fuga ficava exatamente no meio do quadrado e ele mudava de cor exatamente no momento em que as face fica visível do lado oposto. Quando deslocamos o MovieClip para outro ponto no palco, o ponto de fuga mudou em relação a ele e a visão dos 90 graus mudou. Se você não entendeu isso, pegue uma carta de baralho e deixe-a na perpendicular até que ela pareça uma linha. Agora desloque o seu braço para a direita ou esquerda sem mudar a posição da carta em relação ao braço. Vê que uma face ficou mais visível né? Pois é. O flash simula perspectivas.

Meu POG falhou. Mas não desisto!
Pensando com meus botões concluí: deve existir um meio de mudar o ponto de fuga do movieclip!
E tem. Vamos lá:

Podemos declarar um objeto do tipo “PerspectiveProjection” (com p maiúsculo) e mudar o valor de seu “projectionCenter”.
O MovieClip ainda tem uma propriedade chamada “perspectiveProjection” (com p minúsculo). Se atribuirmos essa nova variável a seu resultado final, conseguimos mudar o ponto de fuga. Os novos valores serão o centro do objeto: as coordenadas x e y. Meu código ficou assim:

import fl.transitions.*;
import fl.transitions.easing.*;

var t1:Tween=new Tween(bola,”rotationY”,None.easeNone,0,180,5,true);

t1.addEventListener(TweenEvent.MOTION_CHANGE, teste);
var pp:PerspectiveProjection = new PerspectiveProjection();

function teste(e:Event):void {
pp.projectionCenter=new Point(e.target.obj.x,e.target.obj.y);
e.target.obj.transform.perspectiveProjection=pp;
if (e.target.obj.rotationY>90) {
e.target.obj.gotoAndStop(2);
}
}

Simples, apesar de tudo. Declarei uma variável, atribuí um valor e troquei uma propriedade. Só isso. Não se assuste com o tamanho do negócio, na verdade é só variáveis de nome grande, nada mais.

5. Corrigindo a inversão do MovieClip

Mas ainda não terminei. Preciso saber se meu MovieClip exibe o conteúdo corretamente.
Abrindo o MC “bola”, vou ao quadro 1 e ponho uma grande letra “R” no meio do quadrado. No quadro 2 eu ponho uma letra “K”.

Executando… Mas que diabos! A letra “K” inverteu!
É claro, eu girei o MC inteiro. Se houvesse só um quadro para ver, eu veria ele invertido, espelhado.
Eu pensei a princípio em fazer uma verificação do ângulo do quadrado e quando ele chegasse em 90 graus eu mudaria para -90 graus e terminaria em 0. Isso exigiria dois tweens diferentes. Mas tem uma solução muito mais simples. Vamos a ela:

No quadro 2, vou selecionar tudo. Quadrado e texto. Dou um [F8] para salvar como MovieClip. Ok. Voltano ao quadro 2… vamos dar um nome menos idiota a esse MC. Vou instanciá-lo como “mc”. Simples!
Agora dou um [F7] no quadro 2 do “Layer 2″. E agora [F9].
Escrevo assim ali:

this.mc.rotationY = 180;

Epa.. o quadrado verde foi pro outro lado. A solução também é simples. O “hotpoint” do MC está no topo, à esquerda. É só entrar no MC e alinhá-lo no meio.

Voilá.. um quadrado que gira e não ocupa muita memória e ainda funciona em todas as regiões do palco. =D

Divirtam-se com moderação.

Passos do Algoritmo de Huffman

David A. Huffman, nascido em Ohio, formou-se em Engenharia Elétrica em 1944, sua maior contribuição para a humanidade foi à técnica computacional conhecida como o Código de Huffman, o método para compactar informações que está presente neste momento no seu Ipod, na sua câmera digital, nos modems de Internet, nas TVs de alta definição e até em invenções mais antigas como o seu telefone ou fax do seu trabalho.

Este código foi desenvolvido durante seu doutorado, em 1951, no MIT (Massachussets Institute of Technology), uma das maiores universidades tecnológicas do mundo. Aos 26 anos, o genial Huffman superou o método ensinado em aula por seu autor, o professor Robert Fano, e criou seu proprio codigo para compactar dados.

Mas o que o algoritmo de Huffman faz ?

A compressão pelo algoritmo de Huffman reduz o tamanho do código usado para representar os símbolos de um alfabeto. Símbolos do alfabeto que ocorrem frequentemente são atribuídos por codigos mais curtos. A estratégia geral é permitir ao tamanho do código variar de caracter para caracter e de assegurar que o código utilizado seja menor.

A compressão de Huffman é feita através da construção de uma árvore binária usando um simples conjunto de exemplo. Isso é feito arranjando os símbolos do alfabeto em ordem decrescente de probabilidade. Então repetidamente adicionando duas menores probabilidades e reorganizando. Este processo se repete até a soma das probabilidades dos dois últimos símbolos ser igual a 1.

Se não for obtido uma probabilidade de 1 nos dois últimos símbolos, provavelmente existe um erro no processo.

Estes diagramas mostram como a árvore de codificação associada à codificação de Huffman é construída:

FFFFFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAEEEEEEEEEDDDDDDDDDDDDDDDDBBBBBBBBBBBBBCCCCCCCCCC
CC

nico.Huffman

fonte:
wiki
books.google

Pilha em Java

Pilha:

A forma mais geral de uma lista permite a inserção ou eliminação de um elemento em qualquer posição na lista. Se restringirmos a ocorrência de inserção e eliminação a uma extremidade da lista, por exemplo, extremidades superiores, então temos uma estrutura de dados chamada de pilha.

Utilizando a terminologia de pilhas, operações de inserção e eliminação são comumente citadas como operações “push” e “pop”, respectivamente. O único elemento diretamente acessível de uma pilha é seu elemento superior. O elemento menos acessível é seu elemento inferior.

Desde que as operações de inserção e eliminação são executadas na mesma extremidade da pilha (por exemplo, na extremidade superior), os elementos podem ser removidos somente na ordem oposta a que foram inseridos.

Este interessante fenômeno é conhecido como LIFO. LIFO é um acrônimo para a expressão inglesa Last In, First Out que, em português significa último a entrar, primeiro a sair.

Um exemplo comum de pilha, que permite a seleção de seu elemento superior, é a pilha de pratos num restaurante. Os pratos em pilha fazem com que a pessoa tenha acesso ao prato superior, à remoção de um prato superior faz com que a pessoa tenha acesso ao próximo prato, se colocado um novo prato na pilha, esse será o primeiro a sair.

Em Java, já existe a classe para o TAD pilha, que é a java.util.Stack.

Os métodos disponíveis nesta classe, entre outros, são: push(), pop(), equivalentes a empilha() e desempilha() e peek(), equivalente a topo(), tamanho() e vazia().

Os métodos pop() e peek() lançam a exceção StackEmptyException se a pilha estiver vazia quando eles são chamados.

  • Outros métodos
    • size(): retorna o número de objetos da pilha
    • isEmpty(): retorna true se a pilha estiver vazia
    • top(): retorna, mas não remove, o objeto do topo da pilha, retornando um erro se a pilha estiver vazia

Exemplo simples:

Operação

Conteúdo da Pilha

Saida

Inserir X X -
Inserir Y X Y -
Inserir Z X Y Z -
Remover X Y Z
Inserir W X Y W -
Remover X Y W
Remover X Y
Remover   X
Remover   erro

Traduzindo a tabela em linguagem java.

import java.util.Stack;

/**

* Esta classe demonstra como funciona uma pilha em java

*

* @author Nico

*

* @since 20 MAIO, 2009

*

*/

public class TestarUmaStack {

public static void main(String[] args) {

// DECLARANDO NOSSOS ELEMENTOS/OBJETOS

String nico = “Nico”, kawano = “Kawano”, gaucho = “Gaucho”, erick = “Erick”, cris = “Cris”, junior = “Junior”, silvio = “Silvio”, jean = “Jean”;

// DECLARANDO A PILHA

Stack<String> nossaPilha = new Stack<String>();

// Passo 1: Incrementar Nico

nossaPilha.push(nico);

// Passo 2: Incrementar Kawano

nossaPilha.push(kawano);

// Passo 3: Incrementar Gaucho e Cris

nossaPilha.push(gaucho);

nossaPilha.push(cris);

// Passo 4: Decrementar elemento Cris do topo

nossaPilha.pop();

// Passo 5: Incrementar Erick

nossaPilha.push(erick);

// Passo 6: Incrementar Jean e Junior

nossaPilha.push(jean);

nossaPilha.push(junior);

// Passo 7: Substituir elemento na pilha. Jean por Silvio!

nossaPilha.set(4, silvio);

// EXIBINDO INFORMAÇÕES SOBRE A PILHA

if (nossaPilha.isEmpty()) {

System.out.println(“A PILHA ESTÁ VAZIA!”);

} else {

System.out

.println(“NOSSA PILHA DO GRUPO…\n\nElemento\tÍndice\n———————-”);

for (int i = nossaPilha.size() – 1; i > -1; i–) {

System.out.println(nossaPilha.get(i) + “\t\t” + i);

}

System.out.println(“\nNÚMERO DE ELEMENTOS: “ + nossaPilha.size());

System.out.println(“ELEMENTO NO TOPO: \”" + nossaPilha.peek()

+ “\” no índice “ + nossaPilha.indexOf(nossaPilha.peek()));

}

}

}

Resultado:

NOSSA PILHA DO GRUPO…

Elemento    Índice
———————-
Junior      5
Silvio       4
Erick        3
Gaucho   2
Kawano  1
Nico        0

NÚMERO DE ELEMENTOS:  6
ELEMENTO NO TOPO:  “Junior” no índice 5

CategoriasJava, POO Tags:,

Tratamento de exceções em Java

Hoje vou falar um pouquinho sobre o tratamento de exceções em Java, tambem do porque usar, sua estrutura e o que é uma exceção.

Como é comum no estudo do Java, ao chegar nesta parte e não conseguir visualizar a utilidade desse recurso e confundir os resultados com as instruções condicionais.

Conceito de Exceção

Exceção representa uma situação não esperada ocorrida na execução de algum trecho de programa.

Uma exceção deve ser vista como um retorno alternativo da execução de algum método.

O processo de gerar uma exceção é chamado de “lançamento de exceção” e o processo de processar uma exceção é chamado de “capturar a exceção”.

A exceção pode ser capturada por uma função dentro da seqüência de funções chamadas.

Agora veremos abaixo a estrutura de como tratar um erro ou exceção:

try - é usada para indicar um bloco de código que possa ocorrer uma exceção.

catch – serve para manipular as exceções, ou seja, tratar o erro

finally – sempre será executado depois do bloco try/catch. O importante é saber que esse bloco sempre será executado (exceto nos casos de encerramento da jvm System.exit()).

Veja abaixo as combinações válidas e inválidas para o uso do try{}, cacth{} e finally{} (isso é questão de certificação).

Combinações válidas:

try{}

catch{}

try{}

finally{}

try{}

catch{}

finally{}

Inválidas não Compila:

try{}

catch{}

finally{}

try{}

finally{}

catch{}

Tipos de Exceções em Java

Existem três tipos básicos de exceção em Java

Error

São exceções lançadas internamente pela Máquina Virtual na ocorrência de algum tipo de erro interno ou de falta de algum recurso.

Não se deve lançar nem tratar exceções desse tipo.

RuntimeException

São exceções lançadas devido algum erro do programa, como por exemplo, cast inválido, índice fora dos limites, acesso a referência nula de alguma classe.

Outras Exceções

São as exceções criadas para representar diversas situações. Podem ser as exceções criadas pelas bibliotecas ou exceções criadas pelo usuário.

Documentando as Exceções

A linguagem Java irá obrigar o programador a definir uma lista de exceções no cabeçalho do método quando ocorrer algumas das seguintes situações.

O método chama algum outro método que também possui em seu cabeçalho a indicação de lançamento de exceção e não faz o tratamento dessa exceção. O método lança uma exceção e não trata a mesma.

Sintaxe:

tipo_de_retorno nome ([params]) throws NomeExceção { ….. }

Capturando uma Exceção

Para capturar uma exceção devemos colocar o código passível de lançamento de exceção dentro de um bloco try. Para capturar a exceção devemos usar o catch.

Sintaxe:

try {

…. –> Código que pode lançar uma exceção

}

catch (tipo_exc e){

…. –> Código de tratamento

}

Lançando uma Exceção

Para lançar uma exceção deve-se usar o comando throw seguido de uma referência de uma classe de exceção.

Essa referência deve ter uma instância da classe de exceção a ser lançada.

Sintaxe:

retorno_do_método nome ([params]) throws

NomeExceção {

…..

if (cond_erro)

throw new IOException ();

….

}

Criando uma Classe de Exceção

Para criar uma nova classe de exceção de aplicação deve-se:

  • Criar a classe herdando de alguma outra exceção existente ou da classe Exception.
  • Criar um construtor sem parâmetros e um com um parâmetro do tipo String.
  • No construtor do tipo String chamar o construtor da classe base, usando super, passando a string recebida.
  • Podem-se colocar atributos e métodos adicionais na classe para definição melhor da exceção.

Métodos da Classe Throwable

A classe Throwable, classe base de todas as exceções do Java, possui os seguintes métodos:

  • String getMessage( );

Retorna a descrição usada na criação da exceção.

  • String toString( );

Retorna a descrição curta da exceção (nome/msg).

  • void printStackTrace( );

Mostra todas as informações da pilha no momento da exceção.

  • Throwable fillInStackTrace( );

Recoloca as informações na pilha da exceção.

Relançando uma Exceção

Uma vez capturada uma exceção, ela termina a função de indicar algum erro. Caso seja necessário que o tratamento continue em níveis superiores deve-se relançar a mesma através do comando throw colocado dentro do bloco catch.

O relançamento de uma exceção difere do lançamento no sentido de que não é criada uma nova instância e sim lançada a mesma instância da exceção capturada.

Sintaxe:

catch (tipo_exc e){

…. –> Código de tratamento

throw e; –> Relançando

}

Bloco finally

O bloco finally serve para indicar o código que será sempre executado em uma estrutura try…catch independente do caminho realizado por uma execução, normal ou exceção.

O bloco deve ser colocado após os blocos catch.

Pode-se colocar uma estrutura try com um bloco finnaly somente, sem o bloco catch.

Sintaxe:

finally {

…. –> Código a ser executado sempre

}

Exceções predefinidas do JAVA

Dentro do pacote-padrão java.lang Java define várias classes de exceção.  A maioria destas exceções são subclasses do tipo padrão RuntimeException. Desde que java.lang é implicitamente importada para todos os programas Java, a maioria das exceções derivadas de RuntimeException estão automaticamente disponíveis.

tab1

Então quando Usar Exceções !

Algumas sugestões sobre o uso de exceções:

  • Não utilize exceções no lugar de testes simples. O tratamento de uma exceção custa muito em termos de processamento.
  • Não faça o gerenciamento detalhado de exceção colocando cada comando que pode lançar uma exceção dentro de um bloco try/catch.
  • Não descarte uma exceção, ou seja, não coloque um bloco catch vazio somente para evitar o erro de compilação.
  • Não sinta constrangimento em não tratar todas as exceções que o seu código lançou. Trate somente as exceções cujo contorno você conhece.
CategoriasJava Tags:

Orientação a Objetos – Parte 3

CONCEITO DE ENCAPSULAMENTO

  • Encapsulamento é o mecanismo pelo qual podemos unir numa mesma estrutura de dados, dados e métodos.
  • Por meio do encapsulamento pode-se ocultar os dados.
  • O princípio do encapsulamento: “Princípio do Menor Privilégio” – disponibilize ao usuário somente aquilo que for necessário, o resto esconda.

CONCEITO DE HERANÇA

  • Herança é o processo de definição de uma classe baseada em outra classe.
  • Terminologia
    • Classe Base               Classe Derivada
    • Classe Mãe/Pai          Classe Filha
    • Super-classe              Sub-classe
    • Generalização            Especialização
  • A classe derivada herda e incorpora todos os atributos e métodos da classe base.
  • Podemos adicionar ou redefinir algum método ou adicionar atributos na classe derivada a fim de adaptar a definição à nova classe.

CONCEITO DE POLIMORFISMO

  • O polimorfismo é caracterizado pela frase: “Uma interface, vários métodos”
  • Caso se faça a sobreposição de métodos (com a mesma assinatura) em uma herança, será possível se aplicar o conceito de Polimorfismo.
  • Tendo-se uma variável do tipo da classe mãe, pode-se criar uma instância para qualquer classe filha descendente da mesma e armazenar sua referência na variável.
  • Como o método está definido na classe mãe e sobrecarregado na classe filha, o compilador irá escolher o método baseado no tipo da instância apontada pela referência e não pelo tipo da mesma.
  • Permite uma interface ser usada para representar uma classe geral de ações.
CategoriasPOO, Programação Tags:,