Java Classes and Objects

Learn to write your own classes in Java. Define the fields that hold an object's state, write constructors that give every new object valid starting values, and add instance methods that use and change that state. Protect your objects with private fields, getters, setters and checks, give them a readable toString, and finish by designing, building and testing a complete class from a short description.

BeginnerLesson 5 of 11 in Object-Oriented Programming with Java Course

What you will learn

  1. Explain how a class defines a new type of data with its own behavior, and create and use objects of that type in a program.
    • Explain what a class and an object are
      Describe a class as the definition of a type, an object as one instance of it, and state and behavior as what objects hold and do.
    • Create objects and call their methods
      Create objects with new, call methods on them with dot notation and predict how separate objects behave.
  2. Declare the instance variables that hold an object's state and write constructors that give every new object valid starting values.
    • Declare instance variables
      Declare fields with suitable types, know their default values and tell them apart from local variables and parameters.
    • Write constructors that initialize objects
      Write constructors that set every field, use this to tell fields from parameters and avoid the mistakes that leave fields unset.
    • Offer several constructors and chain them
      Overload constructors for different ways of creating an object, and use this(...) so the setup code is written once.
  3. Write instance methods that read and change an object's state, trace their effect, and decide when something belongs to an object or to the class as a whole.
    • Write instance methods that use and change state
      Write methods that report on or change an object's fields, call other methods of the same object and trace the state of objects step by step.
    • Tell instance members apart from static members
      Use this for the current object, decide what should be static and fix the errors that come from mixing static and instance code.
  4. Hide fields behind access modifiers, give controlled access through getters, setters and meaningful methods, and keep every object in a valid state.
    • Hide data with access modifiers
      Use private, package access, protected and public to control which code can use a class's members, and explain why fields are kept private.
    • Write getters and setters
      Write accessor and mutator methods with the standard naming, and decide which fields need them and when a meaningful method is better.
    • Keep objects valid with checks
      Define the rules an object's state must follow, enforce them in constructors and methods, and avoid handing out internal data that bypasses those checks.
  5. Give objects a readable text form with toString, then design, write and test a complete class from a short description.
    • Write a toString method
      Write a toString method that returns a readable description of an object, and know when Java calls it automatically.
    • Design, build and test a complete class
      Turn a short description into a class with fields, constructors, methods and rules, then test every behavior from a main program.

Java Classes and Objects study guide

5 chapters

1

Classes, objects, and method calls

A program often needs to keep several related values together: a pet's name, species, and age, for example. A class gives that group a type and puts the actions that use it in one place. You will connect class definitions with the objects created while a program runs, then follow method calls to see which object's data changes. The distinction between a class, an object, and a variable will help you read the code you write next.

1.1 A type with state and behavior

A class defines a type: the data its objects remember and the operations they offer. An object, also called an instance, is one value of that type created while a program runs. Writing a class definition does not create an object.

State and behavior

A pet's name, species, and age make up its state. Those current values live in instance variables, also called fields. An operation such as celebrating a birthday is behavior, written as a method. The birthday method belongs with the age it changes, so the rule is kept in one place.

Think of a class as a building plan. Many houses can follow one plan, but each house has its own contents. Likewise, two pets can follow the same definition and have different ages. You write the field names once; each object gets its own values.

Read a small class
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++;
    }
}

Read this from the outside in. public class Pet introduces the type, and the outer braces contain its definition. The first three declarations describe state. The block named Pet is a constructor: it gives a new object its first values. celebrateBirthday is a method: it increases the current object's age. The words private and public control access; later examples use them to protect state.

The constructor's parameters are values supplied when an object is created. In this.age = age;, the left side names the object's field and the right side names the supplied parameter. The constructor stores that input so the object can remember it after construction ends.

Put a class to work

You have already used library classes. Scanner describes objects that read input, ArrayList describes lists, and a String object offers operations such as length(). A class you write follows the same basic idea: it makes a useful type available to the rest of your program.

Without Pet, a program might pass a name, species, and age separately to many methods. It must keep each group together correctly. A Pet object carries the related values as one unit. Methods on that object know which age they should use.

Organize and name the code

For ordinary source files, a public class named Pet is saved in Pet.java, with matching capitalization. A separate Main class can contain the program's main method, create pets, and call their methods. Pet needs no main of its own. Classes in the same unnamed package can use one another without imports; the simple examples keep those classes in one folder.

Use UpperCamelCase nouns for classes, such as LibraryBook. Use lowerCamelCase for fields and methods: pageCount names data; giveBack() names an action. These are conventions that help a reader recognize each part, even though the compiler allows many other names.

Key Takeaways

  • A class defines a type; an object is one instance created while the program runs.
  • Fields hold state, and methods provide behavior.
  • Objects of one class follow the same definition and hold their own instance-field values.
  • A public class in an ordinary source file uses the matching class name as its filename.

1.2 New objects and the references that reach them

Creating an object and declaring a variable are different operations. A variable gives you a name through which to reach an object; new creates the object that the name will refer to.

Read an object-creation statement
Pet luna = new Pet("Luna", "cat", 3);

Pet is the variable's type, and luna is its name. new Pet(...) creates a new object and calls a matching constructor with three arguments. The constructor stores the name, species, and age. The resulting reference is assigned to luna.

A reference tells Java which object to use. It is useful to draw a variable as a name with an arrow to an object. The variable is not a second copy of all the object's fields.

Call a method on a particular object

The dot in luna.celebrateBirthday() connects a reference with a method to run on its object. A returning method can supply a value to another expression:

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

Here getAge() is a public method that returns the pet's age. The birthday call changes state; the getter reads that state. Pet.celebrateBirthday() fails because this instance method needs a particular pet. The class name alone does not answer whose birthday it is.

Separate objects and shared references
Pet max = new Pet("Max", "dog", 5);
luna.celebrateBirthday();
System.out.println(luna.getAge()); // 5
System.out.println(max.getAge());  // 5

Luna was already 4, so the next birthday takes her to 5. Max stays 5. Equal ages do not make them the same object: the two new expressions created separate pets.

Now consider an assignment with no new:

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

The assignment copies Luna's reference. Both names reach one pet, so changing it through other is visible through luna. To make a second pet, call new again.

Match the constructor's parameters

Arguments must fit a declared constructor's number, order, and types. If the only available constructor takes (String, String, int), new Pet() fails to compile. Java does not guess missing values. Swapping the two strings, however, still compiles: new Pet("cat", "Luna", 3) supplies the right types but the wrong meanings. Read the parameter names to check that order.

These two unfinished attempts fail for different reasons:

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

A local variable must be assigned before it is used. Without new, Java searches for a method named Pet, not an object-creation expression. Once an object exists, printing it may show text like Pet@8bcc55f until you supply a readable toString() method; that output does not mean construction failed.

Key Takeaways

  • Use new with arguments that match an available constructor.
  • Dot notation calls an instance method on the object reached by a reference.
  • Another new expression creates another object; reference assignment shares an existing one.
  • Arguments of the same type can be swapped without a compiler error, so check their meanings.
  • A local declaration alone creates no object and gives the variable no usable value.
2

Fields and the first state of an object

Objects need somewhere to keep their data and a reliable way to get their first values. Fields provide the storage; constructors set up each new object. You will choose field types, separate lasting state from temporary local work, and follow construction from default values to a ready object. Then you will offer several useful ways to create the same kind of object while keeping shared setup and checks in one place.

2.1 Data that an object remembers

An object needs a field for each value it must remember between method calls. Choose those values before writing methods: they form the object's lasting state.

Declare fields with suitable types

A field sits inside the class braces but outside every constructor and method. A declaration needs a type and a name; an access modifier and an initializer can also appear.

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

String suits text, int suits a whole-number count, and boolean suits a yes-or-no condition. Fields can also use class types such as ArrayList<String>. These examples use private; leaving the modifier out gives package access, not private access.

