10: Coding Classes and Objects

What We Will Cover


Continuations

Homework Questions?

  • Nothing

Questions from last class?

What type of stream must be used to send data from a program to a file?

  1. input stream
  2. output stream
  3. character stream
  4. binary stream

10.1: Introduction to Object-Oriented Programming

Objectives

At the end of the lesson the student will be able to:

  • Describe the concept of encapsulation and data hiding
  • Describe the relationship between a class and an object
  • Code instance variables, constructors, and instance methods
  • Create objects from classes

10.1.1: About Object-Oriented Programming

Procedural and Object-Oriented Programming

  • There are two major approaches to programming:
    • Procedural programming
    • Object-oriented programming (OOP)
  • So far, we have mostly used procedural programming
  • Procedural programming is about how to use methods to solve problems
  • Work is organized into modules using methods (see lesson 6.3.1)
  • Procedural programming requires you to pass data via method parameters
  • Passing data becomes a problem as programs become more complex
  • Almost always specifications for a program change over time
  • Specification changes often require the data passed around to change
  • Changing the data requires many of the procedures to change
  • This causes lots of added work for the programmer
    • Which causes lot of added bugs

Classes and Encapsulation

  • OOP takes a different approach to handling data
  • It combines both data and procedures into objects
  • An object is a software entity that contains data and procedures
    • Data are stored in variables
    • Procedures are methods that operate on the data
  • To protect data, OOP uses encapsulation and data hiding
  • Encapsulation: inclusion of a number of items into a single unit

    Data hiding: restricting other program code from accessing data stored in a class

  • When data is hidden, access is performed through methods
    • Publicly available methods are known as an object's interface
  • Controlling access through methods helps prevent accidental data corruption
  • Access methods check a new value before assigning it to a variable
  • In addition, changing the way data is stored, the variable's type, is easy
    • You only need to change the access methods
  • Other program code calling the methods do not need to change

Object Reusability

  • Encapsulation used by OOP provides another benefit: reusability
  • Objects are not standalone programs
  • Rather, they are used by programs that need their services
  • This allows one programmer to develop an object to perform one task
    • Such as displaying a graphical image
  • Another programmer can use the object in his or her program
    • Such as a Web browser

10.1.2: Defining Classes for Objects

  • Before an object can be created, it must be designed by a programmer
  • The programmer defines the fields and methods and writes a class
  • Think of a class as a "blueprint" for creating objects
  • Thus, a class is not an object, but a description of an object
  • Programs use a class to create, in memory, as many objects of a specific type as needed
  • Each object created from a class is called an instance of the class

For Example

  • The following is the code for a class named Product
  • Classes contain three general sections:
    • Instance variables
    • Constructors
    • Instance methods
public class Product {
    // Instance variables
    private String name;
    private double price;

    // Constructors
    public Product() {
        name = "Unknown";
        price = 0.0;
    }

    public Product(String newName, double newPrice) {
        setName(newName);
        setPrice(newPrice);
    }

    // Instance methods
    public String getName() { return name; }
    public double getPrice() { return price; }

    public void setName(String newName) {
        if (newName == null || newName.length() == 0) {
            name = "Unknown";
        } else {
            name = newName;
        }
    }

    public void setPrice(double newPrice) {
        if (newPrice > 0.0) {
            price = newPrice;
        } else {
            price = 0.0;
        }
    }

    // For testing
    public static void main(String[] args) {
        Product prod = new Product("Milk", 3.95);
        System.out.println(prod.getName());
    }
}

Access Modifiers and Data Hiding

  • Note the keywords private and public
  • Referred to as access modifiers or visibility modifiers
    • private: can only be accessed by member methods of this class
    • public: can be accessed by member methods of any class
  • Setting private accessibility for all data is a good design practice
  • Protects data by controlling access only through the public methods
  • Allows us to change how data may be stored at some future time
    • Without affecting code outside the class

Programming Style: Class Naming Conventions

  • Use nouns to name classes -- they represent objects
  • Start class names with a capital letter
  • Capital letter differentiates classes from methods and variables

10.1.3: Coding Instance Variables

  • We now look at each section in more detail
  • Instance variables store the attributes (data) of an object
  • Each object has its own copy of these variables
  • Syntax for declaring instance variables:
  • [accessModifier] type variableName
  • For now, use the private access modifier for all instance variables
  • The type can be any primitive type or class name
  • Instance variables work just like variables you have used previously
  • Only difference is they are declared outside of any method body

