a Linguagem de Programaç˜ao Java 1 Criaç˜ao e - FACOM

Propaganda
Universidade Federal de Mato Grosso do Sul
Facom - Faculdade de Computação
Linguagem de Programação Orientada a Objetos
Prof. Me. Liana Duenha
Introdução à Linguagem de Programação Java
A linguagem de programação Java foi anunciada pela Sun Microsystems em 1995
e chamou a atenção da comunidade de negócios por causa do foco voltado ao mercado
Web. O Java é agora utilizado para desenvolver aplicativos corporativos de grande
porte, aprimorar a funcionalidade de servidores na Web, fornecer aplicativos voltados
para o consumo popular (telefones celulares, pagers e PDAs) e para muitos outros
propósitos.
Programas Java consistem em partes chamadas classes. As classes incluem partes
chamadas métodos que realizam tarefas e retornam informações quando as tarefas
são concluı́das. A maioria dos programadores Java tira proveito das ricas coleções
existentes nas bibliotecas de classe Java , que tambem são conhecidas como Java
APIs (Application Programming Interfaces).
Dada a experiência de todos os alunos desta disciplina com a linguagem C++ e
o conhecimento dos fundamentos de programação orientada a objetos, esse tópico visa
apenas apresentar a lingaugem de programação Java e algumas das classes das suas
extensas bibliotecas.
1
Criação e execução de um aplicativo Java
• Edição do programa: consiste em usar um programa editor ou uma IDE
(Integrated Development Environments - IDEs) ou ambiente de desenvolvimento
integrado para editar um programa e salvá-lo em um arquivo com extensão .java.
• Compilação do programa: consiste em utilizar um compilador Java para
compilar o programa, ou seja, para converter o codigo-fonte Java em bytecodes
que representam as tarefas a serem executadas na fase de execução. Os bytecodes
são executados pela JVM (Java Virtual Machine) ou Máquina Virtual Java. Para
compilar o progama arquivo.java, utilizamos o comando:
javac prog.java
O compilador produz o arquivo prog.class que contém a versão compilada
do programa prog.java. Se houver mais de uma classe no arquivo compilado,
o compilador produzirá um arquivo com extensão .class para cada classe do
programa.
1
• Execução do programa pela JVM: Ao contrário da linguagem de máquina,
que é dependente do hardware especı́fico de computador , os bytecodes são independentes de plataforma, e são, portanto, portáveis. Sem recompilar o códigofonte, os mesmos bytecodes podem executar em qualquer plataforma contendo
uma JVM que entende a versão do Java em que os bytecodes foram compilados.
Para executar um aplicativo Java chamado prog.class, utilizaremos o comando:
java arquivo
A JVM armazena o progrma na memória e isto é conhecido como carregamento.
O carregador de classe da JVM transfere para a memória primária os arquivos
.class gerados no passo de compilação e também os arquivos .class utilizados
pelo seu programa.
Enquanto as classes são carregadas, o verificador de bytecodes examina os
bytecodes para assegurar que eles são válidos e e nao violam restrições de segurança do Java. O Java impõe uma forte segurança para certificar-se que os
programas Java que chegam pela rede não danifiquem o sistema.
Para melhorar o desempenho da execução de programas Java, as JVMs atuais
executam bytecodes utilizando uma combinação de interpretação e a chamada
compilação just-in-time (JIT). Nesse processo, a JVM analisa os bytecodes à
medida que eles sao interpretados, procurando partes dos bytecodes que executam com frequência. Para essas partes, o compilador JIT traduz os bytecodes
para a linguagem de máquina de um computador subjacente. Quando a JVM
encontra novamente essas partes compiladas, o código de linguagem de máquina
mais rápido é executado.
2
Primeiros Programas
O nosso primeiro programa em Java apenas exibe uma série de mensagens utilizando o
objeto de saı́da padrão System.out. Todo programa Java consiste em pelo menos
uma classe definida pelo programador. O programa inicia coma declaração de classe
da classe HelloWorld , usando a palavra-chave class seguida pelo nome da classe.
Toda classe em Java pertence a um pacote. Comumente utilizamos classes de
outros pacotes já existentes nas bibliotecas Java ou aqueles que nos mesmos criamos.
Todos as classes pertencentes a um mesmo diretório são consideradas do mesmo pacote, e todas as classes possuem visibilidade pública dentro do pacote a que pertence.
Quando desejamos que uma classe tenha visibilidade pública fora do pacote a que
pertence, usamos o modificador public antes da definição da classe. Se omitimos o
modificador public a visibilidade da classe fora do pacote passa a ser privada. Em
muitos dos exemplos presentes nesse material usamos classes pertencentes a outros
pacotes e no final deste material há os passos para criação de novos pacotes.
2
// Programa HelloWorld.java
// Realiza impress~
ao de mensagens de texto
1. public class HelloWorld
2. {
3.
public static void main (String[] args)
4.
{
5.
System.out.println ("Bem-vindo ao mundo do Java!");
6.
System.out.print ("Esse é seu primeiro programa!");
7.
System.out.printf ("\n \%s" \n", "Como todo primeiro programa, ");
8.
System.out.printf ("\%s" , "este n~
ao faz nada de muito útil.");
9.
}
10. }
O objeto de saı́da padrão System.out utilizado na linha 5, permite que aplicativos Java exibam strings na janela de comando a partir da qual o aplicativo Java
executa. O método System.out.println() exibe uma linha de texto na janela de
comando e posiciona o cursor de saı́da no começo da linha seguinte da janela de comando. O método de impressão da linha 6 é semelhante ao anterior, porém nao
posiciona o cursor na linha seguinte. O caractere de nova linha "\n" pode ser usado
dentro da mensagem a ser impressa para indicar uma quebra de linha. O método
System.out.printf () das linhas 7 e 8 exibe os dados formatados. Dada a semelhança entre esta função e a função printf() da linguagem C (já conhecida por vocês),
não faremos muitas explicações sobre ela neste material.
O nosso segundo programa consiste em um aplicativo para leitura de valores inteiros fornecidos pelo usuário usando a classe Scanner do pacote java.util, geração
de números aleatórios utilizando a classe Random do mesmo pacote e uma sequência
de operações relacionais sobre esses valores para apresentação de operadores de comparação. Para realizar a importação ou inclusão de classes de outros pacotes usamos
o comando import (linhas 1 e 2).
// Programa Operation.java
// Realiza operaç~
oes sobre números fornecidos pelo usuário e
// sobre números gerados aleatoriamente
1.
2.
3.
4.
5.
6.
7.
8.
import java.util.Scanner
import java.util.Random
public class Operation
{
public static void main (String[] args)
{
Scanner input = new Scanner (System.in);
3
9.
10.
11.
12.
13.
14.
14.
15.
16.
17.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
int number1, number2, result;
System.out.print ("Entre com o primeiro número (inteiro):");
number1 = input.nextInt();
System.out.printf ("Entre com o segundo número (inteiro):");
number2 = input.nextInt();
if ( number1 == number2 )
System.out.printf("\%d == \%d\n", number1, number2);
if ( number1 != number2 )
System.out.printf("\%d != \%d\n", number1, number2);
if ( number1 < number2 )
System.out.printf("\%d < \%d\n", number1, number2);
if ( number1 > number2 )
System.out.printf("\%d > \%d\n", number1, number2);
if ( number1 <= number2 )
System.out.printf("\%d < \%d\n", number1, number2);
if ( number1 >= number2 )
System.out.printf("\%d >= \%d\n", number1, number2);
double number3, number4;
System.out.printf ("Entre com o terceiro número (real):");
number3 = input.nextDouble();
System.out.printf ("Entre com o quarto número (real):");
number4 = input.nextDouble();
double number5 = number3 + number4;
System.out.printf ("\%.2f + \%.2f = \%2f",
number3, number4, number5);
Random randomNumbers = new Random ();
int randomNumber1, randomNumber2;
randomNumber1 = 1 + randomNumbers.nextInt(10);
randomNumber2 = 1 + randomNumbers.nextInt(10);
System.out.print ("O primeiro número aleatório gerado é: ");
System.out.print ("\%d\n", randomNumber1);
4
51.
System.out.print ("O segundo número aleatório gerado é: ");
52.
System.out.print ("\%d\n", randomNumber2);
51. }
Na linha 8 declaramos um objeto input da classe Scanner que será utilizado para
realizar a leitura dos dados fornecidos pelo usuário. Na linha 9, declaramos variáveis
inteiras. Nas linhas 11 a 14 realizamos a leitura de dados inteiros utilizando o método
nextInt() a partir do objeto input da classe Scanner. Repare que a mesma lógica
é realizada para leitura de valores reais nas linhas 33 a 38, porém o método utilizado
nesse caso é o nextDouble(), tambem acessı́vel por meio do objeto input.
Para geração de números aleatórios, declaramos o objeto randomNumbers da
classe Random. O método nextInt(int x) gera um valor inteiro aleatório de 0 até
x (não incluindo x). No nosso exemplo, randomNumber1 e randomNumber2 podem
receber valores inteiros entre 1 e 10.
2.1
Exercı́cio
Considere o jogo de dados descrito abaixo, conhecido como Craps, é jogado em cassinos
e nas ruas de todo o mundo. Descreva um aplicativo em Java que para simular o Craps,
utilizando o ”esqueleto”de código fornecido após a descrição do jogo.
Dois dados são lançados e a soma dos pontos nas faces viradas para cima é
calculada. Se a soma for 7 ou 11 no primeiro lance, você ganha. Se a soma for 2,3
ou 12 no primeiro lance (chamado ”craps”), você perde (isto é, a casa ganha). Se
a soma for 4,5,6,8, 9 ou 10 no primeiro lance, esse valor torna-se sua pontuação.
Para ganhar, você deve continuar a rolar os dados até conseguir um valor igual à sua
pontuação. Você perde se obtiver um 7 antes de fazer sua pontuação.
// Craps.java
import java.util.Random
public class Craps
{
private static final Random randomNumbers = new Random ();
private enum Status {CONTINUE, WON, LOST};
public void play ()
{
// método a ser implementado
}
public int rollDice()
{
5
int value1 = 1 + randomNumbers.nextInt ( 6 );
int value2 = 1 + randomNumbers.nextInt ( 6 );
int sum = value1 + value2;
System.out.printf ( "Player rolled \%d+\%d =\%d\n",
value1,value2,sum);
return sum;
}
}
// CrapsTest.java
public class CrapsTest
{
public static void main (String[] args)
{
Craps game = new Craps ();
game.play ();
}
}
O exercı́cio consiste na implementação do método play da classe Craps.
3
Controle de acesso a membros
Os modificadores de acesso public e private controlam o acesso às variáveis e métodos
de uma classe. Posteriormente, utilizaremos também o controle de acesso protected.
Variáveis e métodos private não são acessı́veis fora da classe na qual foram definidos.
Para definir um membro como public, é necessário utilizar essa palavra-chave antes da
declaração do atribuito ou método. Se for omitida a palavra-chave public, o membro
será visı́vel apenas para classes dentro do mesmo pacote.
No exemplo abaixo, os membros inteiros hour, minute e second são declarados
como privados e os membros setTime e toUniversalString () e toString () são
declarados como públicos.
public class Time
{
private int hour;
private int minute;
private int second;
public void setTime (int h, int m, int s)
6
{
hour = (h>=0 && h<24)? h:0;
minute = (m>=0 && h<60)? m:0;
second = (s>=0 && s<60)? s:0;
}
public String toUniversalString ()
{
return String.format ("\%02d:\%02d:\%02d",hour,minute,second);
}
}
Os métodos públicos de uma classe são chamados de interface public da classe
e são acessı́veis para seus clientes.
Como a classe Time não declara um construtor, o compilador fornece um construtor padrão ou default e cada variável de instância recebe implicitamente o valor
padrão de inteiro 0.
Para assegurar a consistência dos dados armazenados em hour, minute e second,
o método setTime valida os valores antes de armazená-los nas variáveis. Se o valor
fornecido estiver fora dos limites desejados, o valor 0 é atribuı́do à variável. Embora o
valor 0 não seja o valor ”correto”destas variáveis, ele é, pelo menos, um valor consistente, dentro dos limites que fazem sentido para as variáveis hour, minute e second
na aplicação.
O método format utilizado em toUniversalString() é semelhante ao printf,
exceto que format retorna uma String formatada ao invés de imprimı́-la na janela de
comando.
4
4.1
Membros de classe static e Importação static
Membros de classe static
Cada objeto tem sua própria cópia de todas as variáveis de instância da classe. Em
certos casos, apenas uma cópia de uma variável particular deve ser compartilhada por
todos os objetos de uma classe e para isso devemos definir esta variável como static.
Quando uma variável é definida como variável de classe usando static, todos os
objetos da classe a compartilham.
Um método static não pode acessar membros nao static da classe, porque o
método static pode ser invocado mesmo quando nenhum objeto da classe foi instanciado.
7
4.2
Importação static
Uma declaração import static permite importar membros static de uma classe ou
interface para que possa acessá-los via os nomes não qualificados dos mesmos na sua
classe. Podemos importar um membro static particular (1) ou todos os membros
static de uma classe (2). A sintaxe é mostrada a seguir:
(1) import static
(2) import static
nomeDoPacote.nomeDaClasse.nomeDoMembroStatic;
nomeDoPacote.nomeDaClasse.*;
Por exemplo, o comando de importação abaixo importa os membros static da
classe Math do pacote java.lang. Dentre eles, funções matemáticas como sqrt para
cálculo de raiz quadrada, log para cálculo de logarı́tmo de um número, cos para
cálculo de cosseno, entre outros métodos.
import static
5
java.lang.Math.*;
Referenciando membros com this
Todo objeto pode acessar uma referência a si próprio com a palavra-chave this (ou
referência this). Quando um método não static é chamado para um objeto particular, o corpo do método utiliza implicitamente a palavra-chave this para referenciar as
variáveis de instância do objeto e outros membros. Pode-se, também, usar a palavrachave this explicitamente no corpo de um método não static.
Não faz sentido o uso de this em um método static, visto que o método static,
por ser um membro de classe, pode ser invocado mesmo que nenhum objeto da classe
tenha sido instanciado. Na seção seguinte há um exemplo de uso da referência this
para acesso aos membros da classe Time.
6
Classes public
Como compilamos um arquivo .java contendo mais de uma classe, o compilador produz
um arquivo separado da classe com a extensão .class para cada classe compilada.
Suponha que as classes Time (definida na seção anterior) e TimeTest (definida abaixo)
estejam no mesmo arquivo TimeTest.java. Ao ser compilado, dois arquivos serão
produzidos: TimeText.class e Time.class.
// TimeTest.java
8
public class TimeTest
{
public static void main (String [] args)
{
Time time = new Time (15,30,19);
System.out.println (time.toUniversalString());
}
}
class Time
{
private int hour;
private int minute;
private int second;
public void setTime (int h, int m, int s)
{
this.hour = (h>=0 && h<24)? h:0;
this.minute = (m>=0 && h<60)? m:0;
this.second = (s>=0 && s<60)? s:0;
}
public String toUniversalString ()
{
return String.format ("\%02d:\%02d:\%02d",
this.hour, this.minute, this.second);
}
}
Um arquivo de código-fonte pode conter apenas uma classe public, caso constrário
ocorre um erro de compilação. Como já vimos, classes não public só podem ser utilizadas por outras classes no mesmo pacote. Nesse exemplo, Time só pode ser usada
pela classe ThisTest.
7
Construtores Sobrecarregados, Setters e Getters
Sobregarregar os construtores de uma classe permite que objetos sejam iniciliazados de
diferentes maneiras assim que criados. Para sobrecarregar construtores basta fornecer
múltiplas definições de construtor com assinaturas diferentes. O compilador diferencia
assinaturas pelo número de parâmetros, por tipo dos parâmetros e pela ordem dos
tipos de parâmetro em cada assinatura. No final desta seção, veremos um exemplo
que englobará construtores sobrecarregados para a classe Time.
9
Como os campos private de uma classe podem ser manipulados somente por
seus métodos, faz sentido oferecer na interface public da classe métodos que permitam
a manipulação de atributos privados, quando essa tarefa for necessária na aplicação.
Esses métodos são chamados setters ou getters. Um método setter é responsável por
validar e armazenar algum valor em um (ou mais) atributo(s) privados da classe. Um
método getter é responsável apenas por devolver (retornar) o valor de um atributo
privado da classe. Os getters são também chamados de métodos de acesso ou métodos
de consulta e os setters são chamados de métodos modificadores.
No exemplo abaixo, definimos construtores sobrecarregados para a classe Time e
métodos de consulta e modificadores para seus atributos privados.
class Time
{
private int hour;
private int minute;
private int second;
public Time ()
{
this(0,0,0); // invoca construtor de Time
// que espera 3 argumentos
}
public Time (int h)
{
this (h,0,0); // invoca construtor de Time
// que espera 3 argumentos
}
public Time (int h, int m)
{
this (0,m,0); // invoca construtor de Time
// que espera 3 argumentos
}
public Time (int h, int m, int s)
{
setTime ( h, m, s);
}
public Time (Time time) // construtor de cópia
{
this (time.getHour(), time.getMinute(), time.getSecond());
}
public void getHour ()
{
return hour;
}
10
public void getMinute ()
{
return minute;
}
public void getSecond ()
{
return second;
}
public int setHour ( int h )
{
this.hour = ( h>=0 && h < 24) ? h : 0;
}
public int setMinute ( int m )
{
this.minute = ( m>=0 && h < 60) ? m : 0;
}
public int setSecond ( int s )
{
this.hour = ( s>=0 && h < 60) ? s : 0;
}
public void setTime (int h, int m, int s)
{
setHour ( h );
setMinute ( m );
setSecond ( s );
}
public String toUniversalString ()
{
return String.format ("\%02d:\%02d:\%02d",
this.hour, this.minute, this.second);
}
}
Para exemplificarmos o uso dos construtores sobrecarregados, podemos modificar
a classe TimeTest como abaixo:
// TimeTest.java
public class TimeTest
{
public static void main (String [] args)
{
Time t1 = new Time (); // 00:00:00
11
Time
Time
Time
Time
Time
t2
t3
t4
t5
t6
=
=
=
=
=
new
new
new
new
new
Time
Time
Time
Time
Time
System.out.println
System.out.println
System.out.println
System.out.println
System.out.println
(2);
(21,
(12,
(27,
(t4)
// 02:00:00
34); // 21:34:00
25, 15); // 12:25:15
65, 78); // 00:00:00
; // 12:25:15
(t1.toUniversalString());
(t2.toUniversalString());
(t2.toUniversalString());
(t3.toUniversalString());
(t4.toUniversalString());
}
}
class Time
{
// definida como no exemplo anterior
}
8
Arrays
Um array é uma estrutura de dados que armazena um conjunto de elementos do
mesmo tipo. Os elementos de um array podem ser tipos primitivos ou tipos por
referência (inclusive outros arrays). Uma expressão de acesso ao array inclui o seu
nome seguido pelo ı́ndice do elemento que se deseja acessar entre colchetes. O primeiro
elemento do array tem ı́ndice zero. Seguem exemplos contendo diferentes formas de
inicializar e manipular arrays:
public class InitArray1
{
public static void main ( String[] args )
{
final int ARRAY_LENGHT = 10; // declara constante
int[] array1 = new int [ARRAY_LENGHT]; // cria o objeto do array
System.out.printf ("\%s\%8s\\n", "Index", "Value" );
for ( int counter = 0; counter < array1.lenght; counter++ )
{
System.out.printf (\%5d\%8d\\n", counter, array1 [ coutnter ] );
}
12
}
}
O programa acima mostrará em uma coluna o valor dos ı́ndices do vetor (de 0 a 9)
e em outra coluna o valor zero, conteúdo de cada uma das posições do array declarado
e não inicializado explicitamente. Nesse exemplo, o tamanho do array é determinado
pelo valor da constante ARRAY LENGHT que foi declarada usando o modificador final.
Uma constante deve ser inicializada antes de ser utilizada e não pode ter seu valor
modificado durante o programa.
Podemos utilizar um inicializador de array como abaixo para criar e inicializar
um array. Nesse caso, o comprimento do array é determinado pela quantidade de
elementos na lista inicializadora. Por exemplo:
public class InitArray2
{
public static void main ( String[] args )
{
int[] array2 = {32, 27, 64, 18, 95, 14, 90, 70, 60, 37};
System.out.printf ("\%s\%8s\\n", "Index", "Value" );
for ( int counter = 0; counter < array2.lenght; counter++ )
{
System.out.printf (\%5d\%8d\\n", counter, array2 [ coutnter ] );
}
}
}
O exemplo contendo a definição da classe InitArray3 mostra outra forma de
percorrer um array usando a instrução for aprimorada. Essa instrução itera pelos
elementos de um array sem usar um contador, evitando assim a possibilidade de ultrapassarmos o limite do array. A sintaxe dessa instrução é a seguinte:
for ( par^
ametro : nomeDoArray )
instruç~
ao
public class InitArray3
{
public static void main ( String[] args )
{
int[] array3 = {32, 27, 64, 18, 95, 14, 90, 70, 60, 37};
13
int total = 0;
for ( int number : array3 )
{
total += number;
}
System.out.printf ("A soma dos elementos do array3 é:
\%d\\n", total);
}
}
A instrução for aprimorada pode ser usada para obter elementos do array, mas
não pode ser usada para modificar seus elementos.
8.1
Arrays Multidimensionais
Arrays multidimensionais são arrays com mais de uma dimensão. Os mais comuns
são os arrays bidimensionais, que requerem dois ı́ndices para identificar um elemento
particular. O Java permite especificar arrays unidimensionais cujos elementos também
são arrays unidimensionais, alcançando o efeito de um array bidimensional. A mesma
lógica pode ser aplicada na modelagem de arrays com mais de duas dimensões. Seguem
alguns exemplos comentados:
// declara um array "bidimensional" a e inicializa-o
// com zeros
int [][] a = new int [2][2];
// declara um array "bidimensional" b
// e inicializa-o
int [][] b = { {1,2}, {3,4} };
// declara um array "bidimensional" c
// e inicializa-o; os comprimentos das linhas
// de c s~
ao distintos
int [][] c = { {1,2}, {3,4,5,6} };
// declara um array "bidimensional" n~
ao inicializado
// em que cada linha tem um número
// diferente de colunas;
int [][]d = new int [2][];
b[0] = new int [5];
// linha 0 tem 5 colunas
b[1] = new int [3];
// linha 1 tem 3 colunas
14
9
9.1
Passagem de Parâmetros
Lista de argumentos de comprimento variável
Podemos criar métodos que recebem um número não especificado de argumentos. Um
tipo seguido de reticências (...) na lista de parâmetros de um método indica que
o método recebe um número variável de argumentos desse tipo particular. O uso
de reticências pode ocorrer apenas uma vez e no fim da lista de parâmetros. Como
exemplo, considere o método average definido abaixo e em seguida diferentes formas
de invocá-lo.
public static double average (double... numbers)
{
double total = 0.0;
for ( double d : numbers )
total += d;
return total / numbers.lenght;
}
Na main ou em outro método da classe, suponha as seguintes declarações e
chamadas do método average:
...
double d1 = 10.0;
double d2 = 20.0;
double d3 = 30.0;
double d4 = 40.0;
doublde result;
result = average ( d1 , d2 );
...
result = average ( d1, d2, d3 );
...
result = average (d1, d2, d3, d4 );
9.2
Utilizando argumentos de linha de comando
Quando um aplicativo é executado utilizando-se o comando java, o Java passa os
argumentos da linha de comando que aparecem depois do nome de classe do comado
15
parqa o método main do aplicativo como um array de Strings chamado args. Os argumentos na linha de comando são separados por espaço em branco e não por vı́rgulas.
O número de argumentos da linha de comando é objeto acessando o atributo lenght
do array.
No exemplo a seguir, a função main recebe 2 argumentos da linha de comando.
O primeiro deles é uma String e o segundo argumento é convertido para um valor
inteiro usando o método parseInt da classe Integer.
public static void main ( String [] args)
{
if (args.lenght != 2)
System.out.println ("Error!");
else
{
System.out.printf ("O primeiro argumento é uma string: \%s", args[0]);
System.out.printf ("O segundo argumento é um inteiro: \%d", Integer.parseInt (
}
}
9.3
Valor vs. Referência
O exemplo a seguir mostra como passar como parâmetro um array. A função main cria
e inicializa um array e sem seguida invoca o metodo modifyArray ( int [] , int )
passando como parâmetro uma referência para o array criado e um inteiro. Suponha
que o método modifyArray ( int [] ) recebe como argumento a referência para um
array e um inteiro y e zera as primeiras y posições de array2.
public class PassArray
{
public stati void main ( String [], args)
{
int [] array = {1,2,3,4,5,6,7,8,9};
int x = 5;
modifyArray ( array , x);
for (int value : array )
System.out.printf ( " \%d", value );
}
public static void modifyArray ( int[] array2, int
{
for (int i=0; i<y; i++)
array2 [i] = 0;
// essa modificaç~
ao será
16
y)
// visı́vel fora do método
y = 10; // essa modificaç~
ao nao será visı́vel fora
// do método
}
}
Ao contrário de algumas outras linguagens, o Java não permite aos programadores escolher passar parâmetros por valor ou por referência. Todos os argumentos
são passados por valor! Uma chamada de método pode passar dois tipos de valores
para um método: cópia de valores primitivos e cópias de referências para objetos. Os
objetos em si não podem ser passados para os métodos. Quando um método modifica um parâmetro do tipo primitivo, as alterações no parâmetro não tem efeito no
valor original do argumento no método chamador. No exemplo, a modificação feita na
variável y não será visı́vel na main. Já no caso da passagem de referência para objetos,
as modificações realizadas dentro do método afetarão o objeto original no chamador.
Desta forma, as modificações realizadas em array2 serão visı́veis na main.
Como o método recebe uma referência para o array, as modificações realizadas
serão visı́veis no array fora do método nem necessidade de retorno. Quando passamos
uma referência para o objeto, o método chamado pode acessar o valor do argumento
no chamador diretamente e modificar esses dados, se necessário.
9.4
Classe Arrays
A API do Java fornece métodos da classe Arrays manipulação de arrays comuns,
incluindo métodos de ordenação (sort), busca binária (binarySearch), comparação
(equals) e outros, de grande utilidade para manipulação dessa estrutura de dados.
Esses métodos são sobrecarregados para manipulação de arrays de tipos primitivos e
arrays de objetos. O exemplo abaixo mostra como utilizar métodos já implementados
da classe Arrays e como usar o método arraycopy da classe System para realizar cópia
de um array.
import java.util.Arrays;
public class ArrayManipulations
{
public static void main ( String[], args )
{
double [] doubleArray = {8.4, 9.3, 0.2, 7.9, 3.4};
Arrays.sort (doubleArray);
// ordena o array doubleArray
int[] filledIntArray = new int [10];
17
Arrays.fill (filledIntArray, 7); // preenche todo o array com
// o valor 7
int[] intArray = {1,2,3,4,5,6};
int[] intArrayCopy = new int [intArray.lenght];
// copia os elementos de intArray para intArrayCopy a partir do
// ı́ndice 0 (segundo argumento) de intArray e a partir do ı́ndice 0
// (quarto argumento) de intArrayCopy; o último argumento especifica
// a quantidade de elementos que devem ser copiados (nesse caso,
// copiamos todos os valores de intArray para intArrayCopy
System.arraycopy (intArray, 0, intArrayCopy, 0, intArray.lenght);
// equals() testa se intArray e intArrayCopy
// possuem os mesmos elementos, na mesma ordem
boolean b = Arrays.equals (intArray, intArrayCopy);
// binarySearch() faz a busca de um determinado valor no array
// e devolve sua posiç~
ao (se o encontra) ou um valor negativo
// (se n~
ao o encontra)
int location = Arrays.binarySearch (intArray, 5);
}
}
9.5
Classe ArrayList
A API do Java fornece várias estruturas de dados predefinidas, chamadas coleções, utilizadas para armazenar grupos de objetos relacionados. Essas classes forncem métodos
eficientes que organizam, armazenam e recuperam seus dados sem que seja necessário
conhecer como os dados são armazenados.
A classe de coleção ArrayList <T> do pacote java.util modela um array de
elementos do tipo T e pode alterar seu tamanho em tempo de execução para acomodar
elementos adicionais.
ArrayList <String> list = new ArrayList <String> ();
A linha acima cria list como uma coleção ArrayList que só pode armazenar
strings (objetos da classe String). Os principais métodos disponı́veis para manipulação
de objetos ArrayList são descritos abaixo:
18
Método
add
clear
contains
Descrição
Adiciona um elemento no final de ArrayList
Remove todos os elementos de ArrayList
Retorna true se Array Lis contiver o elemento
especificado; retorna false, caso contrário
get
Retorna o elemento no ı́ndice especificado
indexOf
Retorna o ı́ndice da primeira ocorrência
do elemento especificado
remove
Remove a primeira ocorrência do valor especificado
size
Retorna o número de elementos armazenados
trimToSize Reduz a capacidade de ArrayList de acordo com
o número de elementos atual
10
Criação de Pacotes
Toda classe na Java API pertence a um pacote que contém um grupo de classes
relacionadas. Esses pacotes são definidos uma vez, mas podem ser importados em
muitos programas. À medida que os aplicativos tornam-se mais complexos, os pacotes
ajudam os programadores a gerenciar a complexidade dos componentes de aplicativos.
Os pacotes tambem facilitam à reutilização de software permitindo que os programas
importem classes de outros pacotes.
Os passos para declarar uma classe reutilizável são:
1. Declare uma classe public. Se a classe for nao-public só poderá ser usada por
outras classes no mesmo pacote;
2. Escolha um nome de pacote e adicione uma declaração package ao arquivo de
código-fonte da classe reutilizável. Em cada arquivo de codigo-fonte pode haver somente uma delcaração de package e ela deve preceder todas as outras
declarações e instruções;
3. Compile a classe de modo que ela seja colocada no diretório de pacotes apropriados;
4. Importe a classe para um programa e a utilize.
11
Herança
A linguagem de programação Java também dá suporte à herança. Uma classe derivada,
também chamada de sub-classe herda membros de uma classe base ou super-classe.
Dizemos que a sub-classe especializa a super-classe ou que a sub-classe estende a
19
super-classe. A classe derivada herda todos os membros não public da classe base.
Os membros definidos com visibilidade protected são herdados classes derivadas,
mas tem visibilidade privada com relação a outras classes. Java não suporta herança
múltipla e portanto cada classe pode estender apenas uma classe base.
Nosso primeiro exemplo consiste de uma hierarquia simples de herança, onde
uma classe chamada SubClasse estende uma classe chamada SuperClasse. O uso
da palavra extends na definição da SubClasse, seguida do nome da super-classe da
qual é derivada, explicita a herança. Os membros inteiros a, b e c são herdados pela
classe derivada. Os construroes não são herados e por isso devem ser definidos em
cada uma das classes. O método print() da SubClasse sobrescreve o seu equivalente
da SuperClasse.
Repare nos construtores da classe derivada SubClasse. O uso de super() e
super(a,b,c) referem-se à invocação de versões dos construtores da SuperClasse. Se
esta invocação não ocorrer explicitamente, o construtor default da SuperClasse será
invocado implicitamente.
class SuperClasse
{
public int a;
protected int b;
protected int c;
public SuperClasse ()
{
this.a=this.b=this.c=0;
}
public SuperClasse(int a, int b, int c)
{
this.a=a;
this.b=b;
this.c=c;
}
public void print()
{
System.out.printf("\n%d %d %d",a,b,c);
}
}
class SubClasse extends SuperClasse
{
public int d;
public int e;
20
public SubClasse ()
{
super();
this.d=this.e=0;
}
public SubClasse(int d, int e)
{
super();
this.d=d;
this.e=e;
}
public SubClasse(int a, int b, int c, int d, int e)
{
super(a,b,c);
this.d=d;
this.e=e;
}
@Override
public void print()
{
System.out.printf("\n");
super.print();
System.out.printf(" %d %d",d,e);
}
}
class exHeranca
{
public static void main (String [] args)
{
SubClasse obj1 = new SubClasse();
SubClasse obj2 = new SubClasse(4,5);
SubClasse obj3 = new SubClasse(1,2,3,4,5);
obj1.print();
obj2.print();
obj3.print();
}
}
É indicado o uso da anotação @Override para indicar que um método da classe
derivada deve sobrescrever o seu equivalente da classe base. Isso evita que aconteçam
erros. Se o programador definiu de forma diferente (nome do método, número ou
tipo de argumentos) e a anotação @Override foi realizada, o compilador comparará
as assinaturas e acusará erros potenciais.
21
11.1
Classes e métodos abstratos
Pode ser útil declarar classes para as quais não pretendemos instanciar objetos. Geralmente, estas classes são usadas como super-classes em hierarquia de herança e são chamadas superclasses abstratas. Classes abstratas possuem pelo menos um método
abstrato, ou seja, sem implementação. As classes concretas derivadas desta superclasse abstrata devem fornecer implementação destes métodos. Vamos modificar a
hierarquia de classes do último exemplo para mostrar o uso de classes e metodos abstratos.
Iniciamos definindo uma outra subclasse denominada SubClasse2 e adicionamos
o método public void method() em cada uma das classes da hierarquia. Na superclasse esse método é definido como abstrato e portanto não tem implementação. A
superclasse foi definida usando a palavra reservada abstract para indicar que é uma
classe abstrata.
abstract class SuperClasse
{
...
public abstract void method();
...
}
class SubClasse extends SuperClasse
{
...
public void method()
{
System.out.printf("Estou em method() da SubClasse");
...
}
...
}
lass SubClasse2 extends SuperClasse
{
...
public void method()
{
System.out.printf("Estou em method() da SubClasse2");
...
}
...
}
22
A classe exHeranca será modificada para exemplificarmos o uso de métodos
abstratos e comportamento polimórfico nessa hierarquia de herança. Na linha 5 instanciamos um vetor de objetos da superclasse com duas posições e nas linhas 6 e 7
instanciamos um objeto de cada subclasse. Nas linhas 9 e 10 atribuimos a cada posição
do vetor a referência para um dos objetos de subclasses criados e em seguida (linhas 12
e 13) invocamos o método method() usando o vetor objSuper. Repare que, embora
o vetor tenha sido definido para armazenamento de referências para objetos da superclasse, a vinculação do método method() nas linhas 12 e 13 ocorrerá corretamente.
Isso quer dizer que, o código execuado em resposta ao comando das linhas 12 e 13 será
aquele definido no método method() de SubClasse e SubClasse2, respectivamente.
1. class exHeranca
2. {
3.
public static void main (String [] args)
4.
{
5.
SuperClasse [] objSuper = new SuperClasse [2];
6.
SubClasse objSub = new SubClasse(1,2,3,4,5);
7.
SubClasse2 objSub2 = new SubClasse(6,7,8,9,10);
8.
9.
objSuper[0] = objSub;
10.
objSuper[1] = objSub2;
11.
12.
objSuper[0].method();
13.
objSuper[1].method();
14.
}
15.}
23
Download