Every object gets a separate copy of each instance field. Two Rectangle objects each have a width and a height, even though the declarations appear only once in the class.

Defaults are not always usable starting values
Field typeDefault value
int, long0
double0.0
booleanfalse
Class types, including String and ArrayListnull

A default is assigned to a field when storage for the object is created. It may not fit the object's purpose. A list field with the value null is not an empty list: you still need to create the list before adding an item.

Local variables receive no such default. Inside a method, int total; followed by System.out.println(total); fails to compile because total has not been assigned. Keep the field rule and the local-variable rule separate.

Decide what must last
Kind of variableWhere it is declaredWhat it is for
Instance fieldIn the class, outside methodsValues remembered by one object
ParameterIn a constructor or method headerInputs for that call
Local variableInside a method or constructor blockTemporary work for that call

A field remains with its object. A parameter is available during its call, and a local variable is available in its block while that call runs. If a counter must retain its count from one call to the next, the count belongs in a field. A temporary subtotal used for one calculation can be local.

Store the inputs; calculate derived values
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;
    }
}

The dimensions are in centimeters, so area() returns an area in square centimeters. Storing a separate area field would create another value to update whenever either dimension changed. Computing it from the dimensions keeps the answer consistent.

Use an instance final field for a value assigned once, such as private final String title;. Give it a value in its declaration or in every constructor. final prevents reassignment. static has a different meaning: it creates one shared class field. Adding static to a pet's name would make different pets share one name variable.

Key Takeaways

  • Instance fields are declared outside methods and remember each object's state.
  • Fields receive defaults; local variables must be assigned before use.
  • Choose fields for lasting data and locals for temporary work.
  • Calculate values that follow from stored fields to avoid inconsistent copies.
  • An instance final field is assigned once; a static field is shared by the class.
  • A null list field still needs a list object before it can be used.

2.2 From arguments to initialized fields

A constructor sets up an object when new creates it. Its name must match the class, and it has no return type. Even void would turn the declaration into a method.

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

A constructor usually accepts inputs as parameters and stores them in fields. Here each parameter has the same name as its field. The bare name age means the parameter; this.age means the field of the object being created. The assignment reads the supplied value on the right and writes the field on the left.

For new Pet("Luna", "cat", 3), first the new object's fields receive defaults: null, null, and 0. The constructor then receives the three arguments and replaces those defaults. When construction finishes, new produces the reference that the caller stores.

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

Both occurrences of name refer to the parameter, so the first line assigns that parameter to itself. The object's name stays null. The code is legal, which is why checking the new object's values matters.

A declaration inside the constructor causes a related problem:

String nick = initialNick;

If a field named nick already exists, this line creates a local variable with the same name. The local disappears when construction ends. Write this.nick = initialNick; to store the input in the field; do not repeat the type.

Know when a no-argument constructor exists

If a class declares no constructors, Java supplies a default constructor with no parameters. For a simple class, its fields keep their declared initializers or default values. As soon as you declare any constructor, Java stops supplying that default one.

A class with only Pet(String name, String species, int age) therefore cannot be created with new Pet(). Add an explicit no-argument constructor only when there is a useful starting state for it. Also watch for public void Pet(...): that is a method, so it does not provide the intended constructor at all.

Set internal starting values too

Not every field needs to come from an argument. A new book can always start with this.lentOut = false;. A class that owns a list can initialize it like this, with ArrayList imported:

private ArrayList<String> tracks;

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

The empty list is ready for add. Leaving tracks at null makes a later tracks.add(...) fail with NullPointerException.

A field initializer runs before the constructor body. If private int score = 10; is followed by this.score = 5; in the constructor, the finished object's score is 5. Test the values after construction, not just the values written beside the field declarations. Constructors also need the same validation rules as later changes, so the first state is valid.

Key Takeaways

  • A constructor has the class name and no return type.
  • Use this.field = parameter when the names match.
  • Neither parameter self-assignment nor a new local variable initializes the intended field.
  • Java supplies a default constructor only when the class declares no constructors.
  • Initialize internal state such as empty lists, and apply validation during construction.

2.3 Several ways to construct one kind of object

A class can offer several useful ways to create an object. Constructor overloading means declaring constructors with different parameter lists.

Distinguish constructors by parameters

Java tells constructors apart by the number, types, and order of their parameters. Parameter names do not distinguish them. Box(String label) and Box(String name) describe the same parameter list, so they cannot both be declared in one class.

A pet may be created with an age or as a newborn:

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") selects the two-parameter constructor. That constructor supplies 0 as the missing age and calls the three-parameter constructor. The new object ends with the state "Pip", "rabbit", and 0.

Chain setup on the same object

Inside a constructor, this(...) calls another constructor of the same class. The shorter constructor chooses defaults; the fuller constructor does the shared setup. Checks placed in that setup apply to both construction routes.

Contrast two lines that look similar:

Line inside a constructorEffect
this(name, species, 0);Initializes the current object through another constructor
new Pet(name, species, 0);Creates a separate pet

The second line does not fill the current object's fields. If its result is never stored, that extra pet is discarded. The current pet may still have null fields.

Follow a chain before tracing later code

A clock can offer midnight as a default:

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

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

For new Clock(), enter the no-argument constructor, follow this(0, 0), and assign both fields in the two-argument constructor. Then control returns to the no-argument constructor. This creates one clock, not two. A call to new Clock(9, 5) starts directly in the fuller constructor.

Keep the chain legal and clear

A constructor can contain at most one this(...) call. The chain must eventually reach setup that does not call back into the chain: two constructors that delegate to each other cause a compile-time recursive-constructor error.

Putting this(...) first is a clear style that works across Java versions. In Java 24 and earlier without preview features, it must be first. Java 25 allows earlier statements for tasks such as computing or checking arguments. Those statements cannot read the current object's instance fields or call its instance methods; assignments to fields declared in the class without declaration initializers are allowed.

Offer overloads because callers have different useful inputs. A midnight clock is meaningful; a book with no title may not be. The existence of a full constructor does not create any shorter overloads automatically.

Key Takeaways

  • Overloaded constructors differ by parameter lists, not parameter names.
  • The call this(...) delegates to another constructor on the same object.
  • Keep shared initialization and checks in one construction route.
  • A constructor chain must not circle back to a constructor already in that chain.
3

Methods that read and change state

A useful object can answer questions about itself and carry out actions that change its state. Instance methods put those operations next to the fields they use. You will trace changes one statement at a time, handle a clock's rollover, and return values that other code can use. You will also decide which data belongs to each object and which data or operations belong to the class, so that separate objects stay separate.

3.1 Calculations, changes, and state traces

An instance method runs for one particular object. Declare it without static, and use fields of that object through names such as this.width. Decide what the caller needs: a state change, a returned result, or both.

Return calculations; keep state changes explicit

For a rectangle whose dimensions are stored in centimeters:

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;
}

A rectangle with sides 3.0 and 4.0 has area 12.0 square centimeters and perimeter 14.0 centimeters. scale(2) changes the sides to 6.0 and 8.0. The next calls return area 48.0 and perimeter 28.0. Each method reads the current fields, so no stored area needs updating.

area() returns a number that can be stored or used in a calculation. If it only printed the number and had return type void, the caller could not write double twice = r.area() * 2;. Leave printing to the caller when a method's job is to compute a value.

Update related fields in order

A clock's advance() method must handle both minute and hour rollover:

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

At 23:58, the first call reaches 23:59 and skips both reset blocks. The next call briefly reaches minute 60, resets it to 0, raises the hour to 24, and resets that to 0. The finished state is 00:00. One more call gives 00:01.

Trace objects separately

Write a row after each statement and a column for each object's fields. Change only the object named by the receiver of the call. For pets aged 2 and 7, two birthdays on the first pet and setAge(1) on the second leave ages 4 and 1. Do not run a method's body for every instance just because they share a class.

