2 capítulo 1: declarações e controles de acessolivrariamarcafacil.com.br/pdf/83030.pdf · esses...

48

Upload: dokhue

Post on 10-Dec-2018

213 views

Category:

Documents


0 download

TRANSCRIPT

2 Capítulo 1: Declarações e Controles de Acesso

Nós partiremos do princípio de que, uma vez que está planejando obter a certificação, você já sabe o básico deJava. Caso seja completamente iniciante na linguagem, este capítulo – e o restante do livro – será confuso, então,certifique-se de que você sabe pelo menos o básico da linguagem antes de mergulhar neste livro. Dito isso,começaremos com uma revisão para refrescar a sua memória sobre Java, caso tenha estado afastado da linguagempor algum tempo.

Revisão de JavaUm programa em Java é principalmente uma coleção de objetos falando com outros objetos por meio dainvocação dos métodos uns dos outros. Cada objeto é de um tipo, e esse tipo é definido por uma classe ou umainterface. A maioria dos programas em Java usa uma coleção de objetos de muitos tipos diferentes.

Classe Um modelo que descreve os tipos de estado e de comportamento que os objetos do seu tipo podem ter.

Objeto No momento da execução, quando a Máquina Virtual Java (Java Virtual Machine, ou JVM) encontra apalavra-chave new, ela usa a classe apropriada para criar um objeto que será uma instância dessa classe. Esseobjeto terá o seu próprio estado e terá acesso a todos os comportamentos definidos pela sua classe.

Estado (variáveis de instâncias) Cada objeto (instância de uma classe) terá o seu conjunto único de variáveisde instâncias conforme definido na classe. Coletivamente, os valores atribuídos às variáveis de instâncias deum objeto compõem o estado do objeto.

Comportamento (métodos) Quando um programador cria uma classe, ele cria métodos para essa classe. Énos métodos que a lógica da classe é armazenada. Nos métodos, o verdadeiro trabalho é realizado. É neles queos algoritmos são executados e que os dados são manipulados.

Identificadores e Palavras-chaveTodos os componentes de Java de que acabamos de falar – classes, variáveis e métodos – precisam de nomes. EmJava, esses nomes são conhecidos como identificadores e, como seria de se esperar, existem regras dizendo comodevem ser os identificadores Java permitidos. Independentemente do que é permitido, no entanto, osprogramadores Java (e a Sun) criaram convenções para a nomeação de métodos, variáveis e classes. Como todas aslinguagens de programação, Java tem um conjunto de palavras-chaves internas. Essas palavras-chave não podemser usadas como identificadores. Mais adiante neste capítulo, veremos os detalhes sobre essas regras e convençõesde nomeação, e sobre as palavras-chave Java.

HerançaFundamental para Java e outras linguagens orientadas a objetos é o conceito de herança, que permite ao códigodefinido em uma classe ser reutilizado em outras classes. Em Java, você pode definir uma superclasse geral (maisabstract), e depois estendê-la com subclasses mais específicas. A superclasse não sabe nada sobre as classes queherdam dela, mas todas as subclasses que herdam da superclasse precisam declarar explicitamente a relação deherança. Uma subclasse que herda de uma superclasse recebe automaticamente as variáveis de instânciasacessíveis e os métodos definidos pela superclasse, mas é também livre para substituir métodos da superclassepara definir comportamentos mais específicos.

Por exemplo, uma superclasse Carro poderia definir métodos gerais comuns a todos os automóveis, mas umasubclasse Ferrari poderia substituir o método acelerar().

InterfacesUm poderoso companheiro da herança é o uso das interfaces. A interface é uma espécie de superclasse 100%abstract que define os métodos que uma subclasse deve suportar, mas não como esse suporte deve serimplementado. Em outras palavras, uma interface Animal poderia declarar que todas as classes de implementaçãode Animal devem ter um método comer(), mas a interface Animal não fornece nenhuma lógica para o métodocomer(). Isso significa que fica a cargo das classes que implementam a interface Animal a definição do códigopara como cada tipo particular de Animal se comporta quando o seu método comer() é invocado.

Encontrando Outras ClassesComo veremos mais adiante no livro, é uma boa idéia manter a coesão das suas classes. Isso significa que cadaclasse deve ter um conjunto bem definido de responsabilidades. Por exemplo, se fosse criar um programa desimulação de um zoológico, você representaria javalis com uma classe, e visitantes do zoológico com outra. Alémdisso, você poderia ter uma classe Tratador de Animais, uma classe Vendedor de Pipoca e assim por diante. Aquestão é que você não deve ter uma classe que tenha comportamentos de Javali e Vendedor de Pipoca ao mesmotempo (falaremos mais sobre isso no Capítulo 3).

3

Até mesmo programas Java simples usam objetos de muitas classes diferentes: algumas que você criou, e algumas criadas poroutros (tais como as classes Java API da Sun). Java organiza as classes em pacotes, e usa declarações import para dar aosprogramadores uma forma consistente de gerenciar a nomeação das classes de que precisam e o acesso a elas. O exameaborda vários conceitos relacionados aos pacotes e ao acesso a classes; exploraremos os detalhes neste e em outros capítulos.

Objetivo para a CertificaçãoObjetivo para a CertificaçãoObjetivo para a CertificaçãoObjetivo para a CertificaçãoObjetivo para a Certificação

Identificadores e JavaBeans (Objetivos 1.3 e 1.4)1.3 Desenvolver código que declare, inicialize e use primitivos, arrays, enums e objetos como variáveis static, de instâncias e locais. Alémdisso, usar identificadores legais para nomes de variáveis.

1.4 Desenvolver código que declare métodos static e não-static e, se apropriado, usar nomes de métodos que obedeçam aos padrõesde nomeação JavaBeans. Além disso, desenvolver código que declare e use uma lista de argumentos de extensão variável.

Lembre-se de que, quando listamos um ou mais Objetivos para a Certificação no livro, como acabamos defazer, isso significa que as seções a seguir abordarão pelo menos parte desses objetivos. Alguns objetivos serãoabordados em vários capítulos diferentes, de modo que você verá o mesmo objetivo em mais de um lugar dolivro. Por exemplo, esta seção cobre declarações, identificadores e nomeação JavaBeans, mas o uso do que vocêvai declarar será abordado em capítulos posteriores.

Assim, começaremos com os identificadores Java. Os três aspectos dos identificadores Java que abordaremos aqui são:

Identificadores Legais As regras que o compilador usa para determinar se um dado nome é legal.

Convenções de Código Java da Sun As recomendações da Sun para nomeação de classes, variáveis emétodos. Normalmente nós obedecemos a esses padrões em todo o livro, exceto quando estivermos tentando lhemostrar como seria uma questão difícil do exame. Não lhe serão feitas perguntas sobre as Convenções de CódigoJava, mas recomendamos enfaticamente que os programadores as usem.

Padrões de Nomeação JavaBeans Os requisitos de nomeação da especificação JavaBeans. Não é precisoestudar a especificação JavaBeans para o exame, mas você precisa saber algumas regras básicas de nomeaçãoJavaBeans que abordaremos neste capítulo.

Identificadores LegaisTecnicamente, os identificadores legais devem ser compostos apenas de caracteres Unicode, números, símbolosde moedas e caracteres de conexão (como underscores). O exame não mergulha nos detalhes de quais faixas doconjunto de caracteres Unicode qualificam como letras e dígitos. Assim, por exemplo, você não precisará saberque os dígitos em Tibetano vão de \u0420 até \u0f29. Eis aqui as regras que você precisa saber:

Os identificadores devem começar com uma letra, um cifrão ($) ou um caracter de conexão, como o under-score ( _ ). Os identificadores não podem começar com um número!

Depois do primeiro caracter, os identificadores podem conter qualquer combinação de letras, caracteres demoedas, caracteres de conexão ou números.

Na prática, não há limite para o número de caracteres que um identificador pode conter.

Não se pode usar uma palavra-chave Java como identificador. A Tabela 1-1 lista todas as palavras-chave Java,incluindo uma novidade da versão 5.0, enum.

Os identificadores em Java são case-sensitive; foo e Foo são dois identificadores diferentes.

Seguem alguns exemplos de identificadores legais e ilegais; primeiro, identificadores legais:

int _a;

int $c;

int ______2_w;

int _$;

int eis_um_nome_bastante_detalhado_para_um_identificador;

Os seguintes são ilegais (agora você já sabe o por quê):

int :b;

int -d;

Identificadores Legais (Objetivo 1.3 e 1.4 do Exame)

4 Capítulo 1: Declarações e Controles de Acesso

int e#;

int .f;

int 7g;

TTTTTabela 1-1abela 1-1abela 1-1abela 1-1abela 1-1 Lista Completa de Palavras-Chave Java (assert adicionada em 1.4, enum adicionada em 1.5)

abstract boolean break byte case catch

char class const continue default do

double else extends final finally float

for goto if implements import instanceof

int interface long native new package

private protected public return short static

strictfp super switch synchronized this throw

throws transient try void volatile while

assert enum

Convenções de Código Java da Sun

Pelas estimativas da Sun, ao longo da vida útil de um código padrão, 20% do esforço será despendido na criação e noteste originais do código, e 80% do esforço será despendido na manutenção e nas melhorias subseqüentes do código.Concordar com um conjunto de padrões e programá-lo ajuda a diminuir o esforço envolvido em testar, fazer amanutenção e melhorar qualquer código. A Sun criou um conjunto de padrões de programação para Java e publicouesses padrões em um documento inteligentemente chamado de “Convenções de Código Java”, o qual você podeencontrar em java.sun.com. Trata-se de um ótimo documento, curto e fácil de ler, que recomendamos enfaticamente.

Dito isso, você verá que muitas das questões do exame não seguem as convenções de código, devido às limitações doprograma de provas que é usado para ministrar o exame internacionalmente. Uma das boas coisas sobre ascertificações da Sun é que os exames são administrados uniformemente em todo o mundo. Para se conseguir isso, aslistagens de códigos que você verá no exame real freqüentemente são bem bagunçadas, e não seguem os padrões decódigo da Sun. Para prepará-lo para o exame, nós freqüentemente iremos apresentar listagens de códigos com umaaparência igualmente bagunçada, usando apenas dois espaços de parágrafo em vez dos quatro espaços do padrão Sun.

Nós também bagunçaremos nossas chaves de forma artificial, e, em alguns casos, colocaremos várias declaraçõesna mesma linha... oh não! Por exemplo:

1. class Wombat implements Runnable {

2. private int i;

3. public synchronized void run() {

4. if (i%5 != 0) { i++; }

5. for(int x=0; x<5; x++, i++)

6. { if (x > 1) Thread.yield(); }

7. System.out.print(i + “”);

8 }

9. public static void main(String[] args) {

10. Wombat n = new Wombat();

11. for(int x=100; x>0; --x) { new Thread(n).start(); }

12. } }

Considere-se avisado–você verá várias listagens de códigos, questões simuladas e questões de exames reais queserão doentias e incompreensíveis dessa maneira. Ninguém quer que você escreva seu código desse jeito. Nem oseu empregador, nem os seus colegas de trabalho, nem nós, nem a Sun e nem a equipe de elaboração do exame!Esse tipo de código foi criado apenas para que conceitos complexos pudessem ser testados usando-se umaferramenta de provas universal. O único padrão que é seguido tanto quanto possível no exame real é o dos padrões denomeação. Eis os padrões de nomeação recomendados pela Sun, e que usamos no exame e na maior parte do livro:

5

Classes e interfaces A primeira letra deve ser maiúscula e, se várias palavras forem escritas juntas para formaro nome, a primeira letra de cada palavra interna deve ser maiúscula (um formato chamado em inglês de“camelCase”). Para classes, os nomes devem normalmente ser substantivos. Por exemplo:

Dog // Cachorro

Account // Conta

PrintWriter // Impressora

Para interfaces, os nomes devem normalmente ser adjetivos, como:Runnable //Executável

Serializable //Serializável

Métodos A primeira letra deve ser minúscula, e depois as regras camelCase normais devem ser usadas. Além disso, osnomes devem normalmente ser pares de verbo-substantivo. Por exemplo:

getBalance // obterBalanço

doCalculation // fazerCálculo

setCustomerName // definirNomeDoCliente

Variáveis Como nos métodos, o formato camelCase deve ser usado, começando com uma letra minúscula. A Sunrecomenda usar nomes curtos e significativos, o que nos parece uma boa idéia. Alguns exemplos:

buttonWidth // LarguraDoBotão

accountBalance // balançoDaConta

myString //minhaString

Constantes As constantes Java são criadas marcando-se variáveis como static e final. Elas devem sernomeadas usando-se letras maiúsculas com caracteres underscore como separadores:

MIN_HEIGHT // ALTURA_MINIMA

Padrões JavaBeans

A especificação JavaBeans foi criada para ajudar os desenvolvedores a criarem componentes Java que possam serfacilmente usados por outros desenvolvedores em uma ferramenta de Ambiente de Desenvolvimento Integrado(“Integrated Development Environment, ou IDE), como o Eclipse ou o NetBeans. Como um programador Java,você desejará usar componentes da API Java, mas seria excelente se você pudesse também comprar o componenteJava que quisesse no “Mercado Beans”, aquela loja de software que fica na sua rua. E, depois de encontrar oscomponentes, você gostaria de poder acessá-los através de uma ferramenta de desenvolvimento de forma tal quenão precise escrever todo o seu código do zero. Ao usar regras de nomeação, a especificação JavaBeans ajuda agarantir que as ferramentas poderão reconhecer e usar componentes criados por diferentes desenvolvedores. AAPI JavaBeans é um tanto complexa, mas você só precisará estudar alguns fundamentos para o exame.

Primeiramente, JavaBeans são classes Java que têm propriedades. Para os nossos propósitos, pense naspropriedades como variáveis de instâncias private. Uma vez que são private, a única maneira pela qualpodem ser acessadas de fora da sua classe é através de métodos da classe. Os métodos que modificam o valor deuma propriedade são chamados métodos setter, e os métodos que obtêm o valor de uma propriedade são chamadosmétodos getter. As regras de nomeação JavaBean que você precisará saber par o exame são as seguintes:

Regras de Nomeação de Propriedades JavaBean

