1
|
- UniverCidade - Prof. Ismael H F Santos
|
2
|
- Modulo I - Introdução a Linguagem JAVA
- Paradigma OO
- Características da linguagem
- Plataformas Java
- Introdução Prática
- Fundamentos da linguagem
- Interfaces e Classes Abstratas
- Classes parametrizadas (não é Generics !)
|
3
|
- Linguagem de Programação JAVA
- Ismael H. F. Santos, Apostila
UniverCidade, 2002
- The Java Tutorial: A practical guide for programmers
- Tutorial on-line: http://java.sun.com/docs/books/tutorial
- Java in a Nutshell
- David Flanagan, O´Reilly &
Associates
- Just Java 2
- Mark C. Chan, Steven W. Griffith
e Anthony F. Iasi, Makron Books.
- Java 1.2
- Laura Lemay & Rogers
Cadenhead, Editora Campos
|
4
|
- Core Java 2, Cay S. Horstmann, Gary Cornell
- Volume 1 (Fundamentos)
- Volume 2 (Características Avançadas)
- Java: Como Programar, Deitel & Deitel
- Thinking in Patterns with JAVA, Bruce Eckel
- Gratuito. http://www.mindview.net/Books/TIJ/
|
5
|
|
6
|
- Paradigmas de Programação
- Programação Procedural ou
Imperativo
- Programação Funcional
- Programação Lógico
- Programação Orientada por
Objetos
|
7
|
- Cenário Exemplo
- “João deseja enviar flores para Maria mas ela mora em outra cidade.
João vai, então, até a floricultura e pede a José, o floricultor, para
que ele envie um bouquet de rosas ao endereço de Maria. José, por sua
vez, liga para uma outra floricultura, da cidade de Maria, e pede para
que as flores sejam entregues.”
|
8
|
- Colocação do Problema -
nomenclatura
- João precisa resolver um problema;
- Então, ele procura um agente,
José, e lhe passa uma mensagem contendo sua requisição: enviar rosas
para Maria;
- José tem a responsabilidade de,
através de algum método, cumprir a requisição;
- O método utilizado por José pode
estar oculto de João.
|
9
|
- Modelo OO
- Uma ação se inicia através do envio de uma mensagem para um agente (um
objeto) responsável por essa ação.
- A mensagem carrega uma requisição, além de toda a informação
necessária, isto é os argumentos, para que a ação seja executada.
- Se o agente receptor da mensagem a aceita, ele tem a responsabilidade
de executar um método para cumprir a requisição.
|
10
|
- Objetos
- Estão preparados para cumprir um determinado conjunto de requisições.
- Recebem essas requisições
através de mensagens.
- Possuem a responsabilidade de
executar um método que cumpra a
requisição.
- Possuem um estado representado
por informações internas.
|
11
|
|
12
|
- Classes
- O conjunto de requisições que um objeto pode cumprir é determinado pela
sua classe.
- A classe também determina que método será executado para cumprir uma
requisição.
- A classe especifica que informações um objeto armazena internamente.
- Objetos são instâncias de classes.
- Classes podem ser compostas em hierarquias, através de herança.
|
13
|
|
14
|
- Encapsulamento
- As classes possuem uma parte invisível, que é a sua implementação, e
uma parte visível que é a sua interface;
- As operações da interface possibilitam o acesso aos objetos.
|
15
|
- Herança
- Compartilhamento de atributos e serviços entre classes;
- A definição de classes em termos de outras classes constitui uma
hierarquia:
- superclasses (classes ancestrais ou bases)
- subclasses (classes derivadas)
- Recurso utilizado para especializar ou estender classes;
|
16
|
- Herança - Hierarquia de Classes
|
17
|
|
18
|
|
19
|
- Polimorfismo
- Implica na redefinição de um método ou serviço da superclasse. Desta
forma, pode haver métodos com diferentes implementações em uma
hierarquia;
- Métodos com várias formas, implica em métodos com várias
implementações.
|
20
|
|
21
|
- Agentes são objetos;
- Ações são executadas através da troca de mensagens entre objetos;
- Todo objeto é uma instância de uma classe;
- Uma classe define uma interface e um comportamento;
- Classes podem estender outras classes através de herança.
|
22
|
|
23
|
|
24
|
|
25
|
|
26
|
- Por que OO ?
- Porque promove o desenvolvimento de software com qualidade
- Correção
- Robusto
- Extensibilidade
- Reusabilidade
- Compatibilidade
|
27
|
|
28
|
- Java é uma Linguagem OO, contendo uma coleção de APIs para o
desenvolvimento de aplicações multiplataforma
- Java foi lançada pela Sun em 1995. Três grandes revisões:
- Java Development Kit (JDK) 1.0/1.0.2
- Java Development Kit (JDK) 1.1/1.1.8
- Java 2 Platform ( Java 2 SDK e JRE 1.2, 1.3, 1.4, 5.0)
- Java segundo a Sun Microsystems
- Simples
object-oriented distribuída
- interpretada
robusta
segura
- architecture-neutral
portável alta
performance
- multithreaded
dinâmica
|
29
|
- Simplicidade
- Poucos comandos, ausência de goto (apesar de suportar break para
label), mecanismos de tratamento de exceção, não permite sobrecarga de
operadores, não suporta herança múltipla, não suporta templates, não
utiliza ponteiros, não trabalha com unions ou estruturas; somente
classes. Vetores e strings são objetos. Java só trabalha com
referências !
|
30
|
- Orientada a Objeto
- Suporte completo a OOP. Define
uma extensa biblioteca de classes, disponibilizadas em pacotes
(packages).
- java.lang => classes para
definição básica da linguagem (core language)
- java.applet => classes
para implementação de Applets
- java.awt => classes para
gráficos, texto, janelas, GUI
- java.awt.image => classes para processamento de imagens
- java.awt.event => classes
para tratamento de eventos na interface GUI
- java.awt.swing => classes
para interface GUI extensão do AWT
- java.awt.peer => classes
para interface GUI independente de plataforma
- java.io => classes para
input / output
- java.net => classes para
network computing
- java.util => classes para
tipos de dados úteis (arrays, listas, etc)
- Diferentemente de C++, a maioria dos tipos em Java são objetos, com
exceção dos tipos: numéricos, caracter e boolean.
|
31
|
- Distribuída
- Java suporta aplicações Cliente/Servidor por ser uma linguagem
distribuída. Suporta vários níveis de conectividade através de classes
presentes no java.net.package. Suporta conexão através de sockets
(socket class).
- Robusta
- Java é uma linguagem fortemente tipada (mais que C++). Requer
declaração explícita de métodos (idem ANSI-C). Não suporta ponteiros,
eliminando assim a possibilidade de invasões de área e manipulação
errônea com aritmética de ponteiros.
|
32
|
- Interpretada
- O compilador Java gera Bytecodes ao invés de código nativo de
cada máquina. Para executar um programa Java é preciso se interpretar
os Bytecodes, o que é feito pelo interpretador Java. Através dos Bytecodes,
Java provê um formato de arquivo objeto neutro (independente de
plataforma), o que permite a sua migração entre plataformas de maneira
eficiente e segura. Um programa em Java pode rodar em qualquer
plataforma que tenha o interpretador Java instalado e as bibliotecas de
run-time.
|
33
|
- Compilação e Interpretação no
Java
- JVM = Interpretador +
Run-time System
|
34
|
|
35
|
|
36
|
|
37
|
- O JSDK (Java System Development Kit) é o ambiente padrão distribuído
pela Sun para desenvolvimento de aplicações Java
- O JSDK consiste de
- JRE (Java Runtime Environment) - também distribuído separadamente:
ambiente para execução de aplicações;
- Ferramentas para desenvolvimento: compilador, debugger, gerador de
documentação, empacotador JAR, etc;
- Código-fonte das classes da API;
- Demonstrações de uso das APIs, principalmente Applets, interface
gráfica com Swing e recursos de multimídia;
- A documentação é distribuída
separadamente
|
38
|
|
39
|
|
40
|
- Segurança
- Referências à memória são resolvidas pelo compilador e traduzidas
durante a execução pelo interpretador. Durante a execução a maquina
virtual Java (JVM) executa um processo de verificação dos Bytecodes do
programa para assegurar que a classe carregada a partir da rede não
tenha sido adulterada (no caso de Applets).
- Verificação de Bytecodes
- Etapa que antecede a execução do
código em classes carregadas através da rede
- Class Loader distingue classes
locais (seguras) de classes remotas (potencialmente inseguras)
|
41
|
- Verificação de Bytecodes (cont)
- Verificação garante
- Aderência ao formato de arquivo especificado [JVMS]
- Não-violação de políticas de acesso estabelecidas pela aplicação
- Não-violação da integridade do sistema
- Ausência de estouros de pilha
- Tipos de parâmetros corretamente especificados e ausência de
conversões ilegais de tipos
|
42
|
- Arquitetura Neutra
- Programas Java são compilados, conforme já vimos, para um formato
neutro (independente de plataforma). A primeira vantagem é a
possibilidade de executar este programa em qualquer HW que suporte um JVM.
Além disso, Java define uma biblioteca gráfica padrão para GUI
(java.awt–Abstract Windowing Toolkit) de forma que a aplicação terá
sempre o mesmo comportamento e aparência em qualquer plataforma
- Coleta de Lixo
- Memória alocada em Java não é
liberada pelo programador, ou seja, objetos criados não são destruídos
pelo programador
- A criação de objetos em Java
consiste de:
- 1. Alocar memória no heap para armazenar dados do objeto
- 2. Inicializar o objeto (via construtor)
- 3. Atribuir endereço de memória a uma variável (referência)
|
43
|
- Coleta de Lixo (cont.)
- Mais de uma referência pode apontar para o mesmo objeto, conforme o
exemplo abaixo:
|
44
|
- Coleta de Lixo (cont.)
- Quando um objeto não tem mais referências apontando para ele, seus
dados não mais podem ser usados, e a memória pode ser liberada. O
coletor de lixo irá liberar a memória na primeira oportunidade
|
45
|
- Portabilidade
- Arquitetura Neutra é apenas uma parte do processo para se obter a
portabilidade! Java se preocupa em não deixar nenhum aspecto da
linguagem sendo dependente de implementação. Por isso o tamanho dos
tipos de dados de Java são definidos independentes de plataforma
(veremos isso adiante)
- Dinâmica
- Java é mais dinâmica que C/C++. Bibliotecas podem livremente
somar novos métodos e instâncias de variáveis sem nenhum efeito em seus
clientes. Em Java descobrir o tipo de uma instância em tempo de
execução é algo extremamente simples.
- Além disso Java apresenta suporte para a mobilidade de código via rede
como é o caso de applets.
|
46
|
|
47
|
- Alta Performance
- Antigamente Java era aproximadamente 10 a 20 vezes mais lenta que o
código gerado em C/C++. Atualmente após diversas pesquisas na area de
compiladores com tecnologia JIT (Just In Time Compiler) já e’ possível a tradução de Bytecodes
direto para código de máquina da CPU durante a execução.
- Mais recentemente a tecnologia HotSpot tem se mostrado bastante
eficiente e já se consegue executar programas com performance
semelhante a de programas em C ou ate mesmo Fortran. Alem disso
conversores de Java para C/C++ já estão disponíveis e podem ser usados
nos casos onde a necessidade de performance seja crítica.
|
48
|
- MultiThreaded
- Aplicações gráficas e distribuídas devem possibilitar a execução de
várias tarefas de forma concorrente (Web Browser). Java é uma linguagem
multithread, suportando múltiplas threads para a execução de várias
tarefas em paralelo. Escrever código com múltiplas threads é
extremamente difícil em C e/ou C++ já que estas linguagens não foram
projetadas com este intuito.
- O pacote java.lang define a classe Thread e inclui suporte a primitivas
de sincronização de threads. Estas primitivas estão baseadas no modelo
de monitor e variáveis de condição definidas por C.A.R. Hoare. Além
disso, Threads em Java têm a capacidade de usar os recursos de sistemas
com múltiplos processadores.
|
49
|
|
50
|
- Java 2 Plataform, Standard Edition (J2SE)
- Java 2 Plataform, Enterprise Edition (J2EE)
- Java 2 Plataform, Micro Edition (J2ME)
|
51
|
|
52
|
|
53
|
|
54
|
- Funções
- Concorrência na execução multi-usuarios
- Consistência, suporte a transações distribuídas
- Segurança
- Disponibilidade
- Escalabilidade
- Suporte a distribuição da aplicações
- Integração de diversas aplicações
- Facilidades de administração
|
55
|
|
56
|
|
57
|
- Containers
- O container é o carro
- Representa o suporte dado pela plataforma, realizando seu trabalho de
forma transparente para o usuario.
- Se encarregam do gerenciamento da comunicação entre as camadas de
Apresentação, Negócios e Persistência.
- Components
- O componente é o motorista
- Aplicação do cliente é mais facilmente codificada através do uso dos
componentes disponibilizados pela plataforma
|
58
|
|
59
|
|
60
|
|
61
|
- O J2ME e dividido em Configurações e Perfis
- Uma Configuração define uma plataforma Java para uma faixa de
equipamentos. Especifica uma JVM e uma API que podem ser portadas
facilmente entre uma larga faixa de dispositivos.
- CLDC (Connected Limited Device Configuration)
- Mínimo: 512 Kb ROM, 256 Kb RAM e algum tipo de conexão, possivelmente
persistente, e com alta taxa de transmissão.
- CLDC (Connected Device Configuration)
- Mínimo: 128 Kb ROM, 32 Kb RAM, GUI restrita, conexão de rede wireless
com baixa taxa de transmissão e acesso intermitente.
|
62
|
- O J2ME Perfis
- O Perfil é o suplemento da configuração para dispositivos específicos,
contem bibliotecas de classes para a criação de aplicações para uma
categoria restrita de dispositivos
- MIDP 2.0 (Mobile Information Device Profile), define aspectos de
seguranca, rede(HTTP, HTTPS, RS232, Sockets, Datagramas), gráficos,
tecnologia Push, sons
- FP (Foundation Profile), JGP (JavaGame Profile)
- PP (Personal Profile), PDAP (PDA Profile)
|
63
|
- /*
- * @(#)HelloWorldMIDlet.java - 1.0
03/03/05
- */
- package example;
- import javax.microedition.midlet.*;
- import javax.microedition.lcdui.*;
- /**
- * An example HelloWorldMIDlet
shows the values of the system properties.
- */
- public class HelloWorldMIDlet extends MIDlet implements CommandListener
{
- private Display display;
- private Command exitCommand,
backCommand, aboutCommand, propsCommand;
- private TextBox textBox;
- private Alert alert;
- private List list;
- private Form props;
- private StringBuffer propbuf =
new StringBuffer(50);
- private boolean firstTime =
true;
- /*
- * Construct a new
HelloWorldMIDlet.
- */
- public HelloWorldMIDlet() {
- // Display
- display =
Display.getDisplay(this);
|
64
|
- // Sintax:
Command("Name", Type, Priority)
- exitCommand = new Command("Exit",
Command.EXIT, 1);
- backCommand = new Command("Back",
Command.BACK, 1);
- aboutCommand = new
Command("About", Command.SCREEN, 2);
- propsCommand = new
Command("SysProps", Command.SCREEN, 2);
- // First Display shows List
options
- String stringElements[] = {
"About", "System Properties", "Alert" };
- list = new
List("Título", List.IMPLICIT, stringElements, null);
- list.addCommand(exitCommand);
- // Sintax:
TextBox("Title", "Initial text", NrChars,
Validations)
- textBox = new
TextBox("HelloWorldMIDlet", "Hello World MIDlet Example
...",256,0);
-
textBox.addCommand(exitCommand);
textBox.addCommand(propsCommand);
-
textBox.addCommand(backCommand);
- // Form info
- props = new Form("System
Properties");
- props.addCommand(exitCommand);
props.addCommand(aboutCommand);
- props.addCommand(backCommand);
- // Alert Message
- alert = new Alert("Hello
Alert", "Testing Alert ...", null, AlertType.INFO);
- }
|
65
|
- /**
- * Show the value of the
properties
- */
- public void startApp() {
- Runtime runtime =
Runtime.getRuntime();
- runtime.gc();
- long free =
runtime.freeMemory();
- if( firstTime ) {
- long total =
runtime.totalMemory();
- props.append("Free
Memory = " + free + "\n");
- props.append("Total
Memory = " + total + "\n");
-
props.append(showProp("microedition.configuration"));
-
props.append(showProp("microedition.profiles"));
-
props.append(showProp("microedition.platform"));
-
props.append(showProp("microedition.locale"));
-
props.append(showProp("microedition.encoding"));
- firstTime = false;
-
list.setCommandListener(this);
- display.setCurrent(list);
- } else {
- props.set(0, new
StringItem("", "Free Memory = " + free +
"\n"));
- }
- }
|
66
|
- /**
- * Handle events
- */
- public void commandAction(Command
c, Displayable s) {
- if ( c == exitCommand ) {
- destroyApp(false);
notifyDestroyed();
- } else if ( c == backCommand )
{
-
list.setCommandListener(this); display.setCurrent(list);
- } else if ( c == aboutCommand
) {
-
textBox.setCommandListener(this); display.setCurrent(textBox);
- } else if ( c == propsCommand
) {
-
props.setCommandListener(this); display.setCurrent(props);
- } else {
- if ( list.getSelectedIndex()
== 0 ) {
-
textBox.setCommandListener(this); display.setCurrent(textBox);
- } else if (
list.getSelectedIndex() == 1 ) {
-
props.setCommandListener(this); display.setCurrent(props);
- } else {
- display.setCurrent(alert);
- }
- }
- }
|
67
|
- /**
- * Show a property.
- */
- String showProp(String prop) {
- String value =
System.getProperty(prop);
- propbuf.setLength(0);
- propbuf.append(prop);
propbuf.append(" = ");
- if (value == null) {
-
propbuf.append("<undefined>");
- } else {
-
propbuf.append("\""); propbuf.append(value);
propbuf.append("\"");
- }
-
propbuf.append("\n");
- return propbuf.toString();
- }
- /**
- * Time to pause, free any space
we don't need right now.
- */
- public void pauseApp() {
- }
- /**
- * Destroy must cleanup
everything.
- */
- public void destroyApp(boolean
unconditional) {
- }
- }
|
68
|
- Disponibiliza Java para “smart cards”
- JavaCard define um subset da linguagem Java e da Java Virtual Machine
para executar em “smart cards”
- OOP para “smart cards” mais simples e poderosa do que programação em C
- Modelo Web browser de funcionamento
- Core and extensions JavaCard API
- JavaCard Runtime Environment (JCRE)
|
69
|
|
70
|
|
71
|
- Programa Exemplo
- Crie o programa “AloMundo.java” (case-sensitive)
- public class AloMundo {
- public static void
main(String[] args){
- System.out.println(“Alô
Mundo!”);
- }
- }
|
72
|
- Applet Exemplo – “AloMundoApplet.java”
- Applets são programas que podem ser executados em Browsers compatíveis
com a linguagem Java
- import java.applet.Applet;
- import java.awt.Graphics;
- public class HelloWorld extends
Applet { public void
paint(Graphics g) {
- g.drawString("Hello
world!", 50, 25);
- }
- }
- Exercício - Questão 2
|
73
|
|
74
|
|
75
|
|
76
|
|
77
|
|
78
|
- Modela uma estrutura de dados através de sua funcionalidade.
- Define a interface de acesso à estrutura.
- Não faz qualquer consideração com relação à implementação.
|
79
|
- Funcionalidade: armazenagem LIFO
- Interface:
|
80
|
- Uma determinada implementação de um TAD pode ser realizada por meio de
uma classe.
- A classe deve prover todos os métodos definidos na interface do TAD.
- Um objeto dessa classe implementa uma instância do TAD.
|
81
|
- Classes e Objetos
- Em Java, a declaração de novas
classes é feita através da construção class.
- Podemos criar uma classe Point
para representar um ponto (omitindo sua implementação) da seguinte
forma:
- class Point {
- ...
- }
|
82
|
- Campos - Atributos ou Métodos
- Como dito, classes definem dados que suas instâncias conterão.
- A classe Point precisa armazenar as coordenadas do ponto sendo
representado de alguma forma.
- class Point {
- int x, y;
- }
|
83
|
- Instanciação ou Criação
- Uma vez definida uma classe, uma nova instância (objeto) pode ser
criada através do comando new.
- Podemos criar uma instância da
classe Point da seguinte forma:
- Point p = new Point();
|
84
|
- Referências para Objetos
- Em Java, nós sempre fazemos
referência ao objeto. Dessa forma, duas variáveis podem se referenciar
ao mesmo ponto.
- Point p1 = new Point();
- Point p2 = p1;
- p2.x = 2;
- p2.y = 3;
- // p1 e p2 representam o ponto
(2,3)
|
85
|
- Acessando Campos
- Os campos de uma instância de
Point podem ser manipulados diretamente.
- Point p1 = new Point();
- p1.x = 1; p1.y = 2;
- // p1 representa o ponto (1,2)
- Point p2 = new Point();
- p2.x = 0; p2.y = 0;
- // e p2 o ponto (0,0)
|
86
|
- Métodos
- Além de atributos, uma classe
deve definir os métodos que irá disponibilizar, isto é, a sua
interface.
- A classe Point pode, por exemplo, prover um método para mover o ponto
de um dado deslocamento.
|
87
|
- Declaração de Método
- Para mover um ponto, precisamos saber quanto deslocar em x e em y. Esse
método não tem um valor de retorno pois seu efeito é mudar o estado do
objeto.
- class Point {
- int x, y;
- void move(int dx, int dy) {
- x += dx; y += dy;
- }
- }
|
88
|
- Envio de Mensagens: Chamadas de
Método
- Em Java, o envio de uma mensagem é feito através de uma chamada de
método com passagem de parâmetros.
- Por exemplo, a mensagem que dispara a ação de deslocar um ponto é a
chamada de seu método move.
- p1.move(2,2);
- // p1 está deslocado de duas
unidades
- // no sentido positivo, nos dois
eixos.
|
89
|
- this
- Dentro de um método, o objeto pode precisar de sua própria referência.
- Em Java, a palavra reservada this significa essa referência ao próprio
objeto.
- class Point {
- int x, y;
- void move(int dx, int dy) {
- this.x += dx; this.y += dy;
- }
- }
|
90
|
- Inicializações
- Em várias circunstâncias, é interessante inicializar um objeto.
- Por exemplo, poderíamos querer que todo ponto recém criado estivesse em
(0,0).
- Esse tipo de inicialização se resume a determinar valores iniciais para
os campos
|
91
|
- Inicialização de Campos
- Por exemplo, a classe Point poderia declarar:
- class Point {
- int x = 0; int y = 0;
- void move(int dx, int dy) {
- this.x += dx;
- this.y += dy;
- }
- }
|
92
|
- Construtores
- Ao invés de criar pontos sempre em (0,0), poderíamos querer especificar
a posição do ponto no momento de sua criação.
- O uso de construtores permite isso.
- Construtores são mais genéricos do que simples atribuições de valores
iniciais aos campos: podem receber parâmetros e fazer um processamento
qualquer.
|
93
|
- Declaração de Construtores
- O construtor citado para a classe Point pode ser definido da seguinte
forma:
- class Point {
- int x = 0;
- int y = 0;
- Point(int x, int y) {
- this.x = x; this.y = y;
- }
- ...
- }
|
94
|
- Usando Construtores
- Como o construtor é um método de inicialização do objeto, devemos
utilizá-lo no momento da instanciação.
- Point p1 = new Point(1,2);
- // p1 é o ponto (1,2)
- Point p2 = new Point(0,0);
- // p2 é o ponto (0,0)
|
95
|
- Construtor Padrão
- Quando não especificamos nenhum construtor, a linguagem Java declara,
implicitamente, um construtor padrão, vazio, que não recebe parâmetros.
- Se declararmos algum construtor, esse construtor padrão não será mais
declarado.
|
96
|
- Finalizações
- Pode ser necessário executar alguma ação antes que um objeto deixe de
existir.
- Para isso são utilizados os destrutores.
- Destrutores são métodos que são chamados automaticamente quando um
objeto deixa de existir.
- Em Java, destrutores são chamados de finalizadores.
|
97
|
- Gerência de Memória – Garbage
Collection
- Java possui uma gerência automática de memória, isto é, quando um
objeto não é mais referenciado pelo programa, ele é automaticamente
coletado (destruído).
- A esse processo chamamos “coleta de lixo”.
- Nem todas as linguagens OO fazem coleta de lixo e, nesse caso, o
programador deve destruir o objeto explicitamente.
|
98
|
- Finalizadores em Java
- Quando um objeto Java vai ser coletado, ele tem seu método finalize
chamado.
- Esse método deve efetuar qualquer procedimento de finalização que seja
necessário antes da coleta do objeto.
|
99
|
- Membros de Classe
- Classes podem declarar membros (campos e métodos) que sejam comuns a
todas as instâncias, ou seja, membros compartilhados por todos os
objetos da classe.
- Tais membros são comumente chamados de ‘membros de classe’ (versus ‘de
objetos’).
- Em Java, declaramos um membro de classe usando o qualificador static.
Daí, o nome ‘membros estáticos’ usado em Java.
|
100
|
- Membros de Classe: Motivação
- Considere uma classe que precise atribuir identificadores unívocos para
cada objeto.
- Cada objeto, ao ser criado, recebe o seu identificador.
- O identificador pode ser um número gerado seqüencialmente, de tal forma
que cada objeto guarde o seu mas o próximo número a ser usado deve ser
armazenado na classe.
|
101
|
- Membros de Classe: Um Exemplo
- Podemos criar uma classe que modele produtos que são produzidos em uma
fábrica.
- Cada produto deve ter um código único de identificação.
- class Produto {
- static int próximo_id = 0;
- int id;
- Produto() {
- id = próximo_id; próximo_id++;
- } ...
- }
|
102
|
- Membros de Classe: Análise do
Exemplo
- // Considere que ainda não há nenhum produto.
- // Produto.próximo_id = 0
- Produto lápis = new Produto();
- // lápis.id = 0
- // lápis.próximo_id = 1
- Produto caneta = new Produto();
- // caneta.id = 1
- // caneta.próximo_id = 2
|
103
|
- Membros de Classe: Acesso Direto
- Como os membros estáticos são da classe, não precisamos de um objeto
para acessá-los: podemos fazê-lo diretamente sobre a classe.
- Produto.próximo_id = 200;
- // O próximo produto criado terá
- // id = 200.
- Java, sendo uma linguagem puramente orientada por objetos, possui
apenas declarações de classes: não é possível escrever código fora de
uma classe.
|
104
|
- Membros de Classe
- Para prover uma biblioteca matemática, Java declara uma classe, Math,
que contém apenas métodos estáticos.
- Exemplo1: calcular a distância entre dois pontos.
- float dx = p1.x - p2.x;
- float dy = p1.y - p2.y;
- float d = Math.sqrt(dx*dx+dy*dy);
- Exemplo2:
- observe na figura ao lado que a a variavel de classe y não esta
presente em nenhum objeto !
|
105
|
- this revisitado
- Vimos que um método estático
pode ser chamado diretamente sobre a classe. Ou seja, não é necessário
que haja uma instância para chamarmos um método estático. Dessa forma,
não faz sentido que o this exista dentro de um método estático.
|
106
|
- Noção de Programa
- Uma vez que tudo o que se escreve em Java são declarações de classes, o
conceito de programa também está relacionado a classes: a execução de
um programa é, na verdade, a execução de uma classe.
- Executar uma classe significa executar seu método estático main. Para
ser executado, o método main deve possuir uma assinatura bem
determinada.
|
107
|
- Executando uma Classe
- Para que a classe possa ser executada, seu método main deve possuir a
seguinte assinatura:
- public static void main(String[]
args)
- Estrutura de um Programa Java
|
108
|
- Programa Exemplo – AloMundo.java
- Usando o método main e um atributo estático da classe que modela o
sistema, podemos escrever nosso primeiro programa:
- public class AloMundo {
- public static void
main(String[] args){
- System.out.println(“Alô
Mundo!”);
- }
- }
- Uma classe deve ser declarada em um arquivo homônimo (case-sensitive) com extensão .java.
- Exercício - Questão 1
|
109
|
- Léxico
- Suporte a Unicode
- Comentários em uma linha
// ...
- Comentários em múltiplas linhas
- /*
...
*/
- Comentários de documentação (javadoc)
- /** ... */
|
110
|
- Tipos Básicos ou Primitivos de
Java
|
111
|
- Formato dos Tipos de Dados
|
112
|
- Tipos de Dados de Referência –
- Reference Data Types
- Todos os tipos não primitivos são tratados como objetos ou arrays, e,
por isso, são acessados pelo Java por “referência”.
- Por isso chamamos os tipos de dados de Java não primitivos de “Reference
Data Types”.
|
113
|
- Exemplo
- Button a,b;
- a=new Button(); //a refere-se a um objeto Button
- b=a; // b refere-se ao
mesmo objeto que a
- b.setLabel(“Ok”);
- String s = b.getLabel(); // s será igual a “Ok”
- Observe que isso não acontece quando utilizamos os tipos primitivos:
- int i = 3; int j = i; i = 2;
- System.out.println(“i=“+i+“-“+“j=“+j); //Exibe: i=3-j=2
|
114
|
- A classe String
- Strings são objetos da classe java.lang.String
- Apesar de String não ser um tipo primitivo, ele pode ser visto como um,
pois pode ser construído diretamente, sem o uso de new. Strings são
imutáveis !
- String s1 = “Sou uma string";
- A forma normal de criação de objetos também é permitida para strings
(embora raramente usada):
- String s2 = new String(“Também sou uma string");
|
115
|
- A classe String (cont.)
- O operador + pode ser utilizado para concatenar strings.
- String result = s1 + s2;
- Em Java, a expressão s1 == s2 testa se s1 e s2 são o mesmo objeto e não
se eles contem os mesmos strings !
- String principais métodos:
- public char charAt(int index)
- public int compareTo(String comparison)
- public int compareTo(Object object)
- public boolean endsWith(String suffix)
|
116
|
- String principais métodos (cont.)
- public String concat(String suffix)
- String result = someString.concat(otherString);
- public boolean equalsIgnoreCase(String comparison)
- public int indexOf(int character)
- public int indexOf(int character, int startIndex)
- public int indexOf(String subString)
- public int indexOf(String subString, int startIndex)
- public int length()
- public String replace(char oldChar, char newChar)
|
117
|
- Exemplo
- public class StringsDemo {
- public static void
main(String[] args) {
- String palindrome = “Niagara.
O roar again";
- int len =
palindrome.length();
- StringBuffer dest = new StringBuffer(len);
- for (int i=len-1; i >=
0; i--)
dest.append(palindrome.charAt(i));
-
System.out.println(dest.toString());
- }
- }
|
118
|
- Arrays
- Seu comprimento pode ser determinado pelo método length
- Pode ser associados a variáveis do tipo Object, assim como a variáveis
de seu tipo específico.
- Arrays podem ser passados para métodos.
- Indexação de seus elementos começa por zero.
- A declaração de um array de um determinado tipo é indicada pelo uso de [
] para cada dimensão do array.
- É necessária também a indicação do tamanho do array para a sua
utilização.
|
119
|
- Exemplos: Declaração de Arrays
- int[ ] arrayDeInts; //
1-dim
- char[ ][ ] matrixDeChars; //
2-dim
- Object[ ] matrixDeObjetos[ ]; // 2-dim
- UmaClasseX[ ] arrayDeUmaClasseX;
- Alocação de memória
- arrayDeInts = new int [7];
- matrixDeChars = new char[3][4];
- Declaração e Alocação
- boolean[] answers = { true, false, true, true };
- String[][] nomes = { {“Maria”, “Jose”, “Joao”},
- {
“Lucia”,“Arthur”, “Carol”} };
|
120
|
- O atributo length
- Carro[] carros = new Carro[3]; // array de 3 carros
- carros[0] = new Carro(“BMW”, 60000);
- carros[1] = new Carro(“Vectra”, 40000);
- carros[2] = new Carro(“Gol”, 20000);
- int[] precos = new int[3];
- for (int i = 0; i < carros.length; i ++) {
- precos[i] =
carros[i].getPreco(); // copia os precos
- System.out.println(“Preço: ” +
precos[i]);
- }
- Outro exemplo:
- int[] list = {1, 2, 3, 4, 5};
- for( int i=0; i<list.length;
++i )
-
System.out.println(“list[“+i+”]=“+list[i]);
|
121
|
- Arrays Multidimensionais
- Array multidimensionais em Java são tratados como arrays de arrays
exatamente como em C/C++
- byte matrix[ ][ ] = new byte [256][16];
|
122
|
- Arrays Multidimensionais – Exemplos
- String texto[][][][] = new String [5][3][][]; // é válida
- double temperatura[][][] = new double [100][][10] // não !
- String parametros[ ][ ] = {
- { “foreground”, “color”, “block” },
- { “background”, “color”, “gray” },
- { “Mensagem”, “String”, “Alô mamãe” } };
- Outro exemplo:
- short triangular[][] = new short [10][];
- for ( int i = 0; i < triangular.length; ++i ) {
- triangular[i] = new short [i + 1];
- for ( int j = 0; j < i + 1; ++j )
- triangular[i][j] = i + j;
- }
|
123
|
- Arrays são limitados pelo fato de não poderem variar de tamanho com o
tempo => Vector array de tamanho variável.
- public Vector()
// Construtores
- public Vector(int initialCapacity)
- public Vector(int initialCapacity, int capacityIncrement)
- Outros métodos:
- public void setSize(int newSize)
- public boolean removeElement(Object object)
- public void removeElementAt(int index)
- public void removeAllElements()
- public boolean isEmpty()
- public boolean contains(Object object)
- public int capacity()
- public int size()
|
124
|
|
125
|
- Operadores
- [] . (params) exp++
exp--
- ++exp --exp +exp
-exp ~exp !exp
- new (tipo)exp
- * / %
- + -
- << >> >>>
- < > <=
>= instanceof
- == !=
- &
- ^
- |
- &&
- ||
- ?:
- = += -=
*= /= %=
<<= >>= >>>= &= ^=
|=
|
126
|
|
127
|
|
128
|
|
129
|
- Expressões
- Formadas por dados, operadores e parentesis
- x * ( y - (a + b) >> 5 ) & m[i].k * f(4)
- Não existe aritmética de ponteiros, pois não existem ponteiros como em
C/C++
- *(mat + lin*tam_linha+col)=0 // Não em Java
- mat[lin][col]=0 // Ok
|
130
|
- Conversões em expressões
- Java utiliza tipagem forte,
assim conversões em expressões podem ser:
- automáticas: implícita ou por promoção (conversão p/ tipo mais geral)
- explícitas (coerção ou type-cast)
- Exemplos:
- byte b = 10; // Conversão automática (implícita)
- float f = 0.0F; int i;
|
131
|
- Exemplos (cont.)
- b = i; // O Compilador vai indicar o erro: “Imcompatible
- // type for=. Explicit cast
needed to convert int”
- double d = 12 + 9L + 12.3; // promoção para double dos numeros
- b = (byte)i; // explícita
(coerção) ou “type cast”
- s = i.toString(); // explícita (coerção) por métodos
- f = i; f = b; // Estas instruções apresentam problema ?
|
132
|
|
133
|
|
134
|
|
135
|
|
136
|
- Controle de Fluxo de execução
- O controle do fluxo da execução em Java utiliza os mesmos comandos
existentes em outras linguagens
- Repetição: for, while, do-while
- Seleção: if-else, switch-case
- Desvios (somente em estruturas de repetição): continue, break, return
e rótulos
- Não existe comando goto
- goto, porém, é palavra-reservada.
|
137
|
- Comandos
- Comando
- expressão de atribuição
- formas pré-fixadas ou pós-fixadas de ++ e --
- chamada de métodos
- criação de objetos
- comandos de controle de fluxo
- bloco
- Bloco = { <lista de comandos> }
|
138
|
- if-else
- if( a>0 && b>0 )
- m = média(a, b);
- else {
- errno = -1;
- m = 0;
- }
|
139
|
- switch-case-default
- switch( i=f() ) {
- case -1:
- ...
- break;
- case 0:
- ...
- break;
- default:
- ...
- }
|
140
|
- while
- int i = 0;
- while( ++i<10 ) {
- System.out.println(i);
- }
- //Que números serão impressos?
- //E se trocarmos por i++<10
- do while
- int i = 0;
- do {
- System.out.println(i);
- } while( ++i<10);
- //Que números serão impressos?
- //E se trocarmos por i++<10
|
141
|
- for
- for(int i=0; i<10; ++i)
- System.out.println(i);
- //Que números serão impressos?
- //E se trocarmos por i++
- return
- int média(int a, int b) {
- return (a+b)/2;
- }
|
142
|
- break
- int i = 0;
- while( true ) {
- if (++i==10) break;
- System.out.println(i);
- }
- //Que números serão impressos?
- //E se trocarmos por i++
- continue
- int i = 0;
- while ( true ) {
- if (++i%2 == 1) continue;
- System.out.println(i);
- }
- //Que números serão impressos?
- //E se trocarmos por i++
|
143
|
- break para Label
- início:
- for (int i=0; i<10; i++)
- for (int j=0; j<10; j++)
- {
- if (v[i][j] < 0)
- break início;
- ...
- }
- ...
- Exercícios
- Questão 3
|
144
|
- Classes
- Classes definem modelos de objetos
- Objetos = Dados + Código
- class Empregado
{ // Define
Classe
- String
nome;
// Atributo
int
h_total;
// Atributo
void Trabalha (int h) { // Método
- h_total += h;
- }
- }
|
145
|
|
146
|
- Inicialização de Classes
- Bloco de inicialização de classe identificado pela palavra reservada
static
- Atributos podem ter atribuição default
- class Nome {
- String Nome = ""; // Inicialização de atributo
static int data[1000];
static {
// Bloco inicialização de classe
- for (int i=0; i<1000; ++i)
data[i] = i;
- }
- }
|
147
|
- Objetos
- Instâncias de classes
- class Empregado { ...
} // Define classe
Empregado Roberto; //
Declara objeto
Roberto = new Empregado; // Instancia objeto
- Quando o objeto é declarado este recebe o valor nulo (null)
- Após new o objeto é efetivamente criado em memória (heap) usando o
construtor da classe
|
148
|
- Acessando Atributos e Métodos
- Operador de acesso aos membros de um objeto ( . )
- Roberto.h_total =
0; // Atributo
Roberto.Trabalha(8); // Método
- Inicialização de Objetos
- Inicialização de objeto é realizada pelo método construtor da classe
- O construtor é invocado automaticamente quando o comando new é
executado
- O construtor é um método que não possui identificação de valor de
retorno e possui o mesmo nome que a classe
|
149
|
|
150
|
- Inicialização de Objetos
- class Ônibus {
- int lotação;
Ônibus(int LotaçãoMáxima) {
- lotação = LotaçãoMáxima;
- }
- }
...
Ônibus
o;
// Declara objeto
o = new Ônibus(32); // Instancia objeto
ou
Ônibus o2 = new Ônibus(40);
|
151
|
- Destruição de Objetos
- O destrutor de um objeto é invocado pelo coletor de lixo quando este
precisa desfazer-se do objeto para liberar memória. Não se pode dizer
quando o destrutor será invocado
- O destrutor é um método especial da classe que não retorna valor (void),
possui o nome de finalize e não possui parâmetros
- class Ônibus {
- void finalize() { ProFerroVelho(); }
- }
- O método finalize() também pode ser executado explicitamente se
desejado: meuÔnibus.finalize();
- Obs: finalize() não tem garantia de funcionar quando desejado, por isso
é melhor usar o código dentro de um bloco try { … } catch( … ) { …. }
finally { ….. }
|
152
|
- Exemplo Classe Pilha
- Classe pilha de números inteiros, armazenados internamente em um array
cujo tamanho máximo é dado no momento de sua criação.
- class Stack {
- int top_index; int[] data; // <- Variáveis
- Stack(int size) { // <- Construtor
- data = new int[size];
- top_index = -1;
- }
- boolean isEmpty() { return
(top_index < 0); }
- void push(int n) {
data[++top_index] = n; }
- int pop() { return
data[top_index--]; } // <- Métodos
- int top() { return
data[top_index]; }
- }
|
153
|
- Uso da classe Pilha declarada
- Stack s = new Stack(2); // Pilha para 2 números.
- s.push(10);
- s.push(20);
- s.push(s.pop()+s.pop());
- System.out.println(s.top()); //
30
- System.out.println(s.isEmpty()); // false
- s.pop();
- System.out.println(s.isEmpty()); // true
|
154
|
- Encapsulamento
- Na classe Stack implementada, nós encapsulamos a definição de pilha que
desejávamos, porém, por falta de controle de acesso, é possível forçar
situações nas quais a pilha não se comporta como desejado.
- Stack s = new Stack(10);
- s.push(6);
- s.top_index = -1;
- System.out.println( s.isEmpty() );
// true!
|
155
|
- Encapsulamento - Controle de Acesso
- As linguagens OO disponibilizam formas de controlar o acesso aos
membros de uma classe. No mínimo, devemos poder fazer diferença entre o
que é público e o que é privado.
- Membros públicos podem ser acessados indiscriminadamente, enquanto os
privados só podem ser acessados pela própria classe.
|
156
|
- Redefinindo a Classe Stack
- class Stack {
- private int[] data;
- private int top_index;
- Stack(int size) { Exemplo - Calculadora Polonesa
- data = new int[size];
- top_index = -1;
- }
- boolean isEmpty() { return
(top_index < 0); }
- void push(int n) {
data[++top_index] = n; }
- int pop() { return
data[top_index--]; }
- int top() { return
data[top_index]; }
- }
|
157
|
- Exemplo de Controle de Acesso
- Com a nova implementação da pilha, o exemplo anterior não pode mais ser
feito pois teremos um erro de compilação.
- Stack s = new Stack(10);
- s.push(6);
- s.top_index = -1; // ERRO! na
compilação
- System.out.println(s.isEmpty());
|
158
|
- Sobrecarga (Overload)
- Um recurso usual em programação OO é o uso de sobrecarga de métodos.
- Sobrecarregar um método significa prover mais de uma versão de um mesmo
método.
- As versões devem, necessariamente, possuir algo que as diferencie: tipo
e/ou número de parâmetros ou tipo do valor de retorno.
|
159
|
- Sobrecarga (Overload)
- Na chamada de um método, seus parâmetros são passados da mesma forma
que em uma atribuição.
- Valores são passados em tipos primitivos
- Referências são passadas em objetos
- Há promoção de tipos de acordo com as regras de conversão de
primitivos e objetos
- Em casos onde a conversão direta não é permitida, é preciso usar
operadores de coerção (cast)
|
160
|
- Sobrecarga de Construtores
- Como dito anteriormente, ao criarmos o construtor da classe Point para
inicializar o ponto em uma dada posição, perdemos o construtor padrão
que, não fazendo nada, deixava o ponto na posição (0,0).
- Nós podemos voltar a ter esse construtor usando sobrecarga.
- class Point {
- int x = 0; int y = 0;
- Point() {}
- Point(int x, int y) {
- this.x = x; this.y = y;
- }
- }
- Agora no momento da criação do objeto podemos escolher qual construtor
usar
- Point p1 = new Point(); //p1
está em (0,0)
- Point p2 = new Point(1,2);//p2
está em (1,2)
|
161
|
- Uma solução melhor para o exemplo dos dois construtores seria o
construtor vazio chamar o construtor que espera suas coordenadas,
passando zero para ambas.
- Isso é um encadeamento de construtores.
- Java suporta isso através da construção this(...). A única limitação é
que essa chamada seja a primeira linha do construtor.
|
162
|
- Encadeamento de Construtores
- class Point {
- int x, y;
- Point() {
- this(0,0); // <- Chama construtor com
parametros
- }
- Point(int x, int y) {
- this.x = x; this.y = y;
- }
- ...
- }
|
163
|
|
164
|
- Pode ser feita da mesma maneira que fizemos com os construtores.
- Quando sobrecarregamos um método, devemos manter a semântica: não é um
bom projeto termos um método sobrecarregado cujas versões fazem coisas
completamente diferentes.
- A classe Math possui vários métodos sobrecarregados. Note que a
semântica das várias versões são compatíveis.
- int a = Math.abs(-10); // a = 10;
- double b = Math.abs(-2.3); // b
= 2.3;
|
165
|
|
166
|
- Herança
- Como vimos anteriormente, classes podem ser compostas em hierarquias,
através do uso de herança.
- Quando uma classe herda de outra, diz-se que ela a estende ou a especializa,
ou os dois.
- Herança implica tanto herança de interface quanto herança de código.
|
167
|
- Herança de Interface x Herança de Código
- Herança de interface significa que a classe que herda recebe todos os
métodos declarados pela superclasse que não sejam privados.
- Herança de código significa que as implementações desses métodos também
são herdadas. Além disso, os campos que não sejam privados também são
herdados.
|
168
|
- Herança em Java
- Quando uma classe A herda de B, diz-se que A é a sub-classe e estende
B, a superclasse.
- Uma classe Java estende apenas uma outra classe a essa restrição damos
o nome de herança simples.
- Para criar uma sub-classe, usamos a palavra reservada extends.
|
169
|
- Herança
- Java somente suporta herança simples para a especialização de classes
- class Ônibus extends Veículo {
- ...
- }
- ...
- Veículo
v[100]; // array heterogêneo
...
v[15] = new Ônibus(100);
v[16] = new Bicicleta;
v[15].Abastece(); // Ônibus.Abastece-Polimorfismo
|
170
|
- Exemplo de Herança
- Podemos criar uma classe que represente um pixel a partir da classe Point.
Afinal, um Pixel é um ponto colorido.
- public class Pixel extends Point {
- int color;
- public Pixel(int x, int y, int
c) {
- super(x, y);
- color = c;
- }
- }
|
171
|
- Herança de Código
- A classe Pixel herda a interface e o código da classe Point. Ou seja,
Pixel passa a ter tanto os campos quanto os métodos (com suas
implementações) de Point.
- Pixel px = new Pixel(1,2,0); //Pixel de cor 0
- px.move(1,0); //
Agora px está em (2,2)
|
172
|
- super
- Note que a primeira coisa que o construtor de Pixel faz é chamar o
construtor de Point, usando, para isso, a palavra reservada super.
- Isso é necessário pois Pixel é uma extensão de Point, ou seja, ela deve
inicializar sua parte Point antes de inicializar sua parte estendida.
- Se nós não chamássemos o construtor da superclasse explicitamente, a
linguagem Java faria uma chamada ao construtor padrão da superclasse
automaticamente.
|
173
|
- super
- Usa-se a palavra reservada super para referenciar a classe-pai em uma
hierarquia de classes Java
- class CaminhãoTanque extends Veículo {
- void Bate() {
- super.Bate(); if
(CargaInflamável()) Explode();
- }
- }
- class A { void f() { ... } }
- class B extends A { void f() { ... } }
- class C extends B {
- void f() { super.f(); ou
B.f(); // Acessando B
super.super.f();
ou A.f(); // Acessando A
- }
- }
|
174
|
- super
- Na implementação de um
construtor, é possível chamar construtor da classe-base usando também a
palavra reservada super
- class Ônibus extends Veículo {
- Ônibus(int LotaçãoMáxima) {
- super(LotaçãoMáxima);
...
- }
- }
|
175
|
|
176
|
|
177
|
- As linguagens OO podem adotar um modelo de hierarquia em árvore ou em floresta.
- Árvore significa que uma única hierarquia compreende todas as classes
existentes, isto é, existe uma superclasse comum a todas as classes.
- Floresta significa que pode haver diversas árvores de hierarquia que não
se relacionam, isto é, não existe uma superclasse comum a todas as
classes.
|
178
|
- Modelo de Classes de Java
- Em Java a classe Object é a raiz da hierarquia de classes à qual todas
as classes existentes pertencem. Quando não declaramos que uma classe
estende outra, ela implicitamente estende Object;
- Uma das vantagens de termos uma superclasse comum, é termos uma
funcionalidade comum a todos os objetos:
- Por exemplo, a classe Object define um método chamado toString que
retorna um texto descritivo do objeto;
- Um outro exemplo é o método finalize usado na destruição de um objeto,
como já dito.
|
179
|
- Especialização ´ Extensão
- Uma classe pode herdar de outra para especializá-la redefinindo
métodos, sem ampliar sua interface.
- Uma classe pode herdar de outra para estendê-la declarando novos
métodos e, dessa forma, ampliando sua interface.
- Ou as duas coisas podem acontecer simultaneamente.
- Exercícios - Questão 4
|
180
|
|
181
|
- Polimorfismo
- Polimorfismo é a capacidade de um objeto tomar diversas formas. A
capacidade polimórfica decorre diretamente do mecanismo de herança. Ao
estendermos ou especializarmos uma classe, não perdemos compatibilidade
com a superclasse.
- A sub-classe de Point, Pixel, é compatível com ela, ou seja, um Pixel,
além de outras coisas, é um ponto. Isso implica que, sempre que
precisarmos de um ponto, podemos usar um Pixel em seu lugar.
- Point[] pontos = new Point[5]; //
um array de pontos
- pontos[0] = new Point();
- pontos[1] = new Pixel(1,2,0); //
OK! um pixel é um ponto
- pontos[2] = new String(“Alo”);//
ERRO!, não é um ponto
|
182
|
- Note que um Pixel pode ser usado sempre que se necessita um ponto.
Porém, o contrário não é verdade: não podemos usar um ponto quando
precisamos de um pixel.
- Point pt = new Pixel(0,0,1); //OK!
pixel é ponto.
- Pixel px = new Point(0,0); //ERRO! ponto não é pixel.
- Conclusão:
- Polimorfismo é o nome formal para o fato de que quando precisamos de um
objeto de determinado tipo, podemos usar uma versão mais especializada
dele. Esse fato pode ser bem entendido analisando-se a árvore de
hierarquia de classes.
|
183
|
|
184
|
- Exemplo
- public class Point {
- ...
- public void print() {
- System.out.println(“Point
(”+x+“,”+y+“)”);
- }
- }
- Com essa modificação, tanto a
classe Point quanto a classe Pixel agora possuem um método que imprime
o ponto representado. Podemos voltar ao exemplo do array de pontos e
imprimir as posições preenchidas.
- Point pt = new Point(); // ponto em (0,0)
- Pixel px = new Pixel(0,0,0); //
pixel em (0,0)
|
185
|
- pt.print(); // Imprime: “Ponto
(0,0)”
- px.print(); // Imprime: “Ponto
(0,0)”
- Porém, a implementação desse
método não é boa para um Pixel pois a cor não é impressa. Para resolver
o problema fazemos a classe Pixel redefinir o método print de forma
adequada.
- public class Pixel extends Point
{
- ...
- public void print() {
-
System.out.println(“Pixel(”+x+ “,” +y+ “,” + color+“)”);
- }
- }
- Com essa nova modificação, a
classe Pixel agora possui um método que imprime o pixel de forma
correta.
|
186
|
- Point pt = new Point(); //
ponto em (0,0)
- Pixel px = new Pixel(0,0,0); // pixel em (0,0)
- pt.print() ; // Imprime: “Ponto (0,0)”
- px.print(); // Imprime: “Pixel
(0,0,0)”
- Voltemos ao exemplo do Array de pontos.
- Point[] pontos = new Point[5];
- pontos[0] = new Point();
- pontos[1] = new Pixel(1,2,0);
- pontos[0].print(); // Imprime: “Ponto (0,0)”
- pontos[1].print(); // Imprime: “Pixel (1,2,0)”
|
187
|
- Polimorfismo – outro exemplo
- class Veiculo {
- public Veiculo() { System.out.print("Veiculo "); }
- public void checkList(){
System.out.println("Veiculo.checkList"); }
- public void adjust() { System.out.println("Veiculo.adjust");
}
- public void cleanup() {
System.out.println("Veiculo.cleanup"); }
- }
- class Automovel extends Veiculo {
- public Automovel() { System.out.println("Automovel"); }
- public void checkList() {
System.out.println("Automovel.checkList"); }
- public void adjust() {
System.out.println("Automovel.adjust"); }
- public void cleanup() {
System.out.println("Automovel.cleanup"); }
- }
- class Bicicleta extends Veiculo {
- public Bicicleta() { System.out.println("Bicicleta"); }
- public void
checkList(){System.out.println("Bicicleta.checkList"); }
- public void adjust() {
System.out.println("Bicicleta.adjust"); }
- public void cleanup() {
System.out.println("Bicicleta.cleanup"); }
- }
|
188
|
- public class Oficina {
- Random r = new Random();
- public Veiculo proximo() {
-
Veiculo v; int code = r.nextInt();
- if (code%2 == 0) v = new
Automovel();
- else v = new Bicicleta();
- return v;
- }
- public void manter(Veiculo v) {
- v.checkList(); v.adjust();
v.cleanup();
- }
- public static void main(String[] args) {
- Oficina o = new Oficina();
Veiculo v;
- for (int i=0; i<4; ++i) {
- v = o.proximo(); o.manter(v);
// polimorfismo !
- }
- }
- } Diga o que será
impresso !
|
189
|
|
190
|
|
191
|
|
192
|
- Late Binding ( Ligação tardia )
- As linguagens OO possuem um recurso chamado late binding, que permite o
adiamento da resolução de um método até o momento no qual ele deve ser
efetivamente chamado. Ou seja, a resolução do método acontecerá em tempo
de execução, ao invés de em tempo de compilação. No momento da chamada,
o método utilizado será o definido pela classe real do objeto.
- Voltando ao exemplo do array de pontos, agora que cada classe possui
sua própria codificação para o método print, o ideal é que, ao
corrermos o array imprimindo os pontos, as versões corretas dos métodos
fossem usadas. Isso realmente acontece, pois as linguagens OO usam um
recurso chamado late binding.
|
193
|
- Graças a esse recurso, agora temos:
- Point[] pontos = new Point[5];
- pontos[0] = new Point();
- pontos[1] = new Pixel(1,2,0);
- pontos[0].print(); // Imprime: “Point (0,0)”
- pontos[1].print(); // Imprime: “Pixel (1,2,0)”
- Suporte ao polimorfismo depende do suporte à ligação tardia (late
binding) de chamadas de função
- A referência (interface) é conhecida em tempo de compilação mas o
objeto a que ela aponta (implementação) não é;
|
194
|
- Late Binding (cont.)
- O objeto chamado pode ser da mesma classe ou de uma subclasse da
referência (TODA a interface está implementada no objeto !);
- Uma única referência, pode ser ligada, durante a execução, a vários
objetos diferentes (a referência é dita polimórfica )
|
195
|
- Late Binding x Eficiência
- O uso de late binding implica em perda no desempenho dos programas
visto que a cada chamada de método um processamento adicional deve ser
feito, devido ao uso da indereção causada pelo mecanismo de
implementação do late-binding (tabelas virtuais). Esse fato levou
várias linguagens OO a permitir a construção de métodos constantes (chamados
métodos finais em Java), ou seja, métodos cujas implementações não
podem ser redefinidas nas sub-classes.
|
196
|
|
197
|
|
198
|
|
199
|
|
200
|
|
201
|
|
202
|
|
203
|
- Atributos Constantes
- Java permite declarar um campo ou uma variável local que, uma vez
inicializada, tenha seu valor fixo. Para isso utilizamos o modificador final.
- class A {
- final int ERR_COD1 =
-1; // constantes !
- final int ERR_COD2 = -2;
- ...
- }
- Métodos e Classes Constantes em Java
- public class A { public final
int f() { ... }}
- Uma classe inteira pode ser
definida final. Isto serve para evitar que também a classe seja
estendida.
- public final class B { ... }
|
204
|
- Conversão de Tipo – Type Casting
- Podemos usar uma versão mais especializada quando precisamos de um
objeto de certo tipo mas o contrário não é verdade. Por isso, para
fazer a conversão de volta ao tipo mais especializado, teremos que
fazê-lo explicitamente.
- A conversão explícita de um objeto de um tipo para outro é chamada type
casting. Tipos genéricos (acima, na hierarquia) sempre podem receber
objetos de suas subclasses: upcasting,
enquanto tipos específicos (abaixo, na hierarquia) não podem
receber explícitamente seus objetos que foram declarados como
referências de suas superclasses: downcasting.
|
205
|
- Conversão de Tipo – Type Casting
(cont)
- Point pt1 = new Pixel(0,0,1); // OK – upcasting, pixel é ponto !
- Pixel px = (Pixel)pt1; //
OK – downcasting valido!
- Point pt2 = new Point(0, 0);
- Pixel px= pt2; // ERRO não
compila, downcasting invalido!
- Pixel px =(Pixel)pt2;// Compila, erro execução ClassCastExcetion!
- Point pt=new Point();
- Pixel px=(Pixel)pt; // Erro execução: ClassCastException, pq ?
- pt = new Pixel(0,0,0);
- px = pt; // ERRO
compilação: falta type-cast explicíto.
|
206
|
- Para evitar a exceção deveríamos fazer o seguinte:
- if (pt instanceof Pixel) {
- Pixel px = (Pixel)pt;
..... Exercícios -
Questão 5
- }
- Note que, assim como o late
binding, o type casting e instanceof só podem ser resolvidos em tempo
de execução: só quando o programa estiver rodando é possível saber o
valor que uma dada variável terá e, assim, decidir se a conversão é
válida ou não.
|
207
|
|
208
|
|
209
|
|
210
|
|
211
|
|
212
|
|
213
|
|
214
|
- Evite chamar métodos locais dentro de construtores
- Construtor (qq um da hierarquia) sempre usa a versão sobreposta do
método (late-binding)
- Isto pode trazer resultados inesperados se alguém estender a sua classe
com uma nova implementação do método que:
- Dependa de variáveis da classe estendida
- Chame métodos em objetos que ainda serão criados provocando NullPointerException
- Dependa de outros métodos sobrecarregados
- Use apenas métodos finais em construtores
- Estes métodos não podem ser sobrecarregados nas subclasses
|
215
|
|
216
|
|
217
|
|
218
|
|
219
|
|
220
|
- Classes Abstratas
- Ao criarmos uma classe para ser
estendida, às vezes codificamos vários métodos usando um método para o
qual não sabemos dar uma implementação, ou seja, um método que só
sub-classes saberão implementar.
- Uma classe desse tipo não deve
poder ser instanciada pois sua funcionalidade está incompleta. Tal
classe é dita abstrata.
- Java utiliza o modificador abstract para declarar uma classe abstrata.
Métodos também podem ser declarados abstratos para que suas
implementações fiquem adiadas para as sub-classes.
|
221
|
- Classes Abstratas em Java
- abstract class Veículo {
- abstract void Abastece();
- }
- class Ônibus extends Veículo {
- void Abastece() {
- EncheTanqueComDiesel();
- }
- }
...
objAbstrato = new Veículo(); // Erro
objConcreto = new Ônibus(); // Ok
|
222
|
- Classes Abstratas em Java
- public abstract class Drawing {
- public abstract void draw();
- public abstract BBox getBBox();
- public boolean contains(Point p)
{
- BBox b = getBBox();
- return (p.x>=b.x &&
p.x<b.x+b.width &&
- p.y>=b.y &&
p.y<b.y+b.height);
- } ...
- }
|
223
|
|
224
|
|
225
|
|
226
|
|
227
|
|
228
|
|
229
|
|
230
|
|
231
|
|
232
|
|
233
|
|
234
|
|
235
|
- Herança: Simples ´ Múltipla
- O tipo de herança que usamos até agora é chamado de herança simples
pois cada classe herda de apenas uma outra. Existe também a chamada herança
múltipla onde uma classe pode herdar de várias classes.
- Herança múltipla não é suportada por todas as linguagens OO, pois
apresenta um problema quando construímos hierarquias de classes onde
uma classe herda duas ou mais vezes de uma mesma superclasse. O que, na
prática, torna-se um caso comum.
|
236
|
- Problemas de Herança Múltipla
- O problema de herdar duas vezes de uma mesma classe vem do fato de
existir uma herança de código.
- Inúmeras vezes, quando projetamos uma hierarquia de classes
usando herança
múltipla, estamos, na verdade, querendo declarar que a
classe é compatível com as
classes herdadas. Em muitos casos, a herança de código não é utilizada.
|
237
|
|
238
|
- Interfaces
- Algumas linguagens OO incorporam o conceito de duas classes serem
compatíveis através do uso de compatibilidade estrutural ou da
implementação explícita do conceito de interface.
- Java não permite herança múltipla com herança de código, mas implementa
o conceito de interface. É possível herdar múltiplas interfaces.
- Em Java, uma classe estende uma outra classe e implementa zero ou mais
interfaces. Para implementar uma interface em uma classe, usamos a
palavra implements.
|
239
|
|
240
|
- Exemplo
- interface Pessoa { void Come(int
Kg);}
- interface Ciclista extends
Pessoa {
- void Pedala(int Km);
- }
- interface Corredor extends
Pessoa{
- void Corre(int Km);
- }
interface Nadador extends
Pessoa {
- void Nada(int Km);
- }
-
...
class Triatleta extends Atleta
- implements Ciclista, Corredor, Nadador
- ...
|
241
|
- public interface Shape {
- double PI = 3.1425926; //static final !
- void draw();
- void resize();
- }
- public class Circle implements Shape {
- public void draw() { /* draw a
circle */ }
- public void resize() { /* draw a circle */ }
- }
- public class Rectangle implements Shape {
- public void draw() { /* draw a rectangle */ }
- public void resize() { /* draw a rectangle */ }
- }
|
242
|
- Comparable é uma interface pré-definida em Java.
- Muitas classes da biblioteca Java implementam essa interface.
- compareTo deve retornar
- inteiro < 0 se o objeto remetente é “menor” que o parâmetro,
- 0 se eles são iguais,
- inteiro > 0 se o objeto remetente é maior que o parâmetro.
|
243
|
|
244
|
|
245
|
- Exemplo de Interface
- Ao implementarmos o TAD Pilha, poderíamos ter criado uma interface que
definisse o TAD e uma ou mais classes que a implementassem.
- interface StackInterf { class
StackImpl implements
-
StackInterf {
- boolean isEmpty();
- void push(int n); int data[], top_index;
- int pop(); ……………….
- int top(); }
- }
|
246
|
- Membros de Interfaces
- Uma vez que uma interface não possui implementação, temos que:
- seus campos devem ser públicos, estáticos e constantes;
- seus métodos devem ser públicos e abstratos.
- Como esses qualificadores são fixos, não precisamos declará-los (note o
exemplo anterior).
- interface StackInterf {
- public abstract boolean
isEmpty();
- public abstract void push(int
n);
- public abstract int pop();
- public abstract int top();
- }
|
247
|
- Pilha revisitada
- class StackImpl implements StackInterf {
- private int[] data;
- private int top_index;
- Stack(int size) {
- data = new int[size];
- top_index = -1;
- }
- boolean isEmpty() { return
(top_index < 0); }
- void push(int n) {
data[++top_index] = n; }
- int pop() { return
data[top_index--]; }
- int top() { return
data[top_index]; }
- }
|
248
|
- Limites da Herança
- O mecanismo de herança que
analisamos não resolve alguns problemas. Considere o TAD Pilha que
implementamos: Ele define uma pilha de números inteiros mas isso não
devia ser (e não é) necessário. Por exemplo, poderia ser útil ter uma
pilha de inteiros e uma outra de objetos Point. Podemos criar pilhas
específicas mas não podemos criar todas as possíveis...
|
249
|
- Resumindo Interfaces
- Não são classes
- Oferece compatibilidade de tipos de objetos
- Comparable x; // Comparable é
uma interface
- x = new Pessoa(); // Pessoa implementa Comparable
- Permite o uso de instanceof
- if (x instanceof Comparable) {…}
- Uma interface pode estender outra
- public interface Compativel extends Comparable { …
- }
|
250
|
|
251
|
|
252
|
|
253
|
|
254
|
|
255
|
|
256
|
- Herança ´ Parametrização
- Uma alternativa a criar novas classes para cada diferente tipo de pilha
que iremos usar é parametrizar a própria classe que implementa a pilha.
Várias linguagens OO suportam parametrização de tipos.
- Parametrizar um tipo significa passar o tipo a ser usada em alguma
operação como um parâmetro. No caso da pilha, poderíamos passar o tipo
dos elementos que pilha deveria conter como um parâmetro do construtor,
por exemplo.
|
257
|
- Parametrização em Java
- Java não provê suporte direto à construção de classes parametrizadas,
ate J2SE 5.0. Como Java adota o modelo de hierarquia em árvore, com uma
superclasse comum a todas as classes, e, além disso, mantém as informações
de tipo em tempo de execução, podemos simular um TAD paramétrico usando
type-casting.
- Para simularmos parametrização em Java podemos consultar as informações
de tipo em tempo de execução através do comando instance of
|
258
|
- Point pt = new Point(); // pt
contém um ponto
- boolean b = pt instanceof Pixel; // b = false
- pt = new Pixel(1,2,3); // pt
contém um pixel
- b = pt instanceof Pixel; // b
= true
- Podemos então mudar a definição do nosso TAD para especificar pilhas de
objetos genéricos.
- interface StackInterf {
- boolean isEmpty();
- void push(Object obj);
- Object pop(); Exercícios – Questão 6
- Object top();
- }
|