Classes e objetos em Java

Aprenda a escrever suas próprias classes em Java. Defina os campos que armazenam o estado de um objeto, escreva construtores que deem valores iniciais válidos a cada novo objeto e adicione métodos de instância que usem e alterem esse estado. Proteja seus objetos com campos privados, métodos de acesso, métodos modificadores e verificações, dê a eles um toString legível e termine projetando, implementando e testando uma classe completa a partir de uma breve descrição.

BásicoAula 5 de 11 do curso Curso de Programação orientada a objetos com Java

O que você vai aprender

  1. Explique como uma classe define um novo tipo de dado com seu próprio comportamento e crie e use objetos desse tipo em um programa.
    • Explique o que são uma classe e um objeto
      Descreva uma classe como a definição de um tipo, um objeto como uma instância desse tipo e o estado e o comportamento como aquilo que os objetos armazenam e fazem.
    • Crie objetos e chame seus métodos
      Crie objetos com new, chame seus métodos com a notação de ponto e preveja como objetos distintos se comportam.
  2. Declare as variáveis de instância que armazenam o estado de um objeto e escreva construtores que deem valores iniciais válidos a cada novo objeto.
    • Declare variáveis de instância
      Declare campos com tipos adequados, conheça seus valores padrão e distinga-os de variáveis locais e parâmetros.
    • Escreva construtores que inicializem objetos
      Escreva construtores que definam cada campo, use this para distinguir campos de parâmetros e evite erros que deixam campos sem valor definido.
    • Disponibilize vários construtores e encadeie-os
      Faça a sobrecarga de construtores para diferentes formas de criar um objeto e use this(...) para escrever o código de inicialização uma única vez.
  3. Escreva métodos de instância que leiam e alterem o estado de um objeto, acompanhe seus efeitos e decida quando algo pertence a um objeto ou à classe como um todo.
    • Escreva métodos de instância que usem e alterem o estado
      Escreva métodos que informem ou alterem os campos de um objeto, chame outros métodos do mesmo objeto e acompanhe o estado dos objetos passo a passo.
    • Distinga membros de instância de membros estáticos
      Use this para o objeto atual, decida o que deve ser estático e corrija os erros causados pela mistura de código estático e de instância.
  4. Oculte campos com modificadores de acesso, forneça acesso controlado por meio de métodos de acesso, métodos modificadores e métodos com funções claras, e mantenha cada objeto em um estado válido.
    • Oculte dados com modificadores de acesso
      Use private, acesso de pacote, protected e public para controlar qual código pode usar os membros de uma classe e explique por que os campos são mantidos privados.
    • Escreva métodos de acesso e métodos modificadores
      Escreva métodos de acesso e modificadores com a nomenclatura padrão e decida quais campos precisam deles e quando um método com função clara é melhor.
    • Mantenha os objetos válidos por meio de verificações
      Defina as regras que o estado de um objeto deve seguir, aplique-as em construtores e métodos e evite fornecer dados internos que permitam contornar essas verificações.
  5. Dê aos objetos uma forma textual legível com toString e depois projete, escreva e teste uma classe completa a partir de uma breve descrição.
    • Escreva um método toString
      Escreva um método toString que retorne uma descrição legível de um objeto e saiba quando o Java o chama automaticamente.
    • Projete, implemente e teste uma classe completa
      Transforme uma breve descrição em uma classe com campos, construtores, métodos e regras e depois teste cada comportamento a partir de um programa com main.

Guia de estudo de Classes e objetos em Java

5 capítulos

1

Classes, objetos e chamadas de métodos

Um programa muitas vezes precisa manter vários valores relacionados juntos: o nome, a espécie e a idade de um animal de estimação, por exemplo. Uma classe dá um tipo a esse grupo e reúne em um só lugar as ações que o utilizam. Você relacionará definições de classes aos objetos criados durante a execução de um programa e depois acompanhará chamadas de métodos para ver os dados de qual objeto mudam. A distinção entre classe, objeto e variável ajudará você a ler o código que escreverá a seguir.

1.1 Um tipo com estado e comportamento

Uma classe define um tipo: os dados que seus objetos lembram e as operações que oferecem. Um objeto, também chamado de instância, é um valor desse tipo criado durante a execução de um programa. Escrever uma definição de classe não cria um objeto.

Estado e comportamento

O nome, a espécie e a idade de um animal de estimação formam seu estado. Esses valores atuais ficam em variáveis de instância, também chamadas de campos. Uma operação como celebrar um aniversário é um comportamento, escrito como método. O método de aniversário fica junto da idade que ele altera, de modo que a regra é mantida em um só lugar.

Pense em uma classe como uma planta de construção. Muitas casas podem seguir uma planta, mas cada casa tem seu próprio conteúdo. Da mesma forma, dois animais podem seguir a mesma definição e ter idades diferentes. Você escreve os nomes dos campos uma vez; cada objeto recebe seus próprios valores.

Leia uma classe pequena
public class Pet {
    private String name;
    private String species;
    private int age;

    public Pet(String name, String species, int age) {
        this.name = name;
        this.species = species;
        this.age = age;
    }

    public void celebrateBirthday() {
        this.age++;
    }
}

Leia de fora para dentro. public class Pet apresenta o tipo, e as chaves externas contêm sua definição. As três primeiras declarações descrevem o estado. O bloco chamado Pet é um construtor: ele dá a um novo objeto seus primeiros valores. celebrateBirthday é um método: ele aumenta a idade do objeto atual. As palavras private e public controlam o acesso; exemplos posteriores as usam para proteger o estado.

Os parâmetros do construtor são valores fornecidos quando um objeto é criado. Em this.age = age;, o lado esquerdo indica o campo do objeto e o lado direito indica o parâmetro fornecido. O construtor armazena essa entrada para que o objeto possa lembrá-la após o fim da construção.

Coloque uma classe em uso

Você já usou classes de biblioteca. Scanner descreve objetos que leem dados de entrada, ArrayList descreve listas e um objeto String oferece operações como length(). Uma classe que você escreve segue a mesma ideia básica: ela disponibiliza um tipo útil para o restante do programa.

Sem Pet, um programa poderia passar nome, espécie e idade separadamente para muitos métodos. Ele precisa manter cada grupo unido corretamente. Um objeto Pet reúne os valores relacionados em uma unidade. Os métodos desse objeto sabem qual idade devem usar.

Organize e nomeie o código

Em arquivos de código-fonte comuns, uma classe pública chamada Pet é salva em Pet.java, com as mesmas letras maiúsculas e minúsculas. Uma classe Main separada pode conter o método main do programa, criar animais e chamar seus métodos. Pet não precisa de seu próprio main. Classes no mesmo pacote sem nome podem usar umas às outras sem importações; os exemplos simples mantêm essas classes em uma pasta.

Use substantivos em UpperCamelCase para classes, como LibraryBook. Use lowerCamelCase para campos e métodos: pageCount nomeia dados; giveBack() nomeia uma ação. Essas convenções ajudam o leitor a reconhecer cada parte, embora o compilador permita muitos outros nomes.

Principais conclusões

  • Uma classe define um tipo; um objeto é uma instância criada durante a execução do programa.
  • Campos armazenam o estado, e métodos fornecem comportamento.
  • Objetos de uma classe seguem a mesma definição e armazenam seus próprios valores nos campos de instância.
  • Uma classe pública em um arquivo de código-fonte comum usa o nome correspondente da classe como nome do arquivo.

1.2 Novos objetos e as referências que os acessam

Criar um objeto e declarar uma variável são operações diferentes. Uma variável fornece um nome pelo qual acessar um objeto; new cria o objeto ao qual o nome se referirá.

Leia uma instrução de criação de objeto
Pet luna = new Pet("Luna", "cat", 3);

Pet é o tipo da variável, e luna é seu nome. new Pet(...) cria um novo objeto e chama um construtor correspondente com três argumentos. O construtor armazena o nome, a espécie e a idade. A referência resultante é atribuída a luna.

Uma referência informa ao Java qual objeto usar. É útil desenhar uma variável como um nome com uma seta apontando para um objeto. A variável não é uma segunda cópia de todos os campos do objeto.

Chame um método em um objeto específico

O ponto em luna.celebrateBirthday() conecta uma referência a um método a ser executado em seu objeto. Um método que retorna um valor pode fornecê-lo a outra expressão:

luna.celebrateBirthday();
int years = luna.getAge();
System.out.println(years); // 4

Aqui getAge() é um método público que retorna a idade do animal. A chamada de aniversário altera o estado; o método de acesso lê esse estado. Pet.celebrateBirthday() falha porque esse método de instância precisa de um animal específico. O nome da classe, sozinho, não responde de quem é o aniversário.

Objetos distintos e referências compartilhadas
Pet max = new Pet("Max", "dog", 5);
luna.celebrateBirthday();
System.out.println(luna.getAge()); // 5
System.out.println(max.getAge());  // 5

Luna já tinha 4 anos, portanto o próximo aniversário a leva a 5. Max continua com 5. Idades iguais não fazem deles o mesmo objeto: as duas expressões new criaram animais distintos.

Agora considere uma atribuição sem new:

Pet other = luna;
other.celebrateBirthday();
System.out.println(luna.getAge()); // 6

A atribuição copia a referência de Luna. Ambos os nomes acessam um único animal, portanto alterá-lo por meio de other é visível por meio de luna. Para criar um segundo animal, chame new novamente.

Faça os argumentos corresponderem aos parâmetros do construtor

Os argumentos devem corresponder à quantidade, à ordem e aos tipos dos parâmetros de um construtor declarado. Se o único construtor disponível aceitar (String, String, int), new Pet() não compila. O Java não adivinha valores ausentes. Trocar as duas cadeias de caracteres, porém, ainda compila: new Pet("cat", "Luna", 3) fornece os tipos certos, mas os significados errados. Leia os nomes dos parâmetros para verificar essa ordem.

Estas duas tentativas incompletas falham por motivos diferentes:

Pet a;                         // declaration only
// System.out.println(a.getAge()); // a has no assigned value
// Pet b = Pet("Bo", "cat", 2);    // missing new

Uma variável local deve receber um valor antes de ser usada. Sem new, o Java procura um método chamado Pet, não uma expressão de criação de objeto. Depois que um objeto existe, exibi-lo pode mostrar um texto como Pet@8bcc55f até que você forneça um método toString() legível; essa saída não significa que a construção falhou.

Principais conclusões

  • Use new com argumentos que correspondam a um construtor disponível.
  • A notação de ponto chama um método de instância no objeto acessado por uma referência.
  • Outra expressão new cria outro objeto; a atribuição de uma referência compartilha um objeto existente.
  • Argumentos do mesmo tipo podem ser trocados sem erro de compilação, portanto confira seus significados.
  • Uma declaração local, por si só, não cria objeto e não dá à variável um valor utilizável.
2

Campos e o estado inicial de um objeto

Objetos precisam de um lugar para guardar seus dados e de uma maneira confiável de receber seus primeiros valores. Campos fornecem o armazenamento; construtores inicializam cada novo objeto. Você escolherá tipos de campos, separará o estado duradouro do trabalho local temporário e acompanhará a construção desde os valores padrão até um objeto pronto. Depois, oferecerá várias formas úteis de criar o mesmo tipo de objeto, mantendo a inicialização e as verificações compartilhadas em um só lugar.

2.1 Dados que um objeto lembra