A local declaration can hide the field you meant to update. public void reset() { int count = 0; } only creates a temporary variable. this.count = 0; resets the lasting count.

Reuse methods and complete return paths

Within an instance method, area() and this.area() call the same object's area method. A description method can reuse that calculation instead of copying its expression. A method may also change state and return success, as lend() does when it marks a book as borrowed and reports true.

A non-void method cannot simply reach the end without returning a compatible value. If get() returns only inside if (count > 0), what happens when the count is 0? Add the needed return path or throw an exception for a value the method rejects. A path that throws does not return to the caller and needs no return value.

Key Takeaways

  • Instance methods read or change the state of the object they are called on.
  • Return computed values so callers can use them in expressions.
  • Trace statements in order, keeping each object's fields separate.
  • Rollover methods must restore every related field to its allowed range.
  • Reuse other methods of the same object by calling them directly or with this.
  • A returning method needs a value on every path that returns normally.

3.2 Per-object members and shared class members

Ask who owns a value or an operation before deciding whether to use static. A pet's age belongs to one pet. A count of all pets created belongs to the class as a whole.

The current object is this

Inside a constructor or instance method, this refers to the object being constructed or receiving the call. In this.age++, it identifies whose age changes. In this.name = name, it separates the field from a same-named parameter. this(...) is the constructor-chaining form.

A static method has no current object, so this cannot be used there. It may still create an object or receive a reference and use that reference to call instance methods.

Shared fields and per-object fields
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;
    }
}

After two new Counter() calls, there are two separate count fields, both initially 0, and one created field equal to 2. Incrementing the first counter changes its count to 1; the second stays 0. Counter.getCreated() still returns 2 because no new object was constructed.

Work through an object from main
public static void main(String[] args) {
    Counter c = new Counter();
    c.increment();
    System.out.println(c.getCount());
}

The classic main method is static. A bare call to increment() there would have no target object and would fail to compile. The variable c supplies that target. Making count static to silence the error would change the design: every counter would then share one count.

Kind of methodDirect access available
Instance methodIts instance members and the class's static members
Static methodStatic members; instance members through an object reference

Java 25 also supports instance forms of main, but the classic static header remains valid. These examples use it consistently.

Choose methods and constants deliberately

An operation that needs an object's fields should be an instance method. An operation that depends only on its parameters can be static, like a helper that converts a total number of minutes into hours. Static calls normally use the class name: Math.sqrt(16) or Counter.getCreated().

A shared fixed value is usually declared as a constant:

public static final int MAX_CELSIUS = 30;

public makes it available to callers, static gives the class one shared field, and final prevents reassignment. UPPER_SNAKE_CASE signals a constant by convention. This is a common exception to making fields private. Do not use static for ordinary names, dimensions, or other state that must differ between objects.

Key Takeaways

  • The reference this identifies the current object inside instance code.
  • Static members belong to the class; instance members belong to individual objects.
  • A static method needs an object reference to use instance members.
  • Fix static-context mistakes by supplying the right object when the state belongs to an object.
  • A public static final field commonly provides a shared constant.
4

Controlled access and valid state

A class should control the values that can enter its state. Private fields and public methods let the class check each change and give callers useful operations. You will choose access levels, write getters and setters where they help, and protect rules such as an allowed temperature range. You will also see why a private list can still escape through a getter and how to keep outside code from bypassing the class's checks.

4.1 Private state and a public interface

Encapsulation keeps an object's state together with the code that controls it. Fields are usually private, while callers use public operations. This hides storage details and gives the class a place to enforce its rules.

Choose an access level
AccessWho can use the member
privateCode in the same class
No modifierCode in the same package
protectedThe same package, plus subclass access under Java's subclass rules
publicCode that can access the declaring type

A package groups classes. The simple examples place ordinary classes together without a package declaration, in one unnamed package. Package access is the result of leaving the modifier out; there is no package access keyword to add to a field.

Start with the narrowest useful access. Make fields private, constructors and operations needed by other classes public, and internal helper methods private. Public constants are a common exception for fields.

Put the class in charge of changes

If Pet declares private int age;, a separate Main class cannot assign luna.age = -5;. The compiler rejects the access. A call such as luna.setAge(-5) can be allowed, because the public method belongs to Pet and can decide whether to store the argument.

A public field would let any caller bypass that method. Once all changes go through the class's code, the checks can live in one place. Private access alone does not validate an age; the methods must perform the checks too.

Keep the public interface stable

Suppose a clock initially stores separate hours and minutes fields. Callers use getHours() and getMinutes(). You later replace the fields with a single minutesSinceMidnight value:

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

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

With 615 stored minutes, division returns 10 and remainder returns 15. The clock reports 10:15 through the same methods. Callers do not need rewriting because they depended on the public operations, not on how the state was stored. This freedom to change internals is information hiding.

Access belongs to classes, not individual objects

Code inside Pet can read a private field of another Pet object. The access permission comes from being inside the class. A different top-level class does not gain permission by holding a pet reference or being in the same folder.

For ordinary top-level class declarations, the access choices are public or no modifier. A top-level private class Pet is illegal. A public top-level class goes in the matching source file, and one ordinary source file contains at most one public top-level class.

Private fields are a program-design boundary. They prevent other ordinary code from depending directly on internal fields, but they are not a way to keep a value secret from a person who can inspect the program. Use them to control your class's interface and protect its state.

Key Takeaways

  • Private fields and public operations keep control of state inside the class.
  • Leaving out an access modifier gives package access.
  • Public methods let internal storage change without changing callers.
  • Private access is checked by class, so code inside the class can access another instance's fields.
  • Ordinary top-level classes use public or package access.

4.2 Access methods that fit the class

A class can let callers read or change selected parts of its state through methods. Decide which operations the class should offer before creating access methods for every field.

Return values with getters

A getter, also called an accessor, returns information without changing the object. A common getter reads a field:

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

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

The returned type matches the information being supplied. A getter that prints and returns void cannot give a value to an expression such as pet.getAge() + 1. The caller should receive the value and decide how to use it.

Change selected values with setters

A setter, also called a mutator, takes a new value and updates state:

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

this.name is the field. name is the parameter. Writing name = name; compiles but changes no field. There is no return value here because this setter's job is to perform a change.

For a pet whose age is 3:

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

The caller never touches a field directly. The setter changes the name, and the getters return the current values for the caller to combine.

Follow names that other Java code expects
FieldGetterSetter, if needed
pageCountgetPageCount()setPageCount(int pageCount)
namegetName()setName(String name)
lentOutisLentOut()setLentOut(boolean lentOut)

Capitalize the first letter of the field name after get, set, or the usual boolean prefix is. A name such as getname() may compile, but it does not follow the convention that tools and other programmers expect.

Expose only useful operations

A book's title may have a getter and no setter because callers should read it but not replace it. A private final field can enforce that it is assigned once. An internal counter may need neither getter nor setter if only the class uses it.

An unchecked setter can accept the same damaging value as a public field. Add checks where a change has restrictions. Also consider an action method: celebrateBirthday() expresses increasing the age by one, and lend() expresses a lending attempt. lend() can inspect the current state and reject a second loan. A setter can perform that check too; the action name makes the operation clearer to its caller.

A getter can compute an answer. getArea() may return the product of width and height without any area field.

Key Takeaways

  • A getter returns information; a setter changes a selected value.
  • Follow getName, setName, and the usual boolean isName naming pattern.
  • Give fields only the access methods that callers need.
  • Action methods such as lend express allowed behavior clearly and can check transitions.

4.3 Rules that survive every change

An invariant is a rule about an object's state that holds after construction and after every public operation. A thermostat might allow targets from 5 °C through 30 °C. Every way to set its target must preserve that range.

Choose what invalid input means

Three useful responses are to keep the old value, clamp the value to a limit, or throw an exception. They have different effects, so choose a clear response for each operation.

ResponseResult of an invalid call
IgnoreThe old field value stays unchanged
ClampThe nearest allowed boundary is stored
ThrowThe call stops with an error such as IllegalArgumentException