Examples

    private String title;
    private double price;
    private Product myProduct;
    

Default Values

  • The compiler will initialize all instance variables to default values as follows:
    • Integer (byte, short, int, long): 0
    • Floating-point (float, double): 0.0
    • Character (char): '\u0000'
    • Boolean: false
    • Objects: null
  • Programmer can explicitly declare an initial value for instance variables
  • For example:
  • private String code = "NONE";
    private String title = "";
    

10.1.4: Coding Constructors

  • Constructors are called whenever an object is created from a class
  • Its primary purpose is to initialize the instance variables
  • Syntax for declaring constructors:
  • [accessModifier] ClassName(parameter list) {
        // statements to initialize instance variables
        // other initializing statements as needed
    }
    
  • For now, use the public access modifier for all class constructors
    • Other objects call the constructor when creating new objects
  • Constructors must use the same name and capitalization as the class name
  • Constructors can have zero or more parameters, just like methods
  • Name of the constructor combined with the parameter list form its signature
  • Can have many constructors in a class, but each must have a different signature
    • Known as overloading

Example: Constructor with no Parameters

  • If you do not want to accept arguments for instance variables, code a constructor with no parameters:
  • public Product() {
        name = "Unknown";
        price = 0.0;
    }
    
  • Note that constructors with no parameters are called no-arg constructors

Example: Constructor with two Parameters

  • If you want to accept arguments for all instance variables, code a constructor with parameters for each variable:
  • public Product(String newName, double newPrice) {
        setName(newName);
        setPrice(newPrice);
    }
    

Example: Constructor with one Parameter

  • If you want to accept only some arguments, code a constructor appropriately:
  • public Product(String newName) {
        setName(newName);
        price = 0.0;
    }
    

Default Constructors

  • If the programmer does not define a constructor, then the compiler supplies an empty one like the following:
  • public Product() {}
  • However, if the programmer defines any constructor, the compiler does not
  • You should always define your own no-arg constructor

10.1.5: Coding Instance Methods

  • Instance methods define the operations that can occur on an object
  • Performing these operations is sometimes referred to as passing messages
  • Objects use methods to pass messages to each other
  • The syntax for declaring instance methods:
  • [accessModifier] returnType methodName(parameter list) {
        // statements of the method
    }
    
  • Most of the time, you should declare methods public
  • However, if you want to prevent other classes from using a method, declare it private
  • The name of the method combined with the parameter list form its signature
  • You can have many methods with the same name in a class
    • However, each must have a different signature

Method Naming Conventions

  • As mentioned before, use verbs for method names
    • Appropriate since they perform an action
  • Also start method names with a lower case letter
  • Not required, but is a convention that professional programmers follow

Set Methods

  • When variables are declared private, you may still need to modify them
  • Use public methods to allow modification of the data
  • Called set methods (a.k.a. mutator methods)
  • Use the name of the variable with the word set prepended
  • Such methods should verify the value is correct before setting it
  • For example:
  • public void setPrice(double newPrice) {
        if (newPrice > 0.0) {
            price = newPrice;
        } else {
            price = 0.0;
        }
    }
    

Get Methods

  • Also, you often need access to private variables
  • Use public methods to access the data
  • Called get methods (a.k.a. accessor methods)
  • Use the name of the variable with the word get prepended
  • For example:
  • public String getName() {
        return name;
    }
    

10.1.6: Creating Objects From Classes

  • After defining a class, we can create objects
  • Syntax for creating an instance of a class:
  • ClassName objectName;
    objectName = new ClassName(argumentList);
    
  • First statement declares the class type and name of the object
  • Second statement actually creates an instance of the object
    • Uses the new keyword to call the constructor for the object
  • You can complete the two steps in one statement:
  • ClassName objectName = new ClassName(argumentList);
    
  • In either case, you must call the constructor with the correct sequence and type of arguments
  • If the class has more than one constructor, the constructor matching the arguments is used