Um objeto precisa de um campo para cada valor que deve lembrar entre chamadas de métodos. Escolha esses valores antes de escrever os métodos: eles formam o estado duradouro do objeto.

Declare campos com tipos adequados

Um campo fica dentro das chaves da classe, mas fora de todos os construtores e métodos. Uma declaração precisa de um tipo e um nome; um modificador de acesso e um inicializador também podem aparecer.

private String title;
private int pageCount;
private boolean lentOut = false;

String é adequado para texto, int para uma contagem inteira e boolean para uma condição de sim ou não. Campos também podem usar tipos de classe, como ArrayList<String>. Estes exemplos usam private; omitir o modificador resulta em acesso de pacote, não em acesso privado.

Cada objeto recebe uma cópia separada de cada campo de instância. Dois objetos Rectangle têm, cada um, um width e um height, embora as declarações apareçam apenas uma vez na classe.

Valores padrão nem sempre são valores iniciais utilizáveis
Tipo do campoValor padrão
int, long0
double0.0
booleanfalse
Tipos de classe, incluindo String e ArrayListnull

Um valor padrão é atribuído a um campo quando o espaço de armazenamento do objeto é criado. Ele pode não ser adequado à finalidade do objeto. Um campo de lista com valor null não é uma lista vazia: você ainda precisa criar a lista antes de adicionar um item.

Variáveis locais não recebem esse valor padrão. Dentro de um método, int total; seguido de System.out.println(total); não compila porque nenhum valor foi atribuído a total. Mantenha separadas a regra dos campos e a das variáveis locais.

Decida o que deve durar
Tipo de variávelOnde é declaradaPara que serve
Campo de instânciaNa classe, fora dos métodosValores lembrados por um objeto
ParâmetroNo cabeçalho de um construtor ou métodoEntradas para essa chamada
Variável localDentro de um bloco de método ou construtorTrabalho temporário para essa chamada

Um campo permanece com seu objeto. Um parâmetro fica disponível durante sua chamada, e uma variável local fica disponível em seu bloco enquanto essa chamada é executada. Se um contador precisa manter sua contagem de uma chamada para a seguinte, a contagem pertence a um campo. Um subtotal temporário usado em um cálculo pode ser local.

Armazene as entradas; calcule os valores derivados
public class Rectangle {
    private double width;
    private double height;

    public Rectangle(double width, double height) {
        this.width = width;
        this.height = height;
    }

    public double area() {
        return this.width * this.height;
    }
}

As dimensões estão em centímetros, portanto area() retorna uma área em centímetros quadrados. Armazenar um campo separado para a área criaria outro valor a atualizar sempre que uma das dimensões mudasse. Calculá-la a partir das dimensões mantém o resultado consistente.

Use um campo de instância final para um valor atribuído uma vez, como private final String title;. Dê a ele um valor em sua declaração ou em cada construtor. final impede a reatribuição. static tem outro significado: cria um campo de classe compartilhado. Adicionar static ao nome de um animal faria animais diferentes compartilharem uma única variável de nome.

Principais conclusões

  • Campos de instância são declarados fora dos métodos e armazenam o estado de cada objeto.
  • Campos recebem valores padrão; variáveis locais devem receber valores antes do uso.
  • Escolha campos para dados duradouros e variáveis locais para trabalho temporário.
  • Calcule valores derivados dos campos armazenados para evitar cópias inconsistentes.
  • Um campo de instância final recebe um valor uma vez; um campo estático é compartilhado pela classe.
  • Um campo de lista com null ainda precisa de um objeto de lista antes de poder ser usado.

2.2 Dos argumentos aos campos inicializados

Um construtor inicializa um objeto quando new o cria. Seu nome deve corresponder ao da classe, e ele não tem tipo de retorno. Até mesmo void transformaria a declaração em um método.

Transfira as entradas para o estado
public Pet(String name, String species, int age) {
    this.name = name;
    this.species = species;
    this.age = age;
}

Um construtor geralmente recebe entradas como parâmetros e as armazena em campos. Aqui cada parâmetro tem o mesmo nome de seu campo. O nome age sozinho se refere ao parâmetro; this.age se refere ao campo do objeto que está sendo criado. A atribuição lê o valor fornecido à direita e o escreve no campo à esquerda.

Para new Pet("Luna", "cat", 3), primeiro os campos do novo objeto recebem valores padrão: null, null e 0. O construtor então recebe os três argumentos e substitui esses valores padrão. Quando a construção termina, new produz a referência que o código que o chamou armazena.

Dois defeitos que compilam
public Pet(String name, String species, int age) {
    name = name;
    this.species = species;
    this.age = age;
}

As duas ocorrências de name se referem ao parâmetro, portanto a primeira linha atribui esse parâmetro a si mesmo. O nome do objeto permanece null. O código é válido, por isso é importante verificar os valores do novo objeto.

Uma declaração dentro do construtor causa um problema relacionado:

String nick = initialNick;

Se um campo chamado nick já existir, essa linha cria uma variável local com o mesmo nome. A variável local desaparece quando a construção termina. Escreva this.nick = initialNick; para armazenar a entrada no campo; não repita o tipo.

Saiba quando existe um construtor sem argumentos

Se uma classe não declarar construtores, o Java fornece um construtor padrão sem parâmetros. Para uma classe simples, seus campos mantêm os valores dos inicializadores declarados ou seus valores padrão. Assim que você declara um construtor, o Java deixa de fornecer o padrão.

Uma classe que tem apenas Pet(String name, String species, int age) não pode, portanto, ser criada com new Pet(). Adicione um construtor explícito sem argumentos apenas quando houver um estado inicial útil para ele. Observe também public void Pet(...): isso é um método, portanto não fornece o construtor pretendido.

Defina também os valores internos iniciais

Nem todo campo precisa vir de um argumento. Um novo livro sempre pode começar com this.lentOut = false;. Uma classe que possui uma lista pode inicializá-la assim, com ArrayList importado:

private ArrayList<String> tracks;

public Playlist() {
    this.tracks = new ArrayList<>();
}

A lista vazia está pronta para add. Deixar tracks como null faz uma chamada posterior a tracks.add(...) falhar com NullPointerException.

Um inicializador de campo é executado antes do corpo do construtor. Se private int score = 10; for seguido de this.score = 5; no construtor, a pontuação do objeto pronto será 5. Teste os valores após a construção, não apenas os valores escritos junto às declarações dos campos. Os construtores também precisam das mesmas regras de validação usadas em alterações posteriores, para que o estado inicial seja válido.

Principais conclusões

  • Um construtor tem o nome da classe e não tem tipo de retorno.
  • Use this.field = parameter quando os nomes forem iguais.
  • Nem a atribuição de um parâmetro a si mesmo nem uma nova variável local inicializa o campo pretendido.
  • O Java fornece um construtor padrão apenas quando a classe não declara construtores.
  • Inicialize o estado interno, como listas vazias, e aplique a validação durante a construção.

2.3 Várias formas de construir um tipo de objeto

Uma classe pode oferecer várias formas úteis de criar um objeto. Sobrecarga de construtores significa declarar construtores com listas de parâmetros diferentes.

Distinga construtores pelos parâmetros

O Java distingue construtores pela quantidade, pelos tipos e pela ordem de seus parâmetros. Os nomes dos parâmetros não os distinguem. Box(String label) e Box(String name) descrevem a mesma lista de parâmetros, portanto não podem ser declarados juntos em uma classe.

Um animal pode ser criado com uma idade ou como recém-nascido:

public Pet(String name, String species, int age) {
    this.name = name;
    this.species = species;
    this.age = age;
}

public Pet(String name, String species) {
    this(name, species, 0);
}

new Pet("Pip", "rabbit") seleciona o construtor com dois parâmetros. Esse construtor fornece 0 como a idade ausente e chama o construtor com três parâmetros. O novo objeto termina com o estado "Pip", "rabbit" e 0.

Encadeie a inicialização no mesmo objeto

Dentro de um construtor, this(...) chama outro construtor da mesma classe. O construtor mais curto escolhe os valores padrão; o mais completo faz a inicialização compartilhada. As verificações colocadas nessa inicialização se aplicam às duas formas de construção.

Compare duas linhas que parecem semelhantes:

Linha dentro de um construtorEfeito
this(name, species, 0);Inicializa o objeto atual por meio de outro construtor
new Pet(name, species, 0);Cria um animal separado

A segunda linha não preenche os campos do objeto atual. Se seu resultado nunca for armazenado, esse animal extra será descartado. O animal atual ainda pode ter campos null.

Acompanhe uma cadeia antes de rastrear o código posterior

Um relógio pode oferecer a meia-noite como padrão:

public Clock() {
    this(0, 0);
}

public Clock(int hours, int minutes) {
    this.hours = hours;
    this.minutes = minutes;
}

Para new Clock(), entre no construtor sem argumentos, siga this(0, 0) e atribua valores aos dois campos no construtor com dois argumentos. Depois, o controle retorna ao construtor sem argumentos. Isso cria um relógio, não dois. Uma chamada a new Clock(9, 5) começa diretamente no construtor mais completo.

Mantenha a cadeia válida e clara

Um construtor pode conter no máximo uma chamada this(...). A cadeia deve chegar a uma inicialização que não chame de volta a cadeia: dois construtores que delegam um ao outro causam um erro de compilação de construtor recursivo.

Colocar this(...) em primeiro lugar é um estilo claro que funciona em várias versões do Java. No Java 24 e em versões anteriores sem recursos de prévia, ela deve vir primeiro. O Java 25 permite instruções antes dela para tarefas como calcular ou verificar argumentos. Essas instruções não podem ler os campos de instância do objeto atual nem chamar seus métodos de instância; são permitidas atribuições a campos declarados na classe sem inicializadores na declaração.

Ofereça sobrecargas porque os códigos que chamam os construtores têm diferentes entradas úteis. Um relógio à meia-noite faz sentido; um livro sem título talvez não faça. A existência de um construtor completo não cria automaticamente sobrecargas mais curtas.

Principais conclusões

  • Construtores sobrecarregados diferem pelas listas de parâmetros, não pelos nomes dos parâmetros.
  • A chamada this(...) delega a outro construtor no mesmo objeto.
  • Mantenha a inicialização e as verificações compartilhadas em uma única forma de construção.
  • Uma cadeia de construtores não deve retornar a um construtor que já esteja nessa cadeia.
3

Métodos que leem e alteram o estado

Um objeto útil pode responder a perguntas sobre si mesmo e executar ações que alteram seu estado. Métodos de instância colocam essas operações ao lado dos campos que usam. Você acompanhará alterações uma instrução por vez, tratará a virada de um relógio e retornará valores que outros códigos possam usar. Você também decidirá quais dados pertencem a cada objeto e quais dados ou operações pertencem à classe, para que objetos distintos permaneçam separados.

3.1 Cálculos, alterações e rastreamento de estado

Um método de instância é executado para um objeto específico. Declare-o sem static e use os campos desse objeto por meio de nomes como this.width. Decida do que o código que o chama precisa: uma alteração de estado, um resultado retornado ou ambos.

Retorne cálculos; deixe alterações de estado explícitas

Para um retângulo cujas dimensões são armazenadas em centímetros:

public double area() {
    return this.width * this.height;
}

public double perimeter() {
    return 2 * (this.width + this.height);
}

public void scale(double factor) {
    this.width = this.width * factor;
    this.height = this.height * factor;
}