Se a propriedade não for booleana, o prefixo do método getter deve ser get. Por exemplo, getSize() é umnome getter JavaBeans válido para uma propriedade chamada “size.” Tenha em mente que você não precisa ter umavariável chamada size (embora alguns IDEs vão esperar que você tenha). O nome da propriedade é inferido a partir dosgetters e setters, e não através de quaisquer variáveis da sua classe. O que você irá retornar a partir de getSize()fica a seu critério.

Se a propriedade for booleana, o prefixo do método getter é ou get ou is. Por exemplo, tantogetStopped() quanto isStopped() são nomes JavaBeans válidos para uma propriedade booleana.

O prefixo do método setter deve ser set. Por exemplo, setSize() é o nome JavaBean válido para umapropriedade chamada size (tamanho, em inglês).

Para completar o nome de um método getter ou setter, deve-se mudar a primeira letra do nome dapropriedade para maiúscula e depois juntar a ela o prefixo adequado (get, is ou set).

As assinaturas de métodos setter devem ser marcadas como public, com um tipo de retorno void e umargumento que represente o tipo da propriedade.

Convenções de Código Java Sun (Objetivo 1.3 e 1.4 do Exame)

8 Capítulo 1: Declarações e Controles de Acesso

no código do cliente para o programa TwelvePointOSteps, você daria ao seu pacote um nome comocom.geeksanonymous.steps.client. Isso modificaria o nome da sua classe para com.geeksanonymous.steps.client.Utilities.Ainda assim, você poderia ter colisões de nomes dentro da sua empresa, se não inventar os seus próprios esquemas denomeação, mas garantidamente não haverá colisões com classes desenvolvidas fora da sua empresa (assumindo que elasseguem a convenção de nomeação da Sun; se elas não o fizerem, bem, coisas bastante desagradáveis podem acontecer).

Acesso a ClassesO que significa acessar uma classe? Quando dizemos que o código de uma classe (a classe A) tem acesso a outra(classe B), isso significa que a classe A pode fazer uma das seguintes coisas:

Criar uma instância da classe B.

Estender a classe B (em outras palavras, tornar-se uma subclasse da classe B).

Acessar certos métodos e variáveis dentro da classe B, dependendo do controle de acesso desses métodos e variáveis.

Na prática, acesso significa visibilidade. Se a classe A não puder ver a classe B, o nível de acesso dos métodos evariáveis dentro da classe B não fará diferença; a classe A não terá como acessar esses métodos e variáveis.

Acesso Default Uma classe com acesso default não tem nenhum modificador precedendo-a na declaração!Esse é o controle de acesso que você obtém quando não digita um modificador na declaração da classe. Penseno acesso default como um acesso de nível de pacote, porque uma classe com acesso default só pode servista por classes de dentro do mesmo pacote. Por exemplo, se a classe A e a classe B estiverem em pacotesdiferentes, e a classe A tiver acesso default, a classe B não será capaz de criar uma instância da classe A, enem mesmo declarar uma variável ou tipo de retorno da classe A. Na verdade, a classe B precisa fingir que aclasse A nem sequer existe, ou o compilador irá reclamar. Observe o seguinte arquivo-fonte:

package cert;

class Beverage { }

Agora observe o segundo arquivo-fonte:package exam.stuff;

import cert.Beverage;

class Tea extends Beverage { }

Como você pode ver, a superclasse (Beverage) está em um pacote diferente da subclasse (Tea). A declaraçãoimport no alto do arquivo Tea está tentando (cruze os dedos!) importar a classe Beverage. O arquivo Beveragecompila sem problemas, mas, quando tentamos compilar o arquivo Tea, obtemos algo como:

Can’t access class cert.Beverage. Class or interface must be public, in same package,or an accessible member class.

import cert.Beverage;

Tea não compila porque a sua superclasse, Beverage, tem acesso default e está em um pacote diferente. Forausar nomes de classes totalmente qualificados, o que abordaremos no Capítulo 10, existem duas coisas que vocêpode fazer para consertar isso. Você poderia colocar ambas as classes no mesmo pacote, ou poderia declararBeverage como public, como descrito na seção seguinte.

Quando você vir uma questão com lógica complexa, certifique-se de olhar os modificadores de acesso primeiro.Dessa forma, se descobrir uma violação de acesso (por exemplo, uma classe do pacote A tentando acessar umaclasse default do pacote B), você saberá que o código não vai compilar, então não precisa nem se dar aotrabalho de tentar entender a lógica. Afinal, você tem mais o que fazer com seu tempo ao fazer a prova.Simplesmente marque a resposta ‘A compilação falha’ e passe para a questão seguinte.

Acesso Público Uma declaração de classe com a palavra-chave public dá a todas as classes, de todos ospacotes, acesso à classe pública. Em outras palavras, todas as classes do Universo Java (JU) têm acesso a uma classepública. No entanto, não se esqueça, de que, se uma classe pública que estiver tentando usar estiver em um pacotediferente do da classe que está escrevendo, você ainda precisará importar a classe pública.

No exemplo da seção anterior, talvez não queiramos colocar a subclasse no mesmo pacote que a superclasse.Para fazer o código funcionar, precisamos adicionar a palavra-chave public na frente da declaração dasuperclasse (Beverage), da seguinte forma:

package cert;

public class Beverage { }

Isso modifica a classe Beverage para que ela se torne visível a todas as classes em todos os pacotes. Essa classeagora pode ser instanciada a partir de todas as outras classes, e qualquer classe está agora livre parasubclassificá-la (estender a partir dela) – a não ser que a classe esteja marcada também com o modificadorfinal. Já falaremos sobre isso.

9

Outros Modificadores de Classes (Não-referentes a Acesso)Você pode modificar uma declaração de classe usando as palavras-chave final, abstract, ou strictfp. Essesmodificadores existem em adição a qualquer controle de acesso existente na classe, então você poderia, por exemplo, declararuma classe como public e final ao mesmo tempo. Mas não é sempre que você pode misturar modificadores não-referentes a acesso. Você pode usar strictfp em combinação com final, por exemplo, mas não deve nunca, jamais,marcar uma classe como final e abstract ao mesmo tempo. Você verá por que nas duas próximas seções.

Você não precisará saber como strictfp funciona, então nos concentraremos apenas em modificar uma classecomo final ou abstract. Para o exame, você só precisa saber que strictfp é uma palavra-chave e que pode serusada para modificar uma classe ou um método, mas nunca uma variável. Marcar uma classe como strictfpsignifica que qualquer código de método na classe se conformará às regras do padrão IEEE 754 para pontos flutuantes.Sem esse modificador, os pontos flutuantes usados nos métodos poderão se comportar de forma variante conforme aplataforma. Se não declarar a classe como strictfp, ainda assim você poderá obter um comportamento strictfppara métodos específicos, declarando o método como strictfp. Se você não conhece o padrão IEEE 754, agora não éo momento para aprendê-lo. Você tem assuntos mais importantes para se preocupar.

Classes Finais Quando usada na declaração de uma classe, a palavra-chave final significa que a classe emquestão não pode ser subclassificada. Em outras palavras, nenhuma outra classe pode jamais estender (herdar de)uma classe final, e qualquer tentativa de fazê-lo lhe dará um erro de compilação.

Então por que você sequer marcaria uma classe como final? Afinal de contas, isso não viola toda a noção deherança presente nas linguagens orientadas a objetos? Você só deve marcar uma classe como final se precisarde uma garantia absoluta de que nenhum dos métodos dessa classe jamais vai ser substituído. Caso seu código sejaprofundamente dependente da implementação de certos métodos, usar final lhe dará a segurança de queninguém poderá modificar a implementação sem você saber.

Você perceberá que muitas classes das bibliotecas fundamentais Java são final. Por exemplo, a classe String nãopode ser subclassificada. Imagine a confusão que ocorreria se você não pudesse garantir a forma como um objetoString funcionaria em qualquer sistema que executasse a sua aplicação! Se os programadores tivessem a liberdadede estender a classe String (e assim colocar as suas novas instâncias da subclasse String onde esperam-se instânciasde java.lang.String), a civilização tal como a conhecemos entraria em colapso. Assim, use final para segurança,mas apenas quando tiver certeza de que a sua classe final de fato já disse tudo o que precisa ser dito nos seusmétodos. Marcar uma classe como final significa, na prática, que a sua classe nunca será aprimorada, oumesmo modificada para uso mais específico, por outro programador.

Um benefício de se ter classes não-final é neste cenário: imagine que você encontrou um problema com ummétodo em uma classe que está usando, mas não tem o código-fonte. Assim, você não pode modificar a fontepara melhorar o método, mas pode estender a classe e substituir o método em questão na sua nova subclasse, esimplesmente usar a subclasse em todas as ocasiões em que a superclasse original for esperada. No entanto, se aclasse for final, então não há nada que você possa fazer.

Vamos modificar o nosso exemplo Beverage colocando a palavra-chave final na declaração:package cert;

public final class Beverage {

public void importantMethod() { }

}

Agora, se tentarmos compilar a subclasse Tea:package exam.stuff;

import cert.Beverage;

class Tea extends Beverage { }

Receberemos um erro como:Can’t subclass final classes: class