For Example

  • We can code a main method to create an instance of our class
  • When the new operator is used, memory space is allocated for the object variables
  • The call to the constructor function copies the argument values to the parameters
  • public static void main(String[] args) {
        Product prod = new Product("Milk", 3.95);
        System.out.println(prod.getName());
    }
    
  • When the constructor is called, memory is allocated for the class variables
  • // Instance variables
    private String name;
    private double price;
    
  • Next, the constructor starts executing
  • You can trace the program flow through the code of the class:
  • // Constructor
    public Product(String newName, double newPrice) {
        setName(newName);
        setPrice(newPrice);
    }
    
    // Instance methods
    public void setName(String newName) {
        if (newName == null || newName.length() == 0) {
            name = "Unknown";
        } else {
            name = newName;
        }
    }
    
    public void setPrice(double newPrice) {
        if (newPrice > 0.0) {
            price = newPrice;
        } else {
            price = 0.0;
        }
    }
    
  • Methods setName() and setPrice() are called with the appropriate arguments
  • Method setName() assigns the instance variable name the parameter newName
  • Method setPrice() assigns the instance variable price the parameter value of newPrice
  • One object, an instance of the class, has now been created and initialized
  • You can create as many objects as you need for your program
  • Once created, your program can access each object using its public methods:
  • System.out.println(prod.getName());

10.1.7: Summary

  • Procedural programming becomes cumbersome as specifications change
  • Changes to data may require many functions to change
  • Object-oriented programming (OOP) gets around this problem by combining data and procedures into objects
  • OOP then addresses the problem of data protection through encapsulation and data hiding
  • Encapsulation and data hiding allow you to change the inner workings of a class without affecting other classes.
  • Classes are like a template or blueprint for creating objects
  • Objects are constructed from these classes
  • When you define classes, you code three general sections:
    • Instance variables
    • Constructors
    • Instance methods
  • Instance variables store the data of an object
  • Constructors are called whenever an object is created from a class
  • Instance methods are the operations that can occur on the object
  • Access modifiers control access to variables, constructors and methods
    • private: can only be accessed by member methods of this class
    • public: can be accessed by member methods of any class
  • Use private for all variables and public for most methods
  • Use "set" methods to control setting of new values to private variables
  • Use "get" methods to return values of private variables
  • To create an instance of a class, you use the new operator:
  • Product prod = new Product("Milk", 3.95);
    

Exercise 10.1

  1. Start a text file named exercise10.txt.
  2. Prepare the exercise header as described in the HowTo on submitting exercises
  3. Label this exercise: Exercise 10.1
  4. Submit all exercises for this lesson in one file unless instructed otherwise
  5. Complete the following and record the answers to any questions in exercise10.txt.

Specifications

  1. Write a definition for a class named Rectangle that has instance variables length and width.
  2. Write a constructor that sets the length and width variables.
  3. Also code get and set methods for both of the variables.
  4. Q1: What should you name the four methods?

  5. Write a main method that instantiates one or more Rectangle objects.
  6. Submit your Rectangle.java file as part of this weeks exercises.

You can use the following code to get started:

public class Rectangle {
    // Put instance variables here

    // Put one or more constructors here

    // Put instance methods here

    public static void main(String[] args) {
        // place statements to instantiate objects here
    }
}

10.2: Using Objects in Programs

Objectives

At the end of the lesson the student will be able to:

  • Use the methods of objects to accomplish required tasks

10.2.1: Working With Objects

  • In OOP, only the simplest programs use a single object
  • More common is to have several objects work together in your program
  • Each object performs one specialized task
  • Often times, one of the tasks is to control the operation of the entire program
  • In this section we look at how use sets of objects to create a program
  • But first we discuss a few odds and ends about objects

Accessing Objects

  • Objects in Java are always accessed through a memory reference
    • Technically known as indirect addressing
  • You never deal with an object directly
  • Instead, you always deal with a variable that holds the address of the object
    • Often called the object name
  • For example, the reference variable in the diagram below is message

About null

  • Reference variables can be assigned a special value: null
  • Special value null means that the object does not refer to anything
  • By default, Java initializes reference variables to null

References, Pointers and Addresses

  • Some people say that Java does not have pointers
  • This is really just a matter of semantics
  • Why else do we get a NullPointerException?
  • What these people mean is that Java does not have pointer arithmetic
    • A source of many bugs in C++
  • In addition, Java automatically dereferences pointers as needed
    • Making it easier to use

10.2.2: Example Application

  • Following is the ProductApp class
  • Has a main method that starts an application
  • Creates Product objects as specified by the user
import javax.swing.JOptionPane;