Um retângulo com lados de 3,0 e 4,0 tem área de 12,0 centímetros quadrados e perímetro de 14,0 centímetros. scale(2) altera os lados para 6,0 e 8,0. As chamadas seguintes retornam área 48,0 e perímetro 28,0. Cada método lê os campos atuais, portanto não é necessário atualizar uma área armazenada.

area() retorna um número que pode ser armazenado ou usado em um cálculo. Se apenas exibisse o número e tivesse tipo de retorno void, o código que o chama não poderia escrever double twice = r.area() * 2;. Deixe a exibição para o código que chama o método quando a função dele for calcular um valor.

Atualize campos relacionados em ordem

O método advance() de um relógio deve tratar a virada dos minutos e das horas:

public void advance() {
    this.minutes++;
    if (this.minutes == 60) {
        this.minutes = 0;
        this.hours++;
        if (this.hours == 24) {
            this.hours = 0;
        }
    }
}

Às 23:58, a primeira chamada chega a 23:59 e pula os dois blocos de reinicialização. A chamada seguinte chega por um instante ao minuto 60, volta-o para 0, aumenta a hora para 24 e a volta para 0. O estado final é 00:00. Mais uma chamada resulta em 00:01.

Rastreie objetos separadamente

Escreva uma linha após cada instrução e uma coluna para os campos de cada objeto. Altere apenas o objeto indicado pelo objeto receptor da chamada. Para animais com idades 2 e 7, dois aniversários no primeiro animal e setAge(1) no segundo deixam as idades em 4 e 1. Não execute o corpo de um método para todas as instâncias só porque elas compartilham uma classe.

Uma declaração local pode ocultar o campo que você pretendia atualizar. public void reset() { int count = 0; } apenas cria uma variável temporária. this.count = 0; reinicia a contagem duradoura.

Reutilize métodos e complete os caminhos de retorno

Dentro de um método de instância, area() e this.area() chamam o método de área do mesmo objeto. Um método de descrição pode reutilizar esse cálculo em vez de copiar sua expressão. Um método também pode alterar o estado e retornar se a operação foi bem-sucedida, como lend() faz ao marcar um livro como emprestado e informar true.

Um método que não seja void não pode simplesmente chegar ao fim sem retornar um valor compatível. Se get() retorna apenas dentro de if (count > 0), o que acontece quando a contagem é 0? Adicione o caminho de retorno necessário ou lance uma exceção para um valor que o método rejeite. Um caminho que lança uma exceção não retorna ao código que chamou o método e não precisa de um valor de retorno.

Principais conclusões

  • Métodos de instância leem ou alteram o estado do objeto no qual são chamados.
  • Retorne valores calculados para que os códigos que chamam os métodos possam usá-los em expressões.
  • Rastreie as instruções em ordem, mantendo separados os campos de cada objeto.
  • Métodos que tratam viradas devem fazer todos os campos relacionados voltarem ao intervalo permitido.
  • Reutilize outros métodos do mesmo objeto chamando-os diretamente ou com this.
  • Um método que retorna um valor precisa fornecê-lo em cada caminho que retorna normalmente.

3.2 Membros de cada objeto e membros compartilhados da classe

Pergunte a quem pertence um valor ou uma operação antes de decidir se deve usar static. A idade de um animal pertence a um animal. A contagem de todos os animais criados pertence à classe como um todo.

O objeto atual é this

Dentro de um construtor ou método de instância, this se refere ao objeto que está sendo construído ou recebendo a chamada. Em this.age++, ele identifica de quem é a idade que muda. Em this.name = name, ele distingue o campo de um parâmetro com o mesmo nome. this(...) é a forma de encadeamento de construtores.

Um método estático não tem objeto atual, portanto this não pode ser usado nele. Ele ainda pode criar um objeto ou receber uma referência e usá-la para chamar métodos de instância.

Campos compartilhados e campos de cada objeto
public class Counter {
    private int count;
    private static int created = 0;

    public Counter() {
        this.count = 0;
        created++;
    }

    public void increment() {
        this.count++;
    }

    public int getCount() {
        return this.count;
    }

    public static int getCreated() {
        return created;
    }
}

Após duas chamadas a new Counter(), há dois campos count separados, ambos inicialmente 0, e um campo created igual a 2. Incrementar o primeiro contador altera sua contagem para 1; o segundo permanece em 0. Counter.getCreated() ainda retorna 2 porque nenhum novo objeto foi construído.

Trabalhe por meio de um objeto a partir de main
public static void main(String[] args) {
    Counter c = new Counter();
    c.increment();
    System.out.println(c.getCount());
}

O método main clássico é estático. Uma chamada a increment() apenas pelo nome nesse método não teria um objeto alvo e não compilaria. A variável c fornece esse alvo. Tornar count estático para eliminar o erro mudaria o projeto: todos os contadores compartilhariam uma única contagem.

Tipo de métodoAcesso direto disponível
Método de instânciaSeus membros de instância e os membros estáticos da classe
Método estáticoMembros estáticos; membros de instância por meio de uma referência a objeto

O Java 25 também aceita formas de main como método de instância, mas o cabeçalho estático clássico continua válido. Estes exemplos o usam de forma consistente.

Escolha métodos e constantes com cuidado

Uma operação que precisa dos campos de um objeto deve ser um método de instância. Uma operação que depende apenas de seus parâmetros pode ser estática, como um método auxiliar que converte um número total de minutos em horas. Chamadas estáticas normalmente usam o nome da classe: Math.sqrt(16) ou Counter.getCreated().

Um valor fixo compartilhado geralmente é declarado como constante:

public static final int MAX_CELSIUS = 30;

public o torna disponível para os códigos que o usam, static dá à classe um campo compartilhado, e final impede a reatribuição. UPPER_SNAKE_CASE indica uma constante por convenção. Essa é uma exceção comum à regra de tornar campos privados. Não use static para nomes, dimensões ou outros estados comuns que precisam ser diferentes entre objetos.

Principais conclusões

  • A referência this identifica o objeto atual dentro de código de instância.
  • Membros estáticos pertencem à classe; membros de instância pertencem a objetos individuais.
  • Um método estático precisa de uma referência a objeto para usar membros de instância.
  • Corrija erros de contexto estático fornecendo o objeto adequado quando o estado pertencer a um objeto.
  • Um campo public static final normalmente fornece uma constante compartilhada.
4

Acesso controlado e estado válido

Uma classe deve controlar os valores que podem entrar em seu estado. Campos privados e métodos públicos permitem que a classe verifique cada alteração e ofereça operações úteis aos códigos que a usam. Você escolherá níveis de acesso, escreverá métodos de acesso e modificadores quando forem úteis e protegerá regras como um intervalo de temperatura permitido. Você também verá por que uma lista privada ainda pode ser exposta por um método de acesso e como impedir que código externo contorne as verificações da classe.

4.1 Estado privado e interface pública

Encapsulamento mantém o estado de um objeto junto com o código que o controla. Campos geralmente são privados, enquanto os códigos que usam o objeto recorrem a operações públicas. Isso oculta os detalhes de armazenamento e dá à classe um lugar para aplicar suas regras.

Escolha um nível de acesso
AcessoQuem pode usar o membro
privateCódigo na mesma classe
Sem modificadorCódigo no mesmo pacote
protectedO mesmo pacote, além do acesso por subclasses segundo as regras de subclasses do Java
publicCódigo que pode acessar o tipo que declara o membro

Um pacote agrupa classes. Os exemplos simples colocam classes comuns juntas sem uma declaração package, em um pacote sem nome. O acesso de pacote é o resultado da omissão do modificador; não existe uma palavra-chave de acesso package para adicionar a um campo.

Comece com o acesso mais restrito que seja útil. Torne os campos privados, os construtores e as operações necessários a outras classes públicos e os métodos auxiliares internos privados. Constantes públicas são uma exceção comum para campos.

Deixe a classe controlar as alterações

Se Pet declarar private int age;, uma classe Main separada não poderá atribuir luna.age = -5;. O compilador rejeita o acesso. Uma chamada como luna.setAge(-5) pode ser permitida, pois o método público pertence a Pet e pode decidir se armazena o argumento.

Um campo público permitiria que qualquer código contornasse esse método. Quando todas as alterações passam pelo código da classe, as verificações podem ficar em um só lugar. O acesso privado, por si só, não valida uma idade; os métodos também devem fazer as verificações.

Mantenha a interface pública estável

Suponha que um relógio inicialmente armazene campos hours e minutes separados. Os códigos que o usam chamam getHours() e getMinutes(). Depois você substitui os campos por um único valor minutesSinceMidnight:

public int getHours() {
    return this.minutesSinceMidnight / 60;
}

public int getMinutes() {
    return this.minutesSinceMidnight % 60;
}

Com 615 minutos armazenados, a divisão retorna 10 e o resto retorna 15. O relógio informa 10:15 por meio dos mesmos métodos. Os códigos que o usam não precisam ser reescritos porque dependiam das operações públicas, não de como o estado era armazenado. Essa liberdade de alterar detalhes internos é a ocultação de informações.

O acesso pertence às classes, não a objetos individuais

Código dentro de Pet pode ler um campo privado de outro objeto Pet. A permissão de acesso decorre de estar dentro da classe. Uma classe de nível superior diferente não recebe permissão por ter uma referência a um animal ou por estar na mesma pasta.

Para declarações comuns de classes de nível superior, as opções de acesso são public ou nenhum modificador. Uma declaração private class Pet no nível superior é ilegal. Uma classe pública de nível superior fica no arquivo de código-fonte correspondente, e um arquivo de código-fonte comum contém no máximo uma classe pública de nível superior.

Campos privados são um limite de projeto do programa. Eles impedem que outro código comum dependa diretamente dos campos internos, mas não são uma forma de manter um valor em segredo de alguém que pode inspecionar o programa. Use-os para controlar a interface da sua classe e proteger seu estado.

Principais conclusões

  • Campos privados e operações públicas mantêm o controle do estado dentro da classe.
  • Omitir um modificador de acesso resulta em acesso de pacote.
  • Métodos públicos permitem alterar o armazenamento interno sem alterar os códigos que os chamam.
  • O acesso privado é verificado por classe, portanto código dentro da classe pode acessar os campos de outra instância.
  • Classes comuns de nível superior usam acesso público ou de pacote.

4.2 Métodos de acesso adequados à classe

Uma classe pode permitir que os códigos que a usam leiam ou alterem partes selecionadas de seu estado por meio de métodos. Decida quais operações a classe deve oferecer antes de criar métodos de acesso para todos os campos.

Retorne valores com métodos de acesso

Um método de acesso, também chamado de método acessor, retorna informações sem alterar o objeto. Um método de acesso comum lê um campo:

public String getName() {
    return this.name;
}

public int getAge() {
    return this.age;
}

O tipo retornado corresponde à informação fornecida. Um método de acesso que exibe o valor e retorna void não pode fornecer um valor a uma expressão como pet.getAge() + 1. O código que chama o método deve receber o valor e decidir como usá-lo.

Altere valores selecionados com métodos modificadores

Um método modificador, também chamado de método mutador, recebe um novo valor e atualiza o estado:

public void setName(String name) {
    this.name = name;
}

this.name é o campo. name é o parâmetro. Escrever name = name; compila, mas não altera nenhum campo. Não há valor de retorno aqui porque a função desse método modificador é fazer uma alteração.

