Java Disciplina: Programação Modular Prof. Marco Túlio de Oliveira Valente Introdução James Gosling e equipe (Sun, 1995) Linguagem compilada e posteriormente interpretada bytecode: linguagem intermediária Assembly de uma máquina hipotética Máquina Virtual Java: interpretador de bytecodes Não é novidade: Pascal-P (Wirth, década de 70) Mesma estratégia em C#: CLR e CIL (ou MSIL) Vantagem: portabilidade prog1.java (fonte) prog1.class COMPILADOR (bytecodes) MÁQUINA VIRTUAL JAVA - JVM (INTERPRETADOR) 2 Princípios de Projetos Linguagem que fosse: Simples, orientada a objetos, familiar Robusta e segura Arquiteturalmente neutra e portável Alto desempenho Interpretada, multi-thread e dinâmica 3 Java é mais simples que C++ Sem ponteiros, apenas referências Sem funções, apenas métodos estáticos Sem variáveis globais, apenas atributos estáticos Sem delete, mas com coletor de lixo Sem arquivos de header, mas interfaces Sem sobrecarga de operadores, apenas de métodos Sem pré-processador, mas com membros final Sem herança múltipla de classes, mas com herança múltipla de interfaces 4 Java é mas segura que C++ Não é possíveis acessar quaisquer áreas de memória: Não existe aritmética de ponteiros. Exemplo: p++ Não existem casts não-verificados. Exemplo: (char *) 2 Não existem acessos além dos limites de um vetor. Exemplo: buffer[-1] 5 Java é mais portátil que C++ Independência de hardware e sistema operacional. Mesmo programa roda em uma grande variedade de hardware e sistemas operacionais. Programas .java são compilados para uma representação intermediária, chamada bytecode (.class) Máquina Virtual Java (JVM): interpretador de bytecodes 6 Java tem mais bibliotecas que C++ Vasta gama de bibliotecas para: construção de interfaces gráficas (java.awt e javax.swing) programação distribuída (java.rmi) programação multithread (java.lang.threads) entrada/saída e redes: (java.io, java.net) estruturas de dados (java.util) bancos de dados (java.sql) etc 7 Primeiro Programa // arquivo HelloWorld.java public class HelloWorld { public static void main(String[ ] args){ System.out.println (“Hello, world”); } } Todo arquivo deve ter uma classe pública com o mesmo nome do arquivo Execução começa pelo método main desta classe Observações: Programa em Java é um conjunto de classes Implementação dos métodos sempre dentro da classe 8 Sintaxe e Tipos Primitivos Sintaxe bastante parecida com C/C++. Mesmos comandos básicos: if, switch, while, do while, for, return, break, continue Mesmos operadores aritméticos, lógicos e relacionais Tipos primitivos: boolean (8 bits) char (16 bits) byte (8 bits), short (16 bits), int (32 bits), long (64 bits) float (32 bits), double (64 bits) 9 Classes class Point { private double x, y; // campos public Point (double x, double y) { // construtora this.x= x; this. y= y; } public double getX() { // métodos return x; } public double getY() { return y; } public void move(double dx, double dy) { x=+ dx; y=+ dy; } 10 Classes (cont.) public double distance(Point that) { double xdiff= this.x - that.getX(); double ydiff= this.y - that.getY(); return Math.sqrt(xdiff*xdiff + ydiff*ydiff); } public void clear() { x= 0; y= 0; } } 11 Objetos Sempre criados via new e alocados no heap. Exemplo: void foo() { Point p1; Point p2; // p1 e p2 são referências para objetos p1= new Point(5,5); p2= new Point(1000,500); double dist= p1.distance(p2); // chamada de método } p1 e p2 são duas variáveis alocadas no stack que referenciam (ou apontam para objetos alocados no heap). Em Java, objetos nunca são alocados no stack. 12 Programa Equivalente em C++ void foo() { Point *p1; Point *p2; p1= new Point(5,5); p2= new Point(1000,500); double dist= p1->distance(p2); delete p1; delete p2; // chamada de método } 13 Coletor de Lixo Não existe free ou delete Programador aloca, mas não precisa liberar memória Tarefa normalmente sujeita a diversos erros Funcionamento: Existe na JVM um processo, chamado coletor de lixo, que fica continuamente procurando por objetos que não estão sendo mais referenciados Quando encontra um objeto inacessível, o coletor de lixo libera a área de memória alocada para o mesmo Não se tem controle sobre o momento em que o coletor de lixo roda Não é uma novidade em LP: LISP, 1960 14 Exemplo de Coleta de Lixo class BigClasse { private int x; private int bigvetor []; // vetor de inteiros public BigClasse (int x) { System.out.println ("Criando " + x1); this.x= x1; bigvetor= new int [1024*1024]; } protected void finalize () { System.out.println("Eliminando " + x); } } // BigClasse 15 Exemplo de Coleta de Lixo public class Exemplo2 { public static void main(String[] args) { BigClasse p; for (int i= 0; i < 100; i++) p= new BigClasse (i); } } Método finalize(): chamado automaticamente pelo coletor antes de liberar a área de memória de um objeto Utilidade: liberar outros recursos (que não memória) Exemplo: fechar arquivos, fechar conexões etc 16 Semântica de Valor e de Referência C++: objetos tratados com semântica de valor ou referência (programador que decide) void foo() { Point *p1; // semântica de referência Point p2; // semântica de valor ... } Java: objetos tratados exclusivamente com semântica de referência void foo() { Point p1; // semântica de referência ... p1= new Point(10,10); } 17 Referência this Referência para o objeto receptor de uma chamada de método class Point { private double x, y; public Point (double x, double y) { this.x= x; this. y= y; } .... } 18 Membros Estáticos Campos estáticos: semântica de variável global; são campos da classe e não de uma instância em particular. Existem mesmo que não existam objetos da classe Point. class Point { private static Point origin= new Point(0,0); .... } Métodos estáticos: semântica de funções de C ou C++ São métodos da classe Não dependem de uma instância para serem chamados. Exemplo: Math.sqrt Podem acessar apenas atributos e métodos estáticos Não podem acessar a referência this 19 Campos Final Campos read-only. Uma vez inicializados, nunca mais podem ser alterados. Normalmente, são também estáticos. Exemplo: public static final double PI = 3.14; 20 Vetores Vetores são tratados com objetos e, portanto, são criados via operador new (e alocados no heap). class Gauss { public static void main(String[] args) { int[] ia = new int[101]; // índices vão de 0 a 100 for (int i = 0; i < ia.length; i++) ia[i] = i; int sum = 0; for (int i = 0; i < ia.length; i++) sum += ia[i]; System.out.println(sum); } } Tamanho do vetor é definido em tempo de criação; uma vez criado, não pode ser modificado Tentativa de usar um vetor além dos limites permitidos gera uma exceção do tipo ArrayIndexOutOfBoundsException 21 Vetores de Vetores Exemplo: float[][] mat= new float[4][4]; setUpMatrix(mat); for (int y= 0; y < mat.length; y++) { for (int x= 0; x < mat[y].length; x++) System.out.print(mat[y][x] + " "); System.out.println(); } 22 Strings Strings são objetos da classe String. Exemplo: String greeting = "Hello world!"; Classe String possui diversos métodos para manipular strings. Exemplos: charAt, concat, endsWith, length, toLowerCase etc Objetos da classe String são imutáveis. Operações sobre strings sempre retornam uma nova string. String original permanece inalterada. 23 Herança Possui apenas herança simples de classes Exemplo: class Pixel extends Point { Color color; // novo atributo public void clear() { // redefine (ou sobresceve) método herdado super.clear(); // chama método da superclasse color= null; } } Polimorfismo: objetos Pixel podem ser usados por qualquer código que espere um Point 24 Chamada Dinâmica de Métodos Não existem métodos virtuais; maioria dos métodos são automaticamente considerados virtuais (isto é, chamados dinamicamente) Exceções: métodos privados e estáticos Exemplo: Figura p; // Quadrado if ( .... ) p= new Quadrado (4); // else p= new Circulo (3); // double a= p.area (); // e Circulo subclasses de Figura atribuição polimórfica atribuição polimórfica chamada dinâmica 25 Classe Object Raiz da hierarquia de classes de Java Toda classe (direta ou indiretamente) é subclasse de Object Utilidade: variável do tipo Object pode se referir a qualquer objeto (de qualquer classe) Exemplo 1: void push(Object item) { ... } Exemplo 2: Object oref= new Pixel(); ... oref = "Alguma String" 26 Classe Object Exemplo 3: String name= "Petronius" Object obj= name; name= obj; // Erro de compilação name= (String) obj; // ok Se coerção falhar em tempo de execução, lança-se uma exceção ClassCastException. 27 Classes e Métodos final Evitando herança: final class Senha { ... } class MinhaSenha extends Senha { ... } // Erro ! Evitando redefinição de métodos: class Senha { ...... public final bool validarSenha () { ..... } .... } class MinhaSenha extends Senha { ...... bool validarSenha () { ...... } // Erro ! ..... } 28 Classes Abstratas Exemplo: abstract class Figura { public abstract double area (); public abstract double perimetro (); } .... void foo() { Figura f1; // ok, f1 é apenas uma referência Figura f2= new Figura() // Erro, não é possível instanciar // objetos de classes abstratas } Implementação de area() e perimetro() ficará a cargo das subclasses de Figura. 29 Interfaces Usadas para enriquecer o modelo de herança simples de Java Permitem alguns benefícios de herança múltipla, sem os problemas que herança múltipla introduz no projeto e implementação de linguagens Interface define um tipo composto apenas por: Assinaturas de métodos Constantes Uma interface não inclui variáveis de instância, nem código para implementação de métodos. Uma classe pode declarar que implementa (implements) uma interface. Neste caso, ela assume o compromisso de implementar todos os métodos desta interface 30 Interfaces Exemplo (declaração da interface): interface Comparable { int compareTo(Object o); } Exemplo (implementação da interface): class Professor extends Pessoa implements Comparable { int matr; ... int compareTo(Object o) { Professor that= (Professor) o; “Compara this.matr e that.matr, retornando -1, 0 ou 1” } } 31 Interfaces Exemplo (uso da interface): void qsort (Comparable[] v) { .... } Não importa a classe dos objetos do vetor v (ou seja, essas classes ficam livres para herdarem de outras classes) 32 Interfaces Interface define um contrato (ou protocolo) entre: Um provedor de serviços (ex: quem implementa compareTo) Um usuário de serviços (ex: método de ordenação) Uma classe pode herdar de uma única classe, mas pode implementar múltiplas interfaces. Logo, objetos em Java podem ter múltiplos tipos, incluindo o tipo de sua classe e os tipos das interfaces que ela implementa. Uma interface pode estender uma ou mais interfaces (adicionando novas constantes ou novos métodos). Ou seja, existe herança múltipla de interfaces (a qual não implica em nenhuma forma de reúso de código) 33 Classes Genéricas Exemplo: public class Box<T> { private T t; public void add(T t) { this.t = t; } public T get() { return t; } } // T stands for "Type" ...... Box<Integer> integerBox = new Box<Integer>(); integerBox.add(new Integer(10)); Integer someInteger = integerBox.get(); // no cast! 34 Interfaces Genéricas Exemplo de interface genérica: interface Table<T> { T find(String name); } É melhor que: interface Table { Object find(String name); } 35 Interfaces Genéricas Implementação da interface class IntegerTable implements Table<Integer> { private String[] names; private Integer[] values; public Integer find(String name) { ... } } 36 Interfaces Genéricas Código que usa interface genérica (1ª tentativa) void processValues(String[] names, Table<Object> table { for (int i= 0; i < names.length; i++) { Object value= table.find(names[i]); if (value != null) process(names[i], value); } } Problema: Table<Integer> t= new IntegerTable(); // ... adiciona itens em t String[] names= { "Um", "Dois" }; processValues(names, t); // Erro! 37 Interfaces Genéricas Integer é subtipo de Object. Mas, Table<Integer> não é um subtipo de Table<Object> Exemplo: List<String> ls= new ArrayList<String>(); List<Object> lo= ls; Atribuição acima é válida? Não, conforme justificado a seguir. lo.add(new Object()); // via lo, seria possível adicionar objetos de quaisquer tipos em ls String s= ls.get(0); // não se garante mais que get retorne sempre um string 38 Tipos Genéricos e Wildcards List <?>: super-tipo de todas as listas E não List<Object> pelas razões descritas no slide anterior Exemplo: List<String> ls= new ArrayList<String>(); List<Object> lo= ls; // Erro compilação List<?> lu= ls; lu.add(new Object()); // ok // Erro compilação Object o= lu.get(0); ?: stands for “some unknown type” Any parameter we pass to add would have to be a subtype of this unknown type. Since we don't know what type that is, we cannot pass anything in. 39 Tipos Genéricos e Wildcards 1a Solução: usando um tipo coringa ilimitado (?) void processValues(String [] names, Table<?> table { for (int i= 0; i < names.length; i++) { Object value= table.find(names[i]); // OK if (value != null) process(names[i], value); } } Table<Integer> t= new IntegerTable(); // ... adiciona itens em t String [] names= { "Um", "Dois" }; processValues(names, t); // ok 40 Tipos Genéricos e Wildcards 2a Solução (melhor): usando um tipo coringa limitado void processValues(String[] names, Table<? extends Number> table { for (int i= 0; i < names.length; i++) { Number value= table.find(names[i]); if (value != null) process(names[i], value); } } 41 Packages Recurso para modularização de programas em Java Package: conjunto de arquivos Todo pacote possui um nome Exemplo: pacote figuras Cada arquivo pode possuir, no máximo, uma classe pública O nome do arquivo é o mesmo de sua classe pública Com classes públicas Figura, Circulo, Quadrado Arquivo c:\temp\figuras\Figura.java: package figuras; public abstract class Figura { ... } // outras classes (não-públicas) 42 Packages Arquivo c:\temp\figuras\Circulo.java package figuras; public class Circulo { ... } // outras classes (não-públicas) Arquivo c:\temp\figuras\Quadrado.java package figuras; public class Quadrado { ... } // outras classes (não-públicas) 43 Packages Nome do pacote deve ser igual ao nome do diretório que contém seus arquivos Variável de ambiente CLASSPATH: deve conter o nome do diretório onde se encontra o diretório do pacote Exemplo: set CLASSPATH=%CLASSPATH%;c:\temp 44 Packages Como referenciar classes públicas de um pacote fora do mesmo? Via qualificação com o nome do pacote: figuras.Figura fig; figuras.Circulo c; java.awt.Button btnOk; Via comando import no início do arquivo: import figuras.*; // importa todas classes de figuras import java.awt.Button; // importa apenas classe Button .......... Figura fig; Circulo c; Button btnOk; 45 Tratamento de Exceções em Java Como ativar uma exceção: throw <expressão> Expressão deve ser um objeto de uma classe derivada da classe pré-definida Exception Similar a C++, porém incluir um new para criar objeto Métodos devem relacionar na clásula throws todas as exceções que podem encerrar a execução do mesmo Exemplo: class DivisaoPorZero extends Exception { } ; ... double divisao (double x, double y) throws DivisaoPorZero { if (y = = 0) throw new DivisaoPorZero (); return x / y; } 46 Tratamento de Exceções em Java Como especificar um tratador de exceções ? try { ... } catch (ExceptionType ident ) { ... } catch (ExceptionType ident) { ... } finally { ... } finally é executado ocorrendo ou não uma exceção no try Exemplo: try { ... } catch (A e) { ... } finally { ... } finally será executado quando: (a) try terminar corretamente; (b) try terminar com uma exceção capturada ou não pelo catch 47 Tratamento de Exceções em Java Exemplo sem finally: file.open(); try { ... } // processa arquivo catch (IOException e) { file.close(); throw e; } file.close(); Exemplo com finally: file.open(); try { .. } finally { file.close(); } 48 Exceções Não-Verificadas Exceções Verificadas: Subclasses de Exception Exemplos: IOException, FileNotFoundException Devem ser tratadas no corpo de um método (em um catch) ou explicitamente declaradas na assinatura do método Em resumo, um método somente pode retornar com exceções verificadas que ele lista em sua cláusula throws Exceções não-verificadas: Subclasses de RuntimeException ou Error Normalmente, exceções que representam algum erro na lógica do programa; clientes normalmente não tem o que fazer nestes casos Exemplos: ArrayIndexOutOfBoundsException, NullPointerException 49 Java RMI Disciplina: Programação Modular Prof. Marco Túlio de Oliveira Valente Java RMI Middleware para programação distribuída em Java Implementado como um pacote da linguagem 51 Java RMI: Exemplo de Aplicação Codificar um servidor com um objeto da seguinte classe: class ContaImpl .... { ... public float obterSaldo (); ... } Codificar um cliente que chame remotamente o método obterSaldo() deste objeto 52 Java RMI: Exemplo de Aplicação Passo 1: Definição da interface remota (assinatura dos métodos que serão invocados remotamente) // arquivo Conta.java import java.rmi.Remote; import java.rmi.RemoteException; interface Conta extends Remote { ... public float obterSaldo () throws RemoteException; ... } 53 Java RMI: Exemplo de Aplicação Passo 2: Implementação da Interface Remota (servidor) class ContaImpl extends UnicastRemoteObject implements Conta { private int numero; private float saldo= 0.0; public ContaImpl (int n) throws RemoteException { numero= n; } public float obterSaldo return saldo; } () throws RemoteException { public static void main (String[] args) { ... Conta c= new ContaImpl (804); Naming.rebind (“Conta804”, c); // registra este objeto } } 54 Java RMI: Exemplo de Aplicação Passo 3: Implementação do Cliente import java.rmi.*; import java.rmi.server.*; public class ClienteImpl { public static void main (String[] args) { ...... Conta c= (Conta) Naming.lookup (“//” + args[0] +“/Conta804”); float s= c.obterSaldo(); // chamada remota, mesma sintaxe chamada local ... } } 55 Java RMI: Exemplo de Aplicação Passo 4: Compilação Compilação do servidor: javac ContaImpl.java Compilação do cliente: javac ClienteImpl.java Geração de stubs: rmic ContaImpl rmic gera os seguintes arquivos: ComtaImpl_Stub.class: stub do cliente ContaImpl_Skel.class: skeleton (nome dado ao stub do serv.) Passo 5: Execução Execução do Servidor: rmiregistry // registry (permanece em execução) java ContaImpl // servidor (em outro processo) Execução do Cliente: java clienteImpl dcc_srv01 56 Passagem de Parâmetros Objetos serializáveis são passador por valor: Classe do objeto deve implementar a interface Serializable Passa-se uma cópia do objeto (atributos + métodos) Objetos remotos são passadas por referência: Passa-se a referência (e não o objeto), a qual pode ser utilizada para realizar um callback no cliente Callback: servidor chama método do cliente Usado, por exemplo, quando o servidor deseja notificar o cliente sobre a ocorrência de algum evento 57 Exemplo de Callback void g () {..... } Cliente Servidor objeto remoto objeto remoto A B void f (A a) { a.g(); // callback } a s s.f(a); 58 Java RMI - Chat Aplicação de chat usando Java RMI, com a seguinte interface: 59 Sistema de Chat em Java RMI remoto conectados remoto void conecta(C c) { “adiciona c em conectados” } void envia (String s) { for (int i= 0; i < conectados.size; i++) conectados[i].display(s); // callback } remoto display (s) c s.conecta(c); ...... s.envia(“Bom dia!”); remoto display (s) c s.conecta(c); display (s) c s.conecta(c); 60 Reflexão Computacional Disciplina: Programação Modular Prof. Marco Túlio de Oliveira Valente Reflexão Computacional Capacidade de um sistema se auto-inspecionar e auto-manipular Um sistema reflexivo possui dois níveis: Nível básico: contém objetos do domínio da aplicação Meta-nível: contém objetos que permitem acessar propriedades e manipular objetos do nível básico Objeto do meta-nível são chamados de meta-objetos Protocolo de meta-objetos: protocolo de interação com metaobjetos Reificação: ação de transformar em meta-objetos informações do nível base Reflexão envolve duas atividades: Inspeção: quando meta-nível inspeciona informações do nível básico Interseção: quando meta-nível interfere no comportamento ou na estrutura do nível básico 62 Reflexão em Java Tudo começa com um meta-objeto do tipo Class Exemplo: Class c= Class.forName(“java.util.Stack”); Pode-se usar métodos do tipo Class para inspeção de informações: Obter a super-classe do tipo base Obter interfaces que são implementadas pelo tipo base Obter informações sobre os construtores do tipo base Obter informações sobre os métodos do tipo base (modificadores, tipo de retorno, tipo dos parâmetros) Pode-se ainda interceder no nível básico do programa para: Criar objetos de tipos cujos nomes somente serão conhecidos em tempo de execução Obter/definir valores de atributos cujos nomes somente serão conhecidos em tempo de execução Invocar métodos cujos nomes somente serão conhecidos em tempo de execução 63 Reflexão em Java Programa que lista informações sobre uma interface cujo nome é informado pelo usuário: Console.readString(s); // le nome da interface do teclado Class c= Class.forName(s); Method[] theMethods= c.getMethods(); for (int i = 0; i < theMethods.length; i++) { String methodString= theMethods[i].getName(); System.out.println("Name: " + methodString); String returnString= theMethods[i].getReturnType().getName(); System.out.println(" Return Type: " + returnString); Class[] parameterTypes= theMethods[i].getParameterTypes(); System.out.print(" Parameter Types:"); for (int k= 0; k < parameterTypes.length; k ++) { String parameterString= parameterTypes[k].getName(); System.out.print(" " + parameterString); } System.out.println(); } 64 Classes Proxy Dinâmicas Recurso de reflexão de Java para criação dinâmica de proxies Proxy: padrão de projeto comum em aplicações distribuídas Proxy: objeto que implementa a mesma interface de um objeto base Exemplo: stubs são exemplos de proxy Em Java, classes proxy dinâmicas têm duas propriedades: Age como um intermediário entre objeto base e seus clientes Normalmente, possuem uma referência para objeto base e interceptam todas as chamadas destinadas ao mesmo Seu código é criado em tempo de execução Implementam interfaces definidas em tempo de criação Instâncias de classes proxy dinâmicas têm ainda um objeto manipulador de invocação (invocation handler), o qual é definido pelo cliente que solicitou a criação das mesmas. 65 Classes Proxy Dinâmicas Toda a invocação de método sobre uma instância de uma classe proxy dinâmica é enviada automaticamente para o método invoke do manipulador desta instância, passando os seguintes parâmetros: a instância da classe proxy sobre a qual a invocação foi realizada; um objeto da classe java.lang.reflect.Method, o qual reifica o método que está sendo chamado; um vetor do tipo Object que contém os argumentos deste método. 66 Classes Proxy Dinâmicas <<interface>> Service service implements Client references DynamicProxyClass ServiceImpl service service references <<interface>> InvocationHandler invoke(Object, Method, Object[]) implements InvocationHandlerIm pl references invoke(Object, Method, Object[]) 67 Exemplo de Classe Proxy class DebugHandler implements java.lang.reflect.InvocationHandler { private Object base; private DebugHandler(Object base) { this.base = base; } public Object invoke(Object proxy, Method m, Object[] args) throws Throwable { Object result; try { System.out.println("before method " + m.getName()); result = m.invoke(base, args); // forward to base object } catch (...) { ... } finally { System.out.println("after method " + m.getName()); } return result; } } // class DebugHandler 68 Exemplo de Classe Proxy Exemplo de Uso: interface Foo { Object bar(Object obj); } class FooImpl implements Foo { Object bar(Object obj) { ... } } ..... Foo base= new FooImpl(); DebugHandler handler= new DebugHandler(base); Class c= base.getClass(); Foo proxy= Proxy.newProxyInstance(c.getClassLoader(), c.getInterfaces(), handler); ..... proxy.bar(....); 69