AP Computer Science

Unit 4: Object-Oriented Programming: Basics

Topics covered in this unit

After completing this unit you will:

4.0. Overview

This unit covers develops the concept of "objects" and "object-oriented programming," and examines how one goes about implementing a class based on its programming interface. If you don't know what an object, a class, or a method is yet, you will very soon.

Let's get started.

  1. An Introduction to Objects
  2. Objects and Methods
  3. Abstraction; Object-Oriented Design
  4. Comments, Instance Variables, Implementing the Class, Testing

4.1. Overview - An Introduction to Objects

This is an important session. Today we're going to be looking at types and variables, the assignment operator, as well as describing what an object is and seeing how one goes about constructing an object.

4.1.1. Objects, Classes, and Methods

Object-oriented programming has to do with objects. But what does that mean?

Objects

Objects are specific "instances" of a class of things. Qualities or characteristics that describe the state of an object are called attributes. Objects can be interacted with by calling their methods.

In object-oriented programming, objects belong to a class. Some examples:

Class

A class is a general category of a thing—a data construct, or a representation of a real life thing—with specific individual objects, or instances, belonging to that class.

A class, as part of its definition, describes both the attributes (or fields) that describe an object of that class, and the methods that can be used to interact with objects of that class.

Definition: Attribute

An attribute is a value that describes the state of the object.

Example: A Person object might have an age variable that keeps track of the person's age. We say that age is an attribute or field of the Person class.

Definition: Method

A method is a sequence of instructions that interacts with an object's internal data.

Example: .celebrateBirthday() is a method of the Person class. Calling that method adds one to the object's age.

Other examples:

These objects, classes, and methods that we've seen here are kind of abstract, and we're not yet to the point where we could design and code them yet. We've discussed the abstract concept of a Person class, but that's not something that we can actually work with on the computer, at least not yet.

4.1.2. Overloaded Methods

Sometimes a class will be capable of doing two different things with two different methods, but the methods will have the same name. For example:

System.out.println(3.14);
System.out.println("Hey there.");

The println method is used to print a double type number in the first line, and the same method (actually a different method with the same name) is used to print a string in the second line. Although it may not be surprising to you that the println method would be able to do this, Java is very particular about what it will allow a method to do. Once you learn to write methods like this, you'll see that you actually have to write two methods: one to handle the String values and one to handle the double values. (And yes, a third to handle the int values.)

When the same println method can handle multiple situations—multiple types of parameters—we say that the method is overloaded.

4.2. Overview - Objects and Methods

In this session we'll be looking at how you construct objects and use accessor and mutator methods. In addition we'll be looking at implementing a test program, API documentation.

4.2.1. Constructing Objects

Sometimes, when you're writing a program, you'll need to write your own class that describes a type of object. Java doesn't have a Person, a Teacher, or a Student class already written, so if you wanted to work with data like that, you've have to write your own classes. We'll learn how to do that soon.

But Java does supply some classes that have already been defined for you, and you're free to use these in writing programs. The String class allows you to create String objects. The Scanner class allows you to create a Scanner in your program that you can use to accept input. The Rectangle class allows you to create virtual Rectangles that might be used in a program.

A partial description of the Rectangle class

So, let's create a Rectangle object. It's important to note at this point that these are all abstractions of objects. We're going to create a rectangle here, but it's not a real rectangle—it's not even a picture of a real rectangle. It's an abstract model of a rectangle, in coded form. That's still going to be enormously useful to us.

Let's construct an object of our own and see how to manipulate it to find out information. The Rectangle class has already been defined for us, and is available to us in a package called awt ("Abstract Windowing Toolkit").

 

How to Construct an Object

Here's how you construct an object in general.

<Class name> <identifier> = new <Class name>([explicit parameters]);

So what does that look like in a program? How would we, say, construct a Rectangle object that we can manipulate?

Program: AreaTester

Write an AreaTester program that constructs a Rectangle object and then computes and prints its area. Use the getWidth and getHeight methods. Also print the expected answer.

Here's the code to solve this problem.

/** 
  * AreaTester program for class
  * @author Richard White
  * @version 2013-09-09
*/

import java.awt.Rectangle;      // import the Rectangle class

public class AreaTester
{
    public static void main(String[] args)
    {
        Rectangle myRect = new Rectangle(10, 30, 50, 60);
        double theArea = myRect.getWidth() * myRect.getHeight();
        System.out.print("The area of the rectangle is: ");
        System.out.println(theArea);
        System.out.println("Expected answer: 3000");
    }   
}