Para um animal com idade 3:

luna.setName("Lulu");
System.out.println(luna.getName() + " is " + luna.getAge());
// Lulu is 3

O código que chama os métodos nunca acessa um campo diretamente. O método modificador altera o nome, e os métodos de acesso retornam os valores atuais para que o código os combine.

Siga os nomes esperados por outros códigos Java
CampoMétodo de acessoMétodo modificador, se necessário
pageCountgetPageCount()setPageCount(int pageCount)
namegetName()setName(String name)
lentOutisLentOut()setLentOut(boolean lentOut)

Coloque em maiúscula a primeira letra do nome do campo depois de get, set ou do prefixo is, usual para booleanos. Um nome como getname() pode compilar, mas não segue a convenção esperada por ferramentas e outros programadores.

Disponibilize apenas operações úteis

O título de um livro pode ter um método de acesso e nenhum método modificador, pois os códigos que o usam devem poder lê-lo, mas não substituí-lo. Um campo privado final pode garantir que ele receba um valor uma única vez. Um contador interno pode não precisar de nenhum dos dois métodos se apenas a classe o usar.

Um método modificador sem verificação pode aceitar o mesmo valor prejudicial que um campo público. Adicione verificações quando uma alteração tiver restrições. Considere também um método de ação: celebrateBirthday() expressa o aumento da idade em uma unidade, e lend() expressa uma tentativa de empréstimo. lend() pode examinar o estado atual e rejeitar um segundo empréstimo. Um método modificador também pode fazer essa verificação; o nome de ação torna a operação mais clara para quem a chama.

Um método de acesso pode calcular uma resposta. getArea() pode retornar o produto da largura pela altura sem nenhum campo area.

Principais conclusões

  • Um método de acesso retorna informações; um método modificador altera um valor selecionado.
  • Siga o padrão de nomenclatura getName, setName e o usual isName para booleanos.
  • Forneça aos campos apenas os métodos de acesso e modificadores necessários aos códigos que os usam.
  • Métodos de ação como lend expressam claramente o comportamento permitido e podem verificar transições.

4.3 Regras preservadas em cada alteração

Uma invariante é uma regra sobre o estado de um objeto que é verdadeira após a construção e após cada operação pública. Um termostato pode permitir temperaturas desejadas de 5 °C a 30 °C. Toda forma de definir essa temperatura deve preservar esse intervalo.

Escolha o que acontece com uma entrada inválida

Três respostas úteis são manter o valor anterior, limitar o valor ao intervalo ou lançar uma exceção. Elas têm efeitos diferentes, portanto escolha uma resposta clara para cada operação.

RespostaResultado de uma chamada inválida
IgnorarO valor anterior do campo permanece inalterado
Limitar ao intervaloO limite permitido mais próximo é armazenado
Lançar uma exceçãoA chamada é interrompida com um erro como IllegalArgumentException

Para uma idade não negativa de um animal, um método modificador que ignora valores inválidos pode atribuir o valor apenas dentro de if (age >= 0). Se a idade armazenada for 4, setAge(-2) a mantém em 4. Ele não muda a idade para 0.

Coloque as verificações de intervalo dentro da classe
public static final int MIN_CELSIUS = 5;
public static final int MAX_CELSIUS = 30;
private int target;

public void setTarget(int celsius) {
    if (celsius < MIN_CELSIUS) {
        this.target = MIN_CELSIUS;
    } else if (celsius > MAX_CELSIUS) {
        this.target = MAX_CELSIUS;
    } else {
        this.target = celsius;
    }
}

public void raise() {
    setTarget(this.target + 1);
}

Começando em 20 °C, setTarget(35) armazena 30. setTarget(-3) armazena 5. Após setTarget(29), uma chamada a raise() armazena 30; outra chamada mantém o valor em 30. Reutilizar o método modificador impede que raise() ultrapasse o limite superior.

Verificações apenas em Main não podem proteger o termostato. Outro código que o use poderia esquecê-las. A classe deve verificar a entrada no ponto em que controla o armazenamento.

Valide também o estado inicial
public Thermostat(int target) {
    setTarget(target);
}

Com esse construtor que limita o valor ao intervalo, new Thermostat(50) termina em 30 °C. Atribuir this.target = target; diretamente permitiria o estado inicial inválido 50. Um método privado de verificação compartilhado é outra forma de reutilizar a validação em construtores e métodos posteriores.

Lançar uma exceção é útil quando um argumento inválido indica um erro de programação. Por exemplo, um construtor pode rejeitar uma contagem negativa com throw new IllegalArgumentException("count must not be negative");. O objeto não é construído com sucesso, portanto nenhum objeto concluído inválido é entregue ao código que chamou o construtor. Ignorar a entrada é mais simples, mas silencioso; o código que chamou o método pode precisar de outra forma de perceber que nada mudou.

Mantenha os dados internos mutáveis dentro da classe

Uma lista privada ainda pode ser exposta se um método de acesso retornar a lista original. O código que chamou o método poderia então adicionar ou remover entradas sem usar os métodos da classe, contornando uma regra de tamanho máximo.

Para um campo ArrayList<String> chamado tracks, return new ArrayList<>(this.tracks); fornece uma lista separada que contém as mesmas cadeias de caracteres. Alterar a lista retornada não altera a lista interna. Operações como addTrack(String title) podem manter as alterações da lista dentro da classe e verificar suas regras antes de aceitá-las.

Principais conclusões

  • Uma invariante é verdadeira após a construção e após cada operação pública.
  • Ignorar, limitar ao intervalo e lançar uma exceção são respostas diferentes a uma entrada inválida.
  • Todo construtor e método que altera o estado deve preservar as mesmas regras.
  • Reutilize a validação para que diferentes formas de alteração não possam contorná-la.
  • Retornar uma lista interna mutável permite que o código externo contorne as verificações da classe.
  • Uma cópia de uma lista interna de cadeias de caracteres protege a lista original de alterações externas na lista.
5

Objetos legíveis e classes completas

Descrições legíveis de objetos facilitam o uso e a verificação de uma classe. Um método toString fornece esse texto sempre que um objeto é exibido ou concatenado a uma cadeia de caracteres. Você escreverá o método com o cabeçalho correto e depois reunirá campos, construtores, métodos e validação em uma classe completa. A partir de uma breve descrição, você transformará requisitos em código e testará chamadas comuns, ações repetidas e casos de valor-limite.

5.1 Uma descrição de objeto retornada como texto

Um objeto útil deve ser fácil de inspecionar como texto. O toString() herdado do Java retorna um nome de classe, um sinal @ e um código de dispersão hexadecimal, como Pet@8bcc55f. Um pacote nomeado passa a fazer parte do nome da classe. O texto do código de dispersão varia e geralmente diz pouco sobre o estado do objeto.

Retorne uma descrição legível
@Override
public String toString() {
    return this.name + " (" + this.species + ", "
        + this.age + " years)";
}

Para Luna, uma gata de 3 anos, a cadeia de caracteres retornada é "Luna (cat, 3 years)". O método lê campos e constrói uma cadeia de caracteres. Ele não altera o animal nem envia saída à tela.

@Override pede ao compilador que verifique se a declaração realmente substitui um método existente. Isso detecta erros como escrever tostring com s minúsculo. A anotação não formata o resultado para você; a expressão de retorno determina o texto.

Reconheça chamadas automáticas
System.out.println(luna);
String label = "Pet: " + luna;
String details = luna.toString();

A primeira linha exibe a descrição legível do animal. A segunda constrói "Pet: Luna (cat, 3 years)". A terceira solicita a mesma descrição explicitamente e a armazena sem exibi-la. Quando um ArrayList de animais é exibido, sua representação usa o toString() de cada animal dentro dos colchetes da lista.

A conversão automática explica por que retornar texto é importante. O código que chama o método pode estar exibindo, armazenando ou concatenando o resultado. Um método que apenas exibe não pode fornecer a cadeia de caracteres necessária a todos esses códigos.

Use o cabeçalho correto do método
DeclaraçãoO que acontece
public String toString()Fornece a descrição do objeto
public String tostring()Declara um método diferente; @Override detecta o erro
public String toString(int width)Declara uma sobrecarga; a exibição automática não a chama
public void toString()Falha: entra em conflito com o método existente que retorna String

Use o cabeçalho exato sem argumentos e inclua a anotação. Uma sobrecarga com parâmetros pode ser um método separado válido, mas a exibição de um objeto não fornece esses parâmetros.

Formate valores sem alterá-los

Um relógio precisa de horas e minutos com dois algarismos. Dentro de seu método toString():

return String.format(java.util.Locale.US,
    "%02d:%02d", this.hours, this.minutes);

Para horas 9 e minutos 5, a cadeia de caracteres é "09:05". Cada %02d formata um inteiro em pelo menos duas posições, usando um zero à esquerda quando necessário. String.format(java.util.Locale.US, "%.2f", 7.5) retorna "7.50". Fornecer a configuração regional torna a saída com ponto decimal independente da configuração regional padrão de formatação do computador.

Mantenha a descrição curta o suficiente para ser lida durante a depuração. Ela pode revelar um estado não inicializado: concatenar um campo de nome null a uma cadeia de caracteres produz o texto "null", o que aponta para a inicialização. A descrição deve informar o estado atual, portanto exibir o objeto duas vezes não deve avançar um relógio nem celebrar um aniversário.

Principais conclusões

  • Escreva public String toString() sem parâmetros e retorne texto legível.
  • A anotação @Override permite que o compilador verifique se o método substitui um método existente.
  • Exibir um objeto e concatená-lo a uma cadeia de caracteres usam toString automaticamente.
  • Mantenha toString sem alterações de estado e deixe que o código que o chama decida para onde vai o texto.
  • String.format pode preencher valores e usar uma configuração regional explícita para uma saída previsível.

5.2 De um requisito a uma classe testada

Comece pelo que um objeto deve lembrar, pelo que os códigos que o usam podem pedir que ele faça e por quais estados devem ser permitidos. Depois transforme cada parte em campos, construtores e métodos.

Extraia o projeto de uma descrição

“Um livro de biblioteca tem título, autor e número de páginas. Ele pode ser emprestado e devolvido. Ele não pode ser emprestado novamente enquanto já estiver emprestado.”

Use LibraryBook como nome da classe. Armazene os três valores descritivos e um estado de empréstimo booleano. O título, o autor e o número de páginas permanecem fixos, portanto declare-os final. O estado de empréstimo muda por meio de ações com funções claras. Um método modificador para cada campo é desnecessário.

Implemente a classe completa
public class LibraryBook {
    private final String title;
    private final String author;
    private final int pages;
    private boolean lentOut;

    public LibraryBook(String title, String author, int pages) {
        this.title = title;
        this.author = author;
        this.pages = pages;
        this.lentOut = false;
    }

    public boolean isLentOut() {
        return this.lentOut;
    }

    public boolean lend() {
        if (this.lentOut) {
            return false;
        }
        this.lentOut = true;
        return true;
    }

    public void giveBack() {
        this.lentOut = false;
    }

    @Override
    public String toString() {
        String status = this.lentOut ? "lent out" : "available";
        return this.title + " by " + this.author + ", "
            + this.pages + " pages, " + status;
    }
}