For a nonnegative pet age, an ignoring setter can assign only inside if (age >= 0). If the stored age is 4, setAge(-2) leaves it at 4. It does not turn the age into 0.

Put range checks inside the class
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);
}

Starting at 20 °C, setTarget(35) stores 30. setTarget(-3) stores 5. After setTarget(29), a call to raise() stores 30; another call still stores 30. Reusing the setter prevents raise() from slipping past the upper limit.

Checks in Main alone cannot protect the thermostat. Another caller could forget them. The class must check the input at the place where it controls storage.

Validate the first state too
public Thermostat(int target) {
    setTarget(target);
}

With this clamping constructor, new Thermostat(50) finishes at 30 °C. Directly assigning this.target = target; would allow the invalid first state of 50. A shared private checking method is another way to reuse validation in constructors and later methods.

Throwing is useful when an invalid argument signals a programming error. For example, a constructor can reject a negative count with throw new IllegalArgumentException("count must not be negative");. The object is not successfully constructed, so no invalid finished object is given to the caller. Ignoring input is simpler but silent; the caller may need another way to notice that nothing changed.

Keep mutable internal data inside

A private list can still escape if a getter returns the original list. A caller could then add or remove entries without using the class's methods, bypassing a maximum-size rule.

For an ArrayList<String> field named tracks, return new ArrayList<>(this.tracks); gives a separate list containing the same strings. Changing that returned list does not change the internal list. Operations such as addTrack(String title) can keep list changes inside the class and check its rules before accepting them.

Key Takeaways

  • An invariant holds after construction and after each public operation.
  • Ignoring, clamping, and throwing are different responses to invalid input.
  • Every constructor and state-changing method must preserve the same rules.
  • Reuse validation so different change routes cannot bypass it.
  • Returning an internal mutable list lets callers bypass the class's checks.
  • A copy of an internal string list protects the original list from outside list changes.
5

Readable objects and complete classes

Readable object descriptions make it easier to use and check a class. A toString method supplies that text wherever an object is printed or joined to a string. You will write the method with the right header, then bring fields, constructors, methods, and validation together in a complete class. Starting from a short description, you will turn requirements into code and test normal calls, repeated actions, and boundary cases.

5.1 An object description returned as text

A useful object should be easy to inspect as text. Java's built-in toString() returns a class name, an @ sign, and a hexadecimal hash code, such as Pet@8bcc55f. A named package becomes part of the class name. The hash text varies and usually says little about the object's state.

Return a readable description
@Override
public String toString() {
    return this.name + " (" + this.species + ", "
        + this.age + " years)";
}

For Luna, a cat aged 3, the returned string is "Luna (cat, 3 years)". The method reads fields and builds a string. It does not change the pet or send output to the screen.

@Override asks the compiler to check that the declaration really replaces an existing method. That catches errors such as writing tostring with a lowercase s. It does not format the result for you; the return expression determines the text.

Recognize automatic calls
System.out.println(luna);
String label = "Pet: " + luna;
String details = luna.toString();

The first line prints the pet's readable description. The second builds "Pet: Luna (cat, 3 years)". The third asks for the same description explicitly and stores it without printing. When an ArrayList of pets is printed, its display uses each pet's toString() inside the list's square delimiters.

Automatic conversion is why returning text matters. The caller may be printing, storing, or joining the result. A method that only prints cannot supply the string needed by all those callers.

Match the method header
DeclarationWhat happens
public String toString()Supplies the object description
public String tostring()Declares a different method; @Override catches it
public String toString(int width)Declares an overload; automatic printing does not call it
public void toString()Fails: it conflicts with the existing String-returning method

Use the exact no-argument header and include the annotation. An overload with parameters may be a valid separate method, but printing an object does not provide those parameters.

Format values without changing them

A clock needs two-digit hours and minutes. Inside its toString() method:

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

For hours 9 and minutes 5, the string is "09:05". Each %02d formats an integer in at least two positions, using a leading zero when needed. String.format(java.util.Locale.US, "%.2f", 7.5) returns "7.50". Supplying the locale makes the decimal-point output independent of the computer's default formatting locale.

Keep the description short enough to read while debugging. It can reveal unset state: joining a null name field to a string produces the text "null", which points you back to initialization. The description should report the current state, so printing the object twice should not advance a clock or celebrate a birthday.

Key Takeaways

  • Write public String toString() with no parameters and return readable text.
  • The annotation @Override lets the compiler check that the method replaces an existing one.
  • Printing an object and joining it to a string use toString automatically.
  • Keep toString free of state changes and let its caller decide where text goes.
  • String.format can pad values and use an explicit locale for predictable output.

5.2 From a requirement to a tested class

Start with what one object must remember, what callers can ask it to do, and which states must be allowed. Then turn each part into fields, constructors, and methods.

Extract the design from a description

"A library book has a title, an author, and a page count. It can be lent out and given back. It cannot be lent out again while already on loan."

Use LibraryBook as the class name. Store the three descriptive values and a boolean loan status. The title, author, and page count stay fixed, so make them final. The loan status changes through meaningful actions. A setter for every field is unnecessary.

Build the complete class
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;
    }
}

The constructor establishes availability. lend() checks the existing state before changing it; returning false on a second loan preserves the rule. giveBack() makes the book available. The getter reports status, and toString() describes the whole book without changing it.

Write expectations before running calls

In a separate Main class's classic main method:

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

The second loan attempt is essential: a method that always sets the flag and returns true would pass the first call but fail this check. Test state as well as return values with isLentOut(). Also try a second book to check that a loan on one book leaves the other available.

Test where behavior changes

Cover every constructor and public method. For range checks, try both endpoints and values just outside them. For a clock, check minute rollover and midnight rollover. For a rejecting or ignoring setter, check that invalid input has the promised effect on the old state. Write the expected result first so an unexpected output does not quietly become your new expectation.

Build in small increments: fields and constructor first, then a readable description, then one operation and its checks at a time. Save ordinary public classes in matching files, compile them together, and run the class containing main. Keeping model operations separate from screen output lets the same class serve different programs.

Key Takeaways

  • Turn remembered data into private fields and allowed actions into methods.
  • Write the state rules before implementing constructors and changes.
  • Use final for fixed per-object values and avoid unnecessary setters.
  • Test return values and resulting state, including repeated calls and separate objects.
  • Check boundaries and invalid input as well as ordinary values.
  • Build and test one useful part at a time.
  • Keep model behavior separate from the main program that prints results.

Java Classes and Objects examples

5 Walkthroughs

1

From one class to two pets

