Java

Wednesday, March 29, 2006

 

Thread

Há duas maneiras de se criar um thread, ou criando uma classe que estende Thread ou criando uma classe que implementa Runnable. A segunda opção é mais recomendada em uma perspectiva POO. Você só vai querer estender uma Thread quando desejar uma classe que tenha um comportamento específico relacionado às threads. Quando deseja apenas que uma tarefa seja executada concorrentemente, implemente Runnable. Em ambos os casos, vai precisar de um objeto Thread para iniciar a execução da sua tarefa em um novo thread.
Seja a classe MyThread uma extensão de Thread e seja a classe MyRunnable uma implementação de Runnable, então, para iniciar a execução concorrente, fazemos:

Thread p = new MyThread();
p.start();

Runnable r = new MyRunnable();
Thread p = new Thread(r);
p.start();

Tuesday, March 28, 2006

 

Anonymous Inner Classes

Uma classe interna anônima, como diz o termo, é uma classe sem nome, ela é declarada ou como estendendo uma classe, ou como implementando uma interface. Vejamos o primero caso:

class Animal{
public void eat(){
System.out.println("food");
}
}

class Dog{
Animal p = new Animal(){
public void eat(){
System.out.println("meat");
}
public void qualquerCoisa(){}
};
}

Repare que a classe Dog tem apenas uma instância de variável, p. A sintaxe peculiar acima indica que uma instância de Animal será criada, mas ela será a instância de uma classe que estende Animal e a declaração dessa classe segue ao new Animal(). Outro ponto importante é que o método qualquerCoisa() não pode ser chamado por p.qualquerCoisa(), já que o tipo de p é a superclasse Animal, que não tem esse método.

Exemplo do segundo caso:

interface Enumeravel{
public boolean contavel();
}

class Numeros{
Enumeravel e = new Enumeravel(){
public boolean contavel(){return true;}
};
}

Por fim, a classse anônima pode ser criada também como argumento de um método, ou seja, no interior da sua declaração. Isso é muito comum ao lidarmos com listeners de objetos swing. Muitos já devem ter visto trechos de código semelhantes ao abaixo:

JButton botao;
botao.addListener(new ActionListener(){
public void actionPerformed(ActioEvent event){
}
};

 

Method-Local Inner Class

Uma classe interna pode ser criada no interior de um método. Neste caso, ela continuará tendo acesso às instâncias de variáveis da classe externa, mas não às variáveis locais do referido método, a não ser que elas sejam declaradas com o modificador final. A razão disto é que as variáveis locais deixam de existir assim que o método é executado, enquanto a instância interna pode continuar existindo se ela passar a sua referência para algum outro objeto instanciado.

class MyOuter2{
private String x = "Outer2";
void doStuff(){
class MyInner{
public void seeOuter(){
System.out.println("Outer x is "+x);
}
}
MyInner mi = new MyInner();
mi.seeOuter();
}

public static void main(String args[]){
MyOuter2 mo = new MyOuter2();
mo.doStuff();
}

}

 

Inner Class

Uma classe interna é uma classe definida no interior de outra classe. Ela tem implicitamente uma referência para uma instância da classe externa e, por isso, pode utilizar as suas instâncias de variáveis, mesmo aquelas declaradas com o modificador private. Observe o exemplo abaixo.


public class MyOuter{
private int x=7;

public void makeInner(){
MyInner in = new MyInner();
in.seeOuter();
}

public static void main(String args[]){
MyOuter o = new MyOuter();
o.makeInner();
}

class MyInner{
public void seeOuter(){
System.out.println("Outer x is: "+x);
}
}
}

É possível criar uma instância da classe interna apartir de outra classe que não lhe seja imediatamente externa:

public class Outra{
public static void main(String args[]){
MyOuter mo = new MyOuter();
MyOuter.MyInner inner = mo.new MyInner();
//Outra possibilidade:
//MyOuter.MyInner inner = new MyOuter().new MyInner();
inner.seeOuter();
}
}

O ponto é que uma instância da classe interna só pode ser criada a partir da classe que lhe é imediatamente externa.

Se, a partir de uma instância da classe interna MyInner, eu preciso fazer uma referência para a instância da classe externa MyOuter, então devo utilizar this.MyOuter, enquanto this refere-se normalmente à instância da classe interna.

Friday, March 24, 2006

 

generics [2]

Supondo que Animal é uma classe e que Dog estende Animal, a declaração abaixo com arrays é permitida:

Animal [] animals = new Dog[]();

Mas a seguinte declarção com generics não é válida:

List<Animal> = new ArrayList<Dog>();

O tipo genérico sempre tem de ser o mesmo.

Essa restrição impede o surgimento de situações de risco como a seguinte:

public static void useAnimals(List<Animal> animais){
animais.add(new Dog());
}

public static void main(....){
List<Cat> cat = new ListArray<Cat>();
useAnimals(cat);
}


Se o compilador não barrasse essa possibilidade, haveria um erro ao se tentar adicionar um objeto do tipo Dog em uma lista do tipo genérico Cat.

Existe, no entanto, a possibilidade de passar como argumento uma coleção com um tipo genérico distinto daquele declarado no método. Por exemplo:

public void useAnimals(List<? extends Animals> animals){}

Agora posso passar um ArrayList<Cat> como argumento do método useAnimals. No entanto, ao usar essa sintaxe, ? extends, me comprometo a não usar o método add da coleção. Isso impede novamente o surgimento da situação indesejada mencionada acima. Ocorrerá um erro em tempo de compilação se houver uma tentativa de usar o referido método. Com esta sintaxe, qualquer coleção List com o tipo genérico Animal ou uma classe herdeira de Animal pode ser usada como argumento do método.

Outra possibilidade é a seguinte:

public void useAnimals(List<? super Dog> animals){}

Com essa sintaxe indico que qualquer coleção List com o tipo genérico Dog ou uma superclasse de Dog pode ser usada como argumento deste método. Agora não existe a restrição de não poder usar o método add de List.

 

generics

O suporte a generics foi introduzido à linguagem java a partir da versão 5 ou 1.5. Sua maior vantagem é permitir que se possa declarar precisamente o tipo de objeto com o qual uma coleção irá lidar. Por exemplo, se preciso de uma lista que irá trabalhar apenas com Strings, então, usando generics, posso declarar uma lista que só lida com Strings:

List <String> = new ArrayList <String>();

Generics, no entanto, foi implementando de forma a ser compatível com o código legado, o que gera situações potenciais de risco. O efeito colateral disso é que esta mesma lista pode ser passada como argumento para um método que não declara o tipo de objeto que a lista pode receber. Dentro deste método, então, podemos inserir um objeto não-String numa lista que, em princípio, só deveria receber Strings. Por exemplo, o código abaixo compila perfeitamente, mas gera uma exceção em tempo de execução, ao tentar acessar, no loop, a String inserida na lista por addString() como se ela fosse um objeto do tipo Integer, já que, supostamente, nesta lista só haveria objetos do tipo Integer.


import java.util.*;

public class List{

public static void main(String args[]){
ArrayList<Integer> array= new ArrayList<Integer>();
array.add(1);
array.add(2);

addString(array);

System.out.println("Tamanho: "+array.size());

for (Integer i: array){
System.out.println(i.intValue());
}
}

public static void addString(ArrayList array){
array.add("Hello");
}
}


Generics foi implementando apenas como um coméstico, isto é, ele serve de informação apenas para o compilador, mas, em tempo real, tudo continua como antes. Para a JVM, uma lista do tipo ArrayList<String> continua sendo uma ArrayList e, por isso, pode receber qualquer tipo de objeto em tempo de execução.

 

interface vs. abstract class

Uma interface pode estender múltiplas interfaces, mas não pode implementar nenhuma. Uma classe abstrata, por outro lado, só pode extender uma outra classe abstrata e implementar múltiplas interfaces. Embora uma classe abstrata possa ser declarada como implementando uma interface, ela não precisa necessariamente implementar os métodos dessa interface. Contudo, a primeira classe não-abstrata que herdar essa classe terá de fazê-lo.

Por exemplo:

public interface XXX extends Runnable,Comparable {}

public abstract class YYY extends XXX implements Comparator{}

public class ZZZ extends YYY{

Aqui os métodos de Runnable, Comparable, Comparator e quaisquer outros métodos abstratos declarados em YYY terão de ser implementados

}

Archives

March 2006   April 2006   May 2006   July 2006   August 2006  

This page is powered by Blogger. Isn't yours?