O construtor define o livro como disponível. lend() verifica o estado existente antes de alterá-lo; retornar false em um segundo empréstimo preserva a regra. giveBack() torna o livro disponível. O método de acesso informa o estado, e toString() descreve o livro inteiro sem alterá-lo.

Anote os resultados esperados antes de executar as chamadas

No método main clássico de uma classe Main separada:

LibraryBook b = new LibraryBook("Night Train", "A. Rivera", 320);
System.out.println(b);        // Night Train by A. Rivera, 320 pages, available
System.out.println(b.lend()); // true
System.out.println(b.lend()); // false
b.giveBack();
System.out.println(b.lend()); // true

A segunda tentativa de empréstimo é essencial: um método que sempre define a variável sinalizadora e retorna true passaria na primeira chamada, mas falharia nessa verificação. Teste o estado e também os valores de retorno com isLentOut(). Experimente também um segundo livro para verificar se um empréstimo de um livro deixa o outro disponível.

Teste onde o comportamento muda

Cubra cada construtor e método público. Para verificações de intervalo, experimente os dois extremos e valores imediatamente fora deles. Para um relógio, verifique a virada dos minutos e a passagem pela meia-noite. Para um método modificador que rejeita ou ignora entradas inválidas, verifique se elas têm o efeito prometido sobre o estado anterior. Escreva primeiro o resultado esperado para que uma saída inesperada não se torne, sem perceber, sua nova expectativa.

Implemente em pequenos passos: primeiro os campos e o construtor, depois uma descrição legível e, em seguida, uma operação e suas verificações por vez. Salve classes públicas comuns em arquivos com nomes correspondentes, compile-as juntas e execute a classe que contém main. Manter as operações do modelo separadas da saída na tela permite que a mesma classe sirva a diferentes programas.

Principais conclusões

  • Transforme os dados que devem ser lembrados em campos privados e as ações permitidas em métodos.
  • Escreva as regras de estado antes de implementar construtores e alterações.
  • Use final para valores fixos de cada objeto e evite métodos modificadores desnecessários.
  • Teste os valores de retorno e o estado resultante, incluindo chamadas repetidas e objetos separados.
  • Verifique valores-limite e entradas inválidas, além de valores comuns.
  • Implemente e teste uma parte útil por vez.
  • Mantenha o comportamento do modelo separado do programa com main que exibe os resultados.

Exercícios resolvidos de Classes e objetos em Java

5 Lições Interativas

1

De uma classe a dois animais

10 passos
Crie objetos, identifique seu estado e acompanhe chamadas por referências separadas e compartilhadas.
  1. 1
    IntroduçãoUm tipo para as coisas no seu programa

    Um programa sobre animais de estimação precisa lembrar nome, espécie e idade juntos. Uma classe dá um tipo a esse grupo e oferece métodos que o usam. Cada objeto é um animal criado a partir dessa definição.

    Acompanhe a diferença entre a definição e os animais que ela produz. Depois rastreie dois objetos de animais e veja por que uma variável extra nem sempre significa um objeto extra.

  2. 2
    AnalogiaUma planta e suas instâncias

    Pense em uma classe como uma planta de construção e em seus objetos como casas construídas a partir dela. A planta descreve o que cada casa contém, mas não é uma casa.

    Uma definição de Pet pode descrever muitos animais. Cada um tem campos para os mesmos tipos de dados, mas um pode ser um gato de três anos e outro, um cachorro de cinco anos. Definir os campos cria a planta; criar objetos fornece instâncias reais.

  3. 3
    ExemploIdentifique estado e comportamento

    Os campos name, species e age de um animal armazenam seu estado. Para Luna, seus valores são "Luna", "cat" e 3.

    O método celebrateBirthday() fornece comportamento. Seu corpo pode executar this.age++;, alterando a idade do animal receptor. O método faz parte da definição da classe; o valor que ele altera pertence a um animal específico.

  4. 4
    DesafioUma definição cria um animal?

    Um programador escreve uma classe Pet com três campos e um método de aniversário. Nenhuma expressão de criação de objeto foi executada. Quantos objetos de animais essa definição criou?

    ---reveal---

    Nenhum. A classe define um tipo e seu estado e comportamento disponíveis. Os objetos aparecem quando o programa os cria, por exemplo com new Pet(...). Três declarações de campos descrevem três dados por animal, não três animais.

  5. 5
    ExemploCrie o primeiro objeto

    Leia Pet luna = new Pet("Luna", "cat", 3); por partes. Pet luna declara uma variável. new Pet(...) cria um animal e executa o construtor com os três argumentos fornecidos.

    O construtor armazena os valores iniciais. A referência produzida por new é atribuída a luna, dando ao código posterior uma forma de acessar esse objeto. Declarar apenas Pet luna; não forneceria um objeto no qual chamar um método.

  6. 6
    ExplicaçãoChame um método em seu objeto receptor

    Em luna.celebrateBirthday(), a expressão antes do ponto identifica o objeto receptor. O método de aniversário é executado para Luna, aumentando sua idade de 3 para 4.

    int age = luna.getAge(); então obtém a idade atual para uso em outro lugar. Pet.celebrateBirthday() não pode escolher um animal: esse é um método de instância, e um nome de classe não fornece um objeto específico.

  7. 7
    ExemploCrie um segundo animal

    Agora execute Pet max = new Pet("Max", "dog", 5);. Uma segunda expressão new cria um segundo objeto com seus próprios campos.

    Após outra chamada a luna.celebrateBirthday(), Luna tem 5 anos e Max continua com 5. Suas idades iguais não fazem deles o mesmo objeto. Um aniversário posterior de Luna altera apenas a idade dela porque a idade de Max fica nos campos de outro objeto.

  8. 8
    Ideia-chaveUma atribuição pode compartilhar um objeto

    Pet other = luna; copia a referência de Luna. Ela não chama um construtor nem copia seus campos para outro animal.

    Os nomes other e luna agora acessam o mesmo objeto. Chamar other.celebrateBirthday() altera a idade desse animal de 5 para 6, e luna.getAge() também vê 6. Conte as criações de objetos separadamente das declarações de variáveis.

  9. 9
    DesafioRastreie uma referência compartilhada e um animal separado

    Dois animais distintos começam com idades 1 para a e 8 para b. O código executa Pet c = a; c.celebrateBirthday(); b.celebrateBirthday();. Quais idades a e b informam?

    ---reveal---

    Eles informam 2 e 9. c compartilha o objeto de a, portanto sua chamada aumenta a idade desse animal. A chamada por meio de b aumenta a idade do animal separado. A classe fornece o mesmo comportamento de aniversário a ambos, mas cada chamada tem seu próprio objeto receptor.

  10. 10
    RecapitulaçãoLeia a criação e as chamadas com atenção

    Mantenha três papéis separados: a classe define o tipo, cada objeto armazena seu próprio estado de instância, e uma variável de referência acessa um objeto.

    Ao ler o código, marque cada new, confira seus argumentos em relação ao construtor e identifique o objeto receptor antes de rastrear uma chamada de método. Uma atribuição simples de referência adiciona um caminho para um objeto existente. Um segundo new cria um objeto separado com seu próprio estado.

2

Construa o estado inicial corretamente

14 passos
Escolha campos, acompanhe atribuições do construtor e use sobrecargas sem criar objetos extras.

Salve esta aula para seguir cada Lição Interativa passo a passo.

  1. 1
    IntroduçãoDê dados úteis a cada novo objeto
  2. 2
    ExplicaçãoEscolha o estado duradouro
  3. 3
    ExplicaçãoSepare valores padrão de valores úteis
  4. 4
    DesafioEscolha um campo ou uma variável local
  5. 5
    ExplicaçãoLeia o cabeçalho do construtor
  6. 6
    ExemploTransfira parâmetros para campos
  7. 7
    DicaUma atribuição válida que não armazena nada
  8. 8
    DesafioIdentifique o campo inalterado
  9. 9
    ConexãoCrie objetos internos também
  10. 10
    ExemploOfereça uma forma útil de criação com valores padrão
  11. 11
    ExplicaçãoAcompanhe um objeto pela cadeia
  12. 12
    DesafioIdentifique o problema em uma expressão new enganosa
  13. 13
    DesafioCombine um campo fixo com uma sobrecarga
  14. 14
    RecapitulaçãoVerifique cada caminho até um objeto concluído
3

Rastreie alterações de estado e estado compartilhado

13 passos
Acompanhe um retângulo e um relógio e depois distinga o comportamento de instância dos membros estáticos.

Salve esta aula para seguir cada Lição Interativa passo a passo.

  1. 1
    IntroduçãoAcompanhe o que cada chamada altera
  2. 2
    ExplicaçãoRetorne um valor ao código que chamou o método
  3. 3
    ExemploAltere a escala das dimensões armazenadas
  4. 4
    DesafioVerifique o resultado retornado após uma alteração
  5. 5
    ExemploAvance pela meia-noite
  6. 6
    DicaCorrija uma reinicialização que não altera o estado
  7. 7
    Ideia-chaveConsidere todos os retornos normais
  8. 8
    ExplicaçãoSepare duas contagens de um contador compartilhado
  9. 9
    ExemploForneça um objeto em código estático
  10. 10
    ConexãoReconheça uma constante
  11. 11
    DesafioRastreie os dois tipos de estado
  12. 12
    DesafioDescubra por que objetos separados mudam juntos
  13. 13
    RecapitulaçãoRelacione cada operação a quem a possui
4

Proteja todos os caminhos de alteração do estado

14 passos
Use métodos de acesso e modificadores, validação e cópias de listas para manter um objeto dentro de suas regras.

Salve esta aula para seguir cada Lição Interativa passo a passo.

  1. 1
    IntroduçãoTorne a classe responsável por suas regras
  2. 2
    ExplicaçãoOculte o campo por trás de uma operação
  3. 3
    DicaEscolha o acesso mais restrito que seja útil
  4. 4
    DesafioDecida onde o acesso privado funciona
  5. 5
    ExemploRetorne informações com um método de acesso
  6. 6
    ConexãoOfereça ações adequadas ao objeto
  7. 7
    DesafioLeia sem permitir substituição
  8. 8
    ExplicaçãoEscolha uma política para entradas inválidas
  9. 9
    ExemploRastreie a limitação no limite superior
  10. 10
    ExemploVerifique o estado inicial
  11. 11
    DesafioRastreie a opção de ignorar em vez de limitar
  12. 12
    Ideia-chaveUma lista privada ainda pode ser exposta
  13. 13
    DesafioFeche os dois caminhos sem verificação
  14. 14
    RecapitulaçãoExamine a interface pública
5

Implemente e teste uma classe útil

12 passos
Escreva uma descrição legível, implemente uma regra de empréstimo e teste uma classe completa de livro de biblioteca.

Salve esta aula para seguir cada Lição Interativa passo a passo.

  1. 1
    IntroduçãoTransforme um requisito em comportamento visível
  2. 2
    ExplicaçãoUse o cabeçalho exato da descrição
  3. 3
    ExemploRetorne o estado atual como texto
  4. 4
    DicaFormate um relógio sem alterá-lo
  5. 5
    DesafioCorrija a exibição automática
  6. 6
    ExemploEscolha campos a partir do requisito
  7. 7
    ExemploEstabeleça o estado inicial
  8. 8
    ExemploImplemente a regra antes da alteração
  9. 9
    DesafioPreveja uma sequência antes de executá-la
  10. 10
    ConexãoTeste os casos que uma execução simples não encontra
  11. 11
    DesafioDistinga informar de alterar
  12. 12
    RecapitulaçãoImplemente uma garantia pública testável