10 steps
Create objects, find their state, and follow calls through separate and shared references.
  1. 1
    IntroductionA type for the things in your program

    A pet program needs to remember a name, species, and age together. A class gives that group a type and offers methods that use it. Each object is one pet created from that definition.

    Follow the difference between the definition and the pets it produces. Then trace two pet objects and see why an extra variable does not always mean an extra object.

  2. 2
    AnalogyA plan and its instances

    Think of a class like a building plan and its objects like houses built from it. The plan describes what each house contains, but it is not a house itself.

    One Pet definition can describe many pets. Each has fields for the same kinds of data, yet one can be a three-year-old cat and another a five-year-old dog. Defining the fields creates the plan; object creation supplies actual instances.

  3. 3
    ExampleFind state and behavior

    A pet's fields name, species, and age store its state. For Luna, their values are "Luna", "cat", and 3.

    The method celebrateBirthday() provides behavior. Its body can execute this.age++;, changing the receiving pet's age. The method is part of the class definition; the value it changes belongs to a particular pet.

  4. 4
    ChallengeDoes a definition create a pet?

    A programmer writes a Pet class with three fields and a birthday method. No object-creation expression has run. How many pet objects has that definition created?

    ---reveal---

    None. The class defines a type and its available state and behavior. Objects appear when the program creates them, for example with new Pet(...). Three field declarations describe three pieces of data per pet, not three pets.

  5. 5
    ExampleCreate the first object

    Read Pet luna = new Pet("Luna", "cat", 3); in parts. Pet luna declares a variable. new Pet(...) creates a pet and runs the constructor with the three supplied arguments.

    The constructor stores the starting values. The reference produced by new is assigned to luna, giving later code a way to reach this object. Declaring Pet luna; alone would provide no object to call.

  6. 6
    ExplanationCall a method on its receiver

    In luna.celebrateBirthday(), the expression before the dot identifies the receiver. The birthday method runs for Luna, increasing her age from 3 to 4.

    int age = luna.getAge(); then retrieves the current age for use elsewhere. Pet.celebrateBirthday() cannot choose a pet: this is an instance method, and a class name supplies no particular object.

  7. 7
    ExampleCreate a second pet

    Now run Pet max = new Pet("Max", "dog", 5);. A second new expression creates a second object with its own fields.

    After another luna.celebrateBirthday(), Luna is 5 and Max is still 5. Their equal ages do not make them the same object. A later birthday on Luna changes only Luna's age because Max's age lives in a different object's fields.

  8. 8
    Key InsightAn assignment can share one object

    Pet other = luna; copies Luna's reference. It does not call a constructor and does not copy her fields into another pet.

    The names other and luna now reach the same object. Calling other.celebrateBirthday() changes that pet from age 5 to age 6, and luna.getAge() sees 6 too. Count object creations separately from variable declarations.

  9. 9
    ChallengeTrace a shared reference and a separate pet

    Two separate pets start with ages 1 for a and 8 for b. The code runs Pet c = a; c.celebrateBirthday(); b.celebrateBirthday();. What ages do a and b report?

    ---reveal---

    They report 2 and 9. c shares a's object, so its call increases that pet's age. The call through b increases the separate pet. The class supplies the same birthday behavior to both, but each call has its own receiver.

  10. 10
    RecapRead creation and calls deliberately

    Keep three roles separate: the class defines the type, each object holds its own instance state, and a reference variable reaches an object.

    When reading code, mark each new, match its arguments to the constructor, and identify the receiver before tracing a method call. A plain reference assignment adds a route to an existing object. A second new creates a separate object with its own state.

2

Build the first state correctly

14 steps
Choose fields, follow constructor assignments, and use overloads without creating extra objects.

Save this lesson to follow every Walkthrough step by step.

  1. 1
    IntroductionGive every new object useful data
  2. 2
    ExplanationChoose lasting state
  3. 3
    ExplanationSeparate defaults from useful values
  4. 4
    ChallengePick a field or a local
  5. 5
    ExplanationRead the constructor header
  6. 6
    ExampleMove parameters into fields
  7. 7
    TipA legal assignment that stores nothing
  8. 8
    ChallengeFind the unchanged field
  9. 9
    ConnectionCreate internal objects too
  10. 10
    ExampleOffer a useful default route
  11. 11
    ExplanationFollow one object through the chain
  12. 12
    ChallengeDiagnose a misleading new expression
  13. 13
    ChallengeCombine a fixed field with an overload
  14. 14
    RecapCheck each route to a finished object
3

Trace changing state and shared state

13 steps
Work through a rectangle and a clock, then separate instance behavior from static members.

Save this lesson to follow every Walkthrough step by step.

  1. 1
    IntroductionFollow what each call changes
  2. 2
    ExplanationReturn a value to the caller
  3. 3
    ExampleScale the stored dimensions
  4. 4
    ChallengeCheck the returned result after a change
  5. 5
    ExampleAdvance through midnight
  6. 6
    TipRepair a reset that changes no state
  7. 7
    Key InsightAccount for every normal return
  8. 8
    ExplanationSeparate two counts from one shared counter
  9. 9
    ExampleSupply an object in static code
  10. 10
    ConnectionRecognize a constant
  11. 11
    ChallengeTrace the two kinds of state
  12. 12
    ChallengeFind why separate objects change together
  13. 13
    RecapMatch each operation to its owner
4

Protect every route into state

14 steps
Use access methods, validation, and list copies to keep an object within its rules.

Save this lesson to follow every Walkthrough step by step.

  1. 1
    IntroductionMake the class responsible for its rules
  2. 2
    ExplanationHide the field behind an operation
  3. 3
    TipChoose the smallest useful access
  4. 4
    ChallengeDecide where private access works
  5. 5
    ExampleReturn information with a getter
  6. 6
    ConnectionOffer actions that fit the object
  7. 7
    ChallengeRead without permitting replacement
  8. 8
    ExplanationChoose a policy for invalid input
  9. 9
    ExampleTrace clamping at the upper limit
  10. 10
    ExampleCheck the first state
  11. 11
    ChallengeTrace ignoring instead of clamping
  12. 12
    Key InsightA private list can still escape
  13. 13
    ChallengeClose both unchecked routes
  14. 14
    RecapAudit the public interface
5

Build and test a useful class

12 steps
Write a readable description, implement a loan rule, and test a complete library-book class.

Save this lesson to follow every Walkthrough step by step.

  1. 1
    IntroductionTurn a requirement into visible behavior
  2. 2
    ExplanationUse the exact description header
  3. 3
    ExampleReturn the current state as text
  4. 4
    TipFormat a clock without changing it
  5. 5
    ChallengeRepair automatic printing
  6. 6
    ExampleChoose fields from the requirement
  7. 7
    ExampleEstablish the starting status
  8. 8
    ExampleImplement the rule before the change
  9. 9
    ChallengePredict a sequence before running it
  10. 10
    ConnectionTest the cases an easy run misses
  11. 11
    ChallengeDistinguish reporting from changing
  12. 12
    RecapBuild with a testable public promise

Java Classes and Objects practice questions

40 Practice Questions in 4 sets

Set 1: Create objects and read their state10 Practice Questions

Question 1 of 10

A delivery program uses one Parcel class to create several parcels. What is one parcel created while the program runs called?
  1. A definition of Parcel.
  2. An instance of Parcel.
  3. A method inside Parcel.
  4. A parameter of Parcel.
Show answerHide answer
Answer: B
An instance is one object created from a class, so each parcel is an instance of Parcel. The class definition describes the data and operations for all those objects; it is not another name for one particular parcel. A method is an operation the object can perform.

Question 2 of 10

A Bell object is stored in bell, and ring() is an instance method. How should the program ring that bell?
  1. Bell.ring(bell);
  2. ring(bell);
  3. new bell.ring();
  4. bell.ring();
Show answerHide answer
Answer: D
Dot notation calls ring() on the object reached by bell. The variable before the dot supplies the receiver that an instance method needs. Bell.ring() names the class instead, so it cannot select this bell for an instance call.

Question 3 of 10

A class declares private int attempts; with no initializer or constructor assignment. What value does a new object store in this field?
  1. 0
  2. 1
  3. null
  4. No value; compilation fails.
Show answerHide answer
Answer: A
An int instance field receives the default value 0 before explicit initialization. The rule requiring assignment before reading an uninitialized local variable does not apply to fields. null is the default for class-type fields, not an int field.

Question 4 of 10

After new Badge("Visitor"), getText() returns null. The field is private String text;, the getter returns it, and the constructor body is text = text;. How should the constructor store its text parameter?
  1. text = this.text;
  2. String text = "Visitor";
  3. this.text = text;
  4. this.text = this.text;
Show answerHide answer
Answer: C
The parameter hides the field when its bare name is used. this.text = text; writes the input into the current object. Reversing the assignment reads the still-null field into the parameter instead, and assigning the field to itself also leaves it unset.

Question 5 of 10

A class has Ticket() { this(4); } and Ticket(int zones) { this.zones = zones + 1; }. What value does new Ticket() store in zones?
  1. 0
  2. 4
  3. 5
  4. 8