Problem: PerimeterTester

Now, based on this program as an example, on paper, write PerimeterTester, a program that creates a Rectangle object and then calculates the perimeter of that rectangle.

4.2.2. The Public Interface of a class

Each object we construct (such as myRect above) belongs to a class, and the class defines the methods for the objects.

There are other methods defined for these classes, as you might expect. The methods that you can use with objects of any given class are collectively referred to as the public interface for the class.

Public Interface

The public interface for a class describes what public constructors and methods a programmer can use to interact with objects of that class.

You'll get lots of practice working with public interfaces in upcoming assignments.

4.2.3. Accessor Methods and Mutator Methods

We've already seen methods, which are defined for objects in a class. Methods can be loosely organized into two categories.

Accessor methods

Accessor methods provide access to the information in an object.

box.getWidth(), for example, returns the width of the Rectangle box.

Mutator methods

Mutator methods alter, or "mutate," the information in an object.

box.translate(x,y); for example, causes the Rectangle box to be relocated x pixels to the right and y pixels down on the screen.

All methods access information in an object, but some of them also change the object's state. If all a method does is access information, it's considered an accessor, but if it also causes a change in the object, it is considered a mutator.

Accessor or Mutator?

What about this statement? Is the Rectangle method .getWidth() an accessor method or a mutator method?

System.out.println(myRect.getWidth());

What about this statement? Is .length() an accessor method or a mutator method?

System.out.println("Hello!".length());

What about this statement? Is .translate(-2,4) an accessor method or a mutator method?