public class ProductApp {
    public static void main(String args[]) {
        int choice = 0;
        String name, priceStr;
        while (choice == 0) {
            name = inputString("Enter a product name");
            priceStr = inputString(
                "Enter the price for a " + name);
            double price = Double.parseDouble(priceStr);
            Product prod = new Product(name, price);
            String message = "You entered:\n"
                + "   Name: " + prod.getName() + "\n"
                + "   Price: " + prod.getPrice() + "\n"
                + "Enter another product?";
            choice = JOptionPane.showConfirmDialog(
                null, message);
        } // end while
        System.exit(0);
    }

    public static String inputString(String message) {
        String input = JOptionPane.showInputDialog(
            message);
        if (input == null) {
            System.exit(0);
        }
        return input;
    }
}
  • Note the following code that instantiates (creates) the object
  • Product prod = new Product(name, price);
    
  • Also has code to use methods of a Product object
  • prod.getName()
    prod.getPrice()
    

10.2.3: Calling Object Methods

  • To call methods of an object, code the object name followed by a period, the method name and the arguments:
  • objectName.methodName(argumentList);
  • For example, to send no arguments and return a value:
  • String name = prod.getName();
  • Sending an argument and returning no value:
  • prod.setName(name);
  • When you send more than one argument, type a comma between each argument
  • Also, you can call a method as part of a statement:
  • String message = "You entered:\n"
        + "   Name: " + prod.getName() + "\n"
        + "   Price: " + prod.getPrice() + "\n"
        + "Enter another product?";
    
  • Method calls are completed before performing other operations

10.2.4: Tracing Code

  • Object-oriented code is more complex to trace
  • Many objects can be instantiated from each class
  • Any of these objects can have the same method called
  • However, the program still executes only one statement at a time
  • The secret to tracing the code is tracking which object is executing a method at any one time
  • When tracing object-oriented code, you need to track both the object and method
  • For example, to trace the flow of ProductApp:
  • ProductApp.main()
        ProductApp.inputString()
        JOptionPane.showInputDialog()
        Double.parseDouble()
        prod.Product()
            prod.setName()
            prod.setPrice()
        prod.getName()
        ...
    
  • Note that static method calls use the Class name
  • Non-static methods calls use the object name

10.2.5: Summary

  • OOP typically has many objects working together in one program
  • Each object performs one specialized task
  • Objects in Java are always accessed through a memory reference
    • A variable that holds the address of the object
  • The reference variable is often called the "object name"
  • When a reference variable does not refer to an object, you assign it the special value null
  • By default, Java sets the value of a reference variable to null when the object is instantiated
  • To call methods of an object, you use its reference variable:
  • prod.getName();
  • To trace the flow of an OOP program, you need to track both the:
    • object name
    • method name
    prod.setName()

Exercise 10.2

  1. Label this exercise: Exercise 10.2
  2. Complete the following and record the answers to any questions in exercise10.txt.

Specifications

  1. Finish tracing the ProductApp program by listing the object names and method calls in the order of their occurrence:
  2. objName.methodName()

    If an object is not instantiated, use the class name instead. For example, the first method few method calls are:

    ProductApp.main()
        ProductApp.inputString()
        JOptionPane.showInputDialog()
        Double.parseDouble()
        prod.Product()
            prod.setName()
            prod.setPrice()
        prod.getName()
        ...
    
  3. Record your sequential listing in your exercise10.txt file.
  4. In addition, record answers to the following questions:

Q1: In ProductApp, what is the number of the line that instantiates the Product object?

Q2: What keyword is missing when a method is an instance method?

10.3: More Class Features

Objectives

At the end of the lesson the student will be able to:

  • Chose appropriate access modifiers
  • Describe how to prevent "local shadowing"

10.3.1: More About Access Modifiers

Access Modifiers and Inheritance

  • You can use the keywords public, private and protected to control access to class instance variables and methods
  • Controls the access for only a particular definition (unlike C++)

Package Access: the Default

  • No access modifier: known as default accessibility
  • Only accessible to other classes in the same package (directory)
  • Less restrictive than private accessibility, but more restrictive than public access
  • class MyClass {
        double x;
        void foo() {}
    }
    

public Access: Interface Access

  • Least restrictive of all access modifiers
  • public fields and methods can be accessed from anywhere the class is visible
  • public class MyClass {
        public double x;
        public void foo() {}
    }
    

private Access: Don't Touch That!

  • Most restrictive of all access modifiers
  • private fields and methods cannot be accessed from outside of the class
  • Good design practice to make all variables private and to provide accessor methods where needed
  • Auxiliary ("helper") usually declared private as well
  • Cannot declare a class private -- how would you use it?
  • public class MyClass {
        private double x;
        private void foo() {}
    }
    

