Por Loost, 31 de jan. de 2011 em Java
info
Grupo: Campones
Registrado: 30/01/10
Posts: 25
Reputação: 0
Char no Tibia: Lord kynax
[Tutorial]Programação em JAVA
A Linguagem de
Programação Java
Índice
1.Introdução 2
2.Histórico 2
3.As palavras que definem Java 3
4.Tipos primitivos 6
5.Tipos Compostos 6
6.Expressões 7
7.Variíveis 8
8.Comandos 9
9.Java e a Orientação a Objetos 10
1.Classes 10
2.Objetos - Instâncias de uma Classe 11
3.Construtores 12
4.Métodos / Mensagens 13
5.Destrutores 14
6.Herança 15
7.Polimorfismo 17
8.Controle de Acesso 18
9.Variíveis e Métodos de Classe 19
10.Classes e Métodos Abstratos 19
11.Interfaces 20
10.Concorrência (Threads) 21
11.Tratamento de Exceções 22
12.Conclusões 24
13.Bibliografia 25
Introdução
Nesse trabalho estaremos falando sobre a linguagem de programação Java. É uma
linguagem singular dentre todas outras jí que é a única que chamou a atenção de pessoas
fora do mundo técnico, o suficiente para que existissem reportagens de mais de 10 minutos
em cadeias de divulgação de massa como a CNN.
Apesar de todo o alarde, Java não é uma linguagem tão revolucioníria quanto se clama.
Muitos dos conceitos implementados estão presentes em linguagens orientadas a objeto
modernas, como Eiffel e Modula-3. O que difere Java das outras linguagens é que ela
promete portabilidade total e a possibilidade de criação de pígina WWW interativas para a
Internet.
Java é uma linguagem definida como simples, orientada a objetos, robusta e segura, de
arquitetura neutra, portível, interpretada, de alta performance, com suporte a concorrência
e dinâmica. Discutirmos o que cada uma dessas palavras querem dizer e olharemos Java
como qualquer outra linguagem de programação, à luz dos conceitos e tópicos em
linguagens de programação.
Java parece ser uma linguagem de programação muito útil e de grande produtividade.
Bjarne Stroustrup, o idealizador de C++: "C faz com que seja muito fícil atirar nos próprios
pés. C++ faz com que isso se torne mais difàcil, mas quando você consegue, destrói toda a
perna." Acreditamos Java que torne muito difàcil atirar na própria perna.
Histórico
Java originou-se como parte de um projeto de pesquisa que visava a criação de um
software avançado que atendesse a uma extensa variedade de maquinírio de redes e
sistemas embutidos. O objetivo inicial era desenvolver um ambiente operacional pequeno,
confiível, portível, distribuàdo e que operasse em tempo real. Inicialmente, a linguagem
escolhida foi C++. Porém, a com o passar do tempo, as dificuldades encontradas com C++
aumentaram até o ponto em que os problemas poderiam ser melhor endereçados se fosse
criada uma linguagem completamente nova. As decisões de arquitetura e desenho da
linguagem foram inspiradas em linguagens como Eiffel, SmallTalk, Objective C, e Cedar /
Mesa. A sintaxe tem suas raàzes claramente definidas em C e C++.
Deste modo, Java foi projetada para atender a vírios requisitos desejíveis em uma LP,
como por exemplo, confiabilidade, devido ao seu gerenciamento de memória, o que resulta
em um ganho de eficiência; redigibilidade, por eliminar alguns conceitos de C e C++ que
dificultavam nesse sentido; reuso de código.
As palavras que definem Java
A documentação de Java [1] fornecida pela Sun utiliza algumas palavras para definir a
linguagem, faremos uma cràtica a respeito de cada uma delas.
1) Simples
Uma caracteràstica marcante de Java é a simplicidade da linguagem, que pode ser
programada sem um treinamento intenso, ou larga experiência anterior. Programadores de
C++ terão uma rípida compreensão de Java devido à sua semelhança com Java. Java foi
criada tão unida quanto possàvel a C++ para se criar sistemas mais compreensàveis. Java
omite muitos termos pouco usados e operações confusas em C++ que trazem mais
complicações que benefàcios.
A versão Java, é na verdade, uma versão mais limpa de C++. Nela não hí ponteiros
aritméticos, estruturas, uniões, sobrecarga de operadores, classes bísicas virtuais e etc.
Ao mesmo tempo que é uma linguagem simples, existem aspectos sutis na construção de
programas para o mundo real, dada a atual situação da biblioteca de classes e da não muito
avançada programação visual. Com o tempo os recursos tendem a aumentar mais e mais
com a criação de bibliotecas e desenvolvimento de ambientes.
2) Orientada a objeto
A orientação a objeto é uma técnica que enfoca o modelo do dado (Objeto) e sua interface.
As facilidades de orientação objeto de Java são essencialmente as de C++. As operações
de OO de Java são comparíveis com as de C++. A maior diferença entre Java e C++ estí
em múltipla herança, pois Java parece ter encontrado uma solução melhor.
Os programadores podem reutilizar código, utilizar bibliotecas de terceiros com proteção e
encapsulamento, e adicionar funcionalidade às jí existentes.
Java possui tipagem forte, o que pode ser uma vantagem para programadores vindos de
uma linguagem como Smalltalk.
3) Robusta e Segura
O projeto de Java visou a construção de uma linguagem para escrita de programas
confiíveis. Java enfatiza em muito a checagem em tempo de compilação de possàveis
problemas, e em tempo de execução realiza a checagem dinâmica, e eliminação de situações
que podem gerar erros.
A maior diferença entre C/C++ e Java é que Java por definição da própria linguagem
elimina uma gama de erros que geralmente surgem em C/C++ quando utilizamos ponteiros.
Java fornece a funcionalidade de ponteiros sem que seja necessírio criar estruturas para tal.
Estas estruturas eliminam a possibilidade de sobreposição de dados na memória
corrompendo dados.
Java é designada para operar em ambientes onde segurança é extremamente importante,
como o ambiente de rede.
4) Arquitetura Neutra
Java é projetada para suportar aplicações que serão distribuàdas para os diversos ambientes
de trabalho em rede. Em tais ambientes aplicações devem ser capazes de executar em uma
grande variedade de míquinas. Nas vírias plataformas de hardware, aplicações devem
executar sobre um universo de sistemas operacionais e operar interagindo com outras
linguagens de programação. Isto é possàvel graças à arquitetura idealizada, onde o
compilador Java gera um código binírio para uma JVM (míquina virtual Java) - uma
arquitetura neutra e portível. Assim, qualquer míquina que possa rodar uma míquina virtual
Java pode rodar programas jí compilados sem requerer a menor mudança.
A natureza "interpretada" de Java resolve ambos os problemas de distribuição biníria e de
versão.
5) Portível
Diferente de C/C++, não hí aspectos de implementação dependentes da especificação. O
tamanho dos tipos primitivos são especificados, bem como os seus comportamentos
aritméticos. Um inteiro tem sempre 32 bits, em C/C++ tem o tamanho da palavra da
míquina.
Tendo fixado o tamanho dos tipos numéricos, é eliminada a maior causa de dores de
cabeça. Os dados binírios são armazenados em formato fixo, eliminando a confusão de big
endian e little endian.
6) Interpretada
O interpretador Java pode executar o código binírio Java diretamente em alguma míquina
para o qual ele tenha sido portado. Em um ambiente interpretado tal como o sistema Java, a
fase de linkagem de um programa é simples, incremental e leve. O processo de
desenvolvimento pode ser muito mais rípido.
Esta é uma vantagem enquanto desenvolvemos uma aplicação, mas ela é claramente mais
lenta que um código compilado.
7) Alta Performance
Enquanto a performance do código binírio interpretado é geralmente adequado, hí
situações onde maior performance é requerida. O código binírio pode ser traduzido em
tempo de execução para outro código de míquina para ser executado em uma aplicação de
uma CPU particular.
Espera-se que em breve teremos compiladores de Java também para míquinas reais.
8) Dinâmica
Java é mais dinâmica que C/C++. Bibliotecas podem livremente somar novos métodos e
instâncias de variíveis sem nenhum efeito em seus clientes. Em Java descobrir o tipo de uma
instância em tempo de execução é algo extremamente simples.
9) Concorrência (Threads)
Concorrência é a habilidade para um programa fazer mais de uma coisa por vez. Os
benefàcios de multiprocessamento são melhor sensibilidade interativa e comportamento em
tempo real.
O threads em Java têm a capacidade para pegar as vantagens de sistemas
multiprocessadores se o sistema operacional faz o mesmo. Por outro lado implementações
threads em plataformas diferem amplamente, e Java não faz esforço para ser uma
independente de plataforma neste caso.
Java suporta multiprocessamento no nàvel de linguagem com a adição de sofisticada
sincronização.
Tipos primitivos
Os tipos inteiros em Java são: byte (8 bits); short (16 bits); int (32 bits) e long (64 bits). O
tipo byte (8 bits) em Java veio a substituir o antigo tipo char (C e C++). Não hí nada em
Java para especificar um tipo inteiro sem sinal como em C e C++.
O tipo de ponto flutuante em Java pode ser o float (32 bits) e o double (64 bits). Os
operadores aritméticos seguem o padrão IEEE 754 1.
O tipo char declarado em Java define um caracter de 16 bits, seguindo o padrão Unicode
(um código anílogo ao ASCII que define caracteres para todas as lànguas, como um código
universal).
Os tipos booleanos em Java, diferentemente dos similares em C, não podem ser convertidos
para nenhum tipo numérico. Valores booleanos em Java assumem apenas true ou false.
Todos os tipos primitivos têm valores default. Todos os tipos numéricos são inicializados
para 0, o tipo caracter é inicializado para o Unicode 0 e variíveis do tipo booleano são
inicializados para false.
Tipos Compostos
As uniões disjuntas, produtos cartesianos e conjuntos de potência foram eliminados em
Java. Os dois primeiros foram deixados de lado pois sendo Java uma linguagem orientada a
objetos, as classes substituem essas construções. Jí os conjuntos de potência são supridos
como classes da API (a classe BitSet). Tipos recursivos são suportados.
Todos os tipos em Java que não são primitivos são tipos de referência a objetos, incluindo
arrays.
Ao contrírio de C e C++, os arrays em Java são objetos de primeira classe. É possàvel ao
programador declarar arrays de qualquer tipo, e ainda declarar arrays de arrays para
vetores multidimensionais.
Um array em Java, como qualquer outro objeto deve ser alocado dinamica e explicitamente
com o operador new. Uma vez que o objeto é alocado e tem um certo tamanho, este não
muda. Tais procedimentos garantem mais confiabilidade ao código escrito em Java, jí que
ficam eliminados os erros por violação de memória e perda de dados durante a execução
do programa. Se o programador viola os limites de um vetor, é gerada uma exceção.
De acordo com as definições descritas acima, pode-se classificar os arrays em Java como
semi-dinâmicos, semelhante aos arrays em Ada.
O acesso aos elementos do array segue o estilo de indexação de C. Porém, no momento
em que é feita qualquer referência a um desses elementos é checado o tamanho do array
para se verificar se não estí sendo tentado um acesso a um àndice fora do tamanho do
array. Caso isso ocorra, é gerada uma exceção. Arrays não são a única implementação de
vetores existente em Java. A API fornece a classe Vector que possibilidade a construção de
vetores dinâmicos. Vale lembrar que o acesso a essa classe Vector é toda feita através de
métodos e não de operadores de arrays.
Strings em Java são objetos, e não "pseudo-arrays" como em C. Existem duas classes na
API de Java que implementam arrays: StringBuffer e String. A definição da linguagem define a
sobrecarga do operador de adição para a utilização com a classe String, e de literais do tipo
String.
Expressões
Uma expressão em Java pode produzir três resultados:
um valor
uma variível (uma referência a uma variível)
nada (a expressão é void)
As expressões literais providas são de números inteiros e de ponto flutuante, caracter,
booleano e string. Não são suportados agregados, e as expressões condicionais são
suportadas através do operador ternírio (o mesmo de C).
Uma expressão produz nada se e somente se ela é uma chamada a um método de tipo de
retorno void. Tal expressão pode ser usada somente como uma expressão comando,
porque qualquer outro contexto em que uma expressão possa ser usada requer que a
expressão produza um valor ou uma variível. Uma expressão que é uma chamada a um
método pode ter o seu valor de retorno silenciosamente descartado. Além disso, a
execução de expressões pode produzir efeitos colaterais, pois além de chamadas a funções
e atribuições, expressões podem conter operadores como ++ e --.
Variíveis
Em Java, como foi dito anteriormente, qualquer variível que não seja de um tipo primitivo é
uma variível de referência a um objeto. Daà concluàmos que somente as variíveis de tipos
primitivos são realmente storables. Todas as variíveis de referência tem campos que podem
ser atualizados seletivamente.
Além de todas variíveis de tipos compostos (não primitivos) serem referências, estas tem
ter seus objetos alocados explicita e dinamicamente através do operador new, e não é
permitido o uso de variíveis não inicializadas. Isto serí discutido adiante no tópico que se
refere a orientação a objetos. Vale lembrar que todos os problemas de ponteiros foram
eliminados, através da ausência de ponteiros (e consequentemente aritmética de ponteiros) e
com a existência do garbage collector. As variíveis de referência suprem a funcionalidade
ponteiros para a criação de listas encadeadas e outras estruturas de dados que dependem
da noção de ponteiro, apesar de não poderem ser de-referenciadas. As variíveis de
referência a objetos têm valor default null, ou seja, não apontam para nenhum objeto.
Java faz o maior esforço para fazer a checagem de tipos em tempo de compilação. Uma
variível de referência a um objeto pode guardar uma referência a um objeto cujo tipo em
tempo de compilação pode ser convertido sem o uso de type casting. Veremos isso
adiante. Java utiliza equivalência nominal, o que era de se esperar de uma linguagem
orientada a objetos, jí que permite a construção de tipos abstratos em que a implementação
(estrutura interna dos dados) é ignorada.
Em Java, as variíveis locais são declaradas e alocadas dentro de um bloco e são
descartadas na saàda do bloco. Parâmetros de métodos também são consideradas variíveis
locais.
Variíveis constantes são definidas com a palavra chave final. Estas devem ser inicializadas
da declaração, e não poderão ser modificadas (amarrações para valor). Podem também ser
declaradas como volatile, o que quer dizer que sabe-se que elas serão modificadas
assincronamente. Isso quer dizer que as variíveis que são declaradas como volatile serão
carregadas e salvadas na memória a cada uso, de forma que possam estar coerentes em
multiprocessadores.
Comandos
Os comandos de controle de fluxo são extremamente semelhantes aos de C, com exceção
do goto, que apesar de ser uma palavra reservada na linguagem não é implementado. Todos
os comandos são sequenciais.
Os comandos de seleção são o if e o switch, sendo o if de caminho simples (com else) e o
switch de múltiplos caminhos:
if ( Expressão ) bloco_de_comandos else bloco_de_comandos
switch ( Expressão ) {
case ExpressãoConstante : bloco_de_comandos
default : bloco_de_comandos
}
Os de iteração são while, do while e for.
while ( Expressão ) bloco_de_comandos
do bloco_de_comandos while ( Expressão );
for ( ExpressãoInicialização; Expressão; ExpressãoAvanço );
Os comandos de escapes englobam o return, o continue, o break e o throw.
O return é utilizado para interromper a execução de um método, especificando a expressão
de retorno, ou não, se o método não for void.
O break transfere o controle para o final da iteração no qual estí inserido, ou encerra a
execução de um switch. O continue transfere o controle para o ponto de continuação do
loop de um comando de iteração. Ambos break e continue podem ser acompanhados de
identificadores que especificam a qual dos loops externos estamos nos referindo, jí que
existe a possibilidade de amarrar labels a comandos de iteração.
O throw "dispara", "joga" uma exceção, desviando o fluxo para o bloco de tratamento de
exceções ou interrompendo o programa.
Além destes comandos existem os chamados guarding statements que estabelecem
condições para o tratamento de exceções e multithreading. São eles o try, o synchronized,
o catch e o finally (serão explicados posteriormente nas seções de tratamento de exceções e
concorrência).
Java e a Orientação a Objetos
A orientação a objetos tem provado seu valor nos últimos quase 30 anos, e é inconcebàvel que uma
linguagem de programação moderna não seja orientada a objetos. Na especificação da linguagem Java
[2] ela é definida como "uma linguagem orientada a objetos baseada em classes", e portanto provê essas
caracteràsticas mànimas, suficientes para possibilitar modularização, proteção e reutilização:
Encapsulamento - Ocultamento de Informações (Information Hiding) e modularidade (abstrações)
Polimorfismo - a mesma mensagem enviada a diferentes objetos resultam em um comportamento que
depende da natureza dos objetos recebendo a mensagem.
Herança - novas classes são definidas em termos de classes existentes, possibilitando o reuso de
código.
Amarração Dinâmica - os objetos são possivelmente amarrados em tempo de execução, o que quer dizer
que um objeto pode ser até passado por uma rede. A amarração dinâmica provê flexibilidade em tempo
de execução, e é a chave para o polimorfismo real.
As caracteràsticas da orientação a objetos de Java são similares às de C++. A maior diferença entre elas é
que Java parece ter achado uma boa solução para substituir a herança múltipla. Todos os tipos de
dados, com exceção dos primitivos, são classes.
Classes
Uma classe é uma construção de software que define variíveis de instância e métodos de um objeto.
Uma classe não é um objeto, uma classe é a "definição" de como um objeto se comportarí quando este
for criado ou instanciado.
A declaração bísica de uma classe em Java é a seguinte:
class nome {
// informações sobre a classe
Abaixo temos um exemplo de uma classe muito simples:
class Pessoa {
public String Nome; /* variível de instância */
public String Telefone; /* variível de instância */
Objetos - Instâncias de uma Classe
Para utilizarmos uma classe nós devemos instanciar objetos. Em Java isto quer dizer que criaremos uma
referência para um objeto (não existe a idéia de um tipo expandido como em Eiffel [6] e amarrações para
valores são possàveis somente para tipos primitivos) - com um fragmento de código como este:
Pessoa meuAmigo;
// declara uma variível que faz referência a um objeto da classe Pessoa
meuAmigo = new Pessoa();
// aloca uma instância de um objeto da classe Pessoa
É possàvel acessar uma variível do objeto de uma classe através do nome da variível, qualificando o
mesmo com o nome do objeto, da mesma forma com que acessamos uma estrutura em C. Por exemplo:
meuAmigo.Nome = "Fulano de Tal";
// atribuição à variível de instância Nome da variível de objeto meuAmigo
Todo objeto deve ser alocado dinamica e explicitamente através do operador new, e deve ser inicializado
antes de ser usado. Uma variível de objeto que não se refere a nenhum objeto deve ter o valor null. Um
erro de tempo de execução ocorre se for utilizado um ponteiro não inicializado ou null.
Um objeto em Java pode ser visto de forma aníloga a ponteiros para objetos em C++. Se você copia uma
variível para outra, ambas se referem ao mesmo objeto, são "ponteiros" para o mesmo objeto. A
diferença reside que, em C++, é muito fícil se criar ponteiros "ruins" (usando aritmética de ponteiros,
não existente em Java) ou termos problemas de objetos e referências pendentes. O garbage collector
garante que tais problemas não ocorrerão.
Construtores
Ao declarar uma classe em Java, opcionalmente definimos construtores. Construtores fazem a
inicialização de objetos ao serem instanciados. Os construtores são métodos com o mesmo nome da
classe e que não têm tipo de retorno especificado.
Quando um objeto é criado (instanciado), o método construtor apropriado é automaticamente invocado,
para, por exemplo, dar um estado inicial ao objeto. Se uma classe não contém declarações de
construtores, então um construtor default é fornecido automatica e implicitamente.
Um construtor só pode ser chamado com a palavra chave new, e não pode ser aplicado a um objeto
existente.
Exemplo:
Pessoa() { /* construtor default */
Nome = "";
Telefone = ""; }
Pessoa(String N, String T) {
Nome = N;
Telefone = T; }
Pessoa outroAmigo = new Pessoa("Fulano 2","444-4444");
// acima temos um exemplo de utilização de construtor:
outroAmigo.Pessoa("XXX","222");
/* ERRO! construtores só podem ser utilizados para
instanciar elementos com new */
Métodos / Mensagens
Métodos são a forma com que os objetos interagem entre si. Na orientação a objetos, para se atingir
encapsulamento e proteção, todas as interações entre objetos (ditas mensagens) devem ser feitas
através dos métodos de uma classe. Não hí funções e procedimentos em Java, haja vista que a
programação procedural foi totalmente substituàda. Mesmo assim, a forma de se invocar métodos em
Java se assemelha à de funções em C e C++. Qualquer método pertence a uma classe, e deve ser definido
dentro do corpo da mesma.
Podemos como exemplo modificar a nossa classe Pessoa:
private String Nome; /* variível de instância */
private String Telefone; /* variível de instância */
public void mudaNome(String Nome) {
this.Nome = Nome;
public String leNome() {
return Nome;
public String leTelefone() {
return Telefone;
No exemplo acima as variíveis de instância Nome e Telefone foram precedidas pela palavra chave
private, o que quer dizer que essas variíveis só poderão ser acessadas por métodos da classe à qual
pertencem.
No exemplo acima utilizamos a palavra chave this. Essa variível se refere ao objeto que estí recebendo a
mensagem, ou seja, o objeto no qual o método estí sendo aplicado (Em C++ this é o ponteiro para o
objeto que recebe a mensagem, e em Java é a referência para esse objeto).
Invocando esses métodos qualificamos o nome do método com o nome do objeto:
Pessoa meuAmigo = new Pessoa("Fulano de Tal","999-9999");
meuAmigo.mudaTelefone("222-2222");
/* invocamos o método mudaTelefone da classe Pessoa sobre o objeto meuAmigo,
ou melhor, mandamos uma mensagem mudaTelefone para o objeto meuAmigo. */
Java permite a sobrecarga independente de contexto de métodos, mas não permite a sobrecarga de
operadores. Para sobrecarregarmos um método basta declararmos outro método de mesmo nome com
uma assinatura diferente (tipo e ordem dos parâmetros formais).
Métodos podem ser declarados nativos, utilizando a palavra chave native. Isto quer dizer que eles serão
implementados de forma dependente de plataforma, por exemplo em C ou assembly. Java trata um
método nativo como outro qualquer.
Destrutores
Além de construtores, a linguagem provê a construção de métodos destrutores. Os destrutores são
métodos responsíveis por liberar os recursos alocados durante a vida de um certo objeto. Eles são
invocados automaticamente pelo garbage collector, imediatamente antes deste "recolher" um objeto.
Esse método deve se chamar finalize.
/* Fecha um arquivo aberto quando o garbage collector atua */
protected void finalize() {
try {
file.close();
} catch (Exception e) {
O exemplo acima mostra um tàpico caso em que o seu objeto deve liberar os recursos alocados do
sistema operacional, como por exemplo fechar descritores de arquivos, liberar contextos em ambientes
gríficos, etc.
Herança
A herança é um mecanismo através do qual novas e mais especializadas classes podem ser definidas em
termos de classes pré-existentes. Um exemplo é a criação de uma classe Funcionario, como uma
subclasse de Pessoa. Em Java:
class Funcionario extends Pessoa {
// Novos métodos e instâncias podem ser inseridos aqui
class Secretaria extends Funcionario {
...
class Gerente extends Funcionario {
A palavra chave extends diz que Funcionario é uma subclasse de Pessoa, chamada de classe base.
Dizemos que Funcionario herda as caracteràsticas de Pessoa, jí que este reutilizarí boa parte do código e
funcionalidade descrita na classe Pessoa.
private float salario;
public Funcionario(String Nome, String Telefone,
float salario) { super(Nome,Telefone);
this.salario = salario;
public Funcionario aumenta_salario(float aumento) {
salario = salario + aumento;
A classe Funcionario herda as variíveis de instância Nome e Telefone, e os métodos (mudaTelefone,
leTelefone, leNome) da classe Pessoa, com a exceção dos construtores. Nesse caso devemos criar novos
construtores que façam, opcionalmente, na primeira linha do corpo, uso da palavra chave super para se
referir ao construtor da superclasse, como no construtor do exemplo acima. Se a subclasse não tem
definições de construtores, o construtor super() é invocado, ou seja, o construtor default da classe
imediatamente superior.
Toda classe em Java é subclasse (não necessariamente imediata) da classe Object. Quando não
utilizamos a palavra chave extends numa declaração de classe, implicitamente esta se torna subclasse
imediata de Object.
Uma referência a um objeto da superclasse B (ou classe base) pode também ser referência de uma
subclasse S de B. Jí o contrírio exige o uso de type casting, ou seja a coerção (coercion) deve ser
explàcita.
Object o;
Pessoa fulano;
Funcionario contador1 =
new Funcionario("Fulano de Tal","222-2222");
Pessoa meuAmigo =
new Pessoa("Amigo da Onça","555-5555");
fulano = contador1; // ok! um funcionírio é uma pessoa
o = contador1; // a classe Funcionario é derivada indireta de Object
contador1 = meuAmigo;
// ERRO! meuAmigo é da classe pessoa, que é uma superclasse de Funcionario
contador1 = (Funcionario) meuAmigo;
// com a utilização de type casting esta conversão se torna possàvel
Se for necessírio modificar um método da classe superior, ou especializí-lo, é possàvel declarando-se um
método de mesma assinatura na subclasse. Não é possàvel sobrepor um método declarado como final.
Ao contrírio de C++, no qual as funções virtuais devem ser declaradas como tal, em Java, por default, as
funções são virtuais. Para acessarmos o método "sobreposto" (overrided) utilizamos o seletor super,
que é, na verdade uma referência à superclasse, equivalente a ((superclasse)this).
Java implementa herança simples, ao contrírio de C++ e Eiffel que implementam herança múltipla. Isso
quer dizer que uma classe só pode ter uma superclasse imediata. Isso pode, a primeira vista, parecer uma
caracteràstica limitante, mas em Java o conceito de Interfaces (presente também no Objective C como
protocols) faz com que a linguagem não perca o seu poder expressivo.
Polimorfismo
O polimorfismo é uma das caracteràsticas marcantes de linguagens orientadas a objetos. Ela permite que
a mesma mensagem enviada a diferentes objetos resultem em um comportamento que depende da
natureza dos objetos recebendo a mensagem, ou seja, permite a construção de abstrações que operem
uniformemente sob uma famàlia de tipos relacionados.
Quando uma mensagem é enviada para um objeto de uma subclasse em Java:
A subclasse checa se ela tem um método aquele nome e com exatamente os mesmos parâmetros. Se a
resposta for positiva, ela usa esse método.
Caso contrírio, Java envia a mensagem à classe imediatamente superior.
Se toda a hierarquia for caminhada sem que um método apropriado seja encontrado um erro em tempo de
compilação ocorre.
A amarração dinâmica é a chave para o polimorfismo. O compilador não gera código em tempo de
compilação para uma chamada de método, ele gera código para determinar que método chamar em tempo
de execução usando a informação de tipo disponàvel para o objeto.
Java não suporta abstrações genéricas, como o template de C++. Essa funcionalidade é implementada
com a utilização da classe Object. Uma clara diferença dessa falta é que ele permite uma flexibilidade
muito grande, que deve ser administrada corretamente pois pode ser perigosa. Vamos tomar como
exemplo uma lista de Object. Essa lista pode conter Funcionarios, Retangulos, Frutas, etc. Jí em C++ ou
Eiffel, na declaração do tipo genérico teràamos a criação de uma nova abstração especàfica para um certo
tipo. Tomando C++ como exemplo, criaràamos uma lista<Funcionario> e teràamos um novo tipo que
somente aceitaria Funcionarios.
Controle de Acesso
Ao declararmos uma classe em Java, indicamos o nàvel de acesso permitido para suas instâncias e
métodos. Existem quatro nàveis, e três modificadores: public, protected, e private. Definimos também o
nàvel de acesso da classe inteira, existindo apenas o nàvel public e o "friendly".
O nàvel public permite o acesso ilimitado, o protected significa que os campos são acessàveis somente
em subclasses, e o private que são acessàveis somente dentro da classe onde são declarados. O quarto
nàvel não tem um nome, mas é freqüentemente chamado de "friendly". Esse é o nàvel default. Ele indica
que os campos são disponàveis para todos objetos dentro daquele pacote (package).
Os packages em Java são coleções de classes que têm nomes hierírquicos. Ao utilizar um pacote, o seu
código deve incluir uma clíusula import, ou qualificar os métodos, variíveis e constantes utilizadas. Isso
permite que você distribua adequadamente suas "bibliotecas" de classes e que essa classes sejam
utilizadas em outros programas.
import java.net.*; // importa todas as classes do pacote java.net
import java.util.Bitset;
// importa somente a classe BitSet do pacote java.util
java.util.Date hoje = new java.util.Date();
/* utilizando a classe Date dentro de java.util, pacote que não
foi completamente importado */Variíveis e Métodos de Classe
Normalmente quando definimos variíveis em uma classe definimos variíveis de instâncias. Para cada
objeto criado uma nova variível de instância é criada, e utilizada apenas para representar o estado deste
objeto. Jí as variíveis de classe são compartilhadas por todos objetos de uma classe, sendo utilizadas
para representar o estado de toda uma classe. Jí os métodos de classe servem para manipular as
variíveis de classe, e não podem, de forma alguma manipular variíveis de instâncias, ou invocar
métodos de instâncias.
Para declarar variíveis ou métodos de classe, utilizamos o modificador static:
class Vendedor extends Funcionario {
private static float comissao = 2.5;
public void static mudaComissao(float c) {
comissao = c;
/* a comissão de todos os vendedores de uma loja é a mesma,
logo ela deve ser declarada como uma variível de classe */
Classes e Métodos Abstratos
Classes Abstratas são construções poderosas no paradigma da orientação a objetos. Elas têm grande
influência sobre a etapa de design, principalmente na concepção das relações de hierarquia entre as
classes.
Ao subirmos na hierarquia de herança, as classes se tornam cada vez mais gerais e provavelmente mais
abstratas. Hí um ponto em que elas são tão abstratas que as vemos como uma representação para
derivação de outras classes, ao invés de as observarmos como classes das quais objetos serão criados.
Métodos abstratos são aqueles que não podem ser implementados em classes tão abstratas, mas que
devem ser implementados em subclasses. Uma classes deve ser declarada abstrata se ela tem pelo menos
um método abstrato (os métodos abstratos eqüivalem às funções virtuais puras de C++ e às deffered
features de Eiffel)
Para declararmos métodos e classes abstratas devemos utilizar a palavra chave abstract. Classes
abstratas não têm construtores nem podem ser instanciadas.
class FormaGeometrica extends Object {
protected Ponto centro; // centróide da forma geométrica
public void mudaCentro(Ponto centro) {
this.centro = centro;
abstract void desenha(); // método abstrato }Interfaces
Uma declaração de uma interface declara um tipo que consiste num conjunto de métodos e constantes
sem especificar a sua implementação. Interfaces podem ser bons substitutos para classes abstratas sem
nenhuma implementação, e fornecem o poder da herança múltipla de interfaces, sem a confusão causada
pela herança múltipla de classes (que por sua vez contêm implementação). Uma interface pode herdar
suas caracteràsticas de diversas superinterfaces.
Quando uma classe é declarada ela pode opcionalmente fornecer uma lista de interfaces as quais são
implementadas por ela. Assim sendo, ela se torna responsível por fazer tal implementação. Uma
subclasse de uma classe que implementa alguma interface automaticamente herda a implementação
dessa interface.
Um exemplo claro é a implementação de uma interface Ordenavel:
public interface Ordenavel {
public int compara(Ordenavel a);
/* compara elementos, retornando positivo para maior que,
negativo para menor que, e zero para iguais */
/* classe que implementa a interface Ordenavel,
lembre-se que interfaces declaram novos tipos, logo podem
ser utilzados como parâmetros formais */
class Circulo extends FormaGeometrica
implements Ordenavel, ... {
private float raio;
public void desenha() {
public int compara(Ordenavel a) {
Circulo ca = (Circulo) a;
return raio - a.raio;
Concorrência (Threads)
A concorrência permite que vírias partes do seu software estejam rodando simultaneamente. Usuírios
de computadores sofisticados tornam-se impacientes ao fazer uma coisa de cada vez em seus
computadores pessoais.
Infelizmente os programadores que necessitam de concorrência em linguagens como C e C++ enfrentam
muitas dificuldades, jí que essas linguagens não suportam diretamente multithreading. Java o faz a
nàvel da linguagem e com classes apropriadas em sua API, com multitarefa pre-emptiva.
A nàvel da linguagem, métodos declarados synchronized não rodam simultaneamente. Tais métodos
rodam sob o controle de monitores que se asseguram que as variíveis permanecerão em um estado
consistente. Java faz o controle de locks automaticamente, sem que o usuírio precise se preocupar.
Para criarmos um objeto que rode em outra thread simplesmente derivamos a nossa classe da classe
Thread, ou implementamos a interface Runnable. A partir de então, sobrecarregamos o método run() com
o código desejado. Quando instanciamos um objeto dessa classe e invocamos o seu método start(), este
imediatamente retornarí e a aplicação ficarí sendo executada em background. Além da simplicidade de
se trabalhar com threads existe a possibilidade do controle de prioridades.
class PingPongThread extends Thread {
String mensagem;
int atraso;
PingPongThread(String mensagem, int atraso) {
this.mensagem = mensagem;
this.atraso = atraso;
start();
public void run() {
while (true) { // loop infinito
System.out.println(mensagem);
// imprimimos a mensagem
sleep(atraso); // geramos o atraso
new PingPongThread("ping",500);
new PingPongThread("pong",600);
Esse trecho de código cria dois objetos que rodarão em diferentes threads. As mensagens de "ping" e
"pong" serão intercaladas na tela.
Tratamento de Exceções
O tratamento de exceções permite que um erro seja tratado pelo programador, ou seja, que ele tome
decisões acerca de erro ocorrido. A missão principal do tratamento de exceções é transferir o controle do
ponto onde o erro ocorreu para um tratador de exceção que sabe como lidar com a situação.
O modelo de tratamento de exceções de Java é similar ao de Delphi e C++. Existe uma hierarquia de
exceções, implementadas como classes, pré-definidas. Isso não descarta, de forma alguma, a
possibilidade do programador criar as suas próprias classes de exceções, derivando subclasses dessa
hierarquia. Abaixo temos um diagrama simplificado da hierarquia de exceções em Java:
A hierarquia Error descreve erros internos e escassez de recurso do sistema Java. Programadores não
deve "jogar" exceções desse tipo, e sim aqueles da hierarquia Exception.
Para criar um trecho de código que trate uma exceção, você deve fazer uma construção try/catch. Além
disso, na declaração do método onde uma exceção vai ser possivelmente jogada é necessíria a inclusão
de uma especificação de exceção.
class Nome_da_Classe {
tipo_de_retorno Método (parâmetros formais)
throws Tipo_de_Exceção1, Tipo_de_Exceção2
{
bloco de código
catch (TipodaExeceção e)
tratador para esse tipo de exceção
catch (OutroTipodaExeceção e)
finally
código que serí executado até mesmo
na presença de uma exceção
Para "jogar" uma exceção, usa-se o comando throw. Quando um comando throw é encontrado, a
execução normal do programa é suspensa, enquanto um tratador adequado é procurado. A clíusula
catch que melhor se adequar para o tratamento daquela exceção serí executada, respeitando a seguinte
ordem:
1.O tipo de exceção da clíusula catch é exatamente da exceção jogada.
2.O tipo de exceção é uma superclasse daquela jogada.
3.O tipo de exceção é uma interface que a exceção jogada implementa.
Qualquer código dentro do bloco try depois da clíusula throw não serí saltado. Uma exceção pode ser
jogada novamente dentro de uma clíusula catch se houver necessidade de propagí-la.
Quando um bloco catch completa sua execução, a clíusula finally é procurada. Se esta não existe, a
execução continua na próxima instrução depois do bloco try. Uma clíusula finally é usada para a parte
do código que deve ser executada mesmo se uma exceção ocorrer.
Se uma exceção não é tratada num método, a execução deste é cancelada e a exceção é propagada para o
método chamador. Se ela não for tratada em lugar algum, a aplicação é interrompida com uma mensagem
(no caso de aplicações gríficas a mensagem é mostrada mais a aplicação não é encerrada).
Conclusões
Java parece ser uma linguagem razoavelmente simples, se, comparada a C++. Muitas das caracteràsticas
de C++ indesejadas e herdadas de C foram eliminadas. Ainda assim com certeza é familiar a
programadores C/C++. É uma linguagem significativamente segura, com a ausência de ponteiros e
garbage collecting. Permite a programação em larga escala, através da orientação a objeto, com
proteção, encapsulamento, reuso de código e outras caracteràsticas desejíveis em uma linguagem de uso
geral. Concorrência e tratamento de exceções são duas caracteràsticas que se destacam na linguagem,
uma preocupação de linguagens modernas, assim como a sua natureza portítil / interpretada. A
linguagem não provê abstrações genéricas, o que consideramos uma falta (apesar de que é possàvel criar
abstrações que possam tratar quaisquer objetos). As interfaces parecem ser uma boa idéia para a
substituição de herança múltipla de classes.
Apesar de suas vantagens como linguagem de programação, Java tem a desvantagem de ser uma
linguagem ainda muito nova. A falta de ambientes de desenvolvimento e ferramentas estí sendo
rapidamente suprida, jí que a linguagem chamou muita atenção da comunidade de programadores.
Esperamos que em breve teremos muitos sistemas desenvolvidos para Java, jí que as próximas versões
de sistemas operacionais para microcomputadores como o Windows e o OS/2 estarão incluindo a
míquina virtual Java. Além disso, existem projetos em andamento para a construção de um processador
Java que acelerarí a execução de aplicações executando o código binírio Java em hardware.
Bibliografia
[1] GOSLING, James e McGILTON, Henry, The Java Language Environment - A White Paper , Sun
Microsystems Computer Corporation, Outubro de 1995.
[2] The Java Language Specification - Version 1.0 Beta, Sun Microsystems Computer Corporation,
Beta Draft of October 30, 1995.
[3] RITCHEY, Tim, Programming with Java! Beta 2.0, Ed. New Riders, 1995.
[4] CORNELL, Gary e HORSTMANN, Cay, Core Java, Ed. Prentice Hall.
[5] Object-Oriented Languages in the Industry: A Comparison
http://www.eiffel.com./doc/manuals/tech ... index.html
[6] MEYER, Bertrand, An Invitation to Eiffel, http://www.eiffel.com/doc/manuals/language/intro
By: Loost :XTibia_smile:
info
Grupo: Campones
Registrado: 30/01/10
Posts: 25
Reputação: 0
Char no Tibia: Lord kynax
[Tutorial]Programação em JAVA
A Linguagem de
Programação Java
Índice
1.Introdução 2
2.Histórico 2
3.As palavras que definem Java 3
4.Tipos primitivos 6
5.Tipos Compostos 6
6.Expressões 7
7.Variíveis 8
8.Comandos 9
9.Java e a Orientação a Objetos 10
1.Classes 10
2.Objetos - Instâncias de uma Classe 11
3.Construtores 12
4.Métodos / Mensagens 13
5.Destrutores 14
6.Herança 15
7.Polimorfismo 17
8.Controle de Acesso 18
9.Variíveis e Métodos de Classe 19
10.Classes e Métodos Abstratos 19
11.Interfaces 20
10.Concorrência (Threads) 21
11.Tratamento de Exceções 22
12.Conclusões 24
13.Bibliografia 25
Introdução
Nesse trabalho estaremos falando sobre a linguagem de programação Java. É uma
linguagem singular dentre todas outras jí que é a única que chamou a atenção de pessoas
fora do mundo técnico, o suficiente para que existissem reportagens de mais de 10 minutos
em cadeias de divulgação de massa como a CNN.
Apesar de todo o alarde, Java não é uma linguagem tão revolucioníria quanto se clama.
Muitos dos conceitos implementados estão presentes em linguagens orientadas a objeto
modernas, como Eiffel e Modula-3. O que difere Java das outras linguagens é que ela
promete portabilidade total e a possibilidade de criação de pígina WWW interativas para a
Internet.
Java é uma linguagem definida como simples, orientada a objetos, robusta e segura, de
arquitetura neutra, portível, interpretada, de alta performance, com suporte a concorrência
e dinâmica. Discutirmos o que cada uma dessas palavras querem dizer e olharemos Java
como qualquer outra linguagem de programação, à luz dos conceitos e tópicos em
linguagens de programação.
Java parece ser uma linguagem de programação muito útil e de grande produtividade.
Bjarne Stroustrup, o idealizador de C++: "C faz com que seja muito fícil atirar nos próprios
pés. C++ faz com que isso se torne mais difàcil, mas quando você consegue, destrói toda a
perna." Acreditamos Java que torne muito difàcil atirar na própria perna.
Histórico
Java originou-se como parte de um projeto de pesquisa que visava a criação de um
software avançado que atendesse a uma extensa variedade de maquinírio de redes e
sistemas embutidos. O objetivo inicial era desenvolver um ambiente operacional pequeno,
confiível, portível, distribuàdo e que operasse em tempo real. Inicialmente, a linguagem
escolhida foi C++. Porém, a com o passar do tempo, as dificuldades encontradas com C++
aumentaram até o ponto em que os problemas poderiam ser melhor endereçados se fosse
criada uma linguagem completamente nova. As decisões de arquitetura e desenho da
linguagem foram inspiradas em linguagens como Eiffel, SmallTalk, Objective C, e Cedar /
Mesa. A sintaxe tem suas raàzes claramente definidas em C e C++.
Deste modo, Java foi projetada para atender a vírios requisitos desejíveis em uma LP,
como por exemplo, confiabilidade, devido ao seu gerenciamento de memória, o que resulta
em um ganho de eficiência; redigibilidade, por eliminar alguns conceitos de C e C++ que
dificultavam nesse sentido; reuso de código.
As palavras que definem Java
A documentação de Java [1] fornecida pela Sun utiliza algumas palavras para definir a
linguagem, faremos uma cràtica a respeito de cada uma delas.
1) Simples
Uma caracteràstica marcante de Java é a simplicidade da linguagem, que pode ser
programada sem um treinamento intenso, ou larga experiência anterior. Programadores de
C++ terão uma rípida compreensão de Java devido à sua semelhança com Java. Java foi
criada tão unida quanto possàvel a C++ para se criar sistemas mais compreensàveis. Java
omite muitos termos pouco usados e operações confusas em C++ que trazem mais
complicações que benefàcios.
A versão Java, é na verdade, uma versão mais limpa de C++. Nela não hí ponteiros
aritméticos, estruturas, uniões, sobrecarga de operadores, classes bísicas virtuais e etc.
Ao mesmo tempo que é uma linguagem simples, existem aspectos sutis na construção de
programas para o mundo real, dada a atual situação da biblioteca de classes e da não muito
avançada programação visual. Com o tempo os recursos tendem a aumentar mais e mais
com a criação de bibliotecas e desenvolvimento de ambientes.
2) Orientada a objeto
A orientação a objeto é uma técnica que enfoca o modelo do dado (Objeto) e sua interface.
As facilidades de orientação objeto de Java são essencialmente as de C++. As operações
de OO de Java são comparíveis com as de C++. A maior diferença entre Java e C++ estí
em múltipla herança, pois Java parece ter encontrado uma solução melhor.
Os programadores podem reutilizar código, utilizar bibliotecas de terceiros com proteção e
encapsulamento, e adicionar funcionalidade às jí existentes.
Java possui tipagem forte, o que pode ser uma vantagem para programadores vindos de
uma linguagem como Smalltalk.
3) Robusta e Segura
O projeto de Java visou a construção de uma linguagem para escrita de programas
confiíveis. Java enfatiza em muito a checagem em tempo de compilação de possàveis
problemas, e em tempo de execução realiza a checagem dinâmica, e eliminação de situações
que podem gerar erros.
A maior diferença entre C/C++ e Java é que Java por definição da própria linguagem
elimina uma gama de erros que geralmente surgem em C/C++ quando utilizamos ponteiros.
Java fornece a funcionalidade de ponteiros sem que seja necessírio criar estruturas para tal.
Estas estruturas eliminam a possibilidade de sobreposição de dados na memória
corrompendo dados.
Java é designada para operar em ambientes onde segurança é extremamente importante,
como o ambiente de rede.
4) Arquitetura Neutra
Java é projetada para suportar aplicações que serão distribuàdas para os diversos ambientes
de trabalho em rede. Em tais ambientes aplicações devem ser capazes de executar em uma
grande variedade de míquinas. Nas vírias plataformas de hardware, aplicações devem
executar sobre um universo de sistemas operacionais e operar interagindo com outras
linguagens de programação. Isto é possàvel graças à arquitetura idealizada, onde o
compilador Java gera um código binírio para uma JVM (míquina virtual Java) - uma
arquitetura neutra e portível. Assim, qualquer míquina que possa rodar uma míquina virtual
Java pode rodar programas jí compilados sem requerer a menor mudança.
A natureza "interpretada" de Java resolve ambos os problemas de distribuição biníria e de
versão.
5) Portível
Diferente de C/C++, não hí aspectos de implementação dependentes da especificação. O
tamanho dos tipos primitivos são especificados, bem como os seus comportamentos
aritméticos. Um inteiro tem sempre 32 bits, em C/C++ tem o tamanho da palavra da
míquina.
Tendo fixado o tamanho dos tipos numéricos, é eliminada a maior causa de dores de
cabeça. Os dados binírios são armazenados em formato fixo, eliminando a confusão de big
endian e little endian.
6) Interpretada
O interpretador Java pode executar o código binírio Java diretamente em alguma míquina
para o qual ele tenha sido portado. Em um ambiente interpretado tal como o sistema Java, a
fase de linkagem de um programa é simples, incremental e leve. O processo de
desenvolvimento pode ser muito mais rípido.
Esta é uma vantagem enquanto desenvolvemos uma aplicação, mas ela é claramente mais
lenta que um código compilado.
7) Alta Performance
Enquanto a performance do código binírio interpretado é geralmente adequado, hí
situações onde maior performance é requerida. O código binírio pode ser traduzido em
tempo de execução para outro código de míquina para ser executado em uma aplicação de
uma CPU particular.
Espera-se que em breve teremos compiladores de Java também para míquinas reais.
8) Dinâmica
Java é mais dinâmica que C/C++. Bibliotecas podem livremente somar novos métodos e
instâncias de variíveis sem nenhum efeito em seus clientes. Em Java descobrir o tipo de uma
instância em tempo de execução é algo extremamente simples.
9) Concorrência (Threads)
Concorrência é a habilidade para um programa fazer mais de uma coisa por vez. Os
benefàcios de multiprocessamento são melhor sensibilidade interativa e comportamento em
tempo real.
O threads em Java têm a capacidade para pegar as vantagens de sistemas
multiprocessadores se o sistema operacional faz o mesmo. Por outro lado implementações
threads em plataformas diferem amplamente, e Java não faz esforço para ser uma
independente de plataforma neste caso.
Java suporta multiprocessamento no nàvel de linguagem com a adição de sofisticada
sincronização.
Tipos primitivos
Os tipos inteiros em Java são: byte (8 bits); short (16 bits); int (32 bits) e long (64 bits). O
tipo byte (8 bits) em Java veio a substituir o antigo tipo char (C e C++). Não hí nada em
Java para especificar um tipo inteiro sem sinal como em C e C++.
O tipo de ponto flutuante em Java pode ser o float (32 bits) e o double (64 bits). Os
operadores aritméticos seguem o padrão IEEE 754 1.
O tipo char declarado em Java define um caracter de 16 bits, seguindo o padrão Unicode
(um código anílogo ao ASCII que define caracteres para todas as lànguas, como um código
universal).
Os tipos booleanos em Java, diferentemente dos similares em C, não podem ser convertidos
para nenhum tipo numérico. Valores booleanos em Java assumem apenas true ou false.
Todos os tipos primitivos têm valores default. Todos os tipos numéricos são inicializados
para 0, o tipo caracter é inicializado para o Unicode 0 e variíveis do tipo booleano são
inicializados para false.
Tipos Compostos
As uniões disjuntas, produtos cartesianos e conjuntos de potência foram eliminados em
Java. Os dois primeiros foram deixados de lado pois sendo Java uma linguagem orientada a
objetos, as classes substituem essas construções. Jí os conjuntos de potência são supridos
como classes da API (a classe BitSet). Tipos recursivos são suportados.
Todos os tipos em Java que não são primitivos são tipos de referência a objetos, incluindo
arrays.
Ao contrírio de C e C++, os arrays em Java são objetos de primeira classe. É possàvel ao
programador declarar arrays de qualquer tipo, e ainda declarar arrays de arrays para
vetores multidimensionais.
Um array em Java, como qualquer outro objeto deve ser alocado dinamica e explicitamente
com o operador new. Uma vez que o objeto é alocado e tem um certo tamanho, este não
muda. Tais procedimentos garantem mais confiabilidade ao código escrito em Java, jí que
ficam eliminados os erros por violação de memória e perda de dados durante a execução
do programa. Se o programador viola os limites de um vetor, é gerada uma exceção.
De acordo com as definições descritas acima, pode-se classificar os arrays em Java como
semi-dinâmicos, semelhante aos arrays em Ada.
O acesso aos elementos do array segue o estilo de indexação de C. Porém, no momento
em que é feita qualquer referência a um desses elementos é checado o tamanho do array
para se verificar se não estí sendo tentado um acesso a um àndice fora do tamanho do
array. Caso isso ocorra, é gerada uma exceção. Arrays não são a única implementação de
vetores existente em Java. A API fornece a classe Vector que possibilidade a construção de
vetores dinâmicos. Vale lembrar que o acesso a essa classe Vector é toda feita através de
métodos e não de operadores de arrays.
Strings em Java são objetos, e não "pseudo-arrays" como em C. Existem duas classes na
API de Java que implementam arrays: StringBuffer e String. A definição da linguagem define a
sobrecarga do operador de adição para a utilização com a classe String, e de literais do tipo
String.
Expressões
Uma expressão em Java pode produzir três resultados:
um valor
uma variível (uma referência a uma variível)
nada (a expressão é void)
As expressões literais providas são de números inteiros e de ponto flutuante, caracter,
booleano e string. Não são suportados agregados, e as expressões condicionais são
suportadas através do operador ternírio (o mesmo de C).
Uma expressão produz nada se e somente se ela é uma chamada a um método de tipo de
retorno void. Tal expressão pode ser usada somente como uma expressão comando,
porque qualquer outro contexto em que uma expressão possa ser usada requer que a
expressão produza um valor ou uma variível. Uma expressão que é uma chamada a um
método pode ter o seu valor de retorno silenciosamente descartado. Além disso, a
execução de expressões pode produzir efeitos colaterais, pois além de chamadas a funções
e atribuições, expressões podem conter operadores como ++ e --.
Variíveis
Em Java, como foi dito anteriormente, qualquer variível que não seja de um tipo primitivo é
uma variível de referência a um objeto. Daà concluàmos que somente as variíveis de tipos
primitivos são realmente storables. Todas as variíveis de referência tem campos que podem
ser atualizados seletivamente.
Além de todas variíveis de tipos compostos (não primitivos) serem referências, estas tem
ter seus objetos alocados explicita e dinamicamente através do operador new, e não é
permitido o uso de variíveis não inicializadas. Isto serí discutido adiante no tópico que se
refere a orientação a objetos. Vale lembrar que todos os problemas de ponteiros foram
eliminados, através da ausência de ponteiros (e consequentemente aritmética de ponteiros) e
com a existência do garbage collector. As variíveis de referência suprem a funcionalidade
ponteiros para a criação de listas encadeadas e outras estruturas de dados que dependem
da noção de ponteiro, apesar de não poderem ser de-referenciadas. As variíveis de
referência a objetos têm valor default null, ou seja, não apontam para nenhum objeto.
Java faz o maior esforço para fazer a checagem de tipos em tempo de compilação. Uma
variível de referência a um objeto pode guardar uma referência a um objeto cujo tipo em
tempo de compilação pode ser convertido sem o uso de type casting. Veremos isso
adiante. Java utiliza equivalência nominal, o que era de se esperar de uma linguagem
orientada a objetos, jí que permite a construção de tipos abstratos em que a implementação
(estrutura interna dos dados) é ignorada.
Em Java, as variíveis locais são declaradas e alocadas dentro de um bloco e são
descartadas na saàda do bloco. Parâmetros de métodos também são consideradas variíveis
locais.
Variíveis constantes são definidas com a palavra chave final. Estas devem ser inicializadas
da declaração, e não poderão ser modificadas (amarrações para valor). Podem também ser
declaradas como volatile, o que quer dizer que sabe-se que elas serão modificadas
assincronamente. Isso quer dizer que as variíveis que são declaradas como volatile serão
carregadas e salvadas na memória a cada uso, de forma que possam estar coerentes em
multiprocessadores.
Comandos
Os comandos de controle de fluxo são extremamente semelhantes aos de C, com exceção
do goto, que apesar de ser uma palavra reservada na linguagem não é implementado. Todos
os comandos são sequenciais.
Os comandos de seleção são o if e o switch, sendo o if de caminho simples (com else) e o
switch de múltiplos caminhos:
if ( Expressão ) bloco_de_comandos else bloco_de_comandos
switch ( Expressão ) {
case ExpressãoConstante : bloco_de_comandos
case ExpressãoConstante : bloco_de_comandos
default : bloco_de_comandos
}
Os de iteração são while, do while e for.
while ( Expressão ) bloco_de_comandos
do bloco_de_comandos while ( Expressão );
for ( ExpressãoInicialização; Expressão; ExpressãoAvanço );
Os comandos de escapes englobam o return, o continue, o break e o throw.
O return é utilizado para interromper a execução de um método, especificando a expressão
de retorno, ou não, se o método não for void.
O break transfere o controle para o final da iteração no qual estí inserido, ou encerra a
execução de um switch. O continue transfere o controle para o ponto de continuação do
loop de um comando de iteração. Ambos break e continue podem ser acompanhados de
identificadores que especificam a qual dos loops externos estamos nos referindo, jí que
existe a possibilidade de amarrar labels a comandos de iteração.
O throw "dispara", "joga" uma exceção, desviando o fluxo para o bloco de tratamento de
exceções ou interrompendo o programa.
Além destes comandos existem os chamados guarding statements que estabelecem
condições para o tratamento de exceções e multithreading. São eles o try, o synchronized,
o catch e o finally (serão explicados posteriormente nas seções de tratamento de exceções e
concorrência).
Java e a Orientação a Objetos
A orientação a objetos tem provado seu valor nos últimos quase 30 anos, e é inconcebàvel que uma
linguagem de programação moderna não seja orientada a objetos. Na especificação da linguagem Java
[2] ela é definida como "uma linguagem orientada a objetos baseada em classes", e portanto provê essas
caracteràsticas mànimas, suficientes para possibilitar modularização, proteção e reutilização:
Encapsulamento - Ocultamento de Informações (Information Hiding) e modularidade (abstrações)
Polimorfismo - a mesma mensagem enviada a diferentes objetos resultam em um comportamento que
depende da natureza dos objetos recebendo a mensagem.
Herança - novas classes são definidas em termos de classes existentes, possibilitando o reuso de
código.
Amarração Dinâmica - os objetos são possivelmente amarrados em tempo de execução, o que quer dizer
que um objeto pode ser até passado por uma rede. A amarração dinâmica provê flexibilidade em tempo
de execução, e é a chave para o polimorfismo real.
As caracteràsticas da orientação a objetos de Java são similares às de C++. A maior diferença entre elas é
que Java parece ter achado uma boa solução para substituir a herança múltipla. Todos os tipos de
dados, com exceção dos primitivos, são classes.
Classes
Uma classe é uma construção de software que define variíveis de instância e métodos de um objeto.
Uma classe não é um objeto, uma classe é a "definição" de como um objeto se comportarí quando este
for criado ou instanciado.
A declaração bísica de uma classe em Java é a seguinte:
class nome {
// informações sobre a classe
}
Abaixo temos um exemplo de uma classe muito simples:
class Pessoa {
public String Nome; /* variível de instância */
public String Telefone; /* variível de instância */
}
Objetos - Instâncias de uma Classe
Para utilizarmos uma classe nós devemos instanciar objetos. Em Java isto quer dizer que criaremos uma
referência para um objeto (não existe a idéia de um tipo expandido como em Eiffel [6] e amarrações para
valores são possàveis somente para tipos primitivos) - com um fragmento de código como este:
Pessoa meuAmigo;
// declara uma variível que faz referência a um objeto da classe Pessoa
meuAmigo = new Pessoa();
// aloca uma instância de um objeto da classe Pessoa
É possàvel acessar uma variível do objeto de uma classe através do nome da variível, qualificando o
mesmo com o nome do objeto, da mesma forma com que acessamos uma estrutura em C. Por exemplo:
meuAmigo.Nome = "Fulano de Tal";
// atribuição à variível de instância Nome da variível de objeto meuAmigo
Todo objeto deve ser alocado dinamica e explicitamente através do operador new, e deve ser inicializado
antes de ser usado. Uma variível de objeto que não se refere a nenhum objeto deve ter o valor null. Um
erro de tempo de execução ocorre se for utilizado um ponteiro não inicializado ou null.
Um objeto em Java pode ser visto de forma aníloga a ponteiros para objetos em C++. Se você copia uma
variível para outra, ambas se referem ao mesmo objeto, são "ponteiros" para o mesmo objeto. A
diferença reside que, em C++, é muito fícil se criar ponteiros "ruins" (usando aritmética de ponteiros,
não existente em Java) ou termos problemas de objetos e referências pendentes. O garbage collector
garante que tais problemas não ocorrerão.
Construtores
Ao declarar uma classe em Java, opcionalmente definimos construtores. Construtores fazem a
inicialização de objetos ao serem instanciados. Os construtores são métodos com o mesmo nome da
classe e que não têm tipo de retorno especificado.
Quando um objeto é criado (instanciado), o método construtor apropriado é automaticamente invocado,
para, por exemplo, dar um estado inicial ao objeto. Se uma classe não contém declarações de
construtores, então um construtor default é fornecido automatica e implicitamente.
Um construtor só pode ser chamado com a palavra chave new, e não pode ser aplicado a um objeto
existente.
Exemplo:
class Pessoa {
public String Nome; /* variível de instância */
public String Telefone; /* variível de instância */
Pessoa() { /* construtor default */
Nome = "";
Telefone = ""; }
Pessoa(String N, String T) {
Nome = N;
Telefone = T; }
}
Pessoa outroAmigo = new Pessoa("Fulano 2","444-4444");
// acima temos um exemplo de utilização de construtor:
outroAmigo.Pessoa("XXX","222");
/* ERRO! construtores só podem ser utilizados para
instanciar elementos com new */
Métodos / Mensagens
Métodos são a forma com que os objetos interagem entre si. Na orientação a objetos, para se atingir
encapsulamento e proteção, todas as interações entre objetos (ditas mensagens) devem ser feitas
através dos métodos de uma classe. Não hí funções e procedimentos em Java, haja vista que a
programação procedural foi totalmente substituàda. Mesmo assim, a forma de se invocar métodos em
Java se assemelha à de funções em C e C++. Qualquer método pertence a uma classe, e deve ser definido
dentro do corpo da mesma.
Podemos como exemplo modificar a nossa classe Pessoa:
class Pessoa {
private String Nome; /* variível de instância */
private String Telefone; /* variível de instância */
Pessoa() { /* construtor default */
Nome = "";
Telefone = ""; }
Pessoa(String N, String T) {
Nome = N;
Telefone = T; }
public void mudaNome(String Nome) {
this.Nome = Nome;
}
public String leNome() {
return Nome;
}
public String leTelefone() {
return Telefone;
}
}
No exemplo acima as variíveis de instância Nome e Telefone foram precedidas pela palavra chave
private, o que quer dizer que essas variíveis só poderão ser acessadas por métodos da classe à qual
pertencem.
No exemplo acima utilizamos a palavra chave this. Essa variível se refere ao objeto que estí recebendo a
mensagem, ou seja, o objeto no qual o método estí sendo aplicado (Em C++ this é o ponteiro para o
objeto que recebe a mensagem, e em Java é a referência para esse objeto).
Invocando esses métodos qualificamos o nome do método com o nome do objeto:
Pessoa meuAmigo = new Pessoa("Fulano de Tal","999-9999");
meuAmigo.mudaTelefone("222-2222");
/* invocamos o método mudaTelefone da classe Pessoa sobre o objeto meuAmigo,
ou melhor, mandamos uma mensagem mudaTelefone para o objeto meuAmigo. */
Java permite a sobrecarga independente de contexto de métodos, mas não permite a sobrecarga de
operadores. Para sobrecarregarmos um método basta declararmos outro método de mesmo nome com
uma assinatura diferente (tipo e ordem dos parâmetros formais).
Métodos podem ser declarados nativos, utilizando a palavra chave native. Isto quer dizer que eles serão
implementados de forma dependente de plataforma, por exemplo em C ou assembly. Java trata um
método nativo como outro qualquer.
Destrutores
Além de construtores, a linguagem provê a construção de métodos destrutores. Os destrutores são
métodos responsíveis por liberar os recursos alocados durante a vida de um certo objeto. Eles são
invocados automaticamente pelo garbage collector, imediatamente antes deste "recolher" um objeto.
Esse método deve se chamar finalize.
/* Fecha um arquivo aberto quando o garbage collector atua */
protected void finalize() {
try {
file.close();
} catch (Exception e) {
}
}
O exemplo acima mostra um tàpico caso em que o seu objeto deve liberar os recursos alocados do
sistema operacional, como por exemplo fechar descritores de arquivos, liberar contextos em ambientes
gríficos, etc.
Herança
A herança é um mecanismo através do qual novas e mais especializadas classes podem ser definidas em
termos de classes pré-existentes. Um exemplo é a criação de uma classe Funcionario, como uma
subclasse de Pessoa. Em Java:
class Funcionario extends Pessoa {
// Novos métodos e instâncias podem ser inseridos aqui
}
class Secretaria extends Funcionario {
...
}
class Gerente extends Funcionario {
...
}
A palavra chave extends diz que Funcionario é uma subclasse de Pessoa, chamada de classe base.
Dizemos que Funcionario herda as caracteràsticas de Pessoa, jí que este reutilizarí boa parte do código e
funcionalidade descrita na classe Pessoa.
class Funcionario extends Pessoa {
private float salario;
public Funcionario(String Nome, String Telefone,
float salario) { super(Nome,Telefone);
this.salario = salario;
}
public Funcionario aumenta_salario(float aumento) {
salario = salario + aumento;
}
}
A classe Funcionario herda as variíveis de instância Nome e Telefone, e os métodos (mudaTelefone,
leTelefone, leNome) da classe Pessoa, com a exceção dos construtores. Nesse caso devemos criar novos
construtores que façam, opcionalmente, na primeira linha do corpo, uso da palavra chave super para se
referir ao construtor da superclasse, como no construtor do exemplo acima. Se a subclasse não tem
definições de construtores, o construtor super() é invocado, ou seja, o construtor default da classe
imediatamente superior.
Toda classe em Java é subclasse (não necessariamente imediata) da classe Object. Quando não
utilizamos a palavra chave extends numa declaração de classe, implicitamente esta se torna subclasse
imediata de Object.
Uma referência a um objeto da superclasse B (ou classe base) pode também ser referência de uma
subclasse S de B. Jí o contrírio exige o uso de type casting, ou seja a coerção (coercion) deve ser
explàcita.
Object o;
Pessoa fulano;
Funcionario contador1 =
new Funcionario("Fulano de Tal","222-2222");
Pessoa meuAmigo =
new Pessoa("Amigo da Onça","555-5555");
fulano = contador1; // ok! um funcionírio é uma pessoa
o = contador1; // a classe Funcionario é derivada indireta de Object
contador1 = meuAmigo;
// ERRO! meuAmigo é da classe pessoa, que é uma superclasse de Funcionario
contador1 = (Funcionario) meuAmigo;
// com a utilização de type casting esta conversão se torna possàvel
Se for necessírio modificar um método da classe superior, ou especializí-lo, é possàvel declarando-se um
método de mesma assinatura na subclasse. Não é possàvel sobrepor um método declarado como final.
Ao contrírio de C++, no qual as funções virtuais devem ser declaradas como tal, em Java, por default, as
funções são virtuais. Para acessarmos o método "sobreposto" (overrided) utilizamos o seletor super,
que é, na verdade uma referência à superclasse, equivalente a ((superclasse)this).
Java implementa herança simples, ao contrírio de C++ e Eiffel que implementam herança múltipla. Isso
quer dizer que uma classe só pode ter uma superclasse imediata. Isso pode, a primeira vista, parecer uma
caracteràstica limitante, mas em Java o conceito de Interfaces (presente também no Objective C como
protocols) faz com que a linguagem não perca o seu poder expressivo.
Polimorfismo
O polimorfismo é uma das caracteràsticas marcantes de linguagens orientadas a objetos. Ela permite que
a mesma mensagem enviada a diferentes objetos resultem em um comportamento que depende da
natureza dos objetos recebendo a mensagem, ou seja, permite a construção de abstrações que operem
uniformemente sob uma famàlia de tipos relacionados.
Quando uma mensagem é enviada para um objeto de uma subclasse em Java:
A subclasse checa se ela tem um método aquele nome e com exatamente os mesmos parâmetros. Se a
resposta for positiva, ela usa esse método.
Caso contrírio, Java envia a mensagem à classe imediatamente superior.
Se toda a hierarquia for caminhada sem que um método apropriado seja encontrado um erro em tempo de
compilação ocorre.
A amarração dinâmica é a chave para o polimorfismo. O compilador não gera código em tempo de
compilação para uma chamada de método, ele gera código para determinar que método chamar em tempo
de execução usando a informação de tipo disponàvel para o objeto.
Java não suporta abstrações genéricas, como o template de C++. Essa funcionalidade é implementada
com a utilização da classe Object. Uma clara diferença dessa falta é que ele permite uma flexibilidade
muito grande, que deve ser administrada corretamente pois pode ser perigosa. Vamos tomar como
exemplo uma lista de Object. Essa lista pode conter Funcionarios, Retangulos, Frutas, etc. Jí em C++ ou
Eiffel, na declaração do tipo genérico teràamos a criação de uma nova abstração especàfica para um certo
tipo. Tomando C++ como exemplo, criaràamos uma lista<Funcionario> e teràamos um novo tipo que
somente aceitaria Funcionarios.
Controle de Acesso
Ao declararmos uma classe em Java, indicamos o nàvel de acesso permitido para suas instâncias e
métodos. Existem quatro nàveis, e três modificadores: public, protected, e private. Definimos também o
nàvel de acesso da classe inteira, existindo apenas o nàvel public e o "friendly".
O nàvel public permite o acesso ilimitado, o protected significa que os campos são acessàveis somente
em subclasses, e o private que são acessàveis somente dentro da classe onde são declarados. O quarto
nàvel não tem um nome, mas é freqüentemente chamado de "friendly". Esse é o nàvel default. Ele indica
que os campos são disponàveis para todos objetos dentro daquele pacote (package).
Os packages em Java são coleções de classes que têm nomes hierírquicos. Ao utilizar um pacote, o seu
código deve incluir uma clíusula import, ou qualificar os métodos, variíveis e constantes utilizadas. Isso
permite que você distribua adequadamente suas "bibliotecas" de classes e que essa classes sejam
utilizadas em outros programas.
import java.net.*; // importa todas as classes do pacote java.net
import java.util.Bitset;
// importa somente a classe BitSet do pacote java.util
java.util.Date hoje = new java.util.Date();
/* utilizando a classe Date dentro de java.util, pacote que não
foi completamente importado */Variíveis e Métodos de Classe
Normalmente quando definimos variíveis em uma classe definimos variíveis de instâncias. Para cada
objeto criado uma nova variível de instância é criada, e utilizada apenas para representar o estado deste
objeto. Jí as variíveis de classe são compartilhadas por todos objetos de uma classe, sendo utilizadas
para representar o estado de toda uma classe. Jí os métodos de classe servem para manipular as
variíveis de classe, e não podem, de forma alguma manipular variíveis de instâncias, ou invocar
métodos de instâncias.
Para declarar variíveis ou métodos de classe, utilizamos o modificador static:
class Vendedor extends Funcionario {
private static float comissao = 2.5;
public void static mudaComissao(float c) {
comissao = c;
}
/* a comissão de todos os vendedores de uma loja é a mesma,
logo ela deve ser declarada como uma variível de classe */
}
Classes e Métodos Abstratos
Classes Abstratas são construções poderosas no paradigma da orientação a objetos. Elas têm grande
influência sobre a etapa de design, principalmente na concepção das relações de hierarquia entre as
classes.
Ao subirmos na hierarquia de herança, as classes se tornam cada vez mais gerais e provavelmente mais
abstratas. Hí um ponto em que elas são tão abstratas que as vemos como uma representação para
derivação de outras classes, ao invés de as observarmos como classes das quais objetos serão criados.
Métodos abstratos são aqueles que não podem ser implementados em classes tão abstratas, mas que
devem ser implementados em subclasses. Uma classes deve ser declarada abstrata se ela tem pelo menos
um método abstrato (os métodos abstratos eqüivalem às funções virtuais puras de C++ e às deffered
features de Eiffel)
Para declararmos métodos e classes abstratas devemos utilizar a palavra chave abstract. Classes
abstratas não têm construtores nem podem ser instanciadas.
class FormaGeometrica extends Object {
protected Ponto centro; // centróide da forma geométrica
public void mudaCentro(Ponto centro) {
this.centro = centro;
}
abstract void desenha(); // método abstrato }Interfaces
Uma declaração de uma interface declara um tipo que consiste num conjunto de métodos e constantes
sem especificar a sua implementação. Interfaces podem ser bons substitutos para classes abstratas sem
nenhuma implementação, e fornecem o poder da herança múltipla de interfaces, sem a confusão causada
pela herança múltipla de classes (que por sua vez contêm implementação). Uma interface pode herdar
suas caracteràsticas de diversas superinterfaces.
Quando uma classe é declarada ela pode opcionalmente fornecer uma lista de interfaces as quais são
implementadas por ela. Assim sendo, ela se torna responsível por fazer tal implementação. Uma
subclasse de uma classe que implementa alguma interface automaticamente herda a implementação
dessa interface.
Um exemplo claro é a implementação de uma interface Ordenavel:
public interface Ordenavel {
public int compara(Ordenavel a);
/* compara elementos, retornando positivo para maior que,
negativo para menor que, e zero para iguais */
}
/* classe que implementa a interface Ordenavel,
lembre-se que interfaces declaram novos tipos, logo podem
ser utilzados como parâmetros formais */
class Circulo extends FormaGeometrica
implements Ordenavel, ... {
private float raio;
public void desenha() {
...
}
public int compara(Ordenavel a) {
Circulo ca = (Circulo) a;
return raio - a.raio;
}
}
Concorrência (Threads)
A concorrência permite que vírias partes do seu software estejam rodando simultaneamente. Usuírios
de computadores sofisticados tornam-se impacientes ao fazer uma coisa de cada vez em seus
computadores pessoais.
Infelizmente os programadores que necessitam de concorrência em linguagens como C e C++ enfrentam
muitas dificuldades, jí que essas linguagens não suportam diretamente multithreading. Java o faz a
nàvel da linguagem e com classes apropriadas em sua API, com multitarefa pre-emptiva.
A nàvel da linguagem, métodos declarados synchronized não rodam simultaneamente. Tais métodos
rodam sob o controle de monitores que se asseguram que as variíveis permanecerão em um estado
consistente. Java faz o controle de locks automaticamente, sem que o usuírio precise se preocupar.
Para criarmos um objeto que rode em outra thread simplesmente derivamos a nossa classe da classe
Thread, ou implementamos a interface Runnable. A partir de então, sobrecarregamos o método run() com
o código desejado. Quando instanciamos um objeto dessa classe e invocamos o seu método start(), este
imediatamente retornarí e a aplicação ficarí sendo executada em background. Além da simplicidade de
se trabalhar com threads existe a possibilidade do controle de prioridades.
class PingPongThread extends Thread {
String mensagem;
int atraso;
PingPongThread(String mensagem, int atraso) {
this.mensagem = mensagem;
this.atraso = atraso;
start();
}
public void run() {
while (true) { // loop infinito
System.out.println(mensagem);
// imprimimos a mensagem
sleep(atraso); // geramos o atraso
}
}
}
new PingPongThread("ping",500);
new PingPongThread("pong",600);
Esse trecho de código cria dois objetos que rodarão em diferentes threads. As mensagens de "ping" e
"pong" serão intercaladas na tela.
Tratamento de Exceções
O tratamento de exceções permite que um erro seja tratado pelo programador, ou seja, que ele tome
decisões acerca de erro ocorrido. A missão principal do tratamento de exceções é transferir o controle do
ponto onde o erro ocorreu para um tratador de exceção que sabe como lidar com a situação.
O modelo de tratamento de exceções de Java é similar ao de Delphi e C++. Existe uma hierarquia de
exceções, implementadas como classes, pré-definidas. Isso não descarta, de forma alguma, a
possibilidade do programador criar as suas próprias classes de exceções, derivando subclasses dessa
hierarquia. Abaixo temos um diagrama simplificado da hierarquia de exceções em Java:
A hierarquia Error descreve erros internos e escassez de recurso do sistema Java. Programadores não
deve "jogar" exceções desse tipo, e sim aqueles da hierarquia Exception.
Para criar um trecho de código que trate uma exceção, você deve fazer uma construção try/catch. Além
disso, na declaração do método onde uma exceção vai ser possivelmente jogada é necessíria a inclusão
de uma especificação de exceção.
class Nome_da_Classe {
...
tipo_de_retorno Método (parâmetros formais)
throws Tipo_de_Exceção1, Tipo_de_Exceção2
{
try {
bloco de código
...
}
catch (TipodaExeceção e)
{
tratador para esse tipo de exceção
}
catch (OutroTipodaExeceção e)
{
tratador para esse tipo de exceção
}
finally
{
código que serí executado até mesmo
na presença de uma exceção
}
}
Para "jogar" uma exceção, usa-se o comando throw. Quando um comando throw é encontrado, a
execução normal do programa é suspensa, enquanto um tratador adequado é procurado. A clíusula
catch que melhor se adequar para o tratamento daquela exceção serí executada, respeitando a seguinte
ordem:
1.O tipo de exceção da clíusula catch é exatamente da exceção jogada.
2.O tipo de exceção é uma superclasse daquela jogada.
3.O tipo de exceção é uma interface que a exceção jogada implementa.
Qualquer código dentro do bloco try depois da clíusula throw não serí saltado. Uma exceção pode ser
jogada novamente dentro de uma clíusula catch se houver necessidade de propagí-la.
Quando um bloco catch completa sua execução, a clíusula finally é procurada. Se esta não existe, a
execução continua na próxima instrução depois do bloco try. Uma clíusula finally é usada para a parte
do código que deve ser executada mesmo se uma exceção ocorrer.
Se uma exceção não é tratada num método, a execução deste é cancelada e a exceção é propagada para o
método chamador. Se ela não for tratada em lugar algum, a aplicação é interrompida com uma mensagem
(no caso de aplicações gríficas a mensagem é mostrada mais a aplicação não é encerrada).
Conclusões
Java parece ser uma linguagem razoavelmente simples, se, comparada a C++. Muitas das caracteràsticas
de C++ indesejadas e herdadas de C foram eliminadas. Ainda assim com certeza é familiar a
programadores C/C++. É uma linguagem significativamente segura, com a ausência de ponteiros e
garbage collecting. Permite a programação em larga escala, através da orientação a objeto, com
proteção, encapsulamento, reuso de código e outras caracteràsticas desejíveis em uma linguagem de uso
geral. Concorrência e tratamento de exceções são duas caracteràsticas que se destacam na linguagem,
uma preocupação de linguagens modernas, assim como a sua natureza portítil / interpretada. A
linguagem não provê abstrações genéricas, o que consideramos uma falta (apesar de que é possàvel criar
abstrações que possam tratar quaisquer objetos). As interfaces parecem ser uma boa idéia para a
substituição de herança múltipla de classes.
Apesar de suas vantagens como linguagem de programação, Java tem a desvantagem de ser uma
linguagem ainda muito nova. A falta de ambientes de desenvolvimento e ferramentas estí sendo
rapidamente suprida, jí que a linguagem chamou muita atenção da comunidade de programadores.
Esperamos que em breve teremos muitos sistemas desenvolvidos para Java, jí que as próximas versões
de sistemas operacionais para microcomputadores como o Windows e o OS/2 estarão incluindo a
míquina virtual Java. Além disso, existem projetos em andamento para a construção de um processador
Java que acelerarí a execução de aplicações executando o código binírio Java em hardware.
Bibliografia
[1] GOSLING, James e McGILTON, Henry, The Java Language Environment - A White Paper , Sun
Microsystems Computer Corporation, Outubro de 1995.
[2] The Java Language Specification - Version 1.0 Beta, Sun Microsystems Computer Corporation,
Beta Draft of October 30, 1995.
[3] RITCHEY, Tim, Programming with Java! Beta 2.0, Ed. New Riders, 1995.
[4] CORNELL, Gary e HORSTMANN, Cay, Core Java, Ed. Prentice Hall.
[5] Object-Oriented Languages in the Industry: A Comparison
http://www.eiffel.com./doc/manuals/tech ... index.html
[6] MEYER, Bertrand, An Invitation to Eiffel, http://www.eiffel.com/doc/manuals/language/intro
By: Loost :XTibia_smile: