Unit 3 notes · 9 topics, read straight through

Unit 3: Class Creation

Every topic in one read: the big idea, the notes, the Java examples and the exam traps. Practice comes after, on each topic's checkpoint.

3.1 Abstraction and Program Design

Big ideaName the data, name the processes, and hide everything else.

1. Abstraction: focus on the main idea

A program can have thousands of details. Abstraction reduces complexity by focusing on the main idea: it hides details that do not matter for the question at hand and brings together the details that are related and useful 3.1.A.1.

You already use abstraction every time you call a method from the Java library. You know what length and Math.sqrt do. You do not know, and do not need to know, how they do it.

String city = "Lisbon";
System.out.println(city.length());
System.out.println(Math.sqrt(49.0));

Output:

6
7.0

2. Data abstraction and attributes

Data abstraction separates the abstract properties of a data type from the concrete details of how it is represented 3.1.A.2. You give data a name, and you work with the name. A double named temperature is a single variable; you never think about the bits inside it. A class is a collection of data with one name: a Song object holds a title, an artist and a length, and you pass it around as one thing 3.1.A.2.

An attribute is a data abstraction declared in a class outside any method or constructor 3.1.A.3. There are two kinds:

Kind of attribute Declared as Belongs to
Instance variable private String title; Each object. Every Song has its own title. 3.1.A.3
Class variable private static int songCount; The class. All Song objects share one count. 3.1.A.3
public class Song
{
    // class variable: one copy shared by every Song
    private static int songCount = 0;

    // instance variables: each Song has its own copy
    private String title;
    private String artist;
    private int seconds;

    public Song(String songTitle, String songArtist, int length)
    {
        title = songTitle;
        artist = songArtist;
        seconds = length;
        songCount++;
    }

    public String getTitle()
    {
        return title;
    }

    public int getSeconds()
    {
        return seconds;
    }

    public static int getSongCount()
    {
        return songCount;
    }
}

Client code in another class:

Song a = new Song("Blue Sky", "The Waves", 215);
Song b = new Song("Night Run", "Mira K", 182);
System.out.println(a.getTitle() + " " + a.getSeconds());
System.out.println(b.getTitle() + " " + b.getSeconds());
System.out.println(Song.getSongCount());

Output:

Blue Sky 215
Night Run 182
2

Each object has its own title and seconds, but there is only one songCount, so it counts both songs. Topics 3.3, 3.4 and 3.7 go deeper into both kinds.

3. Procedural abstraction and method decomposition

Procedural abstraction gives a process a name, a method, so the method can be used by knowing what it does, not how it does it 3.1.A.4.

Through method decomposition, a programmer breaks a large behavior of a class into smaller behaviors and writes one method for each smaller behavior 3.1.A.4. A procedural abstraction can also pull out a shared feature into one method instead of writing the same code twice. This code reuse helps manage complexity 3.1.A.4.

In this class, totalCost is built from smaller methods, and both cost methods reuse one rounding method instead of repeating the rounding code.

public class RoadTrip
{
    private double kilometers;
    private double litersPer100Km;
    private double pricePerLiter;
    private double tolls;

    public RoadTrip(double km, double usage, double price, double tollCost)
    {
        kilometers = km;
        litersPer100Km = usage;
        pricePerLiter = price;
        tolls = tollCost;
    }

    public double fuelLiters()
    {
        return kilometers * litersPer100Km / 100;
    }

    public double fuelCost()
    {
        return roundToCents(fuelLiters() * pricePerLiter);
    }

    public double totalCost()
    {
        return roundToCents(fuelCost() + tolls);
    }

    // shared feature: written once, used by two methods
    private double roundToCents(double amount)
    {
        return (int) (amount * 100 + 0.5) / 100.0;
    }
}
RoadTrip trip = new RoadTrip(350, 6.5, 1.79, 12.40);
System.out.println(trip.fuelLiters());
System.out.println(trip.fuelCost());
System.out.println(trip.totalCost());

Output:

22.75
40.72
53.12

The person who calls totalCost does not need to know that it calls fuelCost, which calls fuelLiters and roundToCents. They only need to know it returns the total cost of the trip.

4. Parameters make a method general

Using parameters lets one method work for a whole range of input values, called arguments, so the same method can be reused again and again 3.1.A.5. Without a parameter you might write fiveDashes, tenDashes and threeStars. With parameters, one method does all of it.

public class TextTools
{
    public static String repeat(String piece, int times)
    {
        String result = "";
        for (int i = 0; i < times; i++)
        {
            result += piece;
        }
        return result;
    }
}
System.out.println("[" + TextTools.repeat("-", 10) + "]");
System.out.println("[" + TextTools.repeat("ab", 3) + "]");
System.out.println("[" + TextTools.repeat("*", 0) + "]");

Output:

[----------]
[ababab]
[]

5. Changing the inside without telling the users

Because callers only use the name and the job of a method, the programmer can change the internals of a method (to make it faster, more efficient or use less storage) without notifying the users of the method. This works only if the method signature and what the method does stay the same 3.1.A.6.

Version 1 adds the numbers one by one:

public class NumberHelper
{
    /** Returns 1 + 2 + ... + n. Precondition: n >= 0 */
    public static int sumUpTo(int n)
    {
        int sum = 0;
        for (int k = 1; k <= n; k++)
        {
            sum += k;
        }
        return sum;
    }
}
System.out.println(NumberHelper.sumUpTo(100));
System.out.println(NumberHelper.sumUpTo(4));

Output:

5050
10

Version 2 uses a formula. It is faster for large n, but the signature sumUpTo(int) and the result are the same:

public class NumberHelper
{
    /** Returns 1 + 2 + ... + n. Precondition: n >= 0 */
    public static int sumUpTo(int n)
    {
        return n * (n + 1) / 2;
    }
}

The client code does not change, and neither does its output:

System.out.println(NumberHelper.sumUpTo(100));
System.out.println(NumberHelper.sumUpTo(4));

Output:

5050
10

Watch out: renaming the method, changing its parameter types or making it return a double changes the signature or the behavior, so every caller would have to change.

6. Design the class before you code it

Before writing a class, take time to design it: list its attributes and its behaviors 3.1.A.7. The design can be written in natural language or drawn as a diagram 3.1.A.7.

Natural language design: “A parking garage knows how many spaces it has and how many cars are inside. A car can enter only if a space is free; the garage reports whether it got in. A car can leave. The garage can report how many spaces are free.”

Diagram design (a box with the class name, then attributes, then behaviors; - means private, + means public):

+-------------------------------+
| ParkingGarage                 |
+-------------------------------+
| - capacity : int              |
| - carsInside : int            |
+-------------------------------+
| + ParkingGarage(spaces : int) |
| + carEnters() : boolean       |
| + carLeaves() : void          |
| + freeSpaces() : int          |
+-------------------------------+

The nouns became attributes (instance variables) and the verbs became behaviors (methods). Now the code almost writes itself:

public class ParkingGarage
{
    private int capacity;
    private int carsInside;

    public ParkingGarage(int spaces)
    {
        capacity = spaces;
        carsInside = 0;
    }

    public boolean carEnters()
    {
        if (carsInside < capacity)
        {
            carsInside++;
            return true;
        }
        return false;
    }

    public void carLeaves()
    {
        if (carsInside > 0)
        {
            carsInside--;
        }
    }

    public int freeSpaces()
    {
        return capacity - carsInside;
    }
}
ParkingGarage garage = new ParkingGarage(2);
System.out.println(garage.carEnters());
System.out.println(garage.carEnters());
System.out.println(garage.carEnters());
garage.carLeaves();
System.out.println(garage.freeSpaces());

Output:

true
true
false
1

Watch out: on the AP® exam, free-response questions often describe a class in words. Underline the nouns (attributes) and the verbs (behaviors) before you write any code.

Exam traps

  • An attribute is declared outside every method and constructor. A variable declared inside a method is a local variable, not an attribute.
  • Changing the method signature (name, parameter types or their order) is not an internal change: callers would break.
  • A method that returns the same result faster has the same behavior. A method that returns a different result has changed what it does.

Simulator and checkpoint for 3.1 →

3.2 Impact of Program Design

Big ideaGood program design includes thinking about who the program might fail, harm or copy from.

1. System reliability: test with many conditions

System reliability means the program can perform its tasks as expected under stated conditions without failure 3.2.A.1. Programmers should try to maximize reliability by testing the program with a variety of conditions 3.2.A.1.

Here is a method that turns a quiz score into a percent. It works on the first test, so it looks finished.

public class QuizScore
{
    public static int percent(int correct, int total)
    {
        return correct * 100 / total;
    }
}
System.out.println(QuizScore.percent(18, 20));
System.out.println(QuizScore.percent(0, 20));
System.out.println(QuizScore.percent(5, 0));

Output:

90
0
Exception in thread "main" java.lang.ArithmeticException: / by zero

The third test, a quiz with no questions yet, makes the program fail with a run-time error. A good test plan includes:

Kind of test Example input Why
Typical value 18 out of 20 The normal case works.
Boundary value 0 out of 20, 20 out of 20 The smallest and largest results are correct.
Unusual value 5 out of 0 The program does not crash on input it did not expect.

The improved version states its behavior for the unusual case, so it works as expected under all stated conditions:

public class QuizScore
{
    /** Returns the percent correct, or 0 when total is 0 */
    public static int percent(int correct, int total)
    {
        if (total == 0)
        {
            return 0;
        }
        return correct * 100 / total;
    }
}
System.out.println(QuizScore.percent(18, 20));
System.out.println(QuizScore.percent(20, 20));
System.out.println(QuizScore.percent(5, 0));

Output:

90
100
0

2. Programs have beneficial and harmful impacts

Creating a program has impacts on society, the economy and culture, and these impacts can be both beneficial and harmful 3.2.A.2. A program meant to fill a need or solve a problem can have unintended harmful effects beyond its intended use 3.2.A.2.

Program Beneficial impact Possible harmful impact
A route planner Drivers save time and fuel (economy). It sends heavy traffic through quiet streets next to a school (society).
A music recommendation app Listeners discover new artists (culture). It keeps showing the same popular songs, so small artists are heard less (culture, economy).
An online grade portal Students see their progress quickly (society). Students without home internet see it later than others (society).

The route planner problem can start with one design choice in the code. This method only looks at travel time:

public class RoutePlanner
{
    public static String choose(int mainRoadMinutes, int sideStreetMinutes)
    {
        if (sideStreetMinutes < mainRoadMinutes)
        {
            return "side street";
        }
        return "main road";
    }
}
System.out.println(RoutePlanner.choose(14, 12));

Output:

side street

Every user gets the same answer, so thousands of cars go down the side street. A more careful design adds a condition the designers care about, such as avoiding a school zone during school hours:

public class RoutePlanner
{
    public static String choose(int mainRoadMinutes, int sideStreetMinutes,
                                boolean schoolHours)
    {
        if (sideStreetMinutes < mainRoadMinutes && !schoolHours)
        {
            return "side street";
        }
        return "main road";
    }
}
System.out.println(RoutePlanner.choose(14, 12, true));
System.out.println(RoutePlanner.choose(14, 12, false));

Output:

main road
side street

Watch out: on the AP® exam, an “impact” answer should name who is affected and how. “It is bad for people” is too vague; “it increases traffic danger near a school” is specific.

Code is intellectual property: it belongs to the person or company that wrote it. Legal issues and intellectual property concerns arise when you create programs 3.2.A.3.

  • Programmers often reuse code written by others that is published as open source and free to use 3.2.A.3. Open source code comes with a license that says what you may do with it, for example that you must keep the author’s name and the license text.
  • To include code that is not published as open source, the programmer must obtain permission and often purchase the code before putting it in their program 3.2.A.3.

A good habit is to record where reused code came from, right in a comment:

public class TextUtils
{
    // The method below is adapted from an open source utility library.
    // It is free to use under that library's license, which asks us
    // to keep this notice and credit the original authors.
    public static String initials(String first, String last)
    {
        return first.substring(0, 1) + last.substring(0, 1);
    }
}
System.out.println(TextUtils.initials("Sam", "Rivera"));
System.out.println(TextUtils.initials("Lee", "Chen"));

Output:

SR
LC
Situation Can you use the code?
Open source library, free to use, you follow its license Yes 3.2.A.3
A company’s code you found in a leaked file No: it is not open source and you have no permission.
A paid library you have not bought or licensed Only after you obtain permission, which often means buying it 3.2.A.3

Exam traps

  • Reliability is about working as expected under the stated conditions, not about running fast.
  • An unintended harmful effect still counts as an impact of the program, even though the programmer did not plan it.
  • Code that is not open source cannot just be credited and used: the programmer must obtain permission and often purchase it.

Simulator and checkpoint for 3.2 →

3.3 Anatomy of a Class

Big ideaHide the data, show the behaviors.

1. The parts of a class

In this course, a class is always designated public and is declared with the keyword class 3.3.A.2. Inside, a typical class has three kinds of parts:

Part What it does Access in AP® code
Instance variables Store the attributes of each object private 3.3.A.5
Constructors Set the initial values when an object is created always public 3.3.A.3
Methods Define the behaviors of the object public, or private for helpers 3.3.A.6

Here is a complete class in the AP® free-response “class design” style. Read the comments: they label each part.

public class LibraryBook
{
    // ----- instance variables: private -----
    private String title;
    private int pages;
    private boolean checkedOut;

    // ----- constructor: public, no return type -----
    public LibraryBook(String bookTitle, int numPages)
    {
        title = bookTitle;
        pages = numPages;
        checkedOut = false;
    }

    // ----- accessor methods: public -----
    public String getTitle()
    {
        return title;
    }

    public boolean isCheckedOut()
    {
        return checkedOut;
    }

    // ----- mutator methods: public -----
    public void checkOut()
    {
        checkedOut = true;
    }

    public void returnBook()
    {
        checkedOut = false;
    }

    public void setPages(int numPages)
    {
        if (numPages > 0)
        {
            pages = numPages;
        }
    }

    /** Returns the number of days needed to read the book
     *  at pagesPerDay pages a day. Precondition: pagesPerDay > 0 */
    public int daysToRead(int pagesPerDay)
    {
        return divideRoundUp(pages, pagesPerDay);
    }

    // ----- helper method: private, used only inside the class -----
    private int divideRoundUp(int a, int b)
    {
        return (a + b - 1) / b;
    }

    // ----- toString: returns a String that describes the object -----
    public String toString()
    {
        return title + " (" + pages + " pages)";
    }
}

Client code in another class:

LibraryBook book = new LibraryBook("Ocean Tides", 250);
book.checkOut();
System.out.println(book.getTitle() + " out: " + book.isCheckedOut());
System.out.println(book.daysToRead(30));
System.out.println(book);

Output:

Ocean Tides out: true
9
Ocean Tides (250 pages)

Background: the last line works because println calls the object’s toString method. You will see toString in class code, but writing your own toString (overriding it) is outside the AP® exam, so the exam will not ask you to write one.

2. Encapsulation: public and private

Data encapsulation is a technique in which the implementation details of a class are kept hidden from external classes 3.3.A.1. Two keywords control access to classes, data, constructors and methods 3.3.A.1:

  • private restricts access to the declaring class (the class where it is written) 3.3.A.1.
  • public allows access from classes outside the declaring class 3.3.A.1.

The class above hides how it stores its data. A client cannot see that checkedOut is a boolean; it only sees the behaviors checkOut, returnBook and isCheckedOut. The class could later store the status another way without breaking any client.

3. Each object has its own instance variables

Instance variables belong to the object, and each object has its own copy of each variable 3.3.A.4.

LibraryBook a = new LibraryBook("Ocean Tides", 250);
LibraryBook b = new LibraryBook("Desert Stars", 120);
a.checkOut();
System.out.println(a.isCheckedOut() + " " + b.isCheckedOut());
System.out.println(a + " / " + b);

Output:

true false
Ocean Tides (250 pages) / Desert Stars (120 pages)

Memory after the code runs:

Variable Object it refers to: title pages checkedOut
a “Ocean Tides” 250 true
b “Desert Stars” 120 false

Calling a.checkOut() changed only the checkedOut that belongs to a.

4. Keep instance variables private

Access to attributes should be kept inside the class to accomplish encapsulation, so it is good practice to make instance variables private unless the class specification says otherwise 3.3.A.5. Then the only way to change pages is through setPages, which refuses bad values.

A client that tries to reach a private instance variable directly does not compile:

LibraryBook book = new LibraryBook("Ocean Tides", 250);
book.pages = -5;

Compiler says:

error: pages has private access in LibraryBook

The public mutator is the correct way in, and it protects the data:

LibraryBook book = new LibraryBook("Ocean Tides", 250);
book.setPages(-5);
System.out.println(book);
book.setPages(300);
System.out.println(book);

Output:

Ocean Tides (250 pages)
Ocean Tides (300 pages)

5. Public and private methods

Access to behaviors can be internal or external to the class 3.3.A.6. A public method can be called from inside the class or from other classes. A private method can only be called inside the class 3.3.A.6.

In LibraryBook, the public method daysToRead calls the private helper divideRoundUp. That is allowed because the call is inside the class. A client calling the helper does not compile:

LibraryBook book = new LibraryBook("Ocean Tides", 250);
System.out.println(book.divideRoundUp(250, 30));

Compiler says:

error: divideRoundUp(int,int) has private access in LibraryBook

Watch out: choose private for a method when it is a small step that only the class itself needs, and public when it is a behavior that the class specification promises to other classes.

Exam traps

  • A client that writes obj.title when title is private gets a compile error, not a run-time error.
  • Do not write private in front of a constructor or a class on the AP® exam: both are always public in this course.
  • A private method can be called inside the class (even by a public method of that class) but never from another class.

Simulator and checkpoint for 3.3 →

3.4 Constructors

Big ideaThe constructor's job is to give a brand new object a complete, valid starting state.

1. State: what an object has, right now

An object’s state is its attributes and their values at a given time. The state is defined by the instance variables that belong to the object 3.4.A.1. This is a has-a relationship: a player has a name, has a score and has a level 3.4.A.1.

public class Player
{
    private String name;
    private int score;
    private int level;

    /** Creates a player at level 1 with a score of 0 */
    public Player(String playerName)
    {
        name = playerName;
        score = 0;
        level = 1;
    }

    /** Creates a player at startLevel with a score of 0 */
    public Player(String playerName, int startLevel)
    {
        name = playerName;
        score = 0;
        level = startLevel;
    }

    public void addPoints(int points)
    {
        score += points;
        if (score >= 100)
        {
            level++;
            score -= 100;
        }
    }

    public String getName()
    {
        return name;
    }

    public int getScore()
    {
        return score;
    }

    public int getLevel()
    {
        return level;
    }

    public String toString()
    {
        return name + " L" + level + " " + score + " pts";
    }
}
Player ana = new Player("Ana");
System.out.println(ana);
ana.addPoints(70);
System.out.println(ana);
ana.addPoints(45);
System.out.println(ana);

Output:

Ana L1 0 pts
Ana L1 70 pts
Ana L2 15 pts

Background: println(ana) shows the text built by the class’s toString method. You will read toString in class code, but writing one is outside the AP® exam.

The state changes over time:

Moment name score level
After new Player("Ana") “Ana” 0 1
After addPoints(70) “Ana” 70 1
After addPoints(45) “Ana” 15 2

2. Writing a constructor

A constructor sets the initial state of an object, and that should include an initial value for every instance variable 3.4.A.2. Constructor parameters, if there are any, provide the data used to initialize the instance variables 3.4.A.2.

When a constructor is called with new, memory is allocated for the object and the reference to the new object is returned 3.4.A.2. The variable stores that reference, not the object itself.

Player p1 = new Player("Ana");
Player p2 = new Player("Ben", 5);
System.out.println(p1.getLevel() + " " + p2.getLevel());

Output:

1 5

Memory after these lines:

p1 [ ref ] ---> Player object:  name "Ana"   score 0   level 1
p2 [ ref ] ---> Player object:  name "Ben"   score 0   level 5

Player has two constructors with different parameter lists (overloaded constructors). Java chooses the one whose parameters match the arguments.

Watch out: a constructor has the same name as the class and no return type. If you write void, Java treats it as a method, not a constructor:

public class Pet
{
    private String name;

    public void Pet(String petName)
    {
        name = petName;
    }
}

Pet cat = new Pet("Miso");

Compiler says:

error: constructor Pet in class Pet cannot be applied to given types;

3. Mutable object parameters: store a copy

When a mutable object (an object whose state can change) is a constructor parameter, the instance variable should be initialized with a copy of the object. Then the instance variable does not hold a reference to the original object, and outside code cannot change the state of your object through the original 3.4.A.3.

Here is a mutable class:

public class Location
{
    private int row;
    private int col;

    public Location(int r, int c)
    {
        row = r;
        col = c;
    }

    public int getRow()
    {
        return row;
    }

    public int getCol()
    {
        return col;
    }

    public void moveTo(int r, int c)
    {
        row = r;
        col = c;
    }

    public String toString()
    {
        return "(" + row + ", " + col + ")";
    }
}

Version 1 (risky): the constructor stores the same reference.

public class Robot
{
    private Location home;

    public Robot(Location start)
    {
        home = start;
    }

    public String homeText()
    {
        return home.toString();
    }
}
Location spot = new Location(2, 3);
Robot bot = new Robot(spot);
spot.moveTo(9, 9);
System.out.println(bot.homeText());

Output:

(9, 9)
spot [ ref ] ---+
                +---> Location object: row 9, col 9
home [ ref ] ---+    (one object, two references)

Version 2 (correct): the constructor makes a new Location with the same values.

public class Robot
{
    private Location home;

    public Robot(Location start)
    {
        home = new Location(start.getRow(), start.getCol());
    }

    public String homeText()
    {
        return home.toString();
    }
}
Location spot = new Location(2, 3);
Robot bot = new Robot(spot);
spot.moveTo(9, 9);
System.out.println(bot.homeText());

Output:

(2, 3)
spot [ ref ] ---> Location object: row 9, col 9
home [ ref ] ---> Location object: row 2, col 3   (the robot's own copy)

String objects are immutable, so a constructor can store a String parameter directly: nobody can change that string.

4. The default constructor and default values

When no constructor is written, Java provides a no-parameter constructor, called the default constructor, and the instance variables are set to default values according to their data types 3.4.A.4.

Type of attribute Default value 3.4.A.5
int 0
double 0.0
boolean false
any reference type (such as String) null
public class Settings
{
    private int volume;
    private double brightness;
    private boolean muted;
    private String theme;

    // no constructor written: Java provides Settings()

    public String toString()
    {
        return volume + " " + brightness + " " + muted + " " + theme;
    }
}
Settings s = new Settings();
System.out.println(s);

Output:

0 0.0 false null

Watch out: once you write any constructor, Java no longer provides the default constructor. Player has two constructors, but neither has zero parameters:

Player p = new Player();

Compiler says:

error: no suitable constructor found for Player(no arguments)

Watch out: a constructor that does not set an instance variable leaves it at its default value. A forgotten String is null, and calling a method on it later (such as name.length()) causes a NullPointerException.

Exam traps

  • A constructor with void in front is not a constructor.
  • Writing any constructor removes the default constructor: new Player() then does not compile unless you wrote Player().
  • A String instance variable that the constructor forgets to set is null, not the empty string.
  • home = start stores the same object; later changes to start also change home.

Simulator and checkpoint for 3.4 →

3.5 Methods: How to Write Them

Big ideaA method's header is its promise: the return type says what comes back, the parameters say what goes in.

1. void and non-void methods

The method header tells you whether a method returns a value.

Kind Header Returns
void method public void refill() nothing; the keyword void comes before the method name 3.5.A.1
non-void method public int getAmount() a single value; the return type takes the place of void 3.5.A.2

Here is a complete class in the AP® free-response “class design” style. It is used in every section of this page.

public class WaterBottle
{
    private static int bottlesMade = 0;   // class variable

    private int capacity;   // in milliliters
    private int amount;     // in milliliters

    public WaterBottle(int maxMilliliters)
    {
        capacity = maxMilliliters;
        amount = maxMilliliters;
        bottlesMade++;
    }

    // ----- accessor methods (non-void) -----
    public int getAmount()
    {
        return amount;
    }

    public boolean isEmpty()
    {
        return amount == 0;
    }

    public double percentFull()
    {
        return 100.0 * amount / capacity;
    }

    public static int getBottlesMade()
    {
        return bottlesMade;
    }

    // ----- mutator methods (void) -----
    public void drink(int milliliters)
    {
        if (milliliters > amount)
        {
            amount = 0;
        }
        else
        {
            amount -= milliliters;
        }
    }

    public void refill()
    {
        amount = capacity;
    }

    public String toString()
    {
        return amount + "/" + capacity + " mL";
    }
}
WaterBottle bottle = new WaterBottle(750);
bottle.drink(300);
System.out.println(bottle.getAmount());
System.out.println(bottle.percentFull());
bottle.drink(500);
System.out.println(bottle.isEmpty() + " " + bottle);
bottle.refill();
System.out.println(bottle);

Output:

450
60.0
true 0/750 mL
750/750 mL

Background: toString lets println show the bottle as text. You will read toString methods in class code, but writing one is outside the AP® exam.

A call to a void method is a statement on its own (bottle.refill();). A call to a non-void method is an expression: its value is printed, stored or used in a calculation.

2. Return by value

In a non-void method, a return expression that is compatible with the return type is evaluated, and that value is returned to the caller. This is called return by value 3.5.A.3.

public class Average
{
    public static double mean(int a, int b)
    {
        return (a + b) / 2.0;
    }

    public static int meanRounded(int a, int b)
    {
        return (int) ((a + b) / 2.0 + 0.5);
    }
}
System.out.println(Average.mean(7, 8));
System.out.println(Average.meanRounded(7, 8));

Output:

7.5
8

A double expression is not compatible with an int return type, so this does not compile:

public class BadAverage
{
    public static int mean(int a, int b)
    {
        return (a + b) / 2.0;
    }
}

Compiler says:

error: incompatible types: possible lossy conversion from double to int

A non-void method must return a value on every path through the method:

public class Grader
{
    public static String letter(int score)
    {
        if (score >= 90)
        {
            return "A";
        }
    }
}

Compiler says:

error: missing return statement

3. return ends the method

The return keyword sends the flow of control back to the point where the method or constructor was called 3.5.A.4. Any code that comes after a return statement in sequence is never executed 3.5.A.4. A return statement inside a selection (if) or iteration (loop) statement stops that statement and exits the whole method or constructor 3.5.A.4.

This method searches a string and stops at the first digit it finds:

public class Finder
{
    /** Returns the index of the first digit in s, or -1 if none */
    public static int firstDigit(String s)
    {
        for (int i = 0; i < s.length(); i++)
        {
            String ch = s.substring(i, i + 1);
            if ("0123456789".indexOf(ch) >= 0)
            {
                return i;   // leaves the loop AND the method
            }
        }
        return -1;          // reached only if no digit was found
    }
}
System.out.println(Finder.firstDigit("Room 42B"));
System.out.println(Finder.firstDigit("Lobby"));

Output:

5
-1

A void method can use return; with no value to exit early:

public class Launch
{
    public static void countdown(int start)
    {
        for (int i = start; i >= 0; i--)
        {
            if (i == 2)
            {
                return;
            }
            System.out.println(i);
        }
        System.out.println("Liftoff!");
    }
}
Launch.countdown(5);

Output:

5
4
3

“Liftoff!” is never printed: the return ended the method, not only the loop.

Code placed directly after a return statement can never run, so the compiler rejects it:

public class Doubler
{
    public static int twice(int n)
    {
        return n * 2;
        System.out.println("done");
    }
}

Compiler says:

error: unreachable statement

4. Accessors and mutators

An accessor method lets objects of other classes obtain a copy of the value of an instance variable or a class variable. An accessor is a non-void method 3.5.A.5. In WaterBottle, getAmount returns a copy of amount, and the class method getBottlesMade returns a copy of the class variable bottlesMade.

A mutator method (also called a modifier method) changes the values of instance variables or class variables. A mutator is often a void method 3.5.A.6. In WaterBottle, drink and refill are mutators.

WaterBottle a = new WaterBottle(500);
WaterBottle b = new WaterBottle(1000);
int copy = a.getAmount();
copy = 0;
b.drink(250);
System.out.println(a.getAmount() + " " + b.getAmount());
System.out.println(WaterBottle.getBottlesMade());

Output:

500 750
2

Changing copy did not empty bottle a: the accessor handed out a copy of the value, not the instance variable itself.

Method Accessor or mutator? void?
getAmount() accessor no, returns int
isEmpty() accessor no, returns boolean
drink(int milliliters) mutator yes
refill() mutator yes

5. Parameters and primitive values

Methods with parameters receive values through them and use those values to do their task 3.5.A.7. When the argument is a primitive value (int, double, boolean), the parameter is initialized with a copy of that value. Changes to the parameter have no effect on the argument 3.5.A.8. Passing copies of argument values like this is called call by value (you met it with constructors in topic 1.13).

public class Bonus
{
    public static int addBonus(int points)
    {
        points = points + 10;
        return points;
    }
}
int myPoints = 50;
int result = Bonus.addBonus(myPoints);
System.out.println(myPoints + " " + result);

Output:

50 60

Memory, step by step:

Moment myPoints (in the caller) points (parameter) result
Before the call 50 does not exist does not exist
Start of addBonus 50 50 (a copy) does not exist
After points = points + 10 50 60 does not exist
After the call returns 50 gone 60

Watch out: if the method should change the caller’s variable, the caller must store the returned value: myPoints = Bonus.addBonus(myPoints);.

Exam traps

  • A non-void method must return a value on every path, or it does not compile (missing return statement).
  • Returning a double from an int method does not compile; returning an int from a double method is fine (widening).
  • A return inside a for loop stops the loop on the first match; the rest of the loop is skipped.
  • After void method calls, check whether the caller's variable was passed as a primitive: it never changes.

Simulator and checkpoint for 3.5 →

3.6 Methods: Passing and Returning References of an Object

Big ideaOne object, two arrows: whatever you do to the object through one arrow, the other arrow sees.

1. Passing an object: the reference is copied

Java passes arguments by value (the AP® term is call by value): the parameter is initialized with a copy of the value stored in the argument. For an object, the variable stores a reference, so the parameter gets a copy of that reference. It does not create a new, independent copy of the object 3.6.A.1. The parameter and the argument now refer to the same object. Two references to one object are called aliases.

If the object is mutable, the method can use its reference to change the object’s state 3.6.A.1.

This class is used on the whole page:

public class BankAccount
{
    private String owner;
    private int balance;

    public BankAccount(String name, int start)
    {
        owner = name;
        balance = start;
    }

    public String getOwner()
    {
        return owner;
    }

    public int getBalance()
    {
        return balance;
    }

    public void deposit(int amount)
    {
        balance += amount;
    }

    /** Returns true if this account has a larger balance than other */
    public boolean hasMoreThan(BankAccount other)
    {
        return balance > other.balance;
    }

    /** Moves amount from this account to other */
    public void transferTo(BankAccount other, int amount)
    {
        balance -= amount;
        other.balance += amount;
    }

    public String toString()
    {
        return owner + ": " + balance;
    }
}

A method in another class receives an account and adds 10 percent interest:

public class Bank
{
    public static void addInterest(BankAccount acct)
    {
        acct.deposit(acct.getBalance() / 10);
    }
}
BankAccount mine = new BankAccount("Rosa", 200);
Bank.addInterest(mine);
System.out.println(mine);

Output:

Rosa: 220

During the call, memory looks like this:

mine (caller)    [ ref ] ---+
                            +---> BankAccount object: owner "Rosa", balance 200 -> 220
acct (parameter) [ ref ] ---+

Only one BankAccount object exists (println shows it through its toString method; writing toString is background, not tested on the AP® exam). acct.deposit(...) changed it, and mine sees the change.

2. Reassigning the parameter does not change the caller

Because the reference was copied, giving the parameter a new object only changes the method’s copy. The caller’s variable still refers to the original object.

public class Bank
{
    public static void replace(BankAccount acct)
    {
        acct = new BankAccount("Temp", 0);
        acct.deposit(5);
    }
}
BankAccount mine = new BankAccount("Rosa", 200);
Bank.replace(mine);
System.out.println(mine);

Output:

Rosa: 200
mine (caller)    [ ref ] ---> BankAccount: owner "Rosa", balance 200   (untouched)
acct (parameter) [ ref ] ---> BankAccount: owner "Temp", balance 5     (gone after the call)
Inside the method Does the caller see a change?
acct.deposit(5); (call a mutator through the parameter) Yes: same object
acct = new BankAccount("Temp", 0); (reassign the parameter) No: only the copy of the reference moved

Watch out: a String parameter is a reference too, but String objects are immutable. No method can change the caller’s string; methods like substring return a new string instead.

3. Do not change parameters unless the specification says so

It is good programming practice not to modify mutable objects that are passed as parameters, unless the specification requires it 3.6.A.1. The caller does not expect a method that only “calculates” something to change their object.

This method counts how many monthly deposits it takes to reach a goal. The first version is wrong: it deposits into the caller’s real account while it counts.

public class Planner
{
    // BAD: changes the account it was given
    public static int monthsToGoal(BankAccount acct, int goal, int monthly)
    {
        int months = 0;
        while (acct.getBalance() < goal)
        {
            acct.deposit(monthly);
            months++;
        }
        return months;
    }
}
BankAccount savings = new BankAccount("Rosa", 100);
System.out.println(Planner.monthsToGoal(savings, 250, 50));
System.out.println(savings);

Output:

3
Rosa: 250

The good version copies the balance into a local int and leaves the object alone:

public class Planner
{
    // GOOD: reads the account but does not change it
    public static int monthsToGoal(BankAccount acct, int goal, int monthly)
    {
        int balance = acct.getBalance();
        int months = 0;
        while (balance < goal)
        {
            balance += monthly;
            months++;
        }
        return months;
    }
}
BankAccount savings = new BankAccount("Rosa", 100);
System.out.println(Planner.monthsToGoal(savings, 250, 50));
System.out.println(savings);

Output:

3
Rosa: 100

4. Returning a reference

When the return expression evaluates to an object reference, the reference is returned, not a reference to a new copy of the object 3.6.A.2. The caller then holds an alias to the object stored inside the class.

public class Club
{
    private String name;
    private BankAccount treasury;

    public Club(String clubName, int startMoney)
    {
        name = clubName;
        treasury = new BankAccount(clubName, startMoney);
    }

    /** Returns the club's own account (an alias) */
    public BankAccount getTreasury()
    {
        return treasury;
    }

    /** Returns a new account with the same values (a copy) */
    public BankAccount getTreasuryCopy()
    {
        return new BankAccount(treasury.getOwner(), treasury.getBalance());
    }

    public int funds()
    {
        return treasury.getBalance();
    }
}
Club chess = new Club("Chess", 500);
BankAccount a = chess.getTreasury();
a.deposit(100);
System.out.println(chess.funds());
BankAccount b = chess.getTreasuryCopy();
b.deposit(1000);
System.out.println(chess.funds());

Output:

600
600

a refers to the club’s real account, so the deposit through a changed the club. b refers to a new object, so the deposit through b did not.

5. Private access through a parameter of the same class

Methods cannot access the private data and private methods of a parameter that refers to an object, unless the parameter is the same type as the method’s enclosing class 3.6.A.3.

That is why hasMoreThan and transferTo in BankAccount can use other.balance directly: other is a BankAccount, and the code is inside BankAccount.

BankAccount x = new BankAccount("Rosa", 300);
BankAccount y = new BankAccount("Theo", 120);
x.transferTo(y, 50);
System.out.println(x + ", " + y);
System.out.println(x.hasMoreThan(y));

Output:

Rosa: 250, Theo: 170
true

The same expression in a different class does not compile:

public class Auditor
{
    public static boolean isNegative(BankAccount acct)
    {
        return acct.balance < 0;
    }
}

Compiler says:

error: balance has private access in BankAccount

The fix is to use the public accessor: return acct.getBalance() < 0;.

Watch out: transferTo changes its parameter other on purpose. That is fine because moving money into the other account is exactly what the method’s specification says it does 3.6.A.1.

Exam traps

  • A void method that calls a mutator on its object parameter does change the caller's object.
  • A method that sets its parameter to a new object does not change the caller's object.
  • Strings are immutable: a method can never change the caller's String, even though it receives a reference to it.
  • other.balance compiles inside the BankAccount class but not inside any other class.

Simulator and checkpoint for 3.6 →

3.7 Class Variables and Methods

Big ideaInstance data lives in each object; class data lives once, in the class.

1. Class variables: one shared copy

Class variables belong to the class, and all objects of the class share a single copy. They are marked with the keyword static before the variable type 3.7.B.1. Instance variables are the opposite: each object has its own copy.

This class is used on the whole page:

public class Ticket
{
    public static final int MAX_TICKETS = 100;   // class variable, final
    private static int nextNumber = 1;           // class variable

    private String event;                        // instance variable
    private int number;                          // instance variable

    public Ticket(String eventName)
    {
        event = eventName;
        number = nextNumber;
        nextNumber++;
    }

    public int getNumber()
    {
        return number;
    }

    public static int ticketsIssued()
    {
        return nextNumber - 1;
    }

    public static int ticketsLeft()
    {
        return MAX_TICKETS - ticketsIssued();
    }

    public static boolean isEarlier(Ticket a, Ticket b)
    {
        return a.number < b.number;
    }

    public String toString()
    {
        return event + " #" + number;
    }
}
Ticket t1 = new Ticket("Concert");
Ticket t2 = new Ticket("Concert");
Ticket t3 = new Ticket("Match");
System.out.println(t1 + ", " + t2 + ", " + t3);
System.out.println(Ticket.ticketsIssued());

Output:

Concert #1, Concert #2, Match #3
3

Memory after the code runs:

class Ticket:   MAX_TICKETS 100   nextNumber 4     (one copy, shared)

t1 [ ref ] ---> Ticket object: event "Concert"  number 1
t2 [ ref ] ---> Ticket object: event "Concert"  number 2
t3 [ ref ] ---> Ticket object: event "Match"    number 3

Printing a Ticket uses its toString method (background only: writing toString is outside the AP® exam). Every constructor call read and changed the same nextNumber. That is how each ticket gets a different number.

2. Using a public class variable from outside

A class variable that is public is accessed outside the class with the class name and the dot operator, because it is associated with the class, not with objects of the class 3.7.B.2. This is a new program, so no tickets exist before it runs:

System.out.println("Limit: " + Ticket.MAX_TICKETS);
Ticket t = new Ticket("Play");
System.out.println("Left: " + Ticket.ticketsLeft());

Output:

Limit: 100
Left: 99

You do not need any Ticket object to read Ticket.MAX_TICKETS. A private class variable such as nextNumber cannot be used from outside at all: other classes use the public class method ticketsIssued instead.

3. final: a value that cannot change

When a variable is declared final, its value cannot be modified 3.7.B.3. Constants are usually public static final, with a name in capital letters.

Ticket.MAX_TICKETS = 500;

Compiler says:

error: cannot assign a value to static final variable MAX_TICKETS

final works for local variables too:

final double TAX_RATE = 0.08;
double price = 50.0;
System.out.println(price + price * TAX_RATE);

Output:

54.0

4. What class methods can do

A class method (a static method) can access or change the values of class variables, and it can call other class methods 3.7.A.2.

In Ticket, the class method ticketsIssued reads the class variable nextNumber, and the class method ticketsLeft calls the class method ticketsIssued. A class method can also change a class variable:

public class Scoreboard
{
    private static int games = 0;
    private static int totalGoals = 0;

    public static void recordGame(int goals)
    {
        games++;
        totalGoals += goals;
    }

    public static double averageGoals()
    {
        return (double) totalGoals / games;
    }

    public static String report()
    {
        return games + " games, " + averageGoals() + " goals per game";
    }
}
Scoreboard.recordGame(3);
Scoreboard.recordGame(0);
Scoreboard.recordGame(2);
System.out.println(Scoreboard.report());

Output:

3 games, 1.6666666666666667 goals per game

5. What class methods cannot do (without an object)

Class methods cannot access or change instance variables, or call instance methods, unless an instance of the class is passed to them through a parameter 3.7.A.1. A class method is called on the class, so there is no “current object” whose instance variables it could use.

public class Seat
{
    private int row;

    public Seat(int r)
    {
        row = r;
    }

    public static boolean isFrontRow()
    {
        return row == 1;
    }
}

Compiler says:

error: non-static variable row cannot be referenced from a static context

The fix is to pass an object in. Ticket.isEarlier does exactly that: it receives two Ticket objects and uses their instance variables.

Ticket a = new Ticket("Concert");
Ticket b = new Ticket("Concert");
System.out.println(Ticket.isEarlier(a, b));
System.out.println(Ticket.isEarlier(b, a));

Output:

true
false

Calling an instance method from a class method without an object fails the same way:

public class Clock
{
    private int minutes;

    public int getMinutes()
    {
        return minutes;
    }

    public static int getHours()
    {
        return getMinutes() / 60;
    }
}

Compiler says:

error: non-static method getMinutes() cannot be referenced from a static context
Can use instance variables and instance methods? Can use class variables and class methods?
Instance method Yes Yes
Class method Only through an object parameter 3.7.A.1 Yes 3.7.A.2

Exam traps

  • Counting objects: a static counter incremented in the constructor counts every object ever created, across all variables.
  • Inside a static method, a bare instance variable name is a compile error: non-static variable cannot be referenced from a static context.
  • Assigning to a final variable after it is set does not compile.
  • Instance methods CAN use class variables; it is only class methods that cannot use instance variables.

Simulator and checkpoint for 3.7 →

3.8 Scope and Access

Big ideaEvery variable has a home block; outside that block, its name means nothing.

1. Local variables live inside their block

Local variables are variables declared in the header or body of a block of code. A block is code between { and }, such as a method body, a loop or an if. A local variable can only be accessed in the block where it is declared 3.8.A.1.

public class Rainfall
{
    public static int total(int days)
    {
        int sum = 0;
        for (int day = 1; day <= days; day++)
        {
            int rain = day * 2;
            sum += rain;
        }
        return sum;
    }
}
System.out.println(Rainfall.total(3));

Output:

12
Variable Declared in Can be used
days the method header (parameter) anywhere in total
sum the method body from its declaration to the end of total
day the for loop header only inside the loop
rain the loop body only inside the loop body

Using a loop variable after the loop does not compile:

int sum = 0;
for (int day = 1; day <= 3; day++)
{
    sum += day;
}
System.out.println(day);

Compiler says:

error: cannot find symbol

Watch out: if you need the value after the loop, declare the variable before the loop, in the outer block.

2. Parameters are local variables

Constructors and methods are blocks of code, so their parameters are local variables too 3.8.A.1. A parameter can only be used inside its own constructor or method 3.8.A.1.

public class Thermometer
{
    private double celsius;

    public void setCelsius(double degrees)
    {
        celsius = degrees;
    }

    public double getFahrenheit()
    {
        return degrees * 9 / 5 + 32;
    }
}

Compiler says:

error: cannot find symbol

degrees exists only inside setCelsius. The second method must use the instance variable celsius, which every method of the class can use.

Local variables, including parameters, cannot be declared public or private 3.8.A.1. Access modifiers are only for the members of a class: instance variables, constructors and methods.

public class Profile
{
    private int age;

    public void setAge(private int newAge)
    {
        age = newAge;
    }
}

Compiler says:

error: modifier private not allowed here

3. Instance variables vs local variables

Instance variable Local variable or parameter
Declared in the class, outside every method and constructor in a block, a method header or a constructor header
Can be used in every constructor and method of the class only inside its block, constructor or method 3.8.A.1
public/private yes (usually private) never 3.8.A.1
Lifetime as long as the object exists only while the block runs

4. Same name: the local variable wins

When a local variable or parameter has the same name as an instance variable, the name refers to the local variable, not the instance variable, inside that constructor or method 3.8.A.2. The instance variable is “shadowed”.

This constructor looks right but does nothing useful:

public class Student
{
    private String name;
    private int grade;

    public Student(String name, int grade)
    {
        name = name;     // parameter = parameter
        grade = grade;   // parameter = parameter
    }

    public String toString()
    {
        return name + " (grade " + grade + ")";
    }
}
Student s = new Student("Lina", 10);
System.out.println(s);

Output:

null (grade 0)

Both assignments copy a parameter into itself (println shows the object through its toString method, which is background: writing toString is outside the AP® exam). The instance variables keep their default values, null and 0. Two fixes:

  • Give the parameters different names: public Student(String studentName, int studentGrade) with name = studentName;.
  • Use the keyword this to name the instance variable: this.name = name; (see topic 3.9).
public class Student
{
    private String name;
    private int grade;

    public Student(String studentName, int studentGrade)
    {
        name = studentName;
        grade = studentGrade;
    }

    public String toString()
    {
        return name + " (grade " + grade + ")";
    }
}
Student s = new Student("Lina", 10);
System.out.println(s);

Output:

Lina (grade 10)

5. A new local variable hides the instance variable

The same rule catches students who add a type in front of an instance variable name inside a method. That declares a new local variable 3.8.A.2.

public class Gamer
{
    private int score;

    public Gamer(int start)
    {
        score = start;
    }

    public void reset()
    {
        int score = 0;   // new local variable, not the instance variable
    }

    public int getScore()
    {
        return score;
    }
}
Gamer g = new Gamer(75);
g.reset();
System.out.println(g.getScore());

Output:

75

The fix is to remove the type: score = 0; assigns to the instance variable.

Exam traps

  • name = name; compiles but does nothing useful: look for it in constructors and setters.
  • int score = 0; inside a method creates a new local variable; it does not reset the instance variable score.
  • A variable declared inside an if block cannot be used after the if.
  • The loop variable of a for loop cannot be printed after the loop.

Simulator and checkpoint for 3.8 →

3.9 this Keyword

Big ideathis is how an object refers to itself.

1. this: a reference to the current object

Inside an instance method or a constructor, the keyword this acts as a special variable that holds a reference to the current object: the object whose method or constructor is being called 3.9.A.1.

The most common use is in a constructor whose parameters have the same names as the instance variables. The parameter hides the instance variable (topic 3.8), and this. names the instance variable.

public class Runner
{
    private String name;
    private double kilometers;

    public Runner(String name, double kilometers)
    {
        this.name = name;               // instance variable = parameter
        this.kilometers = kilometers;
    }

    public void run(double kilometers)
    {
        this.kilometers += kilometers;  // add the parameter to the total
    }

    public String getName()
    {
        return name;
    }

    public double getKilometers()
    {
        return kilometers;
    }

    public String toString()
    {
        return name + " " + kilometers + " km";
    }
}
Runner r = new Runner("Ivy", 5.0);
r.run(3.5);
System.out.println(r);

Output:

Ivy 8.5 km

(println(r) uses the class’s toString method; writing toString is background, outside the AP® exam.) In the call r.run(3.5), the current object is the one r refers to, so inside run, this and r are references to the same object.

r    [ ref ] ---+
                +---> Runner object: name "Ivy", kilometers 8.5
this [ ref ] ---+    (inside run, during the call r.run(3.5))

2. Which object is this?

The same method can run for many objects. Each time, this refers to the object the method was called on 3.9.A.1. Comparing this with a parameter using == checks whether they are the same object.

public class Badge
{
    private String owner;

    public Badge(String owner)
    {
        this.owner = owner;
    }

    public String whoAmI()
    {
        return "I belong to " + this.owner;
    }

    public boolean isSameBadge(Badge other)
    {
        return this == other;
    }
}
Badge a = new Badge("Omar");
Badge b = new Badge("Jun");
Badge c = a;
System.out.println(a.whoAmI());
System.out.println(b.whoAmI());
System.out.println(a.isSameBadge(c) + " " + a.isSameBadge(b));

Output:

I belong to Omar
I belong to Jun
true false

In a.isSameBadge(c), this refers to the object a refers to, and other is a copy of the reference in c. Both point to the same object, so == is true.

Watch out: in whoAmI, writing owner or this.owner gives the same result, because no parameter or local variable is named owner. this. is required only when a local name hides the instance variable.

3. Passing this as an argument

The keyword this can be used to pass the current object as an argument in a method call 3.9.A.2. That lets another object store or use a reference to the current object.

public class Room
{
    private int number;
    private Guest occupant;

    public Room(int number)
    {
        this.number = number;
        occupant = null;
    }

    public void assign(Guest g)
    {
        occupant = g;
    }

    public String describe()
    {
        if (occupant == null)
        {
            return "Room " + number + ": empty";
        }
        return "Room " + number + ": " + occupant.getName();
    }
}

public class Guest
{
    private String name;

    public Guest(String name)
    {
        this.name = name;
    }

    public String getName()
    {
        return name;
    }

    public void checkInto(Room r)
    {
        r.assign(this);   // pass the current Guest object to the room
    }
}
Room r12 = new Room(12);
Room r14 = new Room(14);
Guest maya = new Guest("Maya");
maya.checkInto(r12);
System.out.println(r12.describe());
System.out.println(r14.describe());

Output:

Room 12: Maya
Room 14: empty

During maya.checkInto(r12), this refers to the Guest object that maya refers to. r.assign(this) passes that reference, so the room’s occupant and maya become aliases of one Guest object.

4. Class methods have no this

Class methods (static methods) are called on the class, not on an object, so they do not have a this reference 3.9.A.3.

public class Counter
{
    private int count;

    public static void resetAll()
    {
        this.count = 0;
    }
}

Compiler says:

error: non-static variable this cannot be referenced from a static context
Where the code is Is there a this?
Constructor Yes: the object being constructed 3.9.A.1
Instance method Yes: the object the method was called on 3.9.A.1
Class (static) method No 3.9.A.3

Exam traps

  • In obj.method(), this inside method refers to the same object as obj: they are aliases.
  • this.title = title; works; title = this.title; copies the instance variable into the parameter instead.
  • this in a static method is a compile error: non-static variable this cannot be referenced from a static context.

Simulator and checkpoint for 3.9 →

Notes done

Now check yourself

Close the notes and take each topic's checkpoint. Retrieval practice works better for memory than reading again.

Start with the 3.1 checkpoint →

Was this page helpful?

No names are ever shown, and every public comment is checked by us first. Please do not include personal details. To get a reply, email [email protected].

↑ Top

Enlarged view of the selected figure