cert.Beverage class Tea extends Beverage{

1 error

Na prática, você quase nunca criará uma classe final. As classes final acabam com um benefício fundamental daprogramação OO – a extensibilidade. Assim, a não ser que você tenha uma séria preocupação de segurança, assuma quealgum dia algum outro programador precisará estender a sua classe. Se não o fizer, o próximo programador que forobrigado a fazer a manutenção do seu código irá lhe perseguir e <insira algo muito assustador aqui>.

Classes Abstract Uma classe abstract não pode ser instanciada nunca. O seu único propósito, missão navida, raison d’etre, é ser estendida (subclassificada). (Repare, no entanto, que você pode compilar e executar umaclasse abstract, desde que não tente criar uma instância dela.) Por que criar uma classe se você não pode criarobjetos dela? Porque a classe poderia ser simplesmente, bem, abstract. Por exemplo, imagine que você tenha

Declarações e Modificadores de Classes (Objetivo 1.1 do Exame)

10 Capítulo 1: Declarações e Controles de Acesso

uma classe Car que tenha métodos genéricos comuns a todos os veículos. Mas você não quer que alguém de fato crie umobjeto car genérico, abstract. Como se inicializaria o seu estado? De que cor ele seria? Quantos assentos? Potência domotor? Direção hidráulica ou não? Ou, mais importante, de que forma ele se comportaria? Em outras palavras, como osmétodos seriam implementados?

O que você precisa é que os programadores instanciem tipos reais de carros, como BMWBoxster e SubaruOutback.Temos certeza de que o dono de um Boxster lhe diria que o carro dele é capaz de fazer coisas que o Subaru apenas“sonha em fazer”. Observe a seguinte classe abstract:

abstract class Car {

private double price;

private String model;

private String year;

public abstract void goFast ();

public abstract void goUpHill ();

public abstract void impressNeighbors ();

// Coloque o resto do código importante e sério aqui

}

O código acima irá compilar sem problemas. Entretanto, se você tentar instanciar um Car em outro corpo de código,receberá erros de compilação como o seguinte:

AnotherClass.java:7: class Car is an abstract

class. It can’t be instantiated.

Car x = new Car();

1 error

Repare que os métodos marcados com abstract terminam com ponto-e-vírgula, em vez de chaves.

Procure questões com uma declaração de método que termine com ponto-e-vírgula, em vez de chaves. Se o método estiver emuma classe – e não em uma interface –, então tanto o método como a classe devem ser marcados como abstract. Podeaparecer uma questão que lhe pergunte como consertar uma amostra de código que inclui um método que termina componto-e-vírgula, mas sem um modificador abstract na classe ou método. Nesse caso, você poderia ou marcar o método ea classe como abstract, ou modificar o ponto-e-vírgula para o código apropriado (um par de chaves, por exemplo).Lembre-se, se transformar um método de abstract para não-abstract, não se esqueça de trocar o ponto-e-vírgulano final da declaração do método por um par de chaves!

Examinaremos os métodos abstract com mais detalhes mais adiante neste objetivo, mas lembre-se sempre de que, semesmo um só método for abstract, toda a classe deverá ser declarada como abstract. Um método abstractcontamina toda a turma. Você pode, no entanto, colocar métodos não-abstract em uma classe abstract. Porexemplo, você poderia ter métodos com implementações que não devem mudar de acordo com o tipo de Car, tais comogetColor() ou setPrice(). Ao colocar métodos não-abstract em uma classe abstract, você dá a todasas subclasses concretas (e concreto significa apenas não-abstract) implementações de métodos herdadas. A boanotícia é que as subclasses concretas herdam funcionalidades, e precisam implementar apenas os métodos que definemcomportamentos específicos da subclasse.

(A propósito, se você achou que usamos a expressão raison d’etre fora de contexto, anteriormente, não nos mande e-mail.Queremos ver você colocar uma expressão dessas em um livro de certificação para programadores.)

Programar com tipos de classes abstract (incluindo interfaces, que serão discutidas mais adiante neste capítulo)permite que você tire vantagem do polimorfismo, e lhe dá o maior grau possível de flexibilidade e extensibilidade. Vocêaprenderá mais sobre polimorfismo no Capítulo 2.

Não é possível marcar uma classe como abstract e final ao mesmo tempo. Elas têm significados quase opostos.Uma classe abstract precisa ser subclassificada, enquanto que uma classe final não deve ser subclassificada. Se vocêvir essa combinação de modificadores abstract e final, usados para uma declaração de classe ou método, o códigonão irá compilar.

Exercício 1-1Exercício 1-1Exercício 1-1Exercício 1-1Exercício 1-1

Criando uma Superclasse Abstract e uma Subclasse Concreta

O seguinte exercício testará o seu conhecimento de classes public, default, final e abstract . Crie umasuperclasse abstract chamada Fruit e uma subclasse concreta chamada Apple. A superclasse deve pertencer a um pacote

11

chamado food e a subclasse pode pertencer ao pacote default (significando que ela não será colocada em um pacoteexplicitamente). Torne a superclasse publice dê à subclasse acesso default.1. Crie a superclasse da seguinte maneira:

package food;

public abstract class Fruit{ /* insira qualquer código que desejar */}

2. Crie a subclasse em um arquivo separado, da seguinte maneira:import food.Fruit;

class Apple extends Fruit{ /* insira qualquer código que desejar */}

3. Crie um diretório chamado food dentro do diretório configurado no seu class path.4. Tente compilar os dois arquivos. Se quiser usar a classe Apple, certifique-se de colocar o arquivo Fruit.class no subdiretório food.

Objetivo para a CertificaçãoObjetivo para a CertificaçãoObjetivo para a CertificaçãoObjetivo para a CertificaçãoObjetivo para a Certificação

Declarar Interfaces (Objetivos 1.1 e 1.2 do Exame)1.1 Desenvolver código que declare classes (incluindo classes abstract e todas as formas de classes aninhadas), interfaces e enums, e inclua o usoapropriado de declarações package e import (incluindo importações estáticas).

1.2. Desenvolver código que declare uma interface. Desenvolver código que implemente ou estenda uma ou mais interfaces. Desenvolver códigoque declare uma classe abstract. Desenvolver código que estenda uma classe abstract.

Declarando uma interface

Quando você criar uma interface, estará definindo um contrato com o que a classe pode fazer, sem mencionarnada sobre como a classe o fará. Uma interface é um contrato. Você poderia escrever uma interface Bounceable,por exemplo, que estabeleceria: “Essa é uma interface Bounceable. Qualquer tipo de classe que implementar essainterface precisa concordar em escrever o código dos métodos bounce( ) e setBounceFactor( )”.

Se uma interface Bounceable (Saltitante) for definida, qualquer classe que quiser ser tratada como algo saltitantepoderá simplesmente implementar essa interface e fornecer o código de seus dois métodos.

As interfaces podem ser implementadas por qualquer classe, de qualquer árvore de herança. Isso permitirá quevocê use classes radicalmente diferentes e forneça a elas uma característica em comum. Por exemplo, você podequerer que tanto a classe Ball quanto Tire tenham o mesmo comportamento, mas elas não compartilham nenhumrelacionamento de herança; Ball estende Toy, enquanto Tire só estende java.lang.Object. Porém, ao fazer com queBall e Tire implementem Bounceable, você estará dizendo que as duas classes podem ser tratadas como “coisassaltitantes”, o que em Java é traduzido por “coisas que você pode usar para chamar os métodos bounce( )esetBounceFor( )”. A Figura 1-1 ilustra o relacionamento entre interfaces e classes.

FFFFFigura 1-1igura 1-1igura 1-1igura 1-1igura 1-1 A Relação Entre Interfaces e Classes

Declarando uma Interface (Objetivo 1.1 e 1.2 do Exame)

12 Capítulo 1: Declarações e Controles de Acesso

Considere uma interface como uma classe 100% abstract. Como uma classe abstract, a interface definemétodos abstract com a forma,

abstract void bounce(); // Termina com ponto-e-vírgula, em vez de chaves

Mas, enquanto uma classe abstract pode definir tanto métodos abstract quanto não-abstract, umainterface só pode ter métodos abstract. Outro ponto em que as interfaces diferem das classes abstract é queelas apresentam muito pouca flexibilidade em como os métodos e variáveis definidos na interface são declarados. Asregras são restritas:

Todos os métodos de interface são implicitamente public e abstract. Em outras palavras, você não precisa digitarrealmente os modificadores public ou abstract, na declaração do método, mas mesmo assim ele sempre serápublic e abstract.

Todas as variáveis definidas em uma interface devem ser public, static e final – em outras palavras, asinterfaces só podem se declarar constantes e não variáveis de instância.

Os métodos de interfaces não podem ser static.

Já que os métodos de interface são abstract, não podem ser marcados como final, native, strictfp ousynchronized. (Falaremos mais sobre esses modificadores a seguir)

Uma interface pode estender uma ou mais interfaces diferentes.

Uma interface não pode estender nada que não seja outra interface.

Uma interface não pode implementar outra interface ou classe.

Uma interface deve ser declarada com a palavra-chave interface.

Os tipos de interface podem ser usados polimorficamente (consulte o Capítulo 2 para mais detalhes).

A linha a seguir é uma declaração de interface válida:

public abstract interface Rollable { }

Digitar o modificador abstract é considerado redundante; as interfaces serão implicitamente abstract casovocê digite ou não abstract. Só é preciso saber que essas duas declarações são válidas e funcionalmente idênticas:

public abstract interface Rollable { }

public interface Rollable { }

O modificador public será obrigatório se você quiser que a interface tenha acesso público em vez de padrão.

Examinamos a declaração da interface, mas agora nos aprofundaremos nos métodos de uma interface:

public interface Bounceable {

public abstract void bounce();

public abstract void setBounceFactor(int bf);

}

Porém, digitar os modificadores public e abstract nos métodos é redundante, já que todos os métodos deinterface são implicitamente public e abstract. Dada essa regra, você pode ver que o código a seguir éexatamente equivalente a interface anterior:

public interface Bounceable {

void bounce(); // sem modificadores

void setBounceFactor(int bf); // sem modificadores

}

Você precisa lembrar que todos os métodos de interface são public e abstract independente do que estiverna definição da interface.

Procure métodos de interface declarados com qualquer combinação que envolva public ou abstract, ou semmodificadores. Por exemplo, as cinco declarações de método a seguir, se declaradas dentro de uma interface, serãoválidas e idênticas!

void bounce();

public void bounce();

abstract void bounce();

public abstract void bounce();

14 Capítulo 1: Declarações e Controles de Acesso

Qualquer combinação dos modificadores necessários (porém implícitos) é válida, como também o é a nãoutilização de modificadores! No exame, espere encontrar perguntas as quais não poderá responder corretamente,a menos que saiba, por exemplo, que uma variável de interface é final e nunca poderá receber um valor da classeque a estiver implementando (ou de qualquer outra classe).

Objetivo para a CertificaçãoObjetivo para a CertificaçãoObjetivo para a CertificaçãoObjetivo para a CertificaçãoObjetivo para a Certificação

Declarar Membros de Classes (Objetivos 1.3 e 1.4)1.3 Desenvolver código que declare, inicialize e use primitivos, arrays, enums e objetos como variáveis static, de instâncias e locais. Alémdisso, usar identificadores legais para nomes de variáveis.

1.4 Desenvolver código que declare métodos static e não-static e, se apropriado, usar nomes de métodos que obedeçam aos padrõesde nomeação JavaBeans. Além disso, desenvolver código que declare e use uma lista de argumentos de extensão variável.

Já vimos o que significa usar um modificador em uma declaração de classe, e agora veremos o que significamodificar uma declaração de um método ou uma variável.

Os métodos e as variáveis de instâncias (não-locais) são conhecidos coletivamente como membros. Você podemodificar um membro que tenha tanto modificadores de acesso como modificadores que não se referem a acesso,e você tem mais modificadores para escolher (e combinar) do que quando está declarando uma classe.

Modificadores de Acesso

Pelo fato de os métodos e variáveis normalmente receberem controle de acesso exatamente da mesmas forma,abordaremos ambos nesta seção.

Enquanto uma classe só pode usar dois dos quatro níveis de controle de acesso (default ou public), os membrospodem usar todos os quatro:

public

protect

default

private

A proteção padrão é o que você recebe quando não digita um modificador de acesso na declaração do membro.Os tipos de controle de acesso default e protect têm comportamentos quase idênticos, exceto por uma diferençaque será mencionada posteriormente.

É crucial que você saiba tudo sobre o controle de acesso para o exame. Haverá uma boa quantidade de perguntas paraas quais você deverá usar o seu conhecimento sobre controle de acesso. Algumas questões testam vários conceitos decontrole de acesso ao mesmo tempo, então o desconhecimento de uma pequena parte que seja do assunto poderá lhecustar uma questão inteira.

O que significa o fato de o código em uma classe ter acesso a um membro de outra classe? Por agora, ignore quaisquerdiferenças entre métodos e variáveis. Se a classe A tiver acesso a um membro da classe B, isso significa que o membro daclasse B está visível para a classe A. Quando uma classe não tem acesso a outro membro, o compilador vai brigar comvocê por tentar acessar algo que você não deveria nem saber que existe!

Você precisa entender duas questões diferentes relativas ao acesso:

Se o código de um método em um classe pode acessar um membro de outra classe

Se uma subclasse pode herdar um membro da sua superclasse

O primeiro tipo de acesso ocorre quando um método de uma classe tenta acessar um método ou uma variável de outraclasse, usando o operador ponto (.) para invocar um método ou obter uma variável. Por exemplo:

class Zoo {

public String coolMethod() {

return “Wow baby”;

}

}

15

class Moo {

public void useAZoo() {

Zoo z = new Zoo();

// Se a linha anterior compilar, Moo terá acesso

// à classe Zoo

// Mas... será que tem acesso a coolMethod()?

System.out.println(“A Zoo says, “ + z.coolMethod());

// A linha anterior funciona porque Moo pode acessar o

// método public

}

}

O segundo tipo de acesso refere-se a quais membros de uma superclasse (se é que existem) uma subclasse podeacessar através da herança. Não estamos querendo saber se a subclasse pode, digamos, invocar um método para umainstância da superclasse (o que seria apenas um exemplo do primeiro tipo de acesso). Em vez disso, queremos saberse a subclasse pode herdar um membro da sua superclasse. Lembre-se de que se uma subclasse herda um membro, éexatamente como se a subclasse tivesse declarado o membro ela mesma. Em outras palavras, se uma subclasse herdaum membro, então ela tem esse membro.

class Zoo {

public String coolMethod() {

return “Wow baby“;

}

}

class Moo extends Zoo {

public void useMyCoolMethod() {

// Será que uma instância de Moo herda coolMethod()?

System.out.println(“Moo says, “ + this.coolMethod());

// A linha anterior funciona porque Moo pode acessar o

// método public

// Será que uma instância de Moo pode invocar coolMethod() em

// uma instância de Zoo?

Zoo z = new Zoo();

System.out.println(“Zoo says, “ + z.coolMethod());

// coolMethod() é public, então Moo pode invocá-lo em

// uma referência a Zoo

}

}

A Figura 1-2 faz a comparação entre uma classe herdando um membro de outra classe, e acessando um membro deoutra classe usando uma referência de uma instância dessa classe.

Muito do controle de acesso (ambos os tipos) se concentra em se as duas classes envolvidas estão no mesmo pacote ouem pacotes diferentes. Não se esqueça, no entanto, que se a própria classe A não puder ser acessada pela classe B, entãonenhum membro da classe A poderá ser acessado pela classe B.

Você precisa saber o efeito de diferentes combinações de acesso a classes e membros (por exemplo uma classe padrãocom uma variável public). Para descobrir isso, primeiramente observe o nível de acesso da classe. Se a própria classenão for visível a outra, então nenhum dos seus membros será visível, nem mesmo se forem declarados public. Depoisde confirmar que a classe está visível, é uma boa idéia observar os níveis de acesso nos membros individuais.

Modificadores de Acesso (Objetivo 1.3 e 1.4 do Exame)

16 Capítulo 1: Declarações e Controles de Acesso

Membros PublicQuando um método - ou variável-membro - é declarado public, isso significa que todas as outras classes,independentemente do pacote ao qual pertençam, podem acessar o membro em questão (assumindo-se que a própriaclasse esteja visível).

Figura 1-2 Figura 1-2 Figura 1-2 Figura 1-2 Figura 1-2 Comparação de herança x operador ponto para acesso a membros.

Três formas de acessar um método:

(D)Invocando um método declarado na mesma classe

(R) Invocando um método usando uma referência da classe

(I) Invocando um método herdado

Observe o seguinte arquivo-fonte:

package book;

import cert.*; // Importa todas as classe do pacote certo

class Goo {

public static void main(String[] args) {

Sludge o = new Sludge();

o.testIt();

}

}

Agora observe o segundo arquivo:

package cert;

17

public class Sludge {

public void testIt() { System.out.println(“sludge“); }

}

Como você pode ver, Goo e Sludge estão em pacotes diferentes. Entretanto, Goo pode invocar o método em Sludge semproblemas, porque tanto a classe Sludge quanto o seu método testIt() estão marcados como public.

Para uma subclasse, se um membro da sua superclasse for declarado public, a subclasse herda esse membro,independentemente de se ambas as classes estarem no mesmo pacote ou não:

package cert;

public class Roo {

public String doRooThings() {

// imagine o código divertido que entra aqui

return “fun“;

}

}

A classe Roo declara o membro doRooThings() como public. Assim, se criarmos uma subclasse de Roo,qualquer código presente nessa subclasse Roo poderá chamar o seu próprio método doRooThings() herdado.

package notcert; // Não é o pacote em que Roo se encontra

import cert.Roo;

class Cloo extends Roo {

public void testCloo() {

System.out.println(doRooThings());

}

}

Repare no código anterior que o método doRooThings () é invocado sem a necessidade de prefixá-lo comuma referência. Lembre-se de que se você vir um método invocado (ou uma variável acessada) sem o operadorponto (.), isso significa que o método ou a variável pertence à classe onde você viu esse código. Também significaque o método ou a variável está sendo implicitamente acessado(a) usando-se a referência this. Assim, no códigoanterior, a chamada a doRooThings() na classe Cloo poderia ter sido escrita comohis.doRooThings(). A referência this sempre se refere ao objeto sendo executado atualmente – emoutras palavras, ao objeto que esteja rodando o código quando você vê a referência this. Pelo fato de areferência this ser implícita, você não precisa prefixar o seu código de acesso a ela, mas se o fizer não haveránenhum problema. Alguns programadores o incluem para tornar o código mais fácil de ler para programadoresiniciantes ou desconhecedores de Java.

Além de poder invocar o método doRooThings() para si mesmo, o código de alguma outra classe pode chamardoRooThings() para uma instância de Cloo, da seguinte forma:

class Toon {

public static void main(String[] args) {

Cloo c = new Cloo();

System.out.println(c.doRooThings()); // Sem problema; o método

// é public

}

}

Membros PrivateMembros marcados como private não podem ser acessados por código em nenhuma outra classe que não aquelana qual o membro private foi declarado. Vamos fazer uma pequena modificação na classe Roo apresentada em umexemplo anterior.

package cert;

public class Roo {

Modificadores de Acesso (Objetivo 1.3 e 1.4 do Exame)

18 Capítulo 1: Declarações e Controles de Acesso

private String doRooThings() {

// Imagine o código divertido que entra aqui , mas apenas

// a classe Roo sabe disso

return “fun”;

}

}

O método doRooThings() agora é private, então nenhuma outra classe pode usá-lo. Se tentarmos invocar ométodo a partir de qualquer outra classe, teremos problemas:

package notcert;

import cert.Roo;

class UseARoo {

public void testIt() {

Roo r = new Roo(); // Até aqui, tudo bem; a classe Roo é pública

System.out.println(r.doRooThings()); // Erro de compilação!

}

}

Se tentarmos compilar UseARoo, receberemos um erro de compilação parecido com este:

cannot find symbol

symbol : method doRooThings()

É como se o método doRooThings() não existisse, e, no que diz respeito a qualquer código fora da classe Roo, issoé verdade. Um membro private é invisível para qualquer código fora da própria classe do membro.

E se uma subclasse tentasse herdar um membro private da sua superclasse? Quando um membro é declaradoprivate, uma subclasse não pode herdar dele. Para o exame, você precisa entender que uma subclasse não podever, usar e nem sequer pensar nos membros private da sua superclasse. Você pode, no entanto, declarar ummétodo correspondente na subclasse. Mas, não importa a sua aparência, não se trata de um método substituto! Ésimplesmente um método que por acaso tem o mesmo nome que o método private (de cuja existência vocênão deve sequer saber) da superclasse. As regras de substituição não se aplicam, de forma que você pode fazer essemétodo “recém-declarado-que-por-um-mero-acaso-é-o-mesmo” declarar novas exceções, ou modificar o tipo deretorno, ou qualquer outra coisa que você queira fazer com ele.

package cert;

public class Roo {

private String doRooThings() {

// Imagine o código divertido que entra aqui, mas nenhuma

// outra classe saberá disso

return “fun”;

}

}

O método doRooThings() agora está fora do alcance de todas as subclasses, até mesmo aquelas que estejamno mesmo pacote que a superclasse:

package cert; // Cloo e Roo estão no mesmo pacote

class Cloo extends Roo { // Tudo bem ainda, a superclasse Roo é pública

public void testCloo() {

System.out.println(doRooThings()); // Erro de compilação!

}

}

Se tentarmos compilar a subclasse Cloo, o compilador terá prazer em apresentar um erro parecido com este:

%javac Cloo.java

19

Cloo.java:4: Undefined method: doRooThings()

System.out.println(doRooThings());

1 error

Embora lhe seja permitido marcar variáveis de instâncias como public, na prática quase sempre é melhor manter todas asvariáveis como private ou protect. Se as variáveis precisarem ser modificadas, definidas ou lidas, os programadores devem usarmétodos de acesso public, para que códigos em quaisquer outras classes tenham de pedir para obter ou definir uma variável(passando através de um método), em vez de acessá-la diretamente. Os métodos de acesso compatíveis com JavaBeans têm aforma get<nomeDaPropriedade> ou, para booleanos, is<nomeDaPropriedade> e set<nomeDaPropriedade>, e fornecem umlugar onde você pode verificar e / ou validar antes de retornar ou modificar um valor.

Sem essa proteção, a variável weight (“peso”) de um objeto Cat, por exemplo, poderia ser definida como um número negativo caso o códigoinapropriado tenha acesso direto à variável public, como em somecat.weight = -20. Mas um método de acesso, setWeight(int wt), poderia verificar se o número é apropriado. (Ok, tudo isso é especulação, mas estamos partindo do princípio de que um peso negativopoderia ser inapropriado para um gato. Ou não.) O Capítulo 2 discutirá essa proteção de dados (encapsulamento) com mais detalhes.

É possível um método private ser substituído por uma subclasse? Essa é uma pergunta interessante, mas aresposta, tecnicamente, é não. Uma vez que a subclasse, como vimos, não pode herdar um método private, ela,portanto, não pode substituir o método – a substituição depende da herança. Abordaremos as implicações dissocom mais detalhes mais adiante nesta seção, bem como no Capítulo 2, mas, por agora basta lembrar-se de que ummétodo marcado como private não pode ser substituído. A Figura 1-3 ilustra os efeitos dos modificadorespublic e private em classes de um mesmo ou de diferentes pacotes.

Figura 1-3Figura 1-3Figura 1-3Figura 1-3Figura 1-3 Efeitos do acesso público e privado

Três formas de acessar um método:

(D)Invocando um método declarado na mesma classe

(R) Invocando um método usando uma referência da classe

(I) Invocando um método herdado

Modificadores de Acesso (Objetivo 1.3 e 1.4 do Exame)

20 Capítulo 1: Declarações e Controles de Acesso

Membros Protect e DefaultOs níveis de controle de acesso protect e default são quase idênticos, mas com uma diferença fundamental. Ummembro default só pode ser acessado se a classe que o estiver acessando pertencer ao mesmo pacote, enquanto que ummembro protect pode ser acessado (através da herança) por uma subclasse mesmo se a subclasse estiver em umpacote diferente.

Observe as duas classes seguintes:package certification;

public class OtherClass {

void testIt() { // O fato de não haver modificador

// indica acesso padrão

System.out.println(“OtherClass“);}

}

Em um outro arquivo de código-fonte você tem o seguinte:package somethingElse;

import certification.OtherClass;

class AccessClass {

static public void main(String[] args) {

OtherClass o = new OtherClass();

o.testIt();

}

}

Como pode ver, o método testIt() do primeiro arquivo tem acesso padrão (ou seja, de nível do pacote). Reparetambém que a classe OtherClass se encontra em um pacote diferente de AccessClass. Será que AccessClass poderá usaro método testIt()? Vai causar um erro de compilação? Será que o Daniel vai se casar com a Francesca? Não percaos próximos capítulos.

No method matching testIt() found in class

certification.OtherClass.o.testIt();

Pelos resultados acima, você pode ver que AccessClass não pode usar o método testIt() de OtherClass porquetestIt() tem acesso padrão, e AccessClass não está no mesmo pacote que OtherClass. Assim, AccessClass não pode vê-la, o compilador reclama, e nós não temos nem idéia de quem sejam Daniel e Francesca.

Os comportamentos default e protect diferem apenas quando falamos sobre subclasses. Se a palavra-chaveprotected for usada para definir um membro, qualquer subclasse da classe que faz a declaração pode acessá-lo atravésda herança. Não faz diferença se a superclasse e a subclasse estão em pacotes diferentes, o membro da superclasseprotect ainda estará visível para a subclasse (embora visível apenas de uma forma bastante específica, como veremosmais adiante). Isso contrasta com o comportamento padrão, que não permite que uma subclasse acesse um membro dasuperclasse, a não ser que a subclasse esteja no mesmo pacote que a superclasse.Enquanto que o acesso padrão não estende nenhum consideração especial às subclasses (ou você está no pacote ounão está), o modificador protected respeita a relação parent-child, até mesmo quando a classe child se desloca (ejunta-se a um novo pacote). Assim, quando pensar em acesso padrão, pense em restrições de pacote. Sem exceções. Mas,quando pensar em protect, pense em pacote + kids. Uma classe com um membro protect está marcando essemembro como tendo acesso de nível do pacote para todas as classes, mas com uma exceção especial para subclassesfora do pacote.Mas o que significa uma subclasse de fora do pacote ter acesso a um membro (parent) da superclasse? Significa que asubclasse herda o membro. Não significa, no entanto, que a subclasse de fora do pacote possa acessar o membrousando uma referência a uma instância da superclasse. Em outras palavras, protect = herança. Protect não significaque a subclasse possa tratar o membro protect da superclasse como se ele fosse public. Assim, se a subclasse de forado pacote obtiver uma referência à superclasse (criando, por exemplo, uma instância da superclasse em algum lugar nocódigo da subclasse), a subclasse não pode usar o operador ponto na referência à superclasse para acessar o membroprotec. Para uma subclasse de fora do pacote, um membro protect poderia da mesma forma ser default (oumesmo privado), quando a subclasse está usando uma referência à superclasse. A subclasse só pode ver o membroprotect através da herança.

Está confuso? Nós também. Agüente firme e tudo ficará claro com a série de exemplos seguintes. (E não se preocupe,na verdade, não estamos confusos. Estamos apenas tentando fazê-lo se sentir melhor caso você esteja confuso. Sabe, tiponão tem problema se você estiver achando que nada faz sentido, e não é culpa sua. Ou será que é? <insira risadamalévola aqui>)

21

Detalhes de protectVamos dar uma olhada em uma variável de instância protect (lembre-se de que uma variável de instância é ummembro) de uma superclasse.

package certification;

public class Parent {

protected int x = 9; // acesso protect

}

O código acima declara a variável x como protected. Isso a torna acessível a todas as outras classes dentro dopacote certification, bem como herdável por quaisquer subclasses de fora do pacote. Agora vamos criar umasubclasse em um pacote diferente, e tentar usar a variável x (que a subclasse herda):

package other; // Pacote diferente

import certification.Parent;

class Child extends Parent {

public void testIt() {

System.out.println(“x is “ + x); // Sem problema; Child

// herda x

}

}

O código acima compila sem problemas. Repare, no entanto, que a classe Child está acessando a variável pro-tect através da herança. Lembre-se, sempre que falarmos de uma subclasse ter acesso a um membro de umasuperclasse, poderíamos estar falando de a subclasse herdar o membro, e não simplesmente acessá-lo através deuma referência a uma instância da superclasse (que é a forma como qualquer outra não-subclasse o acessaria).Repare no que acontece se a subclasse Child (fora do pacote da superclasse) tentar acessar uma variável protectusando uma referência à classe Parent.

package other;

import certification.Parent;

class Child extends Parent {

public void testIt() {

System.out.println(“x is “ + x); // Sem problema; Child

// herda x

Parent p = new Parent(); // Podemos acessar x usando

// a referência a p?

System.out.println(“X in parent is “ + p.x); // Erro de compilação!

}

}

O compilador alegremente nos mostra qual é o problema:%javac -d . other/Child.java

other/Child.java:9: x has protected access in certification.Parent

System.out.println(“X in parent is “ + p.x);

1 error

Até aqui, estabelecemos que um membro protect tem, essencialmente, acesso de nível do pacote ou padrão a todas asclasses, exceto as subclasses. Já vimos que as subclasses de fora do pacote podem herdar um membro protect. Finalmente,já vimos que as subclasses de fora do pacote não podem usar uma referência à superclasse para acessar um membro protect.Para uma subclasse de fora do pacote, o membro protect só pode ser acessado através da herança.

Ainda há mais uma questão que não consideramos... Qual é a aparência de um membro protect para outras classes quetentem usar a subclasse de fora do pacote para obter o membro protect da superclasse que foi herdado pela subclasse?Por exemplo, usando as nossas classes Parent/Child anteriores, o que acontece se uma outra classe – digamos, Neighbor –do mesmo pacote que Child (subclasse) tiver uma referência a uma instância de Child e queira acessar a variável-membro x?Em outras palavras, como esse membro protect se comporta depois que a subclasse o herdou? Ele mantém o seustatus de protect, de forma tal que as classes no pacote de Child possam vê-lo?

Não! Depois que a subclasse de fora do pacote herda o membro protect, ele (conforme herdado pela subclasse) torna-seprivate para qualquer código de fora da subclasse, com a exceção das subclasses dessa subclasse. Assim, se a classe

Modificadores de Acesso (Objetivo 1.3 e 1.4 do Exame)

22 Capítulo 1: Declarações e Controles de Acesso

Neighbor instanciar um objeto Child, então mesmo se Neighbor estiver no mesmo pacote que Child, Neighbor não teráacesso à variável x herdada (mas protect) por Child. Resumo da história: quando uma subclasse de fora do pacote herdaum membro protect, esse membro torna-se essencialmente private dentro da subclasse, de forma tal que apenas asubclasse e as suas subclasses podem acessá-lo. A Figura 1-4 ilustra o efeito do acesso protect sobre classes e subclassesno mesmo ou em diferentes pacotes.

Caramba! Com isso terminamos protected, o modificador mais incompreendido em Java. Novamente, ele só é usadoem casos muito especiais, mas pode ter certeza de que aparecerá no exame. Agora que já abordamos o modificador pro-tected, passaremos para o acesso padrão, uma moleza comparado a protected.

Detalhes de DefaultVamos começar com o comportamento padrão de um membro de uma superclasse. Modificaremos o membro x de Parentpara torná-lo default.

package certification;

public class Parent {

int x = 9; // Ausência de modificadores de acesso

// indica acesso padrão (de pacote)

}

Repare que não colocamos um modificador de acesso na frente da variável x. Lembre-se de que, se você não digitar ummodificador de acesso antes da declaração de uma classe ou um membro, o controle de acesso é o padrão, o que significa denível do pacote. Agora tentaremos acessar o membro padrão da classe Child que vimos anteriormente.

Figura 1-4 Figura 1-4 Figura 1-4 Figura 1-4 Figura 1-4 Efeitos do acesso protect

Quando compilarmos o arquivo Child, receberemos um erro parecido com este:Child.java:4: Undefined variable: x

23

System.out.println(“Variable x is “ + x);1 error

O compilador nos dá o mesmo erro de quando um membro é declarado como private. A subclasse Child (em umpacote diferente do da superclasse Parent) não é capaz de ver nem usar o membro padrão x da superclasse! Agora, e quantoao acesso padrão para duas classes do mesmo pacote?

package certification;

public class Parent{

int x = 9; // acesso padrão

}

E, na segunda classe, você tem o seguinte:package certification;

class Child extends Parent{

static public void main(String[] args) {

Child sc = new Child();

sc.testIt();

}

public void testIt() {

System.out.println(“Variable x is “ + x); // Sem problemas}

}

O código-fonte acima compila sem problemas, e a classe Child roda e exibe o valor e x. Basta se lembrar de que os membrospadrão ficam visíveis para as subclasses apenas se elas estiverem no mesmo pacote que a superclasse.

Variáveis Locais e Modificadores de AcessoOs modificadores de acesso podem ser aplicados a variáveis locais? NÃO!

Não existe nenhum caso em que um modificador de acesso possa ser aplicado a uma variável local, então, cuidado comcódigo como o seguinte:

class Foo {

void doStuff() {

private int x = 7;

this.doMore(x);

}

}

Pode ter certeza de que qualquer variável local declarada com um modificador de acesso não vai compilar. Na verdade, sóexiste um modificador que pode ser aplicado a variáveis locais – final.

Isso termina a nossa discussão sobre modificadores de acesso de membros. A Tabela 1-2 mostra todas as combinações deacesso e visibilidade; é uma boa idéia passar algum tempo estudando-a. Em seguida, vamos passar para os outrosmodificadores (não-referentes a acesso) que você pode aplicar a declarações de membros.

TTTTTabela 1-2 abela 1-2 abela 1-2 abela 1-2 abela 1-2 Determinando a Acesso a Membros de Classes

Visibilidade Public Protect Default PrivateA

partir da mesma classe Sim Sim Sim Sim

A partir de qualquer classe do mesmo pacote Sim Sim Sim Não

A partir de uma subclasse do mesmo pacote Sim Sim Sim Não

A partir de uma subclasse de fora do mesmo pacote Sim Sim, através Não Nãoda herança

A partir de qualquer classe que não sejaSim Não Não Não uma subclasse e esteja fora do pacote

Modificadores de Acesso (Objetivo 1.3 e 1.4 do Exame)

24 Capítulo 1: Declarações e Controles de Acesso

Modificadores Não-Referentes a Acesso

Já discutimos o acesso a membros, o qual diz respeito ao código de uma classe pode invocar um método (ou acessar umavariável de instância) a partir de outra classe. Isso ainda não inclui uma série de outros modificadores que você pode usar emdeclarações de membros. Dois deles já lhe são familiares – final e abstract –, porque nós os aplicamos a declaraçõesde classes anteriormente neste capítulo. Mas ainda temos de dar uma rápida olhada em transient, synchronized,native, strictfp, e depois uma longa olhada no grande modificador – static.

Veremos primeiro os modificadores aplicados a métodos, seguidos pelos modificadores aplicados a variáveis de instâncias.Fecharemos esta seção com uma olhada em como static funciona quando aplicado a variáveis e métodos.

Métodos FinalA palavra-chave final impede que um método possa ser substituído em uma subclasse, e frequentemente é usada paraforçar os recursos API de um método. Por exemplo, a classe Thread tem um método chamado isAlive() que verifica seuma determinada thread ainda está ativa. Se você estender a classe Thread, no entanto, realmente não há como você sozinhoimplementar corretamente esse método (ele usa código nativo, só para citar uma das razões), então os elaboradores otornaram final. Assim como não é possível subclassificar a classe String (porque precisamos confiar no comportamentode um objeto String), você não poderá substituir a maioria dos métodos nas bibliotecas de classes fundamentais. Essarestrição quanto à substituição propicia boa segurança, mas você deve usá-la com muito cuidado. Impedir que umasubclasse substitua um método invalida muitos dos benefícios da orientação a objetos, incluindo a estensibilidade atravésdo polimorfismo. Uma declaração de método final típica se pareceria com isto:

class SuperClass{

public final void showSample() {

System.out.println(“One thing.“);}

}

É válido estender SuperClass, uma vez que a classe não está marcada como final, mas não podemos substituir o métodofinal showsample(), como o seguinte código está tentando fazer:

class SubClass extends SuperClass{

public void showSample() { // Tentando substituir o método

// final da superclasse

System.out.println(“Another thing.“);}

}

Se tentar compilar o código acima, você receberá uma mensagem como esta:%javac FinalTest.java

FinalTest.java:5: The method void showSample() declared in class

SubClass cannot override the final method of the same signature

declared in class SuperClass.

Final methods cannot be overridden.

public void showSample() { }

1 error

Argumentos FinalOs argumentos de métodos são as declarações de variáveis que aparecem entre parênteses na declaração de um método. Umadeclaração de método típica, com múltiplos argumentos, se parece com o seguinte:

public Record getRecord(int fileNumber, int recordNumber) { }

Argumentos de métodos são essencialmente o mesmo que variáveis locais. No exemplo anterior, as variáveisfileNumber e recordNumber seguem todas as regras aplicadas a variáveis locais. Isso significa que elastambém podem ter o modificador final:

public Record getRecord(int fileNumber, final int recNumber) { }

Neste exemplo, a variável recordNumber é declarada como final, o que significa obviamente que ela não poderáser modificada dentro do método. Neste caso, “modificar” significa atribuir um novo valor à variável. Em outraspalavras, um argumento final deve manter o mesmo valor que o parâmetro tinha quando foi passado para o método.

25

Métodos AbstractUm método abstract é um método que foi declarado (como abstract) mas não implementado. Em outras palavras, ométodo não contém nenhum código funcional. E, se você se lembrar da seção “Classes abstract”, uma declaração demétodo abstract não tem nem sequer chaves onde um código de implementação pudesse ser colocado,terminando, em vez disso, com ponto-e-vírgula. Em outras palavras, ela não tem um corpo de método. Você marca um métodocomo abstract quando quer forçar as subclasses a fornecer a implementação em questão. Por exemplo, se escrever uma classeabstract Car com um método goUpHill(), você poderia desejar forçar todos os subtipos de Car a definir o seu própriocomportamento de goUpHill(), específico àquele tipo determinado de carro.

public abstract void showSample();

Repare que o método abstract termina com ponto-e-vírgula em vez de chaves. É inválido ter um único métodoabstract que seja em uma classe que não seja declarada explicitamente como abstract! Observe aseguinte classe inválida:

public class IllegalClass{

public abstract void doIt();

}

A classe anterior produzirá o seguinte erro se você a tentar compilar:

IllegalClass.java:1: class IllegalClass must be declared

abstract.

It does not define void doIt() from class IllegalClass.

public class IllegalClass{

1 error

Você pode, no entanto, ter uma classe abstract sem nenhum método abstract. O seguinte exemplo irácompilar sem problemas:

public abstract class LegalClass{

void goodMethod() {

// insira um monte de códigos reais de implementação aqui

}

}

No exemplo anterior, goodMethod() não é abstract. Três dicas diferentes lhe dizem que não se trata de ummétodo abstract:

O método não está marcado como abstract.

A declaração do método inclui chaves, em vez de terminar com ponto-e-vírgula. Em outras palavras, o métodotem um corpo de método.

O método inclui código de implementação.

Qualquer classe que estenda uma classe abstract deve implementar todos os métodos abstract dasuperclasse, a não ser que a subclasse também seja abstract. A regra é a seguinte:

A primeira subclasse concreta de uma classe abstract deve implementar todos os métodosabstract da superclasse.

Concreto significa apenas não-abstract, então, se você tiver uma classe abstract estendendo outra classe abstract, asubclasse abstract não precisa fornecer implementações para os métodos abstract herdados. Mais cedo ou mais tarde, noentanto, alguém vai criar uma subclasse não-abstract (em outras palavras, uma classe que pode ser instanciada), e essa subclasseterá de implementar todos os métodos abstract de cima para baixo na árvore de herança. O seguinte exemplo demonstra umaárvore de herança com duas classes abstract e uma concreta:

public abstract class Vehicle {

private String type;

public abstract void goUpHill(); // Método abstract

public String getType() { // Método não-abstract

return type;

}

}

public abstract class Car extends Vehicle {

Modificadores Não-Referentes a Acesso (Objetivo 1.3 e 1.4 do Exame)

26 Capítulo 1: Declarações e Controles de Acesso

public abstract void goUpHill(); // Ainda abstract

public void doCarThings() {

// Código especial para o carro entra aqui

}

}

public class Mini extends Car {

public void goUpHill() {

// Código específico para o Mini subir ladeiras

}

}

Então, quantos métodos tem a classe Mini? Três. Ela herda os métodos getType() e doCarThings(), porque eles sãopúblicos e concretos (não-abstract). Mas, pelo fato de goUpHill () ser abstract na superclasse Vehicle, e nunca serimplementado na classe Car (permanecendo abstract, portanto), isso significa que a classe Mini – como a primeira classe concretaabaixo de Vehicle – precisa implementar o método goUpHill(). Em outras palavras, a classe Mini não pode deixar aimplementação do método abstract para a próxima classe abaixo dela na árvore de herança, mas a classe Car pode, porque Car,como Vehicle, é abstract. A Figura 1-5 ilustra os efeitos do modificador abstract sobre subclasses concretas e abstratas.

Figura 1-5 Figura 1-5 Figura 1-5 Figura 1-5 Figura 1-5 Os efeitos do modificador abstract sobre subclasses concretas e abstratas

Procure por classes concretas que não forneçam implementações para métodos abstract da superclasse. O seguintecódigo não vai compilar:

public abstract class A {

abstract void foo();

}

class B extends A {

void foo(int I) { }

}

A classe B não vai compilar porque ela não implementa o método abstract herdado foo(). Embora o métodofoo(int I) da classe B pareça ser uma implementação do método abstract da superclasse, na verdade ésimplesmente um método sobrecarregado (um método que usa o mesmo identificador, mas diferentes argumentos), entãoele não atende ao requisito de implementação do método abstract da superclasse. Veremos as diferenças entresubstituição e sobrecarga com mais detalhes no Capítulo 2.

Os métodos abstract devem ser implementados poruma subclasse não-abstract. Se a subclasse for abstrata,ela não é obrigada a implementar os métodos abstract,mas tem a permissão de implementar qualquer um ou todosos métodos abstract da superclasse. A classeAcmeRover é não-abstract, então ela precisaimplementar o método abstract declarado na suasuperclasse, SUV, e precisa implementar também turn(),que não foi implementado por SUV.

27

Um método não pode nunca, jamais, ser marcado como abstract e final ao mesmo tempo, nem comoabstract e private ao mesmo tempo. Pense um pouco – os métodos abstract precisam serimplementados (o que na prática significa serem substituídos por uma subclasse), enquanto que métodos final eprivate não podem jamais ser substituídos por uma subclasse. Ou, dizendo de outra forma, uma designaçãoabstract significa que a superclasse não sabe nada sobre como as subclasses devem se comportar no método emquestão, enquanto que uma designação final significa que a superclasse sabe tudo sober como todas as subclasses(por mais afastadas que estejam na árvore de herança) devem se comportar no método em questão. Os modificadoresabstract e final são praticamente opostos. Pelo fato de os métodos private não poderem nem mesmo servistos por uma subclasse (quanto mais herdados), eles também não podem ser substituídos, então eles também nãopodem ser marcados como abstract.

Finalmente, você precisa saber que o modificador abstract não pode nunca ser combinado com o modificadorstatic. Abordaremos os métodos static mais adiante neste objetivo, mas, por agora, basta lembrar que o seguinteseria inválido:

abstract static void doStuff ();

E lhe daria um erro que a esta altura já deverá lhe parecer familiar:MyClass.java:2: illegal combination of modifiers: abstract and

static

abstract static void doStuff ();

Métodos SynchronizedA palavra-chave synchronized indica que um método só pode ser acessado por um thread de cada vez. Nósdiscutiremos isso à exaustão no Capítulo 9, mas, por agora, tudo o que nos interessa é saber que o modificadorsynchronized só pode ser aplicado a métodos – não a variáveis, nem classes, apenas a métodos. Uma declaraçãosynchronized típica se parece com a seguinte:

public synchronized Record retrieveUserInfo(int id) { }

Você precisa saber também que o modificador synchronized pode ser acompanhado por qualquer um dosquatro níveis de controle de acesso (o que significa que ele pode ser usado juntamente com qualquer uma das trêspalavras-chave modificadoras de acesso).

Métodos NativosO modificador native indica que o método está sendo implementado conforme a plataforma, freqüentementee C. Você não precisa saber como usar métodos nativos para o exame, basta saber que native é um modificador(e, portanto, uma palavra-chave reservada) e que native só pode ser aplicado a métodos – não a classes, nem avariáveis, apenas a métodos. Repare que o corpo de um método nativo deve ser ponto-e-vírgula (;) (como métodosabstract), indicando que a implementação foi omitida.

Métodos StrictfpVimos anteriormente o uso de strictfp como modificador de classe, mas, mesmo que você não declare umaclasse como strictfp, ainda assim você poderá declarar um método individual como strictfp. Lembre-se deque strictfp força os pontos flutuantes (e quaisquer operações com ponto flutuante) a aderirem ao padrãoIEEE 754. Com strictfp, é possível prever como os seus pontos flutuantes se comportarão, independentementeda plataforma subjacente na qual a JVM está rodando. O inconveniente disso é que, se a plataforma subjacente forcapaz de suportar uma maior precisão, um método strictfp não poderá se beneficiar dessa capacidade.

Você só desejará estudar o IEEE 754 se precisar de algo para ajudá-lo a cair no sono. Para o exame, no entanto,você não precisa saber nada sobre strictfp além da sua utilidade, do fato de que pode modificar umadeclaração de classe ou de método, e que uma variável nunca pode ser declarada como strictfp.

Métodos com Listas de Argumentos Variáveis (var-args)Desde a versão 5.0, Java lhe permite criar métodos capazes de usar um número variável de argumentos.Dependendo de onde você pesquisar, poderá ver essa capacidade ser chamada de “listas de argumentos deextensão variável”, “argumentos variáveis”, “var-args”, “varargs” ou o nosso favorito (saído do departamento deobscuridade), “parâmetro com número variável de argumentos”. Todos eles são a mesma coisa, e usaremos otermo “var-args” daqui em diante.

Apenas para informação, gostaríamos de esclarecer como iremos usar os termos “argumento” e “parâmetro” ao longo deste livro.

argumentos Aquilo que você especifica entre parênteses quando está invocando um método:

doStuff(“a“, 2); // estamos invocando doStuff, então a & 2 são argumentos

Modificadores Não-Referentes a Acesso (Objetivo 1.3 e 1.4 do Exame)

28 Capítulo 1: Declarações e Controles de Acesso

parâmetros Aquilo na assinatura do método indica o que o método deve receber quando for invocado:

void doStuff (String s, int a) { } // estamos esperando dois

// parâmetros: String e int

Falaremos mais sobre o uso de métodos var-args nos próximos capítulos, por agora vamos revisar as regras dedeclaração para var-args:

Tipo var-arg Quando declara um parâmetro var-arg, você deve especificar o tipo do(s) argumento(s) que esseparâmetro do seu método pode receber. (Pode ser um tipo primitivo ou um tipo de objeto.)

Sintaxe básica Para declarar um método usando um parâmetro var-arg, você escreve depois do tipo um sinalde reticências (...), um espaço, e depois o nome do array que irá armazenar os parâmetros recebidos.

Outros parâmetros É válido ter outros parâmetros em um método que use um var-arg.

Limites dos var-args O var-arg deve ser o último parâmetro na assinatura do método, e você só pode ter umvar-arg por método.

Vejamos algumas declarações com var-arg válidas e inválidas:

Válidas:void doStuff (int... x) { } // espera de 0 a muitos ints

// como parâmetros

void doStuff2 (char c, int... x) { } // espera primeiramente um char,

// e depois de 0 a muitos ints

void doStuff3 (Animal... animal) { } // de 0 a muitos Animals

Inválidas:void doStuff4(int x...) { } // sintaxe incorreta

void doStuff5(int... x, char... y) { } // mais de um var-arg

void doStuff6(String... s, byte b) { } // var-arg tem de vir por último

Declarações de Construtores

Em Java, os objetos são construídos. Sempre que você cria um novo objeto, pelo menos um construtor é invocado. Todaclasse tem um construtor, e, se você não criar um explicitamente, o compilador vai criar um para você. Existemtoneladas de regras relativas aos construtores, e iremos deixar a discussão detalhada para o Capítulo 2. Por agora, vamosnos concentrar nas regras básicas de declaração. Eis um exemplo simples:

class Foo {

protected Foo() { } // este é o construtor de Foo

protected void Foo() { } // este é um método com um péssimo nome,

// porém válido

}

A primeira coisa a se reparar é que os construtores se parecem um bocado com métodos. Uma diferença fundamental é queum construtor não pode nunca, jamais, ter um tipo de retorno... Nunca! As declarações de construtores podem ter, noentanto, todos os modificadores de acesso normais, e podem usar argumentos (incluindo var-args), da mesma forma comoos métodos. A outra REGRA IMPORTANTE a se entender sobre os construtores é que eles devem ter o mesmo nomeque a classe no qual são declarados. Os construtores não podem ser marcados como static (afinal eles são associadoscom instanciamento de objetos), não podem ser marcados como final nem abstract (porque não podem sersubstituídos). Eis algumas declarações de construtores válidos e inválidos:

class Foo2 {

// construtores válidos

Foo2() { }

private Foo2(byte b) { }

Foo2(int x) { }

Foo2(int x, int... y) { }

30 Capítulo 1: Declarações e Controles de Acesso

fórmula –2(bits – 1) para calcular o intervalo negativo, e usamos –2(bits – 1) – 1 para o intervalo positivo. Novamente, se vocêsouber as duas primeiras colunas desta tabela, estará em boa forma para o exame.

TTTTTabela 1-3abela 1-3abela 1-3abela 1-3abela 1-3 Intervalos de Primitivos Numéricos

Tipo Bits Bytes Intervalo Mínimo Intervalo Máximo

byte 8 1 –27 27 – 1

short 16 2 –215 215 – 1

int 32 4 –231 231 – 1

long 64 8 –263 263 – 1

float 32 4 n/d n/d

double 64 8 n/d n/d

O intervalo para números de ponto flutuante é complicado de determinar, mas felizmente você não precisa sabê-los parao exame (embora é esperado que você saiba que um double armazena 64 bits, e um float armazena 32).

Para tipos booleanos não há um intervalo; um booleano só pode ser true ou false. Se alguém lhe perguntar aprofundidade de bits de um tipo booleano, olhe bem nos olhos da pessoa e diga “depende da máquina virtual”.Ela ficará impressionada.

O tipo char (um caracter) contém um só caracter Unicode de 16 bits. Embora o conjunto ASCII estendidoconhecido como ISO Latin-1 precise de apenas 8 bits (256 caracteres diferentes), é necessário um intervalo maiorpara representar caracteres encontrados em línguas diferentes do inglês. Os caracteres Unicode, na verdade, sãorepresentados por números inteiros de 16 bits não-assinalados, o que significa 216 tipos possíveis, que vão de 0a 65535 (216) – l. No Capítulo 3, você aprenderá que, pelo fato de um char ser na verdade um tipo de númerointeiro, ele pode ser atribuído a qualquer tipo de número grande o suficiente para armazenar 65535 (o quesignifica qualquer coisa maior do que um tipo short. Embora tanto chars quanto shorts sejam tipos de 16 bits,lembre-se de que um short usa 1 bit para representar o sinal, de modo que menos números positivos sãoaceitáveis em um short).

Declarando Variáveis de ReferênciaVariáveis de referência podem ser declaradas como variáveis static, variáveis de instâncias, parâmetros de métodos ouvariáveis locais. Você pode declarar uma ou mais variáveis de referência, do mesmo tipo, em uma mesma linha. No Capítulo3, discutiremos as várias maneiras pelas quais elas podem ser inicializadas, mas por agora apresentaremos apenas algunsexemplos de declarações de variáveis de referência:

Object o;

Dog myNewDogReferenceVariable;

String s1, s2, s3; // declara três variáveis String

Variáveis de InstânciasAs variáveis de instâncias são definidas dentro da classe, mas fora de qualquer método, e só são inicializadas quando a classeé instanciada. As variáveis de instâncias são os campos que pertencem a cada objeto único. Por exemplo, o seguinte códigodefine campos (variáveis de instâncias) para name (nome), title (título) e manager (gerente) para objetos employee(funcionário):

class Employee {

// define campos (variáveis de instâncias) para instâncias de employee

private String name;

private String title,

private String manager;

// outros códigos aqui, incluindo os métodos de acesso para campos privados

}

A classe Employee anterior diz que cada instância de employee saberá qual é o seu próprio nome, título e gerente. Em outraspalavras, cada instância pode ter os seus valores únicos para esses três campos. Se você vir os termos “campo”, “variável de

31

instância”, “propriedade” ou “atributo”, eles significam praticamente a mesma coisa. (Na verdade, existem distinções sutis, masocasionalmente importantes entre os termos, contudo, elas não são usadas no exame.)

Para o exame, você precisa saber que as variáveis de instâncias

Podem usar qualquer um dos quatro níveis de acesso (o que significa que eles podem ser marcados com qualquer um dostrês modificadores de acesso)

Podem ser marcadas como final

Podem ser marcadas como transient

Não podem ser marcadas como abstract

Não podem ser marcadas como sinchronized

Não podem ser marcadas como strictfp

Não podem ser marcadas como native

Não podem ser marcadas como static, porque isso as transformaria em variáveis de classe.

Já abordamos os efeitos de se aplicar controle de acesso a variáveis de instâncias (funciona da mesma maneira que paramétodos membros). Um pouco adiante neste capítulo, veremos o que significa aplicar o modificador final outransient a uma variável de instância. Primeiro, daremos uma rápida olhada na diferença entre variáveis deinstâncias e variáveis locais. A Figura 1-7 compara a maneira pela qual os modificadores podem ser aplicados a métodosem contraste com variáveis.

Variáveis locais Variáveis (não-locais) Métodos

Figura 1-7 Figura 1-7 Figura 1-7 Figura 1-7 Figura 1-7 Comparação de modificadores para variáveis x métodos

Variáveis Locais (Automatic/Stack/Method)Variáveis locais são aquelas declaradas dentro de um método. Isso significa que a variável não é apenas inicializada dentro dométodo, mas também declarada dentro dele. Assim como a variável local inicia a sua vida dentro do método, ela também édestruída quando o método finaliza. As variáveis locais ficam sempre na pilha, e não no heap (Falaremos mais sobre a pilhae o heap no Capítulo 3). Embora o valor da variável possa ser passado para, digamos, outro método que então armazene ovalor em uma variável de instância, a variável propriamente dita só vive dentro do escopo do método.

Apenas não se esqueça de que enquanto a variável local está na pilha, se a variável for uma referência a objeto, o objetopropriamente dito ainda será criado no heap. Não existe um objeto de pilha, apenas uma variável de pilha. Vocêfreqüentemente ouvirá programadores usarem a expressão “objeto local”, o que eles realmente querem dizer é “variável dereferência declarada localmente”. Assim, se ouvir um programador usar essa expressão, você saberá que ele é simplesmentepreguiçoso demais para usar o termo técnico mais preciso. Você pode dizer a ele que nós afirmamos isso – a não ser que elesaiba onde nós moramos.

As declarações de variáveis locais não podem usar a maioria dos modificadores que podem ser aplicados a variáveis deinstâncias, tais como public (ou os outros modificadores de acesso), transient, volatile, abstract oustatic, mas, como vimos anteriormente, as variáveis locais podem ser marcadas como final. E, como você aprenderáno Capítulo 3 (mas aqui vai um adianto), antes que uma variável local possa ser usada, ela precisa ser inicializada com umvalor. Por exemplo:

class TestServer {

public void logIn() {

final

public

protected

private

statict

transient

volatile

final

public

protected

private

static

abstract

synchronized

strictfp

native

final

Declarações de Variáveis (Objetivo 1.3 e 1.4 do Exame)

32 Capítulo 1: Declarações e Controles de Acesso

int count = 10;

}

}

Na maioria dos casos, você vai inicializar uma variável local na mesma linha em que a declarar, embora você possa aindater de reinicializá-la depois, no método. A chave é se lembrar de que uma variável local precisa ser inicializada antes devocê tentar usá-la. O compilador rejeitará qualquer código que tente usar uma variável local que não tenha recebido umvalor, porque – ao contrário das variáveis de instâncias – as variáveis locais não recebem valores-padrão.

Uma variável local não pode ser referenciada em nenhum código fora do método no qual foi declarada. No exemplo decódigo anterior, seria impossível referir-se à variável count em qualquer outro lugar da classe exceto dentro do escopo dométodo logIn(). Novamente, não queremos dizer com isso que o valor de count não possa ser passado para fora dométodo para começar uma nova vida. Mas a variável que armazena esse valor, count, não pode ser acessada depois de ométodo finalizar, como o seguinte código inválido demonstra:

class TestServer {

public void logIn() {

int count = 10;

}

public void doSomething(int i) {

count = i; // Não vai compilar! Não é possível acessar count

// de fora do método login()

}

}

É possível declarar uma variável local com o mesmo nome que uma variável de instância. Isso é conhecido comosombreamento, como o seguinte código demonstra:

class TestServer {

int count = 9; // Declara uma variável de instância chamada count

public void logIn() {

int count = 10; // Declara uma variável local chamada count

System.out.println(“local variable count is “ + count);

}

public void count() {

System.out.println(“instance variable count is “ + count);

}

public static void main(String[] args) {

new TestServer().logIn();

new TestServer().count();

}

}

O código acima produz a seguinte saída:

local variable count is 10

instance variable count is 9

Mas por que razão você iria querer fazer isso?

Normalmente, você não vai. Mas uma das razões mais comuns é para dar a um parâmetro o mesmo nome que a variável deinstância à qual o parâmetro será atribuído. O seguinte código (incorreto) está tentando definir o valor de uma variável deinstância usando um parâmetro:

class Foo {

int size = 27;

public void setSize(int size) {

36 Capítulo 1: Declarações e Controles de Acesso

Os componentes básicos de um enum são as suas constantes (ou seja, BIG, HUGE e OVERWHELMING), embora vocêvá ver logo adiante que pode haver muito mais em um enum. Os enums podem ser declarados como as suas própriasclasses separadas, ou como membros de classes, mas não podem ser declarados dentro de um método!

Declarando um enum fora de uma classe:

enum CoffeeSize { BIG, HUGE, OVERWHELMING } // não pode ser

// private nem protect

class Coffee {

CoffeeSize size;

}

public class CoffeeTest1 {

public static void main(String[] args) {

Coffee drink = new Coffee();

drink.size = CoffeeSize.BIG; // enum fora da classe

}

}

O código acima pode fazer parte de um só arquivo. (Lembre-se, o arquivo deve ser nomeado como CoffeeTest1.java,porque esse é o nome da classe pública do arquivo.) A principal coisa a se lembrar é que o enum pode ser declarado somentecom o modificador public ou o default, assim como uma classe não-interna. Eis um exemplo de declaração deenum dentro de uma classe:

class Coffee2 {

enum CoffeeSize {BIG, HUGE, OVERWHELMING }

CoffeeSize size;

}

public class CoffeeTest2 {

public static void main(String[] args) {

Coffee2 drink = new Coffee2();

drink.size = Coffee2.CoffeeSize.BIG; // incluindo classes

// nome requerido

}

}

As principais coisas a se lembrar desses exemplos são que: 1) enums podem ser declarados como as suas próprias classes,ou podem ser incluídos em outra classe; e 2) que a sintaxe para se acessar os membros de um enum depende de onde oenum foi declarado.

O seguinte exemplo NÃO é válido:public class CoffeeTest1 {

public static void main(String[] args) {

enum CoffeeSize { BIG, HUGE, OVERWHELMING } // ERRADO! Não se

// pode declarar enums

// em métodos

Coffee drink = new Coffee();

drink.size = CoffeeSize.BIG;

}

}

37

Para fazer as coisas ficarem mais confusas para você, os elaboradores da linguagem Java fizeram opcional a colocação deponto-e-vírgula no final da declaração do enum:

public class CoffeeTest1 {

enum CoffeeSize { BIG, HUGE, OVERWHELMING }; // <— o ponto-e-vírgula

// é opcional aqui

public static void main(String[] args) {

Coffee drink = new Coffee();

drink.size = CoffeeSize.BIG;

}

}

Enfim, o que é criado quando você cria um enum? O mais importante a se lembrar é que enums não são Strings nemints! Cada um dos tipos enumerados de CoffeeSize é na verdade uma instância de CoffeeSize. Em outraspalavras, BIG é do tipo CoffeeSize. Pense em um enum como um tipo de classe, que é parecido (mas nãoexatamente) com isto:

// exemplo conceitual de como você

// pode entender os enums

class CoffeeSize {

public static final CoffeeSize BIG =

new CoffeeSize(“BIG“, 0);public static final CoffeeSize HUGE =

new CoffeeSize(“HUGE“, 1);public static final CoffeeSize OVERWHELMING =

new CoffeeSize(“OVERWHELMING“, 2);public CoffeeSize(String enumName, int index) {

// mais coisas aqui

}

public static void main(String[] args) {

System.out.println(CoffeeSize.BIG);

}

}

Observe como os valores enumerados BIG (grande, em inglês), HUGE (enorme) e OVERWHELMING (absurdo) sãoinstâncias do tipo CoffeeSize. Eles são representados como static e final – o que, no mundo Java, é considerado umaconstante. Observe também que cada valor enum sabe o seu índice ou posição. Em outras palavras, a ordem na qual osvalores enum são declarados faz diferença. Pode-se pensar nos enums de CoffeeSize como se eles existissem em umarray do tipo CoffeeSize e, como será mostrado em um capítulo posterior, é possível fazer iterações através dosvalores de um enum invocando o método values() em qualquer tipo enum. (Não se preocupe com isso neste capítulo).

Declaração de Construtores, Métodos e Variáveis em Um EnumComo um enum é um tipo especial de classe, ele pode fazer mais do que simplesmente listar os valoresconstantes enumerados. É possível adicionar construtores, variáveis de instância, métodos e também umacoisa muito esquisita, chamada corpo de classe específico constante (“constant specific class body”, eminglês). Para entender que mais pode ser necessário em enum, vejamos este exemplo: imagine que vocêqueira saber o tamanho real, em mililitros, a ser mapeado para as três constantes de CoffeeSize. Porexemplo, você quer saber que BIG representa 8 onças (medida americana equivalente a 237 ml), HUGE são10 onças (296 ml) e OVERWHELMING significa inacreditáveis 16 onças (473 ml).

É possível fazer algum tipo de tabela de busca usando outras estruturas de dados, mas seria um design pobre e de difícilmanutenção. A maneira mais simples de fazer isso é tratar os valores do tipo enum (BIG, HUGE e OVERWHELMING)como objetos que possuem suas próprias variáveis de instância. Assim, será possível atribuir esses valores quando osenums forem inicializados passando um valor para o construtor enum. Vamos gastar um tempinho para explicar isso,mas observe o código a seguir:

Declarando Enums (Objetivo 1.3 e 1.4 do Exame)

38 Capítulo 1: Declarações e Controles de Acesso

enum CoffeeSize {

// 8, 10 e 16 são passados para o construtor

BIG(8), HUGE(10), OVERWHELMING(16);

CoffeeSize(int ounces) { // construtor

this.ounces = ounces;

}

private int ounces; // variável de instância

public int getOunces() {

return ounces;

}

}

class Coffee {

CoffeeSize size; // cada instância de Coffee tem um enum

public static void main(String[] args) {

Coffee drink1 = new Coffee();

drink1.size = CoffeeSize.BIG;

Coffee drink2 = new Coffee();

drink2.size = CoffeeSize.OVERWHELMING;

System.out.println(drink1.size.getOunces()); // imprime 8 na tela

for (CoffeSize cs: CoffeSize.values ())

System.out.println(cs + “ “ + cs.getOunces ()) ;

}

}

Que produz o seguinte resultado:

8BIG 8HUGE 10OVERWHELMING 16

Observação: cada enum tem um método static chamado values() que retorna um array dos valores de enum naordem em que são declarados.

Os principais pontos a se lembrar sobre os construtores de enums são:

JAMAIS será possível invocar diretamente um construtor enum. Este construtor será invocado automaticamente,com os argumentos definidos pelo programador, após o valor da constante. Por exemplo, BIG(8) invoca oconstrutor CoffeeSize que pega um int, passando o int literal 8 para o construtor. (Nos bastidores, é claro, vocêpode imaginar que BIG também é passado ao construtor, mas não precisamos saber desses detalhes, que não sãoimportantes)

É possível definir mais de um argumento para o construtor, bem como sobrecarregar o construtor enum, assimcomo é possível sobrecarregar um construtor de classe normal. Os construtores serão discutidos maisdetalhadamente no Capítulo 2. Para inicializar um CoffeeType com o número de onças e também com outrotipo, deve-se passar dois argumentos para o construtor, como BIG(8, “A”), significando que o construtor emCoffeeSize é capaz de receber tanto um int quanto uma string

E, finalmente, você pode definir algo realmente estranho em um enum, que se parece com uma classe internaanônima (sobre a qual falaremos no Capítulo 8). É o chamado corpo de classe específico da constate, e você pdoeusá-lo quando precisar que determinada constante substitua um método definido no enum.

39

Imagine este cenário: você quer que os enums tenham dois métodos – um para onças e um para código de registro(uma String). Agora imagine que a maioria dos tamanhos dos cafés usa o mesmo código, “B”, mas o tamanho OVER-WHELMING usa o tipo “A”. Você pode definir um método getLidCode() no enum CoffeeSize que retorne“B”, mas nesse caso você precisa de uma forma de substituí-lo para OVERWHELMING. Você não quer colocar umcódigo if/then de difícil manutenção no método getLidCode(), então a melhor saída poderia ser fazer com quea constante OVERWHELMING de alguma forma substitua o método getLidCode().

Isso parece estranho, mas você precisa entender as regras básicas de declaração:enum CoffeeSize {

BIG(8),

HUGE(10),

OVERWHELMING(16) { // inicie um bloco de código que defina

// o “corpo“ para esta constantepublic String getLidCode() { // substitua o método

// definido em CoffeeSize

return “A“;}

}; // <— o ponto-e-vírgula é OBRIGATÓRIO quando há um corpo

CoffeeSize(int ounces) {

this.ounces = ounces;

}

private int ounces;

public int getOunces() {

return ounces;

}

public String getLidCode() { // este método é substituído

// pela constante OVERWHELMING

return “B”; // o valor padrão que queremos retornar

// para as constantes CoffeeSize

}

}

Resumo para a CertificaçãoApós absorver o material deste capítulo, você deverá estar familiarizado com algumas das nuances da linguagemJava. Você poderá talvez se sentir confuso sobre por que teve a idéia de fazer este exame. Isso é normal a estaaltura. Caso esteja ouvindo a si mesmo dizendo “onde eu estava com a cabeça?”, basta se deitar e descansar até queisso passe. Nós gostaríamos de poder dizer que fica mais fácil, que este foi o capítulo mais difícil e que daqui emdiante fica tudo menos complicado...

Vamos rever brevemente o que você precisará saber para o exame.

Haverá muitas questões indiretamente relativas a palavras-chave, então, certifique-se de que sabe identificar quais sãopalavras-chave reais e quais não são.

Embora as convenções de nomeação como o uso de camelCase não caiam diretamente no exame, ainda assim você teráde entender os fundamentos da nomeação JavaBeans, a qual usa camelCase.

Você precisa entender as regras associadas com a criação de identificadores válidos, e as regras associadas comdeclarações de código-fonte, incluindo o uso de declarações package e import.

Agora você tem um bom entendimento do controle de acesso no que se refere a classes, método e variáveis. Você já viucomo os modificadores de acesso (public, protected e private) definem o controle de acesso de uma classe ouum membro.

Você aprendeu que as classes abstract podem conter tanto métodos abstract quanto não-abstract, masque se um só método for marcado como abstract, então a classe deve ser marcada como abstract. Não seesqueça de que uma subclasse concreta (não-abstract) de uma classe abstract deve fornecer implementaçõespara todos os métodos abstract da superclasse, mas que uma classe abstract não precisa implementar os

Resumo para a Certificação

40 Capítulo 1: Declarações e Controles de Acesso

métodos abstract da sua superclasse. Uma subclasse abstract pode “passar a bola” para a primeirasubclasse concreta.

Examinamos a implementação de interfaces. Lembre-se de que as interfaces podem estender uma outra interface (oumesmo múltiplas interfaces), e que qualquer classe que implemente uma interface deve implementar todos os métodos detodas as interfaces da árvore de herança da interface que a classe está implementando.

Também vimos os outros modificadores, incluindo static, final, abstract, synchronized e assim pordiante. Você aprendeu como alguns modificadores nunca podem ser combinados em uma declaração, por exemplo,misturar abstract com final ou private.

Tenha em mente que não existem objetos final em Java. Uma variável de referência marcada como final nuncapoderá ser modificada, mas o objeto a que se refere pode ser modificado.

Você viu que final aplicado a métodos significa que uma subclasse não os poderá substituir, e, quando aplicado a umaclasse, a classe final não poderá ser subclassificada.

Lembre-se que, a partir do Java 5, os métodos podem ser declarados com um parâmetro var-arg (que pode usar de zero a muitosargumentos do tipo declarado), mas que você só pode ter um var-arg por método, e ele deve ser o último parâmetro do método.

Certifique-se de estar familiarizado com os tamanhos relativos dos primitivos numéricos. Lembre-se de que, enquanto osvalores de variáveis não-final podem ser modificados, o tipo de uma variável de referência não pode.

Você aprendeu também que arrays são objetos que contêm muitas variáveis do mesmo tipo. Os arrays podem tambémconter outros arrays.

Lembre-se do que aprendeu sobre variáveis e métodos static, especialmente que os membros static sãousados por-classe em vez de por-instância. Não se esqueça de que um método static não pode acessardiretamente uma variável de instância a partir da classe onde reside, porque ele não tem uma referênciaexplícita a nenhuma instância particular da classe.

Finalmente, abordamos um recurso novo do Java 5, enums. Um enum é uma forma muito mais segura e flexívelde se implementar constantes do que era possível em versões anteriores de Java. Pelo fato de serem um tipoespecial de classe, os enums podem ser declarados de forma bastante simples, ou podem ser bem complexos –incluindo atributos tais como métodos, variáveis, construtores e um tipo especial de classe interna chamada decorpo de classe específico da constante.

Antes de fazer o teste de treinamento, passe algum tempo com o otimistamente chamado “Exercício Rápido”. Volte aconsultar esse teste freqüentemente, à medida que for lendo este livro e especialmente quando estiver perto da prova evocê estiver tentando memorizar tanto quanto conseguir. Porque – e eis aqui o conselho que você gostaria que sua mãetivesse lhe dito antes de você ir para a faculdade – não importa o que você sabe, o que importa é quando você sabe.

Para o exame, saber o que você não pode fazer com a linguagem Java é tão importante quanto saber o que vocêpode fazer. Experimente as questões de amostra! Elas são bastante semelhantes à dificuldade e à estrutura dasquestões do exame real, e deverão lhe abrir os olhos para o quão difícil o exame pode ser. Não se preocupe seerrar várias delas. Se você perceber que tem dificuldade em um tópico específico, passe mais tempo revisando-oe estudando-o. Muitos programadores precisam de duas ou três leituras sérias de um capítulo (ou um objetivoindividual) antes de conseguirem responder às questões com confiança.

Exercícios RápidosLembre-se de que quando falamos de classes neste capítulo, estamos nos referindo a classes não-internas, ouclasses de nível mais alto. Dedicaremos todo o Capítulo 8 às classes internas.

Identificadores (Objetivo 1.3)Os identificadores podem começar com uma letra, um underscore, ou um caracter monetário.

Depois do primeiro caracter, os identificadores podem incluir também dígitos.

Os identificadores podem ter qualquer extensão.

Os métodos JavaBeans devem ser nomeados usando-se camelCase e, dependendo do propósito do método,devem começar com set (“define”), get (“obtém”), is(“é”), add(“adiciona”) ou remove.

Regras de Declaração (Objetivo 1.1)Um arquivo de código-fonte só pode ter uma classe pública.

Se o arquivo de código-fonte tiver uma classe pública, seu nome terá que coincidir com o dessa classe.

O arquivo só pode ter uma instrução de pacote, porém, várias de importação.

A instrução de pacote (se houver) deve ficar na primeira linha (fora os comentários) do arquivo de código-fonte.

A instrução de importação (se houver) deve vir depois do pacote e antes da declaração de classe.

41

Se não houver instrução de pacote, as instruções de importação terão que ser as primeiras (fora os comentários) doarquivo de código-fonte.

As instruções de pacote e de importação são aplicadas a todas as classes do arquivo.

O arquivo pode ter mais de uma classe não pública.

Os arquivos que não tiverem classes públicas não apresentarão restrições de nomeação.

Modificadores de Acesso a Classe (Objetivo 1.1)Há três modificadores de acesso: public, protected e private.

Há quatro níveis de acesso: public, protected, default e private.

As classes só podem ter acesso public ou default.

Uma classe com acesso default pode ser visualizada somente por outra classe com o mesmo pacote.

Uma classe com acesso public pode ser vizualizada por todas as classes a partir de todos os pacotes.

A visibilidade das classes gira em torno de se o código de uma classe pode:

Criar uma instância de outra classe

Estender (ou criar subclasses) outra classe

Acessar métodos e variáveis de outra classe

Modificadores de Classe (não referentes a acesso) (Objetivo 1.2)As classes também podem ser alteradas com final, abstract ou strictfp.

Uma classe não pode ser final e abstract.

Uma classe final não pode ter subclasses.

Uma classe abstract não pode ser instanciada.

Uma classe com somente um método abstract significa que a classe inteira deve ser abstract.

Uma classe abstract pode ter métodos abstracts ou não.

A primeira classe concreta a estender uma classe abstract terá que implementar todos os métodos ab-stracts.

Implementação de Interfaces (Objetivo 1.2)As interfaces são contratos que definem o que a classe poderá fazer, mas não dizem nada sobre a maneira pela qualela deverá fazê-lo.

As interfaces podem ser implementadas por qualquer classe, de qualquer árvore de herança.

A interface é como uma classe 100% abstract, e será implicitamente abstract caso você digite ou não omodificador abstract na declaração.

Uma interface só pode ter métodos abstracts, nenhum método concreto é permitido.

Os métodos das interfaces são, por padrão, public e abstracts – a declaração explícita dessesmodificadores é opcional.

As interfaces podem ter constantes, que são sempre implicitamente public, static e final.

As declarações da constante de interface com public, static e final são opcionais em qualquer combinação.

Uma classe de implementação não-abstract válida terá as propriedades a seguir:

Fornecerá implementações concretas dos métodos da interface.

Deve seguir todas as regras de sobrecarga válidas para os métodos que implementa.

Não deve declarar nenhuma exceção nova do método de implementação.

Não deve declarar nenhuma exceção que seja mais abrangente do que as declaradas no método da interface.

Pode declarar exceções de tempo de execução em qualquer implementação de método da interface, independentedo que constar na declaração da interface.

Deve manter a assinatura (são permitidos retornos covariantes) e o tipo de retorno exatos dos métodos queimplementa (mas não precisa declarar as exceções da interface).

Uma classe que estiver implementando uma interface pode ela própria ser abstract.

Exercícios Rápidos

42 Capítulo 1: Declarações e Controles de Acesso

Uma classe de implementação abstract não precisa implementar os métodos da interface (mas a primeirasubclasse concreta precisa).

A classe só pode estender uma classe (sem herança múltipla), porém, pode implementar várias.

As interfaces podem estender uma ou mais interfaces.

As interfaces não podem estender uma classe ou implementar uma classe ou interface.

Quando fizer o exame, verifique se as declarações de interface e classe são válidas antes de verificar outraslógicas do código.

Modificadores de Acesso a Membros (Objetivos 1.3 e 1.4)Os métodos e as variáveis de instância (não locais) são conhecidos como “membros”.

Os membros podem usar todos os quatro níveis de acesso: public, protected, default, private.

O acesso aos membros se dá de duas formas:

O código de uma classe pode acessar um membro de outra classe

Uma subclasse pode herdar um membro de sua superclasse.

Se uma classe não puder ser acessada, seus membros também não poderão.

A visibilidade da classe deve ser determinada antes da dos membros.

Os membros public podem ser acessados por todas as outras classes, mesmo de pacotes diferentes.

Se um membro da superclasse for public, a subclasse o herdará – independente do pacote.

Os membros acessados sem o operador ponto (.) têm que pertencer à mesma classe.

this sempre referenciará o objeto que estiver sendo executado no momento.

this.aMethod( ) é o mesmo que simplesmente chamar aMethod( ).

Os membros private só podem ser acessados por um código da mesma classe.

Os membros private não ficam visíveis para as subclasses, portanto, não podem ser herdados.

Os membros default e protect só diferem quando subclasses estão envolvidas.

Os membros default só podem ser acessados por outras classes do mesmo pacote.

Os membros protect podem ser acessados por outras classes do mesmo pacote, além de por subclasses,independente do pacote.

protect = pacote + kids (kids significando subclasses).

Por subclasses externas ao pacote, o membro protect só pode ser acessado através da herança: uma subclasseexterna ao pacote não pode acessar um membro protect usando a referência a uma instância da superclasse (emoutras palavras, a herança é o único mecanismo para uma subclasse externa ao pacote acessar um membroprotect de sua superclasse).

Um membro protect herdado por uma subclasse de outro pacote não pode ser acessado por nenhuma outraclasse do pacote da subclasse, exceto pelas próprias subclasses dessa.

Variáveis Locais (Objetivo 1.3)As declarações de variáveis locais (de método, automáticas, de pilha) não podem ter modificadores de acesso.

final é o único modificador disponível para variáveis locais.

As variáveis locais não recebem valores padrão, portanto, devem ser inicializadas antes do uso.

Outros Modificadores – Membros (Objetivo 1.3)Os métodos final não podem ser sobrecarregados em uma subclasse.

Os métodos abstract foram declarados, com uma assinatura, um tipo de retorno e uma cláusula throws opcional,mas não foram implementados.

Os métodos abstract terminam com um ponto-e-vírgula, e não chaves.

Há três maneiras de identificar um método não abstract:

O método não é marcado como abstract.

O método possui chaves.

O método possui um código entre as chaves.

43

A primeira classe não-abstrata (concreta) a estender uma classe abstract deve implementar todos os métodosabstract dessa.

O modificador synchronized só é aplicado a métodos e a blocos de código.

Os métodos synchronized podem ter qualquer controle de acesso e também serem marcados como final.

Os métodos abstract devem ser implementados por uma subclasse, portanto, têm de ser herdados. Por essa razão:

Os métodos abstract não podem ser private.

Os métodos abstract não podem ser final.

O modificador native só é aplicado a métodos.

O modificador strictfp só é aplicado a classes e métodos.

Métodos com Argumentos Variáveis (var-args) (Objetivo 1.4)A partir de Java 5, os métodos podem declarar um parâmetro que aceita de zero a vários argumentos, é o chamadométodo var-arg.

Um parâmetro var-arg é declarado com a sintaxe tipo... nome; por exemplo:doStuff (int... x) { }

Um método var-arg só pode ter um parâmetro var-arg.

Em métodos com parâmetros normais e um var-arg, o var-arg deve vir por último.

Declarações de Variáveis (Objetivo 1.3)As variáveis de instância podem:

Ter qualquer tipo de controle de acesso

Serem marcadas como final ou transient

As variáveis de instância não podem ser declaradas com abstract, sychronized, native ou strictfp.

É válido declarar uma variável local com o mesmo nome de uma variável de instância; isso é chamado de“sombreamento”.

As variáveis final apresentam as seguintes propriedades:

Não podem ser reinicializadas, uma vez que tiverem um valor atribuído.

As variáveis de referência final não podem referenciar um objeto diferente se já tiverem um objeto atribuído a elas.

As variáveis de referência final devem ser inicializadas antes que a execução do construtor seja concluída.

Não existem objetos final. Uma referência a objeto marcada como final não significa que o objetopropriamente dito seja inalterável.

O modificador transient só pode ser aplicado a variáveis de instância.

O modificador volatile só pode ser aplicado a variáveis de instância.

Declarações de Arrays (Objetivo 1.3)

Arrays podem conter primitivas ou objetos, mas o array em si é sempre um objeto

Ao declarar um array, os colchetes podem estar à esquerda ou à direita do nome da variável.

Nunca é válido incluir o tamanho do array em sua declaração.

Um array de objetos pode conter qualquer objeto que passe no teste de IS-A [É-UM, em inglês] (ou instanceof)para o tipo declarado no array. Por exemplo: se Horse (Cavalo) estende o tipo Animal, então um objeto Horsepoderá entrar no array Animal.

Variáveis e métodos estáticos (Objetivo 1.4)Não estão ligados a qualquer instância específica de uma classe.

Não é preciso qualquer instância de classe para usar membros static de uma classe.

Existe apenas uma cópia de uma variável e/ou classe static, que é compartilhada por todas as instâncias.

Exercícios Rápidos

44 Capítulo 1: Declarações e Controles de Acesso

Métodos static não têm acesso direto a métodos não-static.

Enums (Objetivo 1.3)Um enum especifica uma lista de valores constantes que podem ser atribuídos a um determinado tipo.Um enum não é uma String nem um int; o tipo constante de um enum é o tipo do próprio enum . Porexemplo, INVERNO, PRIMAVERA, VERÃO e OUTONO são do tipo enum Estação.Um enum pode ser declarado fora ou dentro de uma classe, mas não em um método.

Um enum declarado fora de uma classe não pode ser marcado com static, final, abstract,protected ou private.Os enums podem conter construtores, métodos, variáveis e corpos de classes constantes.As constantes enum podem enviar argumentos para o construtor enum, usando a sintaxe BIG(8), onde o literal int8 é passado ao construtor enum.Os construtores enum podem ter argumentos e podem ser sobrecarregados.Os construtores enum nunca podem ser chamados diretamente no código. Eles são sempre chamadosautomaticamente quando um enum é inicializado.O ponto-e-vírgula ao final da declaração de um enum é opcional. Ambos são válidos:enum Foo { ONE, TWO, THREE}

enum Foo { ONE, TWO, THREE};

MyEnum.values() retorna um array dos valores de MyEnum.

Teste IndividualAs questões a seguir vão ajudá-lo a avaliar a compreensão do material apresentado neste capítulo. Leia todas asalternativas com cuidado, pois mais de uma delas pode ser correta. Marque todas as alternativas corretas em cadaquestão. Mantenha-se concentradoSe você encontrar dificuldade ao fazer este teste pela primeira vez, não se martirize. Pense positivo. Repita afirmaçõesestimulantes para si mesmo, como “Eu sou inteligente o suficiente para entender enums” e “Tudo bem, aquele outro carasabe mais sobre enums do que eu, mas aposto que ele não pode <inserir algum assunto que você domine> como eu”.

1. Qual das seguintes afirmativas está correta? (Marque todas as corretas.)A. “X estende Y” é correto se, e somente se, X for uma classe e Y for uma interface.B. “X estende Y” é correto se, e somente se, X for uma interface e Y for uma classe.C. “X estende Y” é correto se X e Y forem ambos classes ou ambos interfaces.D. “X estende Y” é correto para todas as combinações de X e Y sendo classes e/ou interfaces.

2. Quais nomes de métodos obedecem ao padrão JavaBeans? (Marque todas as corretas)A. addSizeB. getcustC. deleteRepD. isColorado

E. putDimensions

3. Dado o código a seguir:1. class Voop {

2. public static void main(String [] args) {

3. doStuff(1);

4. doStuff(1,2);

5. }

6. // insira código aqui

7. }

Qual destas opções, inseridas independentemente na linha 6, irá compilar? (Marque todas as corretas.)

45

A. static void doStuff(int... doArgs) { }

B. static void doStuff(int[ ] doArgs) { }

C. static void doStuff(int doArgs...) { }

D. static void doStuff(int... doArgs, int y) { }

E. static void doStuff(int x, int... doArgs) { }

4. Dado o código a seguir:1. enum Animals {

2. DOG(“woof“), CAT(“meow“), FISH(“burble“);3. String sound;

4. Animals(String s) { sound = s; }

5. }

6. class TestEnum {

7. static Animals a;

8. public static void main(String[] args) {

9. System.out.println(a.DOG.sound + “ “ + a.FISH.sound);10. }

11. }

Qual é o resultado?

A. woof burble

B. Múltiplos erros de compilação

C. A compilação falha devido a um erro na linha 2

D. A compilação falha devido a um erro na linha 3

E. A compilação falha devido a um erro na linha 4

F. A compilação falha devido a um erro na linha 9

5. Dados os dois arquivos mostrados a seguir:1. package pkga;

2. public class Foo {

3. int a = 5;

4. protected int b = 6;

5. public int c = 7;

6. {

3. package pkgb;

4. import pkgA.*;

5. public Class Baz.*;

6. public static void main (String)[] args) {

7. Foo f = new Foo();

8. System.out.print (“ “ + f.a);

9. System.out.print (“ “ + f.b);

10. System.out.println (“ “ + f.c);

11. }

12. }

Qual é o resultado? (Marque todas as corretas.)

Teste Individual

46 Capítulo 1: Declarações e Controles de Acesso

A. 5 6 7

B. 5 seguido de uma exceção

C. Ocorre falha na compilação com um erro na linha 7

D. Ocorre falha na compilação com um erro na linha 8

E. Ocorre falha na compilação com um erro na linha 9

F. Ocorre falha na compilação com um erro na linha 10

6. Dado o código a seguir:1. public class Eletronic implements Device { public void doIt() { } }

2.

3. abstract clas Phonel extendeds Eletronic { }

4.

5. abstract class Phone2 extends Eletronic

{ public void doIt (int x) { } }

6.

7. class Phone3 extends Eletronic implements Device

{ public void doStuff() { } }

8.

9. interface Device { public void doIt (); }

Qual é o resultado? (Marque todas as corretas.)A. A compilação é bem-sucedida.

B. Ocorre falha na compilação com um erro na linha 1

C. Ocorre falha na compilação com um erro na linha 3

D. Ocorre falha na compilação com um erro na linha 5

E. Ocorre falha na compilação com um erro na linha 7

F. Ocorre falha na compilação com um erro na linha 9

7. Dado o código a seguir:4. class Announce {

5. public static coid main (String [] args) {

6. for (int ___x = 0; ___x , 3; ___x++) ;

7. int #1b = 7;

8. long [] x [5];

9. Boolean [] ba [];

10. enum Traffic { RED, YELLOW, GREEN };

11. }

12. }

Qual é o resultado? (Marque todas as corretas.)

A. A compilação é bem-sucedida

B. Ocorre falha na compilação com um erro na linha 6

C. Ocorre falha na compilação com um erro na linha 7

D. Ocorre falha na compilação com um erro na linha 8

E. Ocorre falha na compilação com um erro na linha 9

F. Ocorre falha na compilação com um erro na linha 10

47

8. Dado o código a seguir:3. public class TestDays {

4. public enum Days { MON, TUE, WED };

5. public static void main (String [] args) { ;

6. for (Days d : Days.values () )

7. ;

8. Days [] d2 = Days.values ();

9. System.out.println (d2[2]);

10. }

11. }

Qual é o resultado? (Marque todas as corretas.)

A. TUE

B. WED

C. Não é possível prever o resultado

D. Ocorre falha na compilação com um erro na linha 4

E. Ocorre falha na compilação com um erro na linha 6

F. Ocorre falha na compilação com um erro na linha 8

G. Ocorre falha na compilação com um erro na linha 9

9. Dado o código a seguir :4. public class Frodo extends Hobbit {

5. public static void main (String [] args) {

6. Short myGold = 7;

7. System.out.println (countGold(myGold, 6));

8. }

9. }

10. class Hobbit {

11. int countGold (int x, int y) { return x + Y; }

12. }

Qual é o resultado?

A. 13

B. Ocorre falha na compilação devido a múltiplos erros

C. Ocorre falha na compilação com um erro na linha 6

D. Ocorre falha na compilação com um erro na linha 7

E. Ocorre falha na compilação com um erro na linha 11

Respostas1. C está correta.

A está incorreta porque as classes implementam interfaces, mas não as estendem. B está incorreta porque asinterfaces apenas “herdam de” outras interfaces. D está incorreta com base nas regras explicadas anteriormentes.(Objetivo 1.2)

2. B e D usam os prefixos válidos get e is.

A está incorreta porque “add” pode ser usada apenas com métodos Listener. C e E estão incorretas porque “delete” e “put” não são prefixos válidos para nomes no padrão JavaBeans. (Objetivo 1.4)

Respostas

48 Capítulo 1: Declarações e Controles de Acesso

3. A e E usam a sintaxe válida para argumentos de variáveis.

B e C possuem sintaxe invalida para argumentos de variáveis e D está incorreta porque o argumento de variáveldeve ser o último entre os argumentos de um método (Objetivo 1.4)

4. A está correta; enums podem ter construtores e variáveis.

B, C, D, E e F estão incorretas, pois todas essas linhas possuem sintaxe válida. (Objetivo 1.3)

5. D e E são as alternativas corretas. A variável a tem acesso default, por isso não pode ser acessada de fora do package. A variável b tem acesso protegido em pkgA

A, B, C e F estão incorretas com base nas informações fornecidas acima. (Objective 1.1)

6. A está correta; todas são declarações válidas.

B, C, D, E e F estão incorretas com base nas informações fornecidas acima. (Objective 1.2)7. C, D e F estão corretas. Nomes de variáveis não podem começar com #, uma declaração de array não pode

incluir tamanho sem uma instanciação e enums não podem ser declarados dentro de um método.

A, B, e E estão incorretas com base nas informações fornecidas acima. (Objective 1.3 )

8. B está correta. Cada enum tem um método static values()que retorna um array dos valores do enumna ordem em que foram declarados no enum.

A, C, D, E, F e G estão incorretas com base nas informações fornecidas acima. (Objective 1.3 )

9. D está correta. autobox do Short myGold está correto, mas o método countGold não pode ser invocado apartir de um contexto estático.

A, B, C, e E estão incorretas com base nas informações fornecidas acima. (Objective 1.4 )