Questões de Classes e objetos em Java

40 Questões de Prática em 4 conjuntos

Conjunto 1: Crie objetos e leia seu estado10 Questões de Prática

Questão 1 de 10

Uma classe tem Ticket() { this(4); } e Ticket(int zones) { this.zones = zones + 1; }. Qual valor new Ticket() armazena em zones?
  1. 0
  2. 4
  3. 5
  4. 8
Mostrar respostaOcultar resposta
Resposta: C
O construtor sem argumentos delega com o argumento 4 no mesmo objeto. O construtor mais completo soma 1 e armazena 5. O 4 fornecido é um valor de parâmetro durante a inicialização; ele não é o valor final do campo porque o construtor aplica o cálculo adicional.

Questão 2 de 10

Após new Badge("Visitor"), getText() retorna null. O campo é private String text;, o método de acesso o retorna e o corpo do construtor é text = text;. Como o construtor deve armazenar seu parâmetro text?
  1. text = this.text;
  2. String text = "Visitor";
  3. this.text = text;
  4. this.text = this.text;
Mostrar respostaOcultar resposta
Resposta: C
O parâmetro oculta o campo quando seu nome é usado sozinho. this.text = text; escreve a entrada no objeto atual. Inverter a atribuição lê o campo ainda nulo para o parâmetro, e atribuir o campo a si mesmo também o deixa sem valor definido.

Questão 3 de 10

Um programa de entregas usa uma classe Parcel para criar vários pacotes. Como é chamado um pacote criado durante a execução do programa?
  1. Uma definição de Parcel.
  2. Uma instância de Parcel.
  3. Um método de Parcel.
  4. Um parâmetro de Parcel.
Mostrar respostaOcultar resposta
Resposta: B
Uma instância é um objeto criado a partir de uma classe, portanto cada pacote é uma instância de Parcel. A definição da classe descreve os dados e as operações de todos esses objetos; ela não é outro nome para um pacote específico. Um método é uma operação que o objeto pode executar.

Questão 4 de 10

Um objeto Bell está armazenado em bell, e ring() é um método de instância. Como o programa deve tocar essa campainha?
  1. Bell.ring(bell);
  2. ring(bell);
  3. new bell.ring();
  4. bell.ring();
Mostrar respostaOcultar resposta
Resposta: D
A notação de ponto chama ring() no objeto acessado por bell. A variável antes do ponto fornece o objeto receptor de que um método de instância precisa. Bell.ring() nomeia a classe, portanto não pode selecionar essa campainha para uma chamada de instância.

Questão 5 de 10

Uma classe declara private int attempts; sem inicializador nem atribuição no construtor. Qual valor um novo objeto armazena nesse campo?
  1. 0
  2. 1
  3. null
  4. Nenhum valor; a compilação falha.
Mostrar respostaOcultar resposta
Resposta: A
Um campo de instância int recebe o valor padrão 0 antes da inicialização explícita. A regra que exige atribuição antes da leitura de uma variável local não inicializada não se aplica a campos. null é o valor padrão para campos de tipos de classe, não para um campo int.

Questão 6 de 10

Um MinuteClock armazena horas de 0–23 e minutos de 0–59. advance() adiciona um minuto, tratando a virada da hora e da meia-noite. isMidnight() verifica se o horário é 00:00. Começando em 23:57, execute advance(); advance(); advance(); if (isMidnight()) { advance(); } advance();. Qual é o horário final?
  1. 00:01
  2. 00:02
  3. 00:00
  4. 23:59
Mostrar respostaOcultar resposta
Resposta: B
As três primeiras chamadas chegam a 23:58, depois 23:59 e depois 00:00. A condição agora é verdadeira, portanto sua chamada avança para 00:01, e a chamada final chega a 00:02. Parar em 00:01 deixa de considerar a chamada incondicional após o bloco condicional.

Questão 7 de 10

Cada Lamp deve lembrar seu próprio estado ligado ou desligado. Como esse estado deve ser declarado?
  1. private boolean on;
  2. private static boolean on;
  3. public static final boolean ON = false;
  4. Uma variável local boolean on dentro de switchOn().
Mostrar respostaOcultar resposta
Resposta: A
Um campo de instância mantém um valor separado para cada lâmpada e o lembra entre chamadas. Tornar o campo estático compartilharia um único valor de ligado ou desligado entre todas as lâmpadas. Uma variável local dentro do método de acionamento não forneceria o estado duradouro de cada lâmpada exigido pelo projeto.

Questão 8 de 10

Um campo de Bin é escrito como int capacity; sem um modificador de acesso. Qual é seu acesso?
  1. Acesso privado.
  2. Acesso protegido.
  3. Acesso público.
  4. Acesso de pacote.
Mostrar respostaOcultar resposta
Resposta: D
Um membro sem modificador de acesso tem acesso de pacote, portanto outras classes no mesmo pacote podem usá-lo. Ele não se torna privado apenas porque public foi omitido. Para manter o campo acessível por meio dos métodos da própria classe, declare-o explicitamente com private.

Questão 9 de 10

Uma Session tem private boolean active;. Os códigos que a usam precisam verificar esse estado, mas só podem alterá-lo por meio de start() e stop(). Qual método de acesso se ajusta a esse projeto?
  1. public void isActive() { System.out.println(this.active); }
  2. public boolean setActive(boolean value) { return value; }
  3. public void setActive(boolean value) { this.active = value; }
  4. public boolean isActive() { return this.active; }
Mostrar respostaOcultar resposta
Resposta: D
O método de acesso booleano retorna o valor atual da variável sinalizadora sem fornecer outra forma de alterá-lo. Exibir o valor em um método void não fornece um valor para uma condição no código que o chamou. Um método modificador público adicionaria uma forma de alteração além das duas ações permitidas pelo projeto.

Questão 10 de 10

Um objeto define public String toString() { return "Ready"; }. Qual texto é produzido por System.out.println("State: " + object);?
  1. Ready
  2. State: Ready
  3. State: Object@Ready
  4. State: toString()
Mostrar respostaOcultar resposta
Resposta: B
A concatenação de cadeias de caracteres usa a descrição textual retornada pelo objeto, portanto o rótulo e "Ready" se combinam em "State: Ready". Definir um toString() personalizado sem argumentos substitui a descrição herdada com classe e código de dispersão; o Java não acrescenta esse texto herdado como prefixo.
Conjunto 2: Verifique a inicialização e as alterações controladas10 Questões de Prática

Salve esta aula para ver todas as respostas e praticar cada conjunto.

Questão 1 de 10

Um método converte um número fornecido de minutos em horas usando apenas seu parâmetro. Ele não precisa de campos de objeto. Que tipo de método pode cumprir essa função?
  1. Um campo de instância.
  2. Um método estático.
  3. Uma sobrecarga de construtor.
  4. Uma variável local final.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 2 de 10

Um Locker tem um campo occupied e um método release(). Qual parte dessa classe descreve comportamento?
  1. O campo occupied.
  2. O valor atual true.
  3. O método release.
  4. O tipo de variável Locker.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 3 de 10

Um Panel armazena largura e altura. Sua largura pode mudar, e getArea() deve sempre informar a área atual. Como a área deve ser representada?
  1. Calcular largura vezes altura em getArea.
  2. Armazenar a área do construtor em um campo final.
  3. Armazenar a área uma vez em um campo estático compartilhado.
  4. Manter a última área em uma variável local do construtor.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 4 de 10

Uma classe declara apenas public Sensor(int channel). Um código usa new Sensor(). Por que isso não compila?
  1. O parâmetro deve se chamar sensor.
  2. Toda classe deve declarar um construtor void.
  3. O Java exige que channel seja um campo estático.
  4. Não há construtor sem argumentos disponível.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 5 de 10

Um medidor armazena private int reading = 9;. Seu método é public void reset() { int reading = 0; }. O que um método de acesso que retorna this.reading informa após reset()?
  1. 0
  2. 9
  3. null
  4. Um erro de compilação por falta de retorno.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 6 de 10

Um relógio substitui campos separados de horas e minutos por um único campo minutesSinceMidnight, enquanto seus métodos de acesso continuam retornando os mesmos valores. Por que os códigos que o usam podem manter suas chamadas existentes aos métodos de acesso?
  1. Os campos privados se tornam públicos para o código que os usa.
  2. O compilador troca as chamadas por campos.
  3. Cada código recebe uma cópia dos campos antigos.
  4. O comportamento público permanece consistente.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 7 de 10

Um medidor começa em 16. Seu método modificador limita as entradas ao intervalo de 10–20, inclusive. Após setValue(25) e depois setValue(8), quais são os valores armazenados após cada chamada?
  1. 20, depois 10.
  2. 16, depois 16.
  3. 25, depois 8.
  4. 20, depois 20.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 8 de 10

Um Group deve conter no máximo quatro nomes. addName aplica o limite, mas Group(ArrayList<String> names) armazena diretamente a lista fornecida e getNames() retorna a lista interna. Qual projeto preserva o limite contra alterações feitas pelos códigos que usam a classe?
  1. Validar e copiar a entrada; retornar uma cópia.
  2. Apenas copiar a entrada; retornar a lista interna.
  3. Apenas validar a entrada; retornar a lista interna.
  4. Apenas copiar no retorno; armazenar qualquer lista de entrada.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 9 de 10

Qual tipo de retorno o método toString() sem argumentos deve usar?
  1. void
  2. Object[]
  3. String
  4. boolean
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 10 de 10

Um passe começa sem ter sido usado. use() retorna false se ele já tiver sido usado; caso contrário, define a variável sinalizadora e retorna true. reset() limpa a variável sinalizadora. toString() apenas informa seu valor. O que as chamadas a use retornam em use(); println(pass); use(); reset(); use(); use();?
  1. true, true, true, false
  2. true, false, false, false
  3. true, false, true, true
  4. true, false, true, false
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Conjunto 3: Acompanhe o estado dos objetos em sequências mais longas10 Questões de Prática

Salve esta aula para ver todas as respostas e praticar cada conjunto.

Questão 1 de 10

Um Marker tem um nome e setName. Execute Marker a = new Marker("One"); Marker b = a; a = new Marker("Two"); b.setName("Three");. O que a.getName() e b.getName() retornam?
  1. "Three" e "Three".
  2. "Three" e "Two".
  3. "Two" e "One".
  4. "Two" e "Three".
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 2 de 10

Uma classe declara private int level = 6;. Seu construtor é public Beacon(int level) { this.level = level + 2; }. O que new Beacon(3) armazena?
  1. 6
  2. 5
  3. 3
  4. 8
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 3 de 10

Uma classe já tem public Tag(String text). Qual construtor adicional fornece uma sobrecarga distinta?
  1. public Tag(String text, int count)
  2. public Tag(String label)
  3. public Tag(String value)
  4. public Tag(String name)
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 4 de 10

Um retângulo tem largura de 2,0 cm e altura de 5,0 cm. scale(k) multiplica ambas as dimensões por k; area() retorna seu produto. Execute scale(2); double saved = area(); scale(0.5);. Quais são os valores de saved e do area() final?
  1. 20,0 e 10,0 centímetros quadrados.
  2. 40,0 e 20,0 centímetros quadrados.
  3. 40,0 e 10,0 centímetros quadrados.
  4. 10,0 e 10,0 centímetros quadrados.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 5 de 10

Uma classe Dial recém-criada tem o campo de instância value e o campo estático created, ambos inicialmente 0. Cada construtor incrementa created uma vez; turn() incrementa apenas o valor de seu objeto receptor. Execute Dial a = new Dial(); Dial b = a; b.turn(); b = new Dial(); b.turn(); b.turn();. Quais são os valores de a.value, b.value e created?
  1. 1, 2 e 2.
  2. 2, 2 e 2.
  3. 1, 3 e 2.
  4. 1, 2 e 3.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 6 de 10

Um método de acesso deve informar um rótulo armazenado em private String label;. Qual implementação fornece esse valor ao código que o chama?
  1. public void getLabel() { System.out.println(this.label); }
  2. public void getLabel(String label) { this.label = label; }
  3. public String getLabel() { return "label"; }
  4. public String getLabel() { return this.label; }
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 7 de 10

Um nível é limitado ao intervalo de 0–10, inclusive, por setLevel. O construtor chama esse método modificador, e raise() chama setLevel(this.level + 1). Começando com new Level(13), execute raise(); setLevel(-2); raise(); raise();. Qual é o nível final?
  1. 10
  2. 2
  3. 1
  4. 0
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 8 de 10

Dentro da descrição de um relógio, qual cadeia de caracteres String.format(java.util.Locale.US, "%02d:%02d", 4, 7) retorna?
  1. "4:7"
  2. "40:70"
  3. "04:07"
  4. "04.07"
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 9 de 10

Um Seat deve recusar uma segunda reserva até que a primeira seja cancelada. Um teste verifica atualmente apenas a primeira chamada bem-sucedida a reserve(). Qual próxima chamada verifica melhor a regra de recusa?
  1. Chamar reserve novamente sem cancelar.
  2. Cancelar primeiro e depois chamar reserve novamente.
  3. Criar outro assento e reservá-lo.
  4. Cancelar a reserva sem reservar novamente.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 10 de 10

Um termostato aceita temperaturas desejadas de 6 °C a 28 °C, inclusive. Qual par de entradas testa os valores imediatamente fora dos dois limites?
  1. 6 °C e 28 °C.
  2. 5 °C e 29 °C.
  3. 7 °C e 27 °C.
  4. 17 °C e 18 °C.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Conjunto 4: Analise projetos e combine as regras10 Questões de Prática

Salve esta aula para ver todas as respostas e praticar cada conjunto.

Questão 1 de 10

Um programa gerencia várias bombas. Cada uma tem um identificador e uma velocidade atual diferentes, e cada uma pode ser ligada ou desligada. Como uma classe Pump deve representar isso?
  1. Campos estáticos para identificador e velocidade; métodos para ligar e desligar.
  2. Campos de instância para identificador e velocidade; métodos para ligar e desligar.
  3. Campos de instância para ligar e desligar; identificadores locais em cada chamada.
  4. Valores locais de velocidade em ligar e desligar; uma constante de identificador compartilhada.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 2 de 10

Um Token tem um valor numérico e addOne() o aumenta. Execute Token a = new Token(2); Token b = a; b.addOne(); Token c = new Token(7); a = c; a.addOne(); b.addOne();. Quais valores a, b e c informam?
  1. 4, 4 e 8.
  2. 8, 8 e 8.
  3. 8, 4 e 8.
  4. 8, 3 e 7.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 3 de 10

Um rastreador deve manter um total entre chamadas. Seu add(int amount) atualmente declara int total = amount; dentro do método. Qual alteração no armazenamento torna possível a acumulação?
  1. Declarar um campo de instância total e atualizá-lo em add.
  2. Declarar o mesmo total local novamente no método de acesso.
  3. Declarar amount como variável local apenas no construtor.
  4. Declarar um total local final em cada chamada a add.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 4 de 10

Um Bucket declara private int capacity = 2; e uma lista de instância vazia items. Seu construtor é Bucket(int capacity) { capacity = capacity; }. add retorna false sem adicionar quando o tamanho da lista é pelo menos igual à capacidade armazenada; caso contrário, adiciona o item e retorna true. snapshot() retorna new ArrayList<>(this.items).

Execute Bucket b = new Bucket(4); b.add("A"); ArrayList<String> view = b.snapshot(); view.add("B");. Depois chame b.add("C") e b.add("D"). O que essas duas últimas chamadas retornam e quantos itens b contém ao final?

  1. true, true; 3 itens.
  2. false, false; 2 itens.
  3. true, false; 3 itens.
  4. true, false; 2 itens.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 5 de 10

Uma Route tem o campo final code e o campo estático created, inicialmente 0. Seus construtores são Route() { this("local"); created++; } e Route(String code) { this.code = code; created++; }. Após uma chamada a cada construtor, created deve contar dois objetos. Qual correção produz a contagem certa?
  1. Remover created++ do construtor com String.
  2. Substituir this("local") por new Route("local").
  3. Manter os dois incrementos e tornar created um campo de instância.
  4. Remover created++ do construtor sem argumentos.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 6 de 10

Um relógio começa em 22:59. advance() adiciona um minuto com virada em 24 horas. getHour() lê a hora atual. Execute int h = getHour(); advance(); if (getHour() != h) { advance(); } advance();. Quais são h e o horário final?
  1. 23 e 23:02.
  2. 22 e 23:01.
  3. 22 e 23:02.
  4. 23 e 23:01.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 7 de 10

Um método auxiliar deve poder ser chamado apenas por código dentro de sua própria classe de nível superior. Qual modificador de acesso é adequado?
  1. public
  2. private
  3. protected
  4. Nenhum modificador.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 8 de 10

Um retângulo altera suas dimensões por meio de scale. Seu método de acesso retorna this.width * this.height, e não há campo de área. Por que esse é um projeto válido para um método de acesso?
  1. Ele retorna informações atuais sem expor o armazenamento.
  2. Todo método de acesso deve retornar um campo com seu nome exato.
  3. O método cria um campo de área sempre que é chamado.
  4. O produto se torna uma constante após a primeira chamada.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 9 de 10

Um Album tem um limite de três legendas. Seu construtor rejeita mais de três legendas e armazena new ArrayList<>(captions). getCaptions() retorna outra cópia; addCaption rejeita adições quando o limite é atingido. Um código fornece duas legendas, adiciona uma terceira à lista original, adiciona uma legenda ao resultado de um método de acesso e depois chama addCaption uma vez. Quantas legendas o Album contém?
  1. 2
  2. 4
  3. 5
  4. 3
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 10 de 10

Uma Door deve recusar open() quando estiver trancada. Uma porta nova começa fechada e destrancada. lock() só é bem-sucedido enquanto ela está fechada; unlock() remove a trava. Qual sequência de teste verifica a recusa enquanto a porta está trancada e depois uma abertura bem-sucedida após destrancá-la?
  1. lock; open → false; unlock; open → true.
  2. open → true; lock; open → false; unlock.
  3. lock; unlock; open → true; open → false.
  4. open → true; unlock; lock; open → false.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Travou em uma questão sua? Ajuda com Tarefas

Termos-Chave

59 Termos-Chave, cada um com sua definição

A

Acesso de pacote
O acesso de pacote permite que classes no mesmo pacote usem uma declaração e é selecionado pela omissão de um modificador de acesso.
O acesso de pacote em int count; permite que outra classe no mesmo pacote sem nome leia ou altere o campo.
Anotação @Override
A anotação @Override pede ao compilador que verifique se uma declaração de método substitui um método já fornecido por um supertipo.
@Override acima de tostring() revela o erro de letras maiúsculas e minúsculas em vez de deixar a exibição automática inalterada.
Argumento
Um argumento é um valor fornecido em uma chamada de método ou construtor, associado a um parâmetro por sua posição e por um tipo compatível.
Em new Clock(9, 5), os argumentos 9 e 5 fornecem a hora e o minuto para o novo relógio.

C

Campo estático
Um campo estático é uma única variável da classe compartilhada por todas as instâncias, portanto seu valor não pertence a um objeto específico.
Um campo estático chamado created pode aumentar cada vez que o construtor inicializa uma nova instância da classe.
Campo final
Um campo final pode receber um valor apenas uma vez, portanto é útil para dados de cada objeto que não devem ser substituídos após a inicialização.
O título de um livro pode ser um campo final que recebe um valor no construtor, sem oferecer um método modificador aos códigos que o usam.
Classe
Uma classe define um tipo Java ao descrever os dados que seus objetos armazenam e os métodos que fornecem seu comportamento.
Uma classe Pet reúne nome, espécie e idade com operações como celebrateBirthday().
Comportamento
O comportamento de um objeto é o conjunto de operações que seus métodos fornecem para ler seu estado, calcular a partir dele ou alterá-lo.
Um livro oferece os comportamentos lend() e giveBack() para que os códigos que o usam possam gerenciar seu estado de empréstimo.
Constante
Uma constante é um valor fixo normalmente fornecido por um campo static final, muitas vezes público e nomeado em UPPER_SNAKE_CASE.
Uma constante MAX_CELSIUS fornece o mesmo limite superior de temperatura à classe e aos códigos que a usam.
Construtor
Um construtor é uma declaração com o nome da classe e sem tipo de retorno que inicializa um objeto durante sua criação.
O construtor de Pet copia o nome, a espécie e a idade fornecidos para os campos do novo animal.
Construtor padrão
Um construtor padrão é o construtor sem argumentos que o Java fornece quando uma classe não declara nenhum construtor.
Adicionar um construtor com três argumentos elimina o construtor padrão, portanto new Pet() precisa de uma sobrecarga explícita.
Construtor sem argumentos
Um construtor sem argumentos não aceita valores de entrada; ele pode ser declarado explicitamente ou fornecido pelo Java como construtor padrão.
Um construtor explícito sem argumentos Clock() pode delegar com this(0, 0) para iniciar o relógio à meia-noite.
Contexto estático
Um contexto estático é código sem uma instância atual, como o corpo de um método estático, em que não é possível acessar membros de instância apenas pelo nome.
Em um contexto estático, um campo de idade usado sozinho não tem um animal atual; pet.getAge() fornece um objeto específico.
Cópia defensiva
Uma cópia defensiva é um objeto de dados separado, retornado ou armazenado para impedir que outra parte do programa altere diretamente dados internos.
Uma cópia defensiva feita com new ArrayList<>(this.tracks) impede que alterações externas na lista afetem a lista interna.

D

Desenvolvimento incremental
O desenvolvimento incremental implementa e verifica uma parte útil por vez, facilitando a localização de erros antes que mais código seja adicionado.
Com desenvolvimento incremental, verifique primeiro o construtor e depois adicione e teste uma operação por vez.

E