protected Access: Inheritance Access

  • Accessible in the package of this class and any subclass
  • More restrictive than public accessibility but less restrictive than default
  • public class MyClass {
        protected double x;
        protected void foo() {}
    }
    
  • We will review protected again when we discuss inheritance

10.3.2: Coding More Than One Class Per File

  • For most applications it makes sense to have one class per file
  • However, sometimes it makes sense to place closely-related classes in the same file
  • Often done when coding graphical user interfaces
  • Provides the advantage of having fewer files to keep track of
  • For example:
  • public class ClassName {
        // body of public class
    }
    
    class ClassName2 {
        // body of non-public class
    }
    
  • Note that only one of the files is public
  • Java only allows one public class per file
  • All others cannot be declared public
  • When you compile the one file, the compiler generates two class files
  • ClassName.class
    ClassName2.class
    
  • You can extend this technique to many classes per file

For Example

public class PassObject {
    public static void main(String[] args) {
        int a = 100;
        MyData d = new MyData(100);
        changeData(a, d);
        System.out.println("In main: a = " + a
            + ", data = " + d.getMyInt());
    }

    public static void changeData(int a, MyData data) {
        System.out.println("In changeData: a = " + a
            + ", data = " + data.getMyInt());
        a = 20;
        data.setMyInt(20);
    }
}

class MyData {
    private int myInt;

    public MyData(int anInt) {
        myInt = anInt;
    }

    public int getMyInt() {
        return myInt;
    }

    public void setMyInt(int newInt) {
        myInt = newInt;
    }
}

10.3.3: Local Variables and Shadowing

  • Local variables with same name as a class variable hide the class variable
  • Any use of the variable's name will refer to the method variable
  • This is the source of many an elusive bug
  • Thus, you should not use the same name for a local variable and a class variable
  • Remember that a parameter is like a local variable but initialized in a special way
  • Thus you should use a different name for a parameter and a class variable

CheckStyle to the Rescue!

  • One nice feature of CheckStyle is that it catches shadowed variables
  • Be sure to run CheckStyle and pay attention to the error messages

10.3.4: Garbage Collection

  • What happens to an object that is not longer used?
  • Garbage collection returns memory to system
  • An object is marked for garbage collection if there are no references to the object in the program
  • Java performs garbage collection automatically
  • You can manually choose to run the garbage collector as well
  • System.gc();
    

10.3.4: Summary

  • Access modifiers control access to variables, constructors and methods
    • private: can only be accessed by member methods of this class
    • public: can be accessed by member methods of any class
  • Use private for all variables and public for most methods
  • When two or more classes are closely related, it sometimes makes sense to store them in one file
  • Local variables with same name as a class variable hide the class variable
    • Known as "shadowing"
  • You should not use the same name for a local variable and a class variable

Exercise 10.3

  1. Label this exercise: Exercise 10.3
  2. Complete the following and record the answers to any questions in exercise10.txt.

Specifications

The following object has errors that prevent its correct operation:

/**
 * MyRectangle.java
 * Represents a rectangle.
 *
 * @author Ed Parrish
 * @version 1.0 11/09/04
 */
public class MyRectangle {
    public static final double LENGTH = 3.0;
    public static final double WIDTH = 5.0;
    private double length, width;

    /**
     * Initializes the variables of a MyRectangle object.
     *
     * @param length The length of the rectangle.
     * @param width The width of the rectangle.
     */
    public MyRectangle(double length, double width) {
        length = length;
        width = width;
    }

    /**
     * Returns a String representation of this object.
     *
     * @return A String representation of this object.
     */
    public String toString() {
        return "length: " + length + ", width: " + width;
    }

    /**
     * The main method used to test the class.
     *
     * @param args Not used.
     */
    public static void main(String[] args) {
        MyRectangle rec = new MyRectangle(LENGTH, WIDTH);
        System.out.println(rec.toString());
    }
}
  1. Correct the errors and submit your corrected code as part of this weeks exercises.
  2. Q1: What error messages are displayed by the compiler, if any, before you correct the errors?

    Q2: What error message is displayed by CheckStyle before you correct the errors?

    Q3: Which method contains the errors?

    Q4: What is the name of these type of errors?

Wrap Up

Home | WebCT | Announcements | Schedule | Expectations | Course info
Help | FAQ's | HowTo's | Links

Last Updated: November 04 2004 @16:03:09