Show answerHide answer
Answer: C
The no-argument constructor delegates with argument 4 on the same object. The fuller constructor adds 1 and stores 5. The supplied 4 is a parameter value on the way to initialization; it is not the final field value because the constructor applies the extra calculation.

Question 6 of 10

A MinuteClock stores hours 0–23 and minutes 0–59. advance() adds one minute with hour and midnight rollover. isMidnight() checks for 00:00. Starting at 23:57, run advance(); advance(); advance(); if (isMidnight()) { advance(); } advance();. What is the final time?
  1. 00:01
  2. 00:02
  3. 00:00
  4. 23:59
Show answerHide answer
Answer: B
The first three calls reach 23:58, then 23:59, then 00:00. The condition is now true, so its call advances to 00:01, and the final call reaches 00:02. Stopping at 00:01 misses the unconditional call after the conditional block.

Question 7 of 10

Each Lamp must remember its own on/off state. How should that state be declared?
  1. private boolean on;
  2. private static boolean on;
  3. public static final boolean ON = false;
  4. A local boolean on inside switchOn().
Show answerHide answer
Answer: A
An instance field keeps a separate value for each lamp and remembers it between calls. Making the field static would share one on/off value among all lamps. A local inside the switching method would not provide the lasting per-lamp state that the design needs.

Question 8 of 10

A Bin field is written as int capacity; without an access modifier. What access does it have?
  1. Private access.
  2. Protected access.
  3. Public access.
  4. Package access.
Show answerHide answer
Answer: D
A member with no access modifier has package access, so other classes in the same package can use it. It does not become private merely because public was omitted. To keep the field behind the class's own methods, declare it explicitly with private.

Question 9 of 10

A Session has private boolean active;. Callers need to check it but may change it only through start() and stop(). What accessor fits this design?
  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; }
Show answerHide answer
Answer: D
The boolean getter returns the current flag without giving callers another way to change it. Printing from a void method does not supply a value to a caller's condition. A public setter would add a change route beyond the two actions the design allows.

Question 10 of 10

An object defines public String toString() { return "Ready"; }. What text is produced by System.out.println("State: " + object);?
  1. Ready
  2. State: Ready
  3. State: Object@Ready
  4. State: toString()
Show answerHide answer
Answer: B
String concatenation uses the object's returned text description, so the label and "Ready" combine into "State: Ready". Defining a custom no-argument toString() replaces the built-in class-and-hash description; Java does not attach that built-in text as an extra prefix.
Set 2: Check initialization and controlled changes10 Practice Questions

Save this lesson to see every answer and practice every set.

Question 1 of 10

A meter stores private int reading = 9;. Its method is public void reset() { int reading = 0; }. What does a getter returning this.reading report after reset()?
  1. 0
  2. 9
  3. null
  4. A compile-time missing-return error.
Show answerHide answer

Save this lesson to see this answer.

Question 2 of 10

A Locker has an occupied field and a release() method. What part of this class describes behavior?
  1. The occupied field.
  2. The current true value.
  3. The release method.
  4. The Locker variable type.
Show answerHide answer

Save this lesson to see this answer.

Question 3 of 10

A Panel stores width and height. Its width can change, and getArea() must always report the current area. How should area be represented?
  1. Compute width times height in getArea.
  2. Store the constructor's area in a final field.
  3. Store area once in a shared static field.
  4. Keep the last area in a constructor local.
Show answerHide answer

Save this lesson to see this answer.

Question 4 of 10

A class declares only public Sensor(int channel). A caller uses new Sensor(). Why does this fail to compile?
  1. The parameter must be named sensor.
  2. Every class must declare a void constructor.
  3. Java requires channel to be a static field.
  4. No no-argument constructor is available.
Show answerHide answer

Save this lesson to see this answer.

Question 5 of 10

A method converts a supplied number of minutes to hours using only its parameter. It needs no object fields. What kind of method can serve this role?
  1. An instance field.
  2. A static method.
  3. A constructor overload.
  4. A final local variable.
Show answerHide answer

Save this lesson to see this answer.

Question 6 of 10

A clock replaces separate hour and minute fields with one minutesSinceMidnight field, while its getters still return the same values. Why can callers keep their existing getter calls?
  1. Private fields become public for callers.
  2. The compiler swaps getter calls for fields.
  3. Each caller gets a copy of the old fields.
  4. The public behavior stays consistent.
Show answerHide answer

Save this lesson to see this answer.

Question 7 of 10

A gauge starts at 16. Its setter clamps inputs to 10–20 inclusive. After setValue(25) and then setValue(8), what are the stored values after each call?
  1. 20, then 10.
  2. 16, then 16.
  3. 25, then 8.
  4. 20, then 20.
Show answerHide answer

Save this lesson to see this answer.

Question 8 of 10

A Group must hold at most four names. addName enforces the limit, but Group(ArrayList<String> names) stores the supplied list directly and getNames() returns the internal list. What design preserves the limit against changes made by callers?
  1. Validate and copy the input; return a copy.
  2. Copy the input only; return the internal list.
  3. Validate the input only; return the internal list.
  4. Copy on return only; store any input list.
Show answerHide answer

Save this lesson to see this answer.

Question 9 of 10

What return type must the no-argument method toString() use?
  1. void
  2. Object[]
  3. String
  4. boolean
Show answerHide answer

Save this lesson to see this answer.

Question 10 of 10

A pass begins unused. use() returns false if already used; otherwise it sets the flag and returns true. reset() clears the flag. toString() only reports it. What do the use calls return in 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
Show answerHide answer

Save this lesson to see this answer.

Set 3: Follow object state through longer sequences10 Practice Questions

Save this lesson to see every answer and practice every set.

Question 1 of 10

A Marker has a name and setName. Run Marker a = new Marker("One"); Marker b = a; a = new Marker("Two"); b.setName("Three");. What do a.getName() and b.getName() return?
  1. "Three" and "Three".
  2. "Three" and "Two".
  3. "Two" and "One".
  4. "Two" and "Three".
Show answerHide answer

Save this lesson to see this answer.

Question 2 of 10

A class declares private int level = 6;. Its constructor is public Beacon(int level) { this.level = level + 2; }. What does new Beacon(3) store?
  1. 6
  2. 5
  3. 3
  4. 8
Show answerHide answer

Save this lesson to see this answer.

Question 3 of 10

A class already has public Tag(String text). What additional constructor provides a distinct overload?
  1. public Tag(String text, int count)
  2. public Tag(String label)
  3. public Tag(String value)
  4. public Tag(String name)
Show answerHide answer

Save this lesson to see this answer.

Question 4 of 10

A rectangle has width 2.0 cm and height 5.0 cm. scale(k) multiplies both dimensions by k; area() returns their product. Run scale(2); double saved = area(); scale(0.5);. What are saved and the final area()?
  1. 20.0 and 10.0 square centimeters.
  2. 40.0 and 20.0 square centimeters.
  3. 40.0 and 10.0 square centimeters.
  4. 10.0 and 10.0 square centimeters.
Show answerHide answer

Save this lesson to see this answer.

Question 5 of 10

A fresh Dial class has instance field value and static field created, both initially 0. Each constructor increments created once; turn() increments only its receiver's value. Run Dial a = new Dial(); Dial b = a; b.turn(); b = new Dial(); b.turn(); b.turn();. What are a.value, b.value, and created?
  1. 1, 2, and 2.
  2. 2, 2, and 2.
  3. 1, 3, and 2.
  4. 1, 2, and 3.
Show answerHide answer

Save this lesson to see this answer.

Question 6 of 10

A getter should report a label stored in private String label;. What implementation supplies that value to its caller?
  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; }
Show answerHide answer

Save this lesson to see this answer.

Question 7 of 10

A level is clamped to 0–10 inclusive by setLevel. The constructor calls that setter, and raise() calls setLevel(this.level + 1). Starting with new Level(13), run raise(); setLevel(-2); raise(); raise();. What is the final level?
  1. 10
  2. 2
  3. 1
  4. 0