Encadeamento de construtores
Encadeamento de construtores executa outro construtor da mesma classe no mesmo objeto por meio de uma chamada this(...).
O encadeamento de construtores permite que um animal recém-nascido use this(name, species, 0) para reutilizar a inicialização com uma idade padrão.
Encapsulamento
Encapsulamento agrupa o estado de um objeto com as operações que o controlam e oculta dados internos por trás de uma interface escolhida.
O encapsulamento em Pet combina um campo privado de idade com métodos de verificação que recusam alterações inválidas.
Escopo
O escopo de uma variável é a região do texto do programa em que seu nome pode ser usado para se referir a essa variável.
O escopo de uma variável local declarada dentro de um bloco if termina nesse bloco, portanto o código posterior não pode usar seu nome.
Estado
O estado de um objeto é o conjunto atual de valores armazenados em seus campos de instância, como a hora e o minuto de um relógio.
Depois que um relógio avança a partir de 08:59, seu estado armazena hora 9 e minuto 0, pronto para a próxima chamada.
Exceção IllegalArgumentException
Uma IllegalArgumentException é uma exceção que um método ou construtor pode lançar para rejeitar um argumento que viola suas regras de entrada.
Lançar IllegalArgumentException para uma capacidade negativa impede que a construção retorne um objeto inválido.

I

Inicialização
Inicialização dá a uma variável seu primeiro valor; a inicialização de um objeto estabelece os campos necessários para um estado inicial utilizável.
A inicialização de lista em um construtor de playlist usa new ArrayList<>() para que entradas possam ser adicionadas posteriormente.
Instância
Uma instância é um objeto criado a partir de uma classe específica; o termo indica a relação entre esse objeto e seu tipo.
Um animal chamado Luna e outro chamado Max são duas instâncias de Pet quando cada um é criado separadamente.
Interface pública
A interface pública de uma classe é o conjunto de operações e valores públicos disponíveis aos códigos que podem acessar a classe.
A interface pública de um livro pode oferecer lend(), giveBack() e isLentOut() enquanto sua variável sinalizadora de empréstimo permanece privada.
Invariante
Uma invariante é uma regra sobre o estado que deve ser verdadeira após a construção e após cada operação pública em um objeto.
A invariante de um termostato mantém sua temperatura desejada dentro do intervalo permitido mesmo quando um código solicita 40 °C.
Invocação recursiva de construtor
Uma invocação recursiva de construtor é uma cadeia inválida de construtores que acaba chamando um construtor já presente nessa cadeia.
O Java informa invocação recursiva de construtor quando Box() e Box(int) delegam um ao outro.

L

Limitação ao intervalo (clamping)
A limitação ao intervalo substitui um valor fora de um intervalo permitido pelo extremo mais próximo, preservando os valores que já estão dentro do intervalo.
Com a limitação ao intervalo de 5–30 °C, uma solicitação de 34 °C armazena 30 °C, enquanto uma solicitação de 18 °C armazena 18 °C.

M

Método de ação
Um método de ação nomeia uma operação com função clara que o objeto pode executar, muitas vezes controlando uma alteração com mais precisão que um método modificador direto.
O método de ação lend() verifica o estado atual de empréstimo, rejeita um empréstimo repetido e informa se o empréstimo foi bem-sucedido.
Método de acesso (getter)
Um método de acesso, ou método acessor, retorna informações sobre um objeto sem alterá-lo, muitas vezes usando um nome que começa com get.
O método de acesso getArea() pode calcular largura vezes altura mesmo quando a classe não armazena um campo de área separado.
Método de instância
Um método de instância é um método não estático executado para um objeto específico e que pode usar os campos de instância desse objeto.
scale é um método de instância: a.scale(2) altera o retângulo a enquanto um retângulo separado permanece inalterado.
Método estático
Um método estático pertence a uma classe e não tem objeto atual; ele precisa de uma referência a objeto para usar membros de instância.
Um método estático como main pode criar Counter c e depois chamar c.increment() por meio dessa referência.
Método modificador (setter)
Um método modificador, ou método mutador, aceita um novo valor para parte do estado de um objeto e pode verificar essa entrada antes de armazená-la.
O método modificador setAge(int age) pode ignorar entradas negativas para que a idade armazenada permaneça no intervalo permitido.
Método String.format
O método String.format constrói texto a partir de uma cadeia de formatação e valores, permitindo larguras e casas decimais fixas.
String.format com java.util.Locale.US e "%.2f" formata 7,5 como "7.50", independentemente da configuração regional padrão.
Método toString
O método toString() retorna a representação textual de um objeto, permitindo que a exibição e a concatenação de cadeias de caracteres mostrem detalhes legíveis.
O toString de um relógio retorna "09:05", portanto exibir o relógio mostra um horário útil em vez de um texto com classe e código de dispersão.
Modificador de acesso
Um modificador de acesso é uma palavra-chave Java, como private, protected ou public, que controla o acesso a uma declaração.
O modificador de acesso private mantém um método auxiliar disponível dentro de sua classe sem expô-lo a outras classes.
Modificador private
O modificador private restringe o acesso a um membro ao código dentro de sua classe, mantendo os códigos de classes de nível superior separadas atrás da interface pública.
Um campo privado de idade faz pet.age = -1; falhar em uma classe Main separada, exigindo uma chamada de método controlada.
Modificador protected
O modificador protected permite acesso pelo mesmo pacote e acesso restrito por código de subclasses fora desse pacote.
Um método auxiliar protegido pode ser chamado por outra classe em seu pacote mesmo quando essa classe não é uma subclasse.
Modificador public
O modificador public permite o acesso a um membro onde quer que o tipo que o declara seja acessível, para que outros códigos possam usar a operação exposta.
Um método público lend() permite que Main solicite um empréstimo enquanto o campo privado de estado do livro permanece oculto.

N

Notação de ponto
A notação de ponto indica um membro por meio de um objeto receptor, como uma referência a objeto seguida de um ponto e uma chamada de método.
A notação de ponto em luna.getAge() informa ao Java que o animal acessado por luna deve informar sua idade.
null
O valor Java null significa que uma referência não tem objeto para acessar; campos de tipos de classe o recebem, a menos que sejam inicializados de outra forma.
Chamar add em um campo de lista que ainda está null falha porque nenhum objeto de lista foi criado.

O

Objeto
Um objeto é uma instância de uma classe que existe durante a execução de um programa e tem seus próprios valores atuais de campos de instância.
Dois objetos de animais criados com expressões new separadas podem ter idades diferentes enquanto seguem uma mesma definição de classe.
Objeto receptor
O objeto receptor é o objeto no qual um método de instância é invocado, identificado pela expressão antes do ponto em uma chamada.
Em book.lend(), o objeto receptor é o livro acessado por book, cuja variável sinalizadora de empréstimo o método verifica.
Ocultação de informações
Ocultação de informações mantém os códigos que usam um objeto dependentes de suas operações disponíveis em vez dos detalhes de seu armazenamento interno.
A ocultação de informações permite que um relógio altere seus campos mantendo getHours() consistente para os códigos existentes que o chamam.
Operador new
A palavra-chave Java new inicia uma expressão de criação de objeto que executa um construtor e produz uma referência ao objeto.
new Pet("Luna", "cat", 3) cria um animal e fornece três argumentos para seu estado inicial.

P

Palavra-chave this
A palavra-chave this refere-se ao objeto atual dentro de código de instância, distinguindo seus campos de parâmetros com o mesmo nome.
Dentro de um método modificador de animal, this.name = name; escreve a nova entrada no campo desse animal específico.
Parâmetro
Um parâmetro é uma entrada nomeada declarada no cabeçalho de um método ou construtor que recebe um argumento em cada chamada.
O parâmetro age em um construtor de animal recebe 3 quando a chamada fornece 3 nessa posição.
Projeto de classes
O projeto de classes escolhe o estado, as formas de construção, as operações e as regras que permitem que uma classe represente um tipo útil de coisa.
O projeto de classes transforma uma descrição de livro de biblioteca em campos de identificação, uma variável sinalizadora de empréstimo e operações que aplicam as regras de empréstimo.
Propriedade somente de leitura
Uma propriedade somente de leitura é uma informação disponibilizada para leitura sem oferecer aos códigos que a usam uma operação que a substitua diretamente.
Um título fixo é uma propriedade somente de leitura quando os códigos que o usam têm getTitle(), mas nenhuma operação para substituí-lo.

R

Rastreamento de estado
Um rastreamento de estado registra os valores dos campos após cada instrução para mostrar como uma sequência de operações altera objetos específicos.
Um rastreamento de estado com colunas para dois animais mostra que um aniversário no primeiro deixa o segundo inalterado.
Referência
Uma referência é um valor que identifica um objeto, permitindo que uma variável ou expressão o acesse quando necessário.
Após Pet other = luna;, as duas variáveis armazenam referências ao mesmo animal, portanto qualquer uma delas pode acessá-lo.
Resultado esperado
Um resultado esperado é o valor de retorno, a saída ou o estado previsto a partir de um requisito antes da execução de um teste.
O resultado esperado de uma segunda chamada a lend() em um livro emprestado é false, com a variável sinalizadora de empréstimo inalterada.

S

Sobrecarga de construtores
Sobrecarga de construtores é a declaração de vários construtores para uma classe usando listas de parâmetros diferentes para diferentes entradas de criação.
A sobrecarga de construtores permite que um relógio aceite horas e minutos ou comece à meia-noite sem argumentos.
Sombreamento
Sombreamento ocorre quando uma declaração mais próxima, como um parâmetro, oculta o nome simples de um campo em parte do código.
O sombreamento por parâmetro torna this.age = age; útil: o lado esquerdo é o campo, e o direito é a entrada.

T

Tempo de vida
O tempo de vida de uma variável é o período durante a execução em que seu armazenamento existe; um campo de instância dura enquanto seu objeto existir.
O tempo de vida de um campo de contagem se estende entre chamadas de incremento, enquanto uma variável local temporária existe apenas durante sua chamada.
Teste de valor-limite
Um teste de valor-limite verifica o comportamento em um limite permitido ou próximo dele, onde uma condição muda se uma operação deve ser bem-sucedida.
Um teste de valor-limite de um método modificador de temperatura desejada experimenta um extremo permitido e um valor imediatamente fora dele para verificar a comparação.

V

Validação
Validação verifica uma entrada ou alteração proposta em relação às regras da classe antes de aceitá-la como parte do estado do objeto.
A validação compartilhada em um construtor e em um método modificador impede que qualquer um dos caminhos armazene um estado inválido.
Valor de retorno
Um valor de retorno é o resultado que um método envia de volta ao código que o chamou, onde pode ser armazenado, exibido ou usado em uma expressão.
O valor de retorno de r.area() pode ser dobrado em uma expressão; apenas exibir a área não fornece um valor.
Valor padrão
Um valor padrão é o valor inicial que o Java atribui a um campo sem inicializador explícito, como 0, false ou null.
Um campo booleano tem o valor padrão false; um booleano local deve receber um valor antes de poder ser lido.
Variável de instância (campo de instância)
Uma variável de instância, também chamada de campo de instância, armazena parte do estado de um objeto e dura enquanto esse objeto existir.
A variável de instância age de cada animal mantém seu próprio valor, embora a declaração apareça apenas uma vez em Pet.
Variável local
Uma variável local é declarada em um bloco dentro de um método ou construtor e fornece armazenamento temporário para essa execução.
A variável local total dentro de um método de cálculo armazena trabalho temporário que o objeto não precisa lembrar.
void
O tipo de retorno void declara que um método não fornece valor de retorno, mesmo quando o método altera o estado ou exibe uma saída.
Um método de aniversário pode retornar void porque sua função é aumentar a idade armazenada de seu objeto receptor.

Sobre esta aula

Por StudeliRelatar um erro

Crie seus próprios Materiais de Estudo

Transforme suas anotações, slides e documentos em Guias de Estudo, Questões de Prática, Flashcards e mais 6 ferramentas.

Começar