Session 6: Using objects

What is an object? (Sections 3.1 and 3.2)
Some basic graphics classes (Sections 6.1 and 6.2)
    The DrawableFrame class
    The Graphics class
    The Color class
Putting it together
References (Section 3.7)

What is an object?

Textbook: Sections 3.1 and 3.2

The types we've seen so far - int, char, boolean, and double - are what Java calls primitive types. These are the simplest types - you might say they're the most primitive.

But programs tends to deal with more complicated things too. In our upcoming labs, we'll have programs that deal with all of the following.

We'll want to represent all these objects in our programs - and to do that, it's useful to have types so we can have variables representing the objects. Thus, Java has a whole other category of types: the object type.

The object type is called a class, and individual instances of the type are instances. For example, we might have a class named Ball for representing balls, and a program manipulating balls might want to manipulate two separate instances of this class. It could do this by declaring two variables of the Ball type.

Ball quaffle;
Ball snitch;

As you might expect, an object type is a conglomeration of data. For example, a ball bouncing around the screen has several properties: an x-coordinate, a y-coordinate, an angle of trajectory, and a speed. In this case, each piece of data would be a double, but there could be any combination. In any case, each individual ``fact'' about the object would be called an instance variable.

But, in fact, when we write programs using an object types, we'll almost never refer to instance variables directly. Instead, the class will define instance methods - basically, a method that manipulates the instance variables. Among the instance methods for the Ball class, for example, are the following.

int getTop()
Returns the y-coordinate of the ball's top.

int getLeft()
Returns the x-coordinate of the ball's left side.

void step()
Alters the ball's x- and y-coordinates according to its current trajectory.

void draw(Graphics g)
Draws the ball according to its current position on the canvas represented by g.

As with class methods, instance methods can take parameters. The last of these instance methods happens to take a Graphics object as a parameter - a class about which we'll learn more next.

Some basic graphics classes

Textbook: Sections 6.1 and 6.2

The csbsju.cs160 package defines several useful classes. Among them are three classes for graphics with which we'll become very familiar over the course of the semester.

The DrawableFrame class

Suppose, for example, we want to create a variable referring to a window.

DrawableFrame window;
This, however, only creates a variable that refers to a window. It doesn't actually create a window. To do that, we'll have to explicitly use the new keyword.
window = new DrawableFrame();
The new keyword generates a new instance of the class - in this case the class DrawableFrame. The parentheses are required; later, we'll see that you can pass parameters inside the parentheses to specify how to set up the new instance (similar to how you pass parameters to methods).

The DrawableFrame class defines several methods. One particularly useful method in DrawableFrame is its show() method, which displays the window on the screen. We'll always want to use this basically just after we create an instance.

window.show();

Note the syntax: When you want to call an instance method on a particular object instance, name the instance, followed by a period, followed by the instance method name, followed by parentheses (which in many cases will enclose arguments to be passed into the method).

As an another example, the getWidth() method of DrawableFrame returns an integer representing how many pixels the window is wide.

IO.println(window.getWidth());

The Graphics class

You can think of a Graphics object as being something like a paintbrush that you can use to draw onto a window.

The Graphics class is a little different from DrawableFrame in that we'll never actually create instances of Graphics objects directly - instead, we'll use the getGraphics() instance method in DrawableFrame, which returns an instance of the Graphics class.

Graphics g = window.getGraphics();

The Graphics class provides several useful instance methods. For example, one of them is fillOval, which draws an oval in the window. It takes four int parameters, representing respectively the x-coordinate of the oval's left side, the y-coordinate of the oval's top side, the oval's width, and the oval's height.

Note that, in numbering pixels, Java (like just about all other windowing programs) starts at the top left corner and goes downwards and to the left. Thus the oval drawn at (90,67) is above the oval drawn at (85,85), since its y-coordinate is smaller.

Consider the following complete program.

import csbsju.cs160.*;

public class SnowPerson {
    public static void run() {
        DrawableFrame window = new DrawableFrame();
        window.show();
            
        Graphics g = window.getGraphics();
        g.fillOval(90, 67, 20, 20);
        g.fillOval(85, 85, 30, 30);
        g.fillOval(75, 112, 50, 50);
    }
}
This creates the following window.