Show answerHide answer

Save this lesson to see this answer.

Question 8 of 10

Inside a clock description, what string does String.format(java.util.Locale.US, "%02d:%02d", 4, 7) return?
  1. "4:7"
  2. "40:70"
  3. "04:07"
  4. "04.07"
Show answerHide answer

Save this lesson to see this answer.

Question 9 of 10

A Seat must refuse a second reservation until canceled. A test currently checks only the first successful reserve() call. What next call best checks the refusal rule?
  1. Call reserve again without canceling.
  2. Cancel first, then call reserve again.
  3. Create another seat and reserve that one.
  4. Cancel the reservation without reserving again.
Show answerHide answer

Save this lesson to see this answer.

Question 10 of 10

A thermostat accepts targets from 6 °C through 28 °C inclusive. What pair of inputs tests the values just outside both boundaries?
  1. 6 °C and 28 °C.
  2. 5 °C and 29 °C.
  3. 7 °C and 27 °C.
  4. 17 °C and 18 °C.
Show answerHide answer

Save this lesson to see this answer.

Set 4: Diagnose designs and combine the rules10 Practice Questions

Save this lesson to see every answer and practice every set.

Question 1 of 10

A program handles several pumps. Each has a different identifier and current speed, and each can start or stop. How should a Pump class represent this?
  1. Static fields for identifier and speed; methods for start and stop.
  2. Instance fields for identifier and speed; methods for start and stop.
  3. Instance fields for start and stop; local identifiers inside each call.
  4. Local speed values in start and stop; one shared identifier constant.
Show answerHide answer

Save this lesson to see this answer.

Question 2 of 10

A Token has a numeric value and addOne() increases it. Run Token a = new Token(2); Token b = a; b.addOne(); Token c = new Token(7); a = c; a.addOne(); b.addOne();. What values do a, b, and c report?
  1. 4, 4, and 8.
  2. 8, 8, and 8.
  3. 8, 4, and 8.
  4. 8, 3, and 7.
Show answerHide answer

Save this lesson to see this answer.

Question 3 of 10

A tracker must retain a total between calls. Its add(int amount) currently declares int total = amount; inside the method. What storage change makes accumulation possible?
  1. Declare an instance total field and update it in add.
  2. Declare the same local total again in the getter.
  3. Declare amount as a local in the constructor only.
  4. Declare a final total local inside every add call.
Show answerHide answer

Save this lesson to see this answer.

Question 4 of 10

A Bucket declares private int capacity = 2; and an empty instance list items. Its constructor is Bucket(int capacity) { capacity = capacity; }. add returns false without adding when the list size is at least the stored capacity; otherwise it adds the item and returns true. snapshot() returns new ArrayList<>(this.items).

Run Bucket b = new Bucket(4); b.add("A"); ArrayList<String> view = b.snapshot(); view.add("B");. Then call b.add("C") and b.add("D"). What do these last two calls return, and how many items does b finally hold?

  1. true, true; 3 items.
  2. false, false; 2 items.
  3. true, false; 3 items.
  4. true, false; 2 items.
Show answerHide answer

Save this lesson to see this answer.

Question 5 of 10

A Route has final field code and static field created, initially 0. Its constructors are Route() { this("local"); created++; } and Route(String code) { this.code = code; created++; }. After one call to each constructor, created should count two objects. What correction gives the right count?
  1. Remove created++ from the String constructor.
  2. Replace this("local") with new Route("local").
  3. Keep both increments and make created an instance field.
  4. Remove created++ from the no-argument constructor.
Show answerHide answer

Save this lesson to see this answer.

Question 6 of 10

A timer starts at 22:59. advance() adds one minute with 24-hour rollover. getHour() reads the current hour. Run int h = getHour(); advance(); if (getHour() != h) { advance(); } advance();. What are h and the final time?
  1. 23 and 23:02.
  2. 22 and 23:01.
  3. 22 and 23:02.
  4. 23 and 23:01.
Show answerHide answer

Save this lesson to see this answer.

Question 7 of 10

A helper should be callable only by code inside its own top-level class. What access modifier fits?
  1. public
  2. private
  3. protected
  4. No modifier.
Show answerHide answer

Save this lesson to see this answer.

Question 8 of 10

A rectangle changes dimensions through scale. Its getter returns this.width * this.height, and there is no area field. Why is this a valid getter design?
  1. It returns current information without exposing storage.
  2. Every getter must return a field with its own exact name.
  3. The method creates an area field whenever it is called.
  4. The product becomes a constant after the first call.
Show answerHide answer

Save this lesson to see this answer.

Question 9 of 10

An Album has a limit of three captions. Its constructor rejects more than three captions and stores new ArrayList<>(captions). getCaptions() returns another copy; addCaption rejects additions at the limit. A caller supplies two captions, adds a third to the original list, adds a caption to a getter result, then calls addCaption once. How many captions does the Album hold?
  1. 2
  2. 4
  3. 5
  4. 3
Show answerHide answer

Save this lesson to see this answer.

Question 10 of 10

A Door must refuse open() when locked. A fresh door starts closed and unlocked. lock() succeeds only while closed; unlock() removes the lock. What test sequence checks refusal while locked and then a successful open after unlocking?
  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.
Show answerHide answer

Save this lesson to see this answer.

Stuck on your own question? Homework Help

Key Terms

59 Key Terms, each with its definition

A

Access modifier
An access modifier is a Java keyword such as private, protected, or public that controls access to a declaration.
The private access modifier keeps a helper available inside its class without exposing it to other classes.
Action method
An action method names a meaningful operation the object can perform, often controlling a change more precisely than a raw setter.
The lend() action method checks current loan status, rejects a repeat loan, and reports whether lending succeeded.
Argument
An argument is a value supplied at a method or constructor call, matched to a parameter by its position and compatible type.
In new Clock(9, 5), the arguments 9 and 5 supply the hour and minute for the new clock.

B

Behavior
An object's behavior is the set of operations its methods provide to read, calculate from, or change its state.
A book offers the behaviors lend() and giveBack() so callers can manage its loan status.
Boundary test
A boundary test checks behavior at or near an allowed limit, where a condition changes whether an operation should succeed.
A boundary test of a target setter tries an allowed endpoint and a value just outside it to check the comparison.

C

Clamping
Clamping replaces a value outside an allowed range with the nearest endpoint while preserving values already inside the range.
With clamping to 5–30 °C, a request for 34 °C stores 30 °C, while a request for 18 °C stores 18 °C.
Class
A class defines a Java type by describing the data its objects hold and the methods that provide their behavior.
A Pet class keeps a name, species, and age together with operations such as celebrateBirthday().
Class design
Class design chooses the state, construction routes, operations, and rules that let a class represent one useful kind of thing.
Class design turns a library-book description into identifying fields, a loan flag, and operations that enforce loan rules.
Constant
A constant is a fixed value commonly provided by a static final field, often public and named in UPPER_SNAKE_CASE.
A MAX_CELSIUS constant supplies the same upper temperature limit to the class and to its callers.
Constructor
A constructor is a class-named declaration with no return type that initializes an object during object creation.
The Pet constructor copies the supplied name, species, and age into the new pet's fields.
Constructor chaining
Constructor chaining runs another constructor of the same class on the same object by using a this(...) call.
Constructor chaining lets a newborn pet use this(name, species, 0) to reuse setup with a default age.
Constructor overloading
Constructor overloading declares several constructors for one class using different parameter lists for different creation inputs.
Constructor overloading lets a clock accept hours and minutes or start at midnight with no arguments.

D

