Aula 4
- Listas
- Tópicos de programação orientada a objetos
Listas ("Arrays") são utilizadas para agrupar objetos do mesmo tipo. O tipo pode ser
qualquer tipo primitivo ou qualquer classe de objetos. Para declarar que uma variável
representa uma lista, acrescenta-se colchetes após o nome da variável. A lista
é criada utilizando-se a palavra-chave new
e
indicando o número de elementos entre colchetes:
int c[]; // declara uma lista de inteiros
c = new int[ 12 ]; // cria uma lista de 12 inteiros
double d[] = new double[ 30 ]; // combina declaração e criação
No caso de uma lista de tipos primitivos, a lista pode ser criada e inicializada
através de uma lista de valores entre chaves:
int b[] = { 3, 5, 7, 9};
O índice especificando um elemento de uma lista é contado a partir de 0. Por exemplo,
o comando acima é equivalente ao seguinte:
int b[] = new int[ 4 ];
b[ 0 ] = 3;
b[ 1 ] = 5;
b[ 2 ] = 7;
b[ 3 ] = 9;
No caso de uma lista de objetos, deve-se notar que a criação da lista não cria os
objetos. Cria simplesmente uma lista de referências null
.
Os objetos ainda precisam ser criados e as suas referências atribuidas aos elementos
da lista. Por exemplo, o código abaixo cria 3 botões organizados numa lista:
Button ldb[] = new Button[ 3 ];
ldb[ 0 ] = new Button( "Começar" );
ldb[ 1 ] = new Button( "Parar" );
ldb[ 2 ] = new Button( "Zerar" );
Qualquer lista possui uma variável inteira length
que fornece o número de
elementos da lista. Exemplo de uso desta variável:
for( int i = 0; i < ldb.length; i++)
{
ldb[ i ].setBackground( Color.blue );
}
Uma lista pode ser passada como argumento a um método. Um exemplo é a lista de argumentos
(objetos do tipo String
) passados ao método main
de um aplicativo
independente. Deve-se notar que listas são objetos e, na linguagem Java, objetos são
sempre passados aos métodos por referência, ao passo
que tipos primitivos são sempre passados por valor.
Isto quer dizer que uma modificação à lista realizada no método chamado implicará na mesma
modificação à lista definida no programa que chamou o método em questão.
Listas de múltiplos indices podem ser definidas, sendo consideradas como listas de listas.
Os seguintes exemplos criam objetos que são essencialmente matrizes:
int b[][];
b = new int[ 2 ][ 3 ];
int c[][] = { { 1, 2, 3 }, { 4, 5, 6} } ;
Porém, listas de listas podem ser mais gerais, pois as "linhas" podem ter tamanhos
diferentes:
int b[][];
b = new int[ 2 ][ ];
b[ 0 ] = new int[ 2 ];
b[ 1 ] = new int[ 3 ];
int c[][] = { { 1, 2 }, { 3, 4, 5} } ;
Tópicos de programação orientada a objetos
-
É permitido incluir numa classe métodos que possuem o mesmo nome e o mesmo tipo de retorno,
mas que diferem pelo número e/ou pelos tipos dos argumentos. Qual destes métodos é
executado depende do número e/ou tipos dos argumentos passados pelo programa que chama
o método. Esta técnica é chamada sobrecarga
("overloading") de métodos. Ela é frequentemente
utilizada, por exemplo para definir vários construtores para uma determinada
classe. Exemplo:
public class Ponto
{
protected int x, y;
public Ponto()
{
setPonto( 0, 0 );
}
public Ponto( int a, int b )
{
setPonto( a, b );
}
public void setPonto( int a, int b )
{
x = a;
y = b;
}
public String emPalavras()
{
return "[" + x + ", " + y + "]";
}
}
-
Pode-se criar uma nova classe, acrescentando recursos a uma classe já construída, ou
modificando alguns recursos desta classe. A nova classe herda (possivelmente com
modificações) os recursos já disponíveis na classe anterior. A classe herdeira é
chamada subclasse da classe anterior, que é a sua
superclasse. Este processo de herança pode ser
repetido em cascata, criando várias gerações de classes. Vale notar que a linguagem
Java permite somente herança simples, i.e. uma
classe pode herdar diretamente de uma única classe (possui uma única superclasse
direta). Em contrapartida, uma classe pode possuir várias subclasses diretas.
A relação de herança é indicada através da palavra-chave
extends
. Por "default", uma classe herda da
classe Object
. O exemplo abaixo cria uma subclasse da classe definida
no exemplo anterior:
public class Circulo extends Ponto
{
protected double r;
public Circulo()
{
// chamada implicita ao construtor da superclasse
setRaio( 0 );
}
public Circulo( int a, int b, double r )
{
super( a, b );
setRaio( r );
}
public void setRaio( double r )
{
this.r = r;
}
}
As variáveis x
e y
da superclasse são acessíveis
à subclasse pois foram declaradas protected
.
A palavra-chave super
permite
referência à superclasse, e em especial, utilizada como nome de método, ao construtor
da superclasse. Nota-se que se não houver, no construtor da subclasse, nenhuma chamada
explicita ao construtor da superclasse, o construtor sem argumento é chamado
por "default". Se for incluída uma chamada ao construtor da superclasse, ela deve ser
o primeiro comando executado no construtor da subclasse.
-
Na construção de uma subclasse a partir de uma superclasse, pode-se também substituir
um método já presente na superclasse por outro, de mesmo nome, tipo de retorno,
número e tipos de argumentos. Este procedimento é chamado
"overriding" em inglés, o que será traduzido aqui
por superação. Por exemplo, na classe
Circulo
acima, podemos substituir o método emPalavras
por
uma versão incrementada cujo valor de retorno inclui também o raio do círculo:
public class Circulo extends Ponto
{
protected double r;
public Circulo()
{
setRaio( 0 );
}
public Circulo( int a, int b, double r )
{
super( a, b );
setRaio( r );
}
public void setRaio( double r )
{
this.r = r;
}
public String emPalavras()
{
return "[" + x + ", " + y + ", " + r + "]";
}
}
Vale notar que o método superado ainda pode ser utilizado, caso for necessário,
fazendo-se uso da palavra-chave super
. Por
exemplo, uma possível alternativa à construção acima (produzindo porém
um resultado ligeiramente diferente) seria:
public class Circulo extends Ponto
{
protected double r;
public Circulo()
{
setRaio( 0 );
}
public Circulo( int a, int b, double r )
{
super( a, b );
setRaio( r );
}
public void setRaio( double r )
{
this.r = r;
}
public String emPalavras()
{
return super.emPalavras() + "[" + r + "]";
}
}
-
Já que uma subclasse herda as propriedades da superclasse, uma instância de uma subclasse
é também uma instância da sua superclasse (e da superclasse desta, etc... até a classe
raiz
Object
). No exemplo acima, um Circulo
também é um
Ponto
e uma instância de Circulo
pode ser atribuída a uma
referência declarada como Ponto
. Exemplo:
import java.awt.Label;
import java.applet.Applet;
public class Test extends Applet
{
private Ponto meusPontos[];
private Label rohtulos[];
public void init()
{
meusPontos = new Ponto[ 2 ];
meusPontos[ 0 ] = new Ponto( 3, 5 );
meusPontos[ 1 ] = new Circulo( 15, 5, 1.5 );
rohtulos = new Label[ 2 ];
for( int i = 0; i < meusPontos.length;
i++ )
{
rohtulos[ i ] = new
Label( meusPontos[ i ].emPalavras() );
add( rohtulos[ i ] );
}
}
}
Neste exemplo, apesar de ambos objetos serem declarados como Ponto
, o segundo
é de fato uma instância da subclasse Circulo
e portanto, quando for chamado
o método emPalavras
deste objeto, será executado o método da classe
Circulo
(que retorna informação também sobre o raio).
Se uma instância de uma subclasse for atribuída a uma referência do tipo da superclasse,
somente os métodos que já estão definidos na superclasse podem ser chamados como descrito
acima. Para chamar um método definido na subclasse, mas não na superclasse, é necessário
efetuar uma coerção explicita. Por exemplo, se
acrescentarmos à classe Circulo
um método para calcular a área, ou seja,
public class Circulo extends Ponto
{
protected double r;
public Circulo()
{
setRaio( 0 );
}
public Circulo( int a, int b, double r )
{
super( a, b );
setRaio( r );
}
public void setRaio( double r )
{
this.r = r;
}
public double ahrea( )
{
return Math.PI * r * r;
}
public String emPalavras()
{
return "[" + x + ", " + y + ", " + r + "]";
}
}
devemos usar a coerção para chamar este método numa instância de Circulo
que
foi atribuída a uma referência de tipo Ponto
:
import java.awt.Label;
import java.applet.Applet;
public class Test extends Applet
{
private Ponto meusPontos[];
private Label rohtulos[];
public void init()
{
meusPontos = new Ponto[ 2 ];
meusPontos[ 0 ] = new Ponto( 3, 5 );
meusPontos[ 1 ] = new Circulo( 15, 5, 1.5 );
rohtulos = new Label[ 2 ];
for( int i = 0; i < meusPontos.length;
i++ )
{
rohtulos[ i ] = new
Label( meusPontos[ i ].emPalavras() );
add( rohtulos[ i ] );
}
double a = ( ( Circulo ) meusPontos[ 1 ] ).ahrea();
rohtulos[ 1 ].setText( rohtulos[ 1 ].getText() + "[" + a
+ "]" );
}
}