Graphics defines a host of instance methods. Now would be a good time to open up the csbsju.cs160 documentation, which gives an exhaustive list of the methods you can use on the various objects we'll be using for the first part of this semester. One of the skills you'll need to develop this semester is being able to use this documentation to determine how classes work based on the documentation. Being able to navigate this documentation is essential for using Java well.

The Color class

The final class we'll investigate is Color, which represents a color on the canvas. To create a Color object, you pass parameters into its constructor method, representing the red, green, and blue components of the color.

Color brown = new Color(0.6, 0.6, 0.0);
In fact, the Color class defines several constants (class variables) that already represent useful colors: Color.red, Color.green, etc.

The Color class doesn't really define any methods; the class exists primarily so that you can pass instances of it into the getGraphics() instance method of Graphics. Once you do this, the Graphics instance will use it whenever it draws anything to the screen in the future.

We might modify our earlier program to draw brown arms for our snow person.

        g.setColor(new Color(0.6, 0.6, 0.0));
        g.drawLine(100, 100, 140, 80);
        g.drawLine(100, 100, 60, 80);
        g.setColor(Color.black);
        g.fillOval(90, 67, 20, 20);
        g.fillOval(85, 85, 30, 30);
        g.fillOval(75, 112, 50, 50);

Putting it together

Here's a somewhat longer program that draws a gradual color switch, with a color scheme resembling a sunrise (dark blue to yellow).

It accomplishes this by drawing a series of horizontal lines of colors of various shades between the extremes.
import csbsju.cs160.*;

public class Sunrise {
    public static void run() {
        DrawableFrame window = new DrawableFrame();
        window.show();

        Graphics g = window.getGraphics();
        int y = 0;
        while(y < window.getHeight()) {
            // mix color for this row of window
            double yellow = 1.0 * y / window.getHeight();
            double blue = 0.4 - 0.4 * y / window.getHeight();
            Color color = new Color(yellow, yellow, blue);

            // draw this row
            g.setColor(color);
            g.drawLine(0, y, window.getWidth(), y);

            // move to next row
            y++;
        }
    }
}

References

Textbook: Section 3.7

There's an important detail about objects that makes objects very unlike the primitive types. In a primitive type, when you move a value, a copy of the value is placed in memory. So if the memory looks like this:

   a: 45    b: 23
And then I do ``a=b;,'' the memory would change to the following.
   a: 23    b: 23
Now, if I alter a again (maybe with ``a=5;''), the value of b is unchanged.
   a: 5     b: 23

Object's don't work that way: A variable holding an object only refers to a specific, individual object in the world. We would say that the variable points to the object. Say we execute the following.

Graphics blue_g = window.getGraphics();
Graphics green_g = blue_g;
Here, we've created a variable blue_g that refers to a specific Graphics object. In the next line, I made green_g also refer to that same object. They are both pointing to the same location in memory, where the graphics data is stored.

This distinction turns out to be very important. Suppose we do the following.

blue_g.setColor(Color.blue);
green_g.setColor(Color.green);
You may think this sets the colors so that I can use blue_g to draw blue things and green_g to draw green things. But in fact, since both are pointing to the same instance, both setColor methods are being called on the same instance. As a result, after both statements occur, that single instance is thinking that green is the current color. Say we now try to draw a circle using blue_g.
blue_g.fillOval(80, 80, 40, 40);
This would actually draw a green circle!

We say that an object variable is actually a reference to the actual object in memory. This distinction of objects as references is pervasive throughout Java. Object parameters are passed by reference, so that changes to a parameter object's fields within the method affect the object's fields outside the method.

In this case, the solution is simple: Don't make both blue_g and green_g refer to the same object. Instead, create two separate Graphics objects.

Graphics blue_g = window.getGraphics();
Graphics green_g = window.getGraphics();

There's a special reference that's worth noting, called the null object. You use this when you want to denote that a variable no longer refers to a valid object.

blue_j = null;
When a variable is null, then you can't use it - it's effectively pointing to nothing at all, so attempts to access it result in crashing your program. Setting a variable to null is useful as a placeholder when you want to remember that something doesn't exist; we'll see examples of its use later.