Default constructor
A default constructor is the no-argument constructor Java supplies when a class does not declare any constructors.
Adding a three-argument constructor removes the default constructor, so new Pet() needs an explicit overload.
Default value
A default value is the initial value Java assigns to a field without an explicit initializer, such as 0, false, or null.
A boolean field has the default value false; a local boolean must be assigned before it can be read.
Defensive copy
A defensive copy is a separate data object returned or stored to stop another part of the program from changing internal data directly.
A defensive copy made by new ArrayList<>(this.tracks) keeps outside list changes away from the internal list.
Dot notation
Dot notation names a member through a receiver, such as an object reference followed by a period and a method call.
Dot notation in luna.getAge() tells Java that the pet reached by luna should report its age.

E

Encapsulation
Encapsulation groups object state with the operations that control it and hides internal data behind a chosen interface.
Encapsulation in Pet pairs a private age field with checking methods that refuse invalid changes.
Expected result
An expected result is the return value, output, or state predicted from a requirement before a test is run.
The expected result of a second lend() on a borrowed book is false with an unchanged loan flag.

F

final field
A final field can be assigned only once, so it is useful for per-object data that should not be replaced after setup.
A book's title can be a final field assigned in its constructor, with no setter offered to callers.

G

Getter
A getter, or accessor, returns information about an object without changing it, often using a name that starts with get.
The getArea() getter can calculate width times height even when the class stores no separate area field.

I

IllegalArgumentException
An IllegalArgumentException is an exception a method or constructor can throw to reject an argument that breaks its input rules.
Throwing IllegalArgumentException for a negative capacity prevents construction from returning an invalid object.
Incremental development
Incremental development builds and checks one useful piece at a time, making errors easier to locate before more code is added.
With incremental development, check the constructor first, then add and test one operation at a time.
Information hiding
Information hiding keeps callers dependent on an object's available operations instead of on its internal storage details.
Information hiding lets a clock change its fields while keeping getHours() consistent for existing callers.
Initialization
Initialization gives a variable its first value; object initialization establishes the fields needed for a usable starting state.
List initialization in a playlist constructor uses new ArrayList<>() so entries can be added afterward.
Instance
An instance is an object created from a particular class; the term names the relationship between that object and its type.
A pet named Luna and a pet named Max are two instances of Pet when each is created separately.
Instance method
An instance method is a non-static method that runs for a particular object and can use that object's instance fields.
scale is an instance method: a.scale(2) changes rectangle a while a separate rectangle stays unchanged.
Instance variable
An instance variable, also called an instance field, stores part of one object's state and lasts as long as that object.
Each pet's age instance variable keeps its own value even though the declaration appears only once in Pet.
Invariant
An invariant is a rule about state that must hold after construction and after every public operation on an object.
A thermostat's invariant keeps its target within the allowed range even when a caller requests 40 °C.

L

Lifetime
A variable's lifetime is the period during execution when its storage exists; an instance field lasts with its object.
A count field's lifetime extends between increment calls, while a temporary local exists only during its call.
Local variable
A local variable is declared in a block within a method or constructor and provides temporary storage for that execution.
The local variable total inside a calculation method holds temporary work that the object need not remember.

N

new
The Java keyword new begins an object-creation expression that runs a constructor and produces a reference to the object.
new Pet("Luna", "cat", 3) creates a pet and supplies three arguments for its starting state.
No-argument constructor
A no-argument constructor accepts no input values; it may be explicitly declared or supplied by Java as a default constructor.
An explicit no-argument constructor Clock() can delegate with this(0, 0) to start the clock at midnight.
null
The Java value null means a reference has no object to reach; class-type fields receive it unless initialized differently.
Calling add on a list field still set to null fails because no list object was created.

O

Object
An object is one instance of a class that exists while a program runs and has its own current instance-field values.
Two pet objects created with separate new expressions can have different ages while following one class definition.

P

Package access
Package access lets classes in the same package use a declaration and is selected by omitting an access modifier.
Package access on int count; lets another class in the same unnamed package read or change the field.
Parameter
A parameter is a named input declared in a method or constructor header that receives an argument for each call.
The parameter age in a pet constructor receives 3 when the call supplies 3 in that position.
private
The modifier private restricts member access to code inside its class, keeping separate top-level callers behind the public interface.
A private age field makes pet.age = -1; fail in a separate Main class, requiring a controlled method call.
protected
The modifier protected permits same-package access and restricted access from subclass code outside that package.
A protected helper can be called by another class in its package even when that class is not a subclass.
public
The modifier public allows access to a member wherever the declaring type is accessible, so callers can use the exposed operation.
A public lend() method lets Main request a loan while the book's private status field stays hidden.
Public interface
A class's public interface is the set of public operations and values available to callers that can access the class.
A book's public interface can offer lend(), giveBack(), and isLentOut() while its loan flag stays private.

R

Read-only property
A read-only property is information exposed for callers to read without providing them an operation that directly replaces it.
A fixed title is a read-only property when callers have getTitle() but no operation to replace the title.
Receiver
The receiver is the object on which an instance method is invoked, identified by the expression before the dot in a call.
In book.lend(), the receiver is the book reached by book, whose loan flag the method checks.
Recursive constructor invocation
A recursive constructor invocation is an illegal constructor chain that eventually calls a constructor already in that chain.
Java reports recursive constructor invocation when Box() and Box(int) delegate back to each other.
Reference
A reference is a value that identifies an object, allowing a variable or expression to reach that object when needed.
After Pet other = luna;, the two variables hold references to the same pet, so either can reach it.
Return value
A return value is the result a method sends back to its caller, where it can be stored, printed, or used in an expression.
The return value from r.area() can be doubled in an expression; printing the area alone supplies no value.

S

Scope
The scope of a variable is the region of program text where its name can be used to refer to that variable.
The scope of a local declared inside an if block ends at that block, so later code cannot use its name.
Setter
A setter, or mutator, accepts a new value for part of an object's state and can check that input before storing it.
The setAge(int age) setter can ignore negative inputs so the stored age stays in its allowed range.
Shadowing
Shadowing occurs when a nearer declaration, such as a parameter, hides a field's simple name in part of the code.
Parameter shadowing makes this.age = age; useful: the left side is the field, and the right side is the input.
State
An object's state is the current set of values stored in its instance fields, such as a clock's hour and minute.
After a clock advances from 08:59, its state holds hour 9 and minute 0, ready for the next call.
State trace
A state trace records field values after each statement to show how a sequence of operations changes particular objects.
A state trace with columns for two pets shows that a birthday on the first leaves the second pet unchanged.
Static context
A static context is code with no current instance, such as a static method body, where bare instance-member access is unavailable.
In a static context, a bare age field has no current pet; pet.getAge() instead supplies a particular object.
Static field
A static field is one class-wide variable shared by all instances, so its value does not belong to one particular object.
A static field named created can rise each time the constructor sets up a new instance of the class.
Static method
A static method belongs to a class and has no current object; it needs an object reference to use instance members.
A static method such as main can create Counter c and then call c.increment() through that reference.
String.format
The method String.format builds text from a format string and values, supporting fixed widths and decimal places.
String.format with java.util.Locale.US and "%.2f" formats 7.5 as "7.50" despite the default locale.

T

this
The keyword this refers to the current object inside instance code, distinguishing its fields from same-named parameters.
Inside a pet's setter, this.name = name; writes the new input into that particular pet's field.
toString
The method toString() returns an object's text representation, allowing printing and string concatenation to show readable details.
A clock's toString returns "09:05", so printing the clock shows a useful time instead of class-and-hash text.

V

Validation
Validation checks an input or proposed change against the class's rules before accepting it as part of object state.
Shared validation in a constructor and setter prevents either route from storing an invalid state.
void
The return type void declares that a method supplies no return value, even when the method changes state or prints output.
A birthday method can return void because its job is to increase the stored age of its receiver.

#

@Override
The annotation @Override asks the compiler to verify that a method declaration replaces a method already provided by a supertype.
@Override above tostring() reveals its capitalization error instead of leaving automatic printing unchanged.

About this lesson

By StudeliReport a mistake

Make your own Study Materials

Turn your notes, slides and documents into Study Guides, Practice Questions, Flashcards and 6 more tools.

Get Started