System.out.println(myRect.translate(-2,4);

Trick question! Is .toUpperCase() an accessor method or a mutator method?

System.out.println(riverName.toUpperCase());

4.2.4. The Java API

We're still working our way around to starting to write some serious programs, and something that will help you along that path is the Application Programming Interface (API) for the language.

Definition: API

An Application Programming Interface lists the classes and methods that are available to a programmer for a given language or library.

Just as the Public Interface for a class that you write will describe what methods a programmer can use in interacting with objects of that class, the API documents the thousands of classes and their methods that are available to you in the Java library.

One of the things that makes Java amazing is that a lot of people have been working on it for a very long time, and if you need a programming tool to help you solve a certain type of problem, the chances are very good that somebody else has already addressed that problem, and made their solution available.

Those solutions are available to you in the Java Application Programming Interface!

We won't be taking full advantage of the Java API, because we're actually trying to learn how to do computer science, and not just write applications in Java. Still, you'll want to keep the online version of the Java API handy.

Research the Rectangle class

Do an online search for the Java API for your version of Java and find the Rectangle class in there. What methods are available to you for interacting with Rectangle objects?

Steps:

  1. Launch a browser
  2. Search for keywords "Java 7 API"
  3. Load Oracle's official API page
  4. Press ctrl-f (command-f on Apple) to Find on the page the package you're looking for. (Rectangle? Ellipse? Random?)
  5. In the menu on the left side, click on the class you're interested in—hit ctrl-g/command-g to search for the next occurrence of the term if you don't immediately find what you're looking for—and read the documentation there in the main window

Up to this point we've written programs of our own that perform a series of calculations. And now that we know that some types of data can be represented as objects that are organized into classes, we can use classes that other people have written (like the Rectangle class) in our own programs.

The next thing that we'd really like to be able to do is to write our own classes.

4.3. Overview: Abstraction; Object-Oriented Design

We've been using classes that someone at some point wrote, including the Rectangle class for rectangles and the String class for sequences of characters.

As part of this course, ultimately, we're going to be designing and writing our own classes, which is one of the single most powerful things that you can do as a programmer. Designing classes requires a whole lot more experience than you currently have, but implementing a class—writing a class that someone else has designed and given us specifications for—we should be able to manage.

In this section we'll consider levels of abstraction, and how one goes about implementing the Public Interface of a class.

4.3.1. Object-Oriented concepts

A Black Box is a device for which the inner workings are hidden. We don't need to know how things work inside a black box—we just need to know how to use it. Think of a car: You don't need to know how a car works to be able to drive it. The Black Box is based on the idea of encapsulation: the hiding of unimportant details.

OOP Term: Encapsulation

Encapsulation in Object-Oriented Programming refers to the hiding of details that the user doesn't need to know in order to be able to use an object or feature.

Example: It isn't necessary for you to know how Google's search feature was programmed—you can just use it. The implementation details of that search feature are encapsulated.

Example: It isn't necessary for you to know how your car's four-stroke engine works. The details of that operation are encapsulated. The car's engine is a Black Box, whose details are effectively hidden from you.

Here, an engineer programs the "black box" on a MotoGP motorcycle which will help determine how the motorcycle's engine, throttle, braking, and steering work. The rider gives feedback to the engineers on how the motorcycle is "riding," but isn't aware of all the software details that control the bike.

Somewhat related to the Black Box idea is the concept of abstraction.

OOP Term: Abstraction

Abstraction allows us to model only the details of a process that are most important, interesting, or relevant to us. Other details of the model are ignored.

Example: An abstraction of a car may consist of considering only its velocity (speed and direction). We might consider its engine temperature or how many cylinders it has, or whether the windows are up or down, but if that's not important for our problem, we're going to ignore those aspects of the car. Our abstraction of the car will only include velocity.

Example: An abstraction of a rectangle might include its length and width, while ignoring its position in space and its color.

Example: An abstraction of a playing card might include the suit and the value of the card, while ignoring the color of the suit, the design on the back of the card, the manufacturer, the material the card is made of, etc.

4.3.2. Object-Oriented Design

Computer used to use only primitive data types: numbers, and maybe characters. As programs become increasingly complex, the need for more sophisticated data structures arose: "strings" of characters, "lists" of numbers, etc.

At this point in the history of computer science, one of the predominant paradigms for computer programming is object-oriented design and programming, in which "black boxes"—objects—--are designed, programmed, and used to solve complex problems.

Objects get designed and built by one person, and used by another.

  1. Example: Automotive
  2. Example: Programming

As a programmer, you may find yourself designing an object at one point, programming it at another, and then using the object itself a few moments later to write a program.

There are two challenges associated with these ideas. One, you have to be flexible, and look at the objects you're working with from different perspectives. And two, writing good programs and bad programs is equally easy to do. You have to work hard to write good programs, with well-designed projects.

4.3.3. The Public Interface of a Class (Reviewed)

The Public Interface

The public interface of a class describes the behaviors of that class: the methods that will allow programmers to interact with that class, the features that we're going to implement.

When we create a class to describe some object, some features of the real life object are essential and will become part of our abstraction of the class; other features of the real life object aren't significant, and we won't need to worry about those when we create our class.

Take a guess

What features are most important for, say, a BankAccount class?

Show/hide answer

Answers will vary depending on how detailed our class is, but all bank accounts should include information about deposits, withdrawals, and allow you to get the balance.

What features are perhaps distantly related to the bank, but not really important for the function of our BankAccount class?

Show/hide answer

The bank's logo design, branch locations, ATM construction, Human Resources hiring practices, etc.

When designing a class, you want to imagine how someone would carry out each operation interacting with that class.

4.3.4. Writing the Person class

Work with the instructor to implement the Person class.

It's often helpful to summarize the attributes and methods that you plan to implement for a class, using a diagram similar to the one here. We'll often use something like this to develop our classes before we start coding.

 

4.3.5. Writing the Counter class

A little tally counter is used to count how many people walk into a concert, exhibition, or amusement park. Let's write a Counter class that will model the behavior of a tally counter.

What will this counter need to keep track of?

How will we need to be able to interact with this counter?

 

4.3.6. Writing the BankAccount class

If we have a BankAccount class, we'd want to be able to make a deposit:

myChecking.deposit(5000);

We also want to get our money back out:

myChecking.withdraw(40);

And we'd want to be able to figure out how much money we have in our account:

System.out.println(myChecking.getBalance());

In each of these examples above, what class are we working with? What are the objects? Which are the accessor methods? Which are the mutator methods?

For each of the three methods that we've been given to design here, we need to write code that will define these methods.

Let's see how to do that.

4.3.7. Writing a Method

How to write a Method

When you write a method description, you have to provide a header that specifies some important information about the method, and a body that describes exactly what to do when that method is called.

Here's a comparison of the headers for the three methods that we're going to write, along with some comments.

4.3.8. Writing a Constructor

We're almost to the point where we can write a class, but there's one more thing that we need to be able to provide in addition to the methods. We need to write the code that will allow a BankAccount object to be constructed in the first place. Before we can move money around in a bank account we have to initiate the bank account. To do that, we're going to write a constructor that will make that happen.

You already know how to use a constructor to create a new object. To create a new Rectangle object, you'd write something like this:

Rectangle myRect = new Rectangle(20, 30, 100, 50);

For our BankAccount class we want to allow a programmer to write something like this:

BankAccount momsSavings = new BankAccount();

So how do we go about writing a constructor that will allow a programmer to create BankAccount objects?

How to write a constructor

A constructor definition includes a header for the constructor that has a public access type, no return type (not even void), and a name that is the same as the class. Parentheses enclose the type and name of any parameters, followed by curly braces enclosing any instructions that will be executed when the new object gets constructed. This typically includes initializing variables in the new object.

In our example, we could write the constructor for our BankAccount in a couple of different ways:

public BankAccount()
{

}

You can imagine that we might also want to construct a BankAccount that has some initial balance, in which case we would write something like this.

public BankAccount(double startingBalance)
{

}

4.3.9. The BankAccount class

At this point, we can create a skeleton version of our BankAccount class. It's missing a lot of pieces, but we're going to fill those in soon.

/**
 * BankAccount
 *
 * This class allows the user to manipulate a BankAccount object.
 *
 * @author Richard White
 * @version 2014-09-21
 */

public class BankAccount()
{

    // instance variables go here later
    
    

    // ******* Constructors *******
    
    public BankAccount()
    {
        // body goes here
    }
    
    public BankAccount(double balance)
    {
        // body goes here
    }
    
    // ******* Methods *******
    
    public void deposit(double amount)
    {
        // body goes here
    }
    
    public void withdraw(double amount)
    {
        // body goes here
    }
    
    public double getBalance()
    {
        // body goes here
    }

}

4.0. Overview - Comments, Instance Variables, Implementing the Class, Testing

Last time we used a given Public Interface to create the initial outline of a class description.

In this section, we'll fill in all the missing pieces: the Public Interface comments, instance fields, and constructors and methods. We'll also look at unit testing; examine different categories of variables, and learn about implicit and explicit parameters.

4.4.1. Commenting the Public Interface

Java has three ways of writing comments, and you need to be familiar with all three.

3 types of Comments in Java

Both the multiline comments and JavaDoc comments can occur over multiple lines. The important difference is that JavaDoc comments will be used both by us, the programmers, to help us write our code, and by the Java Development Kit (JDK) to create user documentation for our code.

How to write a JavaDoc comment

In the JavaDoc comments:

  1. Describe the method's purpose briefly (on a single line?)
  2. For each parameter, write @param <parameterName> and give a short explanation of the parameter's purpose. You can omit this line if there are no parameters.
  3. If the method returns a value, in the JavaDoc write @return and describe the value that is being returned. You can omit this line if there is no return value (ie. the method returns void).

There are really two purposes for these comments. You already know that comments are useful for other people who are trying to learn how to use the class that you've written.

Even more importantly for us, though, is the fact that writing your JavaDoc comments before you write your program makes program writing a LOT easier. Writing the JavaDoc comments before you code helps to ensure that you have a good idea of what the method is going to do. For much of what you write, if you've already written the JavaDoc, writing the actual method itself is almost trivial in comparison.

Let's add JavaDoc comments to our BankAccount class...

4.4.2. Instance Fields, aka Instance Variables

We're getting very close to finishing up our object. We've got the object itself more or less planned out, we've got an idea of the 4 methods that we have to write—one constructor method, two mutator methods, and one accessor method. We've even got documentation written for the class, which means we'll have less clean-up documenting to do at the end. Just two things left to do...

Most objects have data in them that needs to be stored, and the places that these data are stored are called instance fields, or instance variables. These are variables that are created when an instance of your class is created, and they're used to track information about your object.

For our BankAccount class, there's really only one thing that we need to keep track of for our account at this point: the balance!

An instance field is almost always a private location, as opposed to a public one, meaning that nobody outside of the object has direct access to this information. If people want to see if, they're going to have to access it via the accessor methods that we've written which allow them to have access. Keeping the value of this field private is part of the concept of encapsulation: the hiding of details that the user shouldn't have to worry about.

Here, there's only one thing that we really need to keep track of in our BankAccount: the balance. You declare the private instance field in the class like this, usually just before the constructor method:

private double balance;

4.4.3. Implementing our Constructors and Methods

Okay, so far we have given some thought to designing our class, and designed the public interface for our class by considering what methods we want our class to have.

We've also commented that public interface—written JavaDoc comments for our methods—that have described in some detail what those methods will do.

All that's left is to actually write the constructors and methods that make up our program. And at this point, that's easy.

In the code below, comments are indicated in normal weight text, while Java syntax is in bold.

/**
  * BankAccount.java
  * @author Richard White
  * @version 2013-04-12
  *   
  * A bank account has a balance can be changed by deposits
  * and withdrawals.
*/

public class BankAccount
{

    // declares the instance field here!
    
    

    /**
     * Constructor1: Constructs a bank account with a zero balance.
     */
    public BankAccount()
    {
    
        
    }

    /**
      * Constructor2: Constructs a bank account with a given balance.
      * Because there are two different constructors for this class,
      * we say that the constructor is "overloaded."
      * @param initialBalance the initial balance
      */
    public BankAccount(double initialBalance)
    {
        
    }

    /**
      * Deposits money into the bank account.
      * @param amount    the amount to be deposited
      */
    public void deposit(double amount)
    {
         
         
    }

    /**
     * Withdraw money from the bank account.
     * @param amount    the amount to be withdrawn
     */
    public void withdraw(double amount)
    {
         
         
    }

    /**
     * Return the balance in the account.
     * @return the current balance
     */
    public double getBalance()
    {
        
        
    }
}

And what does the completed class look like?

Show/hide code

In the listing below, the added Java statements are listed in bold.

/**
  * BankAccount.java
  * @author Richard White
  * @version 2013-04-12
  *   
  * A bank account has a balance can be changed by deposits
  * and withdrawals.
*/

public class BankAccount
{

    private double balance;  // declares the instance field!

    /**
     * Constructor1: Constructs a bank account with a zero balance.
     */
    public BankAccount()
    {
        balance = 0;
    }

    /**
      * Constructor2: Constructs a bank account with a given balance.
      * Because there are two different constructors for this class,
      * we say that the constructor is "overloaded."
      * @param initialBalance the initial balance
    */

    public BankAccount(double initialBalance)
    {
        balance = initialBalance;
    }

    /**
      *Deposits money into the bank account.
      * @param amount    the amount to be deposited
    */
    public void deposit(double amount)
    {
        double newBalance = balance + amount;
        balance = newBalance;
    }

    /**
        Withdraw money from the bank account.
        @param amount    the amount to be withdrawn
    */
    public void withdraw(double amount)
    {
        balance = balance - amount;
    }

    /**
        Return the balance in the account.
        @return the current balance
    */
    public double getBalance()
    {
        return balance;
    }
}

4.4.4. Testing the Class

Okay, we've written a class. Does it compile? Enter the code into BlueJ and make sure it compiles. If it doesn't compile, you'll need to go through and correct your syntax errors until it compiles without errors.

Does it run? It does not run, because what we've written isn't really a program—it's a class description, a template that will be used for creating BankAccount objects by a program that IS running.

So how do we know if our class works? We need to test it. We need to run it using another program that we'll write. That program will include a main program that does run, and we'll use that main program to create BankAccount objects and manipulate them, to see if they work as we intended.

You'll usually call our test program something like BankAccountTester or BankAccountRunner.

The Testing process

For our example, assume we've written the class BankAccount and we want to test it with a program BankAccountTester.

  1. Put the Class you've just written, BankAccount.java and the Tester program (BankAccountTester.java) in the same folder.
  2. Compile the Class you've written. Make sure that there are no compilation (syntax) errors.
    $ javac BankAccount.java
  3. Compile the Tester program. Make sure that there are no compilation (syntax) errors.
    $ javac BankAccountTester.java
  4. Run the Tester program.
    $ java BankAccountTester

The tester program will construct and manipulate the Class that you've written, and print out the results of using that class. If your Class passes all the tests, then that's a good sign that you might have done it correctly!

For today, I've already written a Tester program for your class. Here's what you should do.

Download the Tester and run it

To download the BankAccountTester.java and use it to test your class:

  1. Use the Terminal to navigate to the folder where you want to download the file, possibly your Desktop.
  2. Use scp to copy the file BankAccountTester.java from my Public folder on the server to your local computer.
    $ scp studentID@servername:/home/rwhite/Public/BankAccountTester.java .
  3. Move the Tester into your BlueJ project folder for this assignment; you can either click-drag the file into that directory, or use the command-line to mv it there.
  4. Double-click on the package.bluej file in your BlueJ project folder to launch this project in BlueJ. The Tester file will be recognized by BlueJ and automatically included on your BlueJ desktop.
  5. Right-click (PC) or Ctrl-click (Mac) on the Tester file and select Compile to compile the Tester.
  6. Right-click (PC) or Ctrl-click (Mac) on the Tester file again and select void main(String[] args) to run the program, and see what kind of results are produced.
  7. Diagnose errors as necessary to get your BankAccount class working correctly.