Especialização em web com interfaces ricas Conceitos avançados de programação Prof. Fabrízzio Alphonsus A. M. N. Soares [email protected] [email protected] Instituto de Informática Universidade Federal de Goiás Aula 2 25 de maio de 2012 Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 1/103 Conceitos avançados Nesta aula conheceremos elementos interessantes para auxílio na programação Java. Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 2/103 Conceitos Elementos que serão aprendidos nesta aula: TypeCast e InstanceOf Tipos genéricos (Generics) Encaixotamento (Boxing) e Envelopadores (Wrappers) Coleções, etc Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 3/103 TypeCast I Quando lidamos com linguagens de programação fortemente tipadas como Java, nos confrontamos muitas vezes com a necessidade de variar de um tipo de dado para outro. Há casos, também, em que até mesmo o compilador não compreende que tipo de dado estamos atribuindo a uma variável. Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 4/103 TypeCast II Em Java, nós podemos fazer uso do que chamamos de indução de tipo ou typecast. O typecast dita ao compilador como tal dado deve ser interpretado e manipulado. Essa indução de tipo ou typecast pode ser implícita ou explícita. Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 5/103 TypeCast III O typecast implícito é feito automaticamente pelo compilador quando um tipo de dado pode ser facilmente manipulado no lugar de outro tipo de dado. Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 6/103 TypeCast IV O typecast explícito é feito diretamente no algorítmo para indicar ao compilador qual a forma de interpretação de um dado quando ele entende que há ambiguidade ou formatos incompatíveis. Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 7/103 TypeCast V O typecast explícito é dado sempre dentro de parênteses que sempre vem antes do dado a ser induzido. Ex.: (int) var1, (float) var2, (Object) var3, ... Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 8/103 TypeCast de Tipos Primitivos I O typecast de dados primitivos é dado basicamente em questão de seu consumo de memória. Se tentamos designar um tipo de dado que consome menos memória para um que consome mais memória, o typecast é realizado implicitamente. Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 9/103 TypeCast de Tipos Primitivos II No exemplo abaixo, atribuimos um dado inteiro (varInt) a uma variável do tipo float (varFloat). 1 2 3 4 5 6 7 8 9 public class ExemploTypecast1 { public static void main(String[] args) { float varFloat; int varInt; varInt = 200; varFloat = varInt; System.out.println(varFloat); } } Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 10/103 TypeCast de Tipos Primitivos III O contrário não se aplica. Tentar atribuir um tipo de dado maior para um tipo de dado menor irá resultar em um erro de tipos incompatíveis (type mismatch). Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 11/103 TypeCast de Tipos Primitivos IV Para demonstrar isso, usaremos dois tipos de dados inteiros. Porém, iremos atribuir um inteiro longo (que consome mais memória) a um dado inteiro que consome menos. Nesse caso, somos obrigados a usar typecast explícito. Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 12/103 TypeCast de Tipos Primitivos V 1 2 3 4 5 6 7 8 9 public class ExemploTypecast2 { public static void main(String[] args) { long varLong; int varInt; varLong = 200; varInt = (int) varLong; System.out.println(varInt); } } Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 13/103 TypeCast de Classes e Objetos I Typecast também pode ser usado em Classes e Objetos. Sempre e uma classe for genérica, ela poderá receber qualquer tipo de objeto que será feito o typecast implicitamente. Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 14/103 TypeCast de Classes e Objetos II Exemplo Por exemplo, vamos utilizar a classe TV abaixo. 1 2 3 4 5 6 7 8 9 10 11 12 13 public class TV { int tamanho; int canal; int volume; boolean ligada; public TV(int tamanho, int canal, int volume, boolean ligada ) { this.tamanho = tamanho; this.canal = canal; this.volume = volume; this.ligada = ligada; } } Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 15/103 TypeCast de Classes e Objetos III Agora, vamos instanciar uma variável da classe genérica Object com a classe TV. 1 2 3 4 5 6 7 8 public class ExemploTypecast3 { public static void main(String[] args) { Object obj = new TV(29, 1, 0, false); System.out.println("A variável obj é " + obj.getClass()); } } Como podemos perceber, o resultado de getClass da variável obj não é sua classe original (Object), mas sua instância: class TV. Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 16/103 TypeCast de Classes e Objetos IV Agora, não será possível criar uma cópia desse objeto para uma variável do mesmo tipo de sua instância. Neste caso, devemos fazer o typecast explícito da classe. 1 2 3 4 5 6 7 8 9 10 11 public class ExemploTypecast4 { public static void main(String[] args) { Object obj = new TV(29, 1, 0, false); TV tv = (TV) obj; TV tv2 = new TV(29, 1, 0, false); System.out.println("A variável tv é cópia de obj" + "\nobj: " + obj.toString() + "\ntv: " + tv.toString()); System.out.println("TV2 é outro objeto: " + tv2.toString ()); } } Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 17/103 TypeCast de Classes e Objetos V O resultado do código acima seria algo como: 1 2 3 4 A variável tv é cópia de obj obj: TV@12345f tv: TV@12345f TV2 é outro objeto: TV@abcde1 Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 18/103 InstanceOf I No exemplo anterior, se tentássemos atribuir obj diretamente a tv ocorreria um erro de tipos incompatíveis (type mismatch). Quando lidamos com classes, podemos testar qual seu tipo de instancia usando o operador instanceof. Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 19/103 InstanceOf II Instanceof indica se um objeto (já instanciado) pertence a uma classe. O uso de instanceof é: objeto instanceof nomeDaClasse. Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 20/103 InstanceOf III Para melhorar o exemplo anterior, usaremos instanceof antes de atribuirmos obj a tv. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class ExemploTypecast { public static void main(String[] args) { Object obj = new TV(29, 1, 0, false); TV tv = null; if (obj instanceof TV) { tv = (TV) obj; } TV tv2 = new TV(29, 1, 0, false); System.out.println("A variável tv é cópia de obj" + "\nobj: " + obj.toString() + "\ntv: " + tv.toString()); System.out.println("TV2 é outro objeto: " + tv2.toString ()); } } Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 21/103 Tipos Genéricos I O que são tipos genéricos? Generics, ou programação genérica, serve para determinar para o compilador, qual tipo de classe deve ser interpretada. Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 22/103 Tipos Genéricos II Por exemplo, vamos imaginar que será criada uma classe chamada Aparelho que irá conter um objeto de alguma outra classe. Para que essa classe possa aceitar qualquer tipo de classe, devemos fazer uso de generics. Generics é indicado como um identificador entre os sinais de maior e menor < > . Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 23/103 Criar classes usando generics I Para criar uma classe usando generics, basta que logo após o nome da classe coloquemos o indicador genérico. Esse indicador genérico é simplesmente uma letra na qual será substituída dentro da classe no momento da execução. Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 24/103 Criar classes usando generics II 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class Aparelho <T> { T objeto; public Aparelho(T objeto) { this.objeto = objeto; } public T getObjeto() { return objeto; } public void setObjeto(T objeto) { this.objeto = objeto; } } Como a letra T identifica um tipo genérico, ela será substituída por qualquer classe. Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 25/103 Criar classes usando generics III Vamos imaginar agora que temos duas classes distintas. A classe TV: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class TV { int tamanho; int canal; int volume; boolean ligada; public TV(int tamanho, int canal, int volume, boolean ligada ) { this.tamanho = tamanho; this.canal = canal; this.volume = volume; this.ligada = ligada; } // métodos get e set } Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 26/103 Criar classes usando generics IV E a classe radio: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class Radio { public static int AM = 1; public static int FM = 2; private float frequencia; private int volume; private int banda; public Radio(float frequencia, int volume, int banda) { this.frequencia = frequencia; this.volume = volume; this.banda = banda; } // métodos get e set } Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 27/103 Instanciar uma classe genérica I Se fossemos criar um programa que usa as duas classes de aparelhos acima, faríamos: 1 2 3 4 5 6 7 8 public class MinhaClasse { public static void main(String[] args) { Aparelho<TV> aparelho1 = new Aparelho<TV>(new TV(29, 0, 0, false)); Aparelho<Radio> aparelho2 = new Aparelho<Radio>(new Radio(88.1f, 0, Radio.FM)); System.out.println(aparelho1.getObjeto().getClass()); System.out.println(aparelho2.getObjeto().getClass()); } } Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 28/103 Instanciar uma classe genérica II Perceba o seguinte: sem o uso de generics, o compilador não conseguiria saber qual a diferença entre aparelho1 e aparelho2, pois ele os trataria da mesma forma. Nesse caso, seria obrigatório o uso de typecast para determinar ao compilador que dado está sendo processado. Se pensarmos em uma aplicação muito grande, além de ficar cansativo ter que usar typecast toda vez que fossemos usar um aparelho, seria muito provável que erraríamos em algum momento. Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 29/103 Instanciar uma classe genérica III Java usa uma pequena convenção de nomenclatura para as letras de identificação de generics (que são vastamente utilizadas no Framework de coleções Java), sendo: E Elemento K Chave N Número T Tipo V Valor Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 30/103 Generics é um assunto bastante extenso com vários tópicos que podem ser abordados, dentre os quais podemos citar: Multiplos tipos genéricos. Ex.: <T, E, N>; Tipos genéricos limitados. Ex.: <U extends Number>; Wildcards; e Subtipos; Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 31/103 Exemplo mais robusto I Iremos criar duas classes, a primeira “Obj” contém dois métodos (add e get) que recebem e retornam um tipo “Integer”. 1 2 3 4 5 6 7 8 9 10 11 public class Obj { private Integer i; public void add(Integer i){ this.i = i; } public Integer get(){ return this.i; } } Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 31/103 Exemplo mais robusto II A segunda classe utiliza a classe Obj para “guardar” um objeto: 1 2 3 4 5 6 7 8 9 10 11 public class UsaObj { public static void main(String[] args) { Obj integerObj = new Obj(); integerObj.add(new Integer(10)); Integer someInteger = (Integer)integerObj.get(); System.out.println(someInteger); } } Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 32/103 Exemplo mais robusto III O exemplo abaixo irá causar erro: 1 2 3 4 5 6 7 8 9 10 11 public class UsaObj { public static void main(String[] args) { Obj stringObj = new Obj(); stringObj.add("Teste"); String someString = (String)stringObj.get(); System.out.println(someString); } } Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 33/103 Exemplo mais robusto IV No caso acima, somente é possível colocar em Obj um objeto do tipo Integer, agora veremos como tipos genéricos pode nos ajudar quando queremos colocar um Integer ou uma String na classe Obj por exemplo. Vamos recriar o cenário anterior com a utilização de tipos genéricos. Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 34/103 Usando Generics I Veja que agora o tipo de objeto que será armazenado é representado pela letra T, que também deverá ser informado quando uma instância de Obj for criada. Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 35/103 Usando Generics II 1 2 3 4 5 6 7 8 9 10 11 public class ObjGen<T>{ private T t; // T é o tipo do objeto public void add(T t){ this.t = t; } public T get(){ return this.t; } } Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 36/103 Usando Generics III Agora vamos criar uma classe que utiliza a classe ObjGen. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class UsaObjGen { public static void main(String[] args) { ObjGen<Integer> integerObj = new ObjGen<Integer>(); integerObj.add(new Integer(10)); Integer someInteger = (Integer)integerObj.get(); System.out.println(someInteger); ObjGen<String> stringObj = new ObjGen<String>(); stringObj.add("Teste"); String someString = (String)stringObj.get(); System.out.println(someString); } } Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 37/103 Generics como tipo mínimo I Podemos utilizar um “tipo mínimo” para garantir um tipo obrigatório quando criamos classes genéricas. 1 2 3 4 5 6 public class ObjMin <T extends Runnable> { void inicia(T t){ new Thread(t).start(); } } Aqui estamos definindo que o tipo do objeto (T) deve ser no mínino um “Runnable”. Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 38/103 Generics como tipo mínimo II Criaremos agora uma classe chamada Programa que implementa Runnable e utiliza o ObjMin. 1 2 3 4 5 6 7 8 9 10 11 12 public class Programa implements Runnable { public static void main(String[] args){ ObjMin<Programa> o = new ObjMin<Programa>(); o.inicia(new Programa()); } public void run(){ System.out.println("ola"); } } Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 39/103 Boxing, Unboxing e Autoboxing I O que é boxing? Em certas situações, é mais conveniente utilizar objetos no lugar de tipos primitivos (byte, short, int, long, float, double, boolean e char). Assim, para cada tipo primitivo, foi criado uma classe Wrapper (Byte, Short, Integer, Long, Float, Double, Boolean e Character) que serve para “encaixotar” (boxing) o tipo primitivo. Boxing consiste em inserir um tipo primitivo dentro de um objeto, de forma que o valor primitivo possa ser usado como um objeto. Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 40/103 Boxing, Unboxing e Autoboxing II Vejamos este Exemplo: 1 Integer i = new Integer(100); Vemos neste exemplo que o tipo primitivo int de valor ’100’ é inserido no construtor de Integer, que é a classe wrapper (empacotadora) associada. Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 41/103 Wrappers I Tabela de Tipos primitivos e Classes Wrappers Lógico Caractere Inteiro Inteiro Inteiro Inteiro Ponto Flutuante Ponto Flutuante Tipo primitivo boolean char byte short int long float double Classe Wrapper Boolean Character Byte Short Integer Long Float Double Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação Super Classe Object Object Number Number Number Number Number Number 42/103 Wrappers II Classes Wrappers possuem métodos públicos disponíveis na subclasse Object, devemos dar um maior destaque para os métodos equals(Object) e toString, o primeiro é utilizado para comparações enquanto que o segundo permite que o conteúdo de um objeto seja representado em formato de texto. Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 43/103 Wrappers III Classes derivadas da subclasse Number possuem vários métodos para devolverem um tipo primitivo, tais como: byteValue(), shortValue(), intValue(), longValue(), doubleValue(), floatValue(). Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 44/103 Wrappers IV Alem disso a as classes derivadas de Number possuem também o método comparareTo(Object) que faz comparações entre objetos wrapper. Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 45/103 Quais as vantagens de usar tipos primitivos? I Tipos primitivos são bem rápidos Consomem pouca memória Além de permitirem operações mais complexas São bastantes eficientes em laços e expressões Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 46/103 Usando Wrappers I Para criar objetos Integer ,Double , etc. Basta apenas chamar : 1 2 Integer i = new Integer(); Double d = new Double(); Para fazer obter uma valor encapsulado basta apenas: 1 2 float f = real.FloatValue(); double d = inteiro.doubleValue(); Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 47/103 Autoboxing I A criação das classes wrapper resolveram vários problemas, porém a conversão entre tipo primitivo para objeto (boxing) e objeto para primitivo (unboxing) se tornou uma tarefa trivial e tediosa. A solução surgiu a partir do JDK 1.5. Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 48/103 Autoboxing II A Sun resolveu este problema através do autoboxing, que consiste no boxing automático, ou seja, na conversão automática pelo compilador de tipo primitivo para objeto. Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 49/103 Autoboxing III Além do autoboxing, existe o autounboxing, que é a conversão automática de objeto para tipo primitivo. Assim, fecha-se o ciclo: a conversão de tipo primitivo para tipo wrapper é automática (autoboxing) e o retorno também é automático (autounboxing), facilitando o uso de um e outro, como se fossem equivalentes. Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 50/103 Autoboxing IV Vejamos o exemplo: 1 2 3 4 5 6 7 8 9 10 11 12 public class TesteAutoboxing { public static void main(String[] args) { Integer a = 2; // autoboxing Integer b = 2; // equivale a Integer b = new Integer(2); a++; // autounboxing e autoboxing b++; // autounboxing e autoboxing // int x = a.intValue(); // para jdk < 1.5, isto era necessário // int y = b.intValue(); // System.out.println(x+y); // a linha abaixo é equivalente a esta System.out.println(a+b); // graças a autounboxing } } Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 51/103 Autoboxing V Note neste exemplo: O compilador ’sabe’ que a atribuição ’Integer a = 2’ são de tipos diferentes, por isso é necessário autoboxing - a conversão implícita pelo compilador de int para Integer. A soma de objetos não é definida, por isso ’a’ e ’b’ são convertidos implicitamente pelo compilador para int; Em geral, o código-fonte fica mais curto e operações de conversões triviais são criadas implicitamente pelo compilador. Você pode utilizar os operadores de incremento em objetos, como se fossem tipos primitivos; Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 52/103 Exemplos de Autoboxing I Autoboxing ou autounboxing ocorre sempre que houver a necessidade de conversão de tipos primitivos em objetos e vice-versa. Isto se aplica em várias situações [3]: comparação, atribuição, em estruturas de repetição, etc. Veremos a seguir um exemplo de cada situação. Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 53/103 Autoboxing em atribuição I Veja no exemplo abaixo a utilização de autoboxing e autounboxing na atribuição de variáveis e passagem de parâmetros para métodos: 1 2 3 4 5 6 7 8 9 10 11 12 13 public class AutoboxingEmAtribuicao { private static double soma(double x, double y) { // autounboxing return x+y; } public static void main(String[] args) { Double a = 1.0; //autoboxing Double b = 1.0; // autoboxing Double resultado = soma(a,b); // autounboxing Boolean imprimir = true; ///autoboxing if (imprimir) // autounboxing System.out.println("resultado: "+resultado); //autounboxing } } Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 54/103 Autoboxing em atribuição II Note a atuação do autoboxing/autounboxing neste exemplo: Na atribuição de valores double para tipos objeto Double; Na passagens de parâmetros do método soma. Note que o método soma recebe como parâmetros dois tipos primitivos double e foram passados dois objetos Double ’a’ e ’b’. Na atribuição do valor booleano ’true’ à variável do tipo objeto Boolean; No uso de um tipo objeto Boolean na condição do ’if’; Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 55/103 Autoboxing em comparação I Comparações podem ser realizadas através do operador ’==’ ou pelo método ’equals’; o primeiro, quando é aplicado entre objetos, compara se as variáveis referenciam o mesmo objeto, enquanto que o segundo avalia se os objetos possuem o valor significativamente iguais. Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 56/103 Autoboxing em comparação II Veremos no código-fonte de exemplo a seguir, que as comparações entre tipos diferentes podem ser realizadas: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public class AutoboxingEmComparacao { public static void main(String[] args) { Integer a = new Integer(2); Integer b = new Integer(2);; int c = 2; // compara se a e b referenciam o mesmo objeto: if (a == b) System.out.println("Comparação 1: a e b são os mesmos objetos"); // compara se a e b possuem o mesmo valor: if (a.equals(b)) System.out.println("Comparação 2: a e b tem valores iguais") ; // a é convertido para tipo primitivo // os dois valores são comparados como tipos primitivos if (a == c) Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 57/103 Autoboxing em comparação III 17 System.out.println("Comparação 3: a e c tem valores iguais") ; 18 19 20 21 22 23 24 // c é convertido para objeto // os dois valores são comparados como objetos if (a.equals(c)) System.out.println("Comparação 4: a e c tem valores iguais") ; } } Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 58/103 Autoboxing em comparação IV Note a atuação do autoboxing/autounboxing neste exemplo: Na comparação entre tipos diferentes (objeto e tipo primitivo); No comportamento diferente na comparação com ’==’ ou ’equals’; Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 59/103 Autoboxing em laço de repetição for I A partir do jdk 1.5, surgiu uma melhoria na estrutura de repetição for, chamado de ’for melhorado’ ou ’enhanced for’. Através do novo for, é possível percorrer toda uma array ou conjunto (veremos mais detalhadamente sobre isso depois) de forma bem fácil, sem necessitar criar contadores ou índices. 1 for (Tipo item: array_ou_conjunto)... Onde: Tipo - é uma classe ou algum tipo primitivo; item - é a variável que receberá um elemento do array ou conjunto em cada iteração (loop); array_ou_conjunto - é uma array ou conjunto contendo vários elementos; Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 60/103 Autoboxing em laço de repetição for II Veremos o uso do ’for melhorado’ neste exemplo a seguir. Note que iremos percorrer uma array de tipos primitivos char e uma array (objeto) de inteiros (Integer): 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import java.util.ArrayList; public class AutoboxingEmRepeticaoFor { public static void main(String[] args) { char[] ola = {’o’, ’l’, ’a’}; // percorre a array ola for (Character letra: ola) // autoboxing System.out.println(letra); // esta é um array com vários elementos inteiros; // veremos esta sintaxe quando for estudado "Genericos" ArrayList<Integer> numerospares = new ArrayList<Integer>(); // inclui objetos inteiros no array numerospares.add(new Integer(2)); numerospares.add(new Integer(4)); numerospares.add(new Integer(6)); Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 61/103 Autoboxing em laço de repetição for III 17 18 19 20 21 22 23 numerospares.add(new Integer(8)); // realiza o autounboxing de cada elemento Integer for (int i: numerospares) System.out.println(i); } } Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 62/103 Autoboxing em laço de repetição for IV Note neste exemplo: O for melhorado percorre a array de tipos primitivos char, realizando o autoboxing de cada um de seus elementos, atribuindo a variável ’letra’, que é do tipo objeto Character; A sintaxe ArrayList<Integer> numerospares = new ArrayList<Integer>(), tem o seguinte significado: crie uma array de objetos Integer, associando à varíavel numerospares, que por sua vez é uma ’array de Integer’; O for melhorado percorre a array de Integer, realizando o autounboxing de cada um de seus elementos, atribuindo a variável ’i’, que é do tipo primitivo int; Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 63/103 Coleções I Um dos conceitos mais difundidos entre todas as linguagens de programação é o conceito de array. Embora seja a base de muita coisa nem sempre trabalhar com arrays diretamente é uma boa ideia. Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 64/103 Coleções II O Java Collections Framework é um conjunto de classes desenhados para superar as limitações dos arrays e aumentar a capacidade do programador para trabalhar com coleções de objetos. Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 65/103 Coleções III Com classes de alto nível como estas é possível implementar padrões como Produtor-Consumidor sem esforço. Ou escolher a implementação mais eficiente sem a implementar. Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 66/103 Sobre Arrays I Um array, em java, é um objeto que agrega outros objetos que compartilham um supertipo comum e aos quais nos podemos referir por um índice (ou seja, um numero inteiro). Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 67/103 Sobre Arrays II Arrays em java são imutáveis o que significa que para criar um array menor ou maior baseando-nos num que já existe é necessário criar um novo array e fazer uma cópia, elemento a elemento do antigo para o novo. Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 68/103 Sobre Arrays III Arrays são muito uteis para substituir condições de seleção, como vemos no exemplo a seguir: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 // sem array public String getDayOfWeek(int weekDayOrdinal){ switch(weekDayOrdinal){ case 1: return "Domingo"; case 2: return "Segunda-Feira"; case 3: return "Terça-Feira"; case 4: return "Quarta-Feira"; case 5: return "Quinta-Feira"; case 6: return "Sexta-Feira"; case 7: return "Sábado"; } } // com array public String getDayOfWeek(int weekDayOrdinal){ return WEEK_DAY_NAMES[weekDayOrdinal-1]; } Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 69/103 Sobre Arrays IV Esta é uma situação simples que pode não parecer muito vantajosa ainda para mais quando seria necessário inicializar o array ( embora, essa inicialização seria feita apenas uma vez em toda a vida do programa). Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 70/103 Sobre Arrays V A razão para que o Array seja um objeto pouco maleável é de eficiência. Mas java oferece um recurso muito mais poderoso que permite ao programador não usar arrays se não quiser : o Java Collections Framework (JCF). Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 71/103 Java Collections Framework I O Java Collections Framework é um conjunto de interfaces e classes que permitem uma vasta gama de opções na hora de trabalhar com agregações de objetos. A recente (Java 5) introdução de tipos genéricos e de coleções desenhadas para ambientes concorrentes não devem deixar dúvidas a ninguem, que em Java, usar arrays não é o padrão a seguir. Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 72/103 Java Collections Framework II Os algoritmos existentes relativos a coleções são amplamente divulgados e estudados. A eficiência é a prioridade ao trabalhar com grandes coleções de objetos. Por esse motivo, o JCF é bastante flexível e vasto. Esses algoritmos são tão importantes que obrigam todos os objetos a seguir contratos bem definidos. O primeiro e mais importante deles é o contrato de definição de igualdade. Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 73/103 Definindo igualdade com equals I Em Java o operador de igualdade == não determina se os objetos são iguais, apenas se as variáveis de referencia a eles são iguais. Duas variáveis de referencia a objetos podem referenciar objetos iguais ou não. Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 74/103 Definindo igualdade com equals II Para resolver o problema todos os objetos em Java definem o método equals(). Este método é definido em Object - a classe mãe de todas as classes - e como tal o método é onipresente na linguagem. Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 75/103 Definindo igualdade com equals III Por padrão, este método apenas verifica se as referências dos objetos são iguais. Ou seja, por padrão, um objeto só é igual a outro se a variável de referencia é a mesma. Isso garante que objeto quando igual tem as mesma características, mas muitas vezes necessitamos que a igualdade seja determinada pelas características em si e não pela referência do objeto. Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 76/103 Definindo igualdade com equals IV Para conseguirmos isso basta sobre-escrever o método equals() no nosso objeto. Para fazermos isso temos que seguir algumas regras: 1 2 3 4 O resultado de invocar equals() para os mesmos dois objetos, sempre retorna o mesmo resultado independentemente de quando essa invocação é feita. null nunca é igual a nenhum objecto Um objeto é igual a si próprio. Ou seja, a.equals(a) tem que ser verdade. A ordem da invocação para dois objetos não importa. Se a.equals(b) é verdade então também tem que ser verdade que b.equals(a) Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 77/103 Definindo igualdade com equals V 5 Se a.equals(b) e b.equals(c) são verdade então também tem que ser verdade que a.equals(c) Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 78/103 Definindo igualdade com equals VI Esta regras traduzem as propriedades do método equals(). Se o método não tem estas propriedades ele não está bem implementado. A saber: 1 equals() é Consistente 2 e é consistente com null 3 equals() é Reflexivo 4 equals() é Simétrico 5 equals() é Transitivo Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 79/103 HashCode I Hash é um código desenvolvido em criptografia. Função de Hash é um mecanismo que baseado numa entrada produz um código de hash (hashCode). Funções de Hash não são reversiveis e sempre produzem o mesmo resultado para a mesma entrada. Contudo não são obrigadas a produzirem códigos diferentes para entradas diferentes ( ou seja, não são injetivas). Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 80/103 HashCode II Por outro lado, funções de hash produzem códigos do mesmo tamanho para entradas de tamanhos aleatoriamente diferentes. Estas propriedades são extremamente uteis já que pela simples comparação do código de hash poderemos saber se dois objetos são diferentes. Atenção para o fato que elas não revelam se os objetos são iguais, mas na maioria dos casos ser diferente é mais importante que ser igual. Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 81/103 HashCode III Sabendo disto, à semelhança de equals() Object também define o método hashCode() que não é mais que uma função de hash aplicada ao próprio objeto. É fácil de compreender que se alteramos o mecanismo padrão de verificação de igualdade, temos também que alterar o mecanismo padrão de produção do código de hash. Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 82/103 HashCode IV Isso nos leva à regra de consistência que diz que: Sempre que sobrescrever equals() sobrescreva também hashCode() de forma compatível. De forma compatível significa que : Se a.equals(b) é verdade então também é verdade que a.hashCode()==b.hashcode() Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 83/103 HashCode V Existem muitas formas de redefinir o calculo do código de hash. Da mais simples e com pior performance que é fazer todos os objetos terem o mesmo código até à mais complexa de deixar todos os objetos terem um código diferente. Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 84/103 HashCode VI Embora seja teoricamente possível ter uma função de hash tão eficiente que produz um código diferente para cada objeto diferente, na prática nos encontramos limitados já que o código tem que caber num int (32 bits). Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 85/103 HashCode VII Então temos que vier com fato que nossas funções de hash vão produzir código iguais em algum ponto. A isso se chama Colisão de Hash. O objetivo é diminuir as colisões, ou seja diminuir a frequencia com que dois objetos diferentes produzem o mesmo código de hash. Quanto menos colisões, mais eficiente é a nossa função de hash. Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 86/103 HashCode VIII A função de hash mais simples é a operação de ou-exclusivo (XOR) que em Java se representa pelo operador .̂ Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 87/103 Coleções e Mapas I São classes voltadas para estruturas de dados, pertencentes ao pacote java.util: Conjuntos Conjuntos ordenados Mapas Mapas Ordenados e listas. É largamente utilizado em programas: quem não precisa de um vetor, uma lista ou conjunto? Melhora a performance e a qualidade: evita ’reinventar’ a roda; Estimula o reuso; São conhecidos também como conjuntos; Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 88/103 Organização em Interfaces e Classes I O conjunto de classes java para coleções (Java Collection Framework) é composto de várias interfaces (I), e classes concretas (C). A seguir mostramos estas classes no formato hierárquico em árvore: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 Collection (I) Set (I) HashSet (C) Sorted Set (I) TreeSet(C) List (I) ArrayList (C) Vector (C) LinkedList (C) Queue (I) ... Map (I) HashMap (C) Hashtable (C) Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 89/103 Organização em Interfaces e Classes II 15 16 SortedMap (I) TreeMap (C) Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 90/103 Definindo cada uma das implementações I 1 Coleções Collection: interface que define operações comuns de coleções. Esta interface possui duas sub-interfaces - Set (Conjunto) e List (Lista); 2 Conjuntos Set: implementação de Collection, que modela um conjunto de elementos únicos; HashSet: implementação de Set, modela conjuntos não ordenados; SortedSet: implementação de Set, modela conjuntos ordenados; 3 Listas Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 91/103 Definindo cada uma das implementações II List: modela listas de dados, onde os elementos (repetidos ou não) estão ordenados; ArrayList: usa métodos não-sincronizados e Vector utiliza métodos sincronizados (synchronized) Vector: é apropriado para uso em multithread, porém é mais lento que ArrayList; LinkedList: é uma Lista, onde os elementos estão ligados. Tem uma inserção e deleção muito mais rápidos que ArrayList e Vector. 4 Mapas Map: modela mapeamentos entre chaves não-repetidas a valores; Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 92/103 Definindo cada uma das implementações III HashMap: subclasse de Map, modela mapas não classificados, com métodos não-sincronizados; Hashtable: subclasse de Map, modela mapas não classificados, com métodos sincronizados; SortedMap: modela mapas classificados; 5 Filas Queue: é uma interface, que modela filas, Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 93/103 Definindo cada uma das implementações IV Não confunda array (criados com []) com as classes ArrayList ou Vector! Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 94/103 Exemplo comparativo entre array e ArrayList I Veja a tabela comparativa array não tem dimensão dinâmica suporta tipos primitivos não é uma classe não suporta métodos possui atributo length ArrayList tem dimensão dinâmica não suporta tipos primitivos diretamente é uma classe suporta métodos não possui atributo length Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 95/103 Exemplo comparativo entre array e ArrayList II Veja o exemplo abaixo, comparando array e ArrayList: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 import java.util.ArrayList; public class ComparandoArrayEArrayList { public static void main(String[] args) { // inicialização: String[] ola1 = new String[3]; ArrayList<String> ola2 = new ArrayList<String>(); // atribuição ola1[0] = "o"; ola1[1] = "l"; ola1[2] = "a"; ola2.add("o"); ola2.add("l"); ola2.add("a"); ola2.add("!"); // percorrendo com for for (String s: ola1) System.out.print(s); System.out.println(); for (String s: ola2) System.out.print(s); Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 96/103 Exemplo comparativo entre array e ArrayList III 18 19 } } Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 97/103 Interface Collection I A interface Collection define várias operações básicas e operações entre coleções. Vejamos sua implementação: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public interface Collection<E> extends Iterable<E> { // Operações Básicas int size(); boolean isEmpty(); boolean contains(Object element); boolean add(E element); boolean remove(Object element); Iterator<E> iterator(); // Operações em massa boolean containsAll(Collection<?> c); boolean addAll(Collection<? extends E> c); boolean removeAll(Collection<?> c); boolean retainAll(Collection<?> c); void clear(); // Operações de array Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 98/103 Interface Collection II 18 19 20 Object[] toArray(); <T> T[] toArray(T[] a); } Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 99/103 Interface Iterator I Uma interface bastante importante é a interface Iterator, que permite navegar (iterar) pelos vários elementos de uma coleção. 1 2 3 4 5 public interface Iterator<E> { boolean hasNext(); E next(); void remove(); } Note que a interface Iterator é bastante simples, um Iterator é obtido da própria coleção através do método iterator() e depois podemos navegar pela coleção por meio dos métodos hasNext(), next() e remove(); Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 100/103 Exemplo simples I 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 import java.util.*; public class TesteArray { public static void main(String[] args) { ArrayList<String> a1 = new ArrayList<String>(); ArrayList<String> a2 = new ArrayList<String>(); a1.add("a"); a1.add("b"); a1.add("c"); a2.add("d"); a2.add("e"); a2.add("f"); Iterator i1 = a1.iterator(); Iterator i2 = a2.iterator(); // imprime a1 while (i1.hasNext()) { System.out.println(i1.next()); } // imprime a2 while (i2.hasNext()) { System.out.println(i2.next()); Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 101/103 Exemplo simples II 21 22 23 } } } Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 102/103 Exercício 1 2 Criando somente uma instância auxiliar de ArrayList, adicione os elementos de a2 em a1, de forma mesclada, ou seja, seu resultado final deverá ser: a, d, b, e, c, f. Imprima o novo a1 resultante. Sem criar novas instâncias de ArrayList, adicione os elementos de a1 no final de a2 e imprima o novo a2 resultante. Prof. Fabrízzio Alphonsus A. M. N. Soares | Conceitos avançados de programação 103/103