Table of ContentsThe Nature of a ProgramBasic Syntax

Objects Everywhere

Java is a purely object-oriented programming language, so nothing can exist in Java that isn't part of an object. With that in mind, I think the best way to start understanding Java is to understand the nature of an object.

Fully appreciating exactly what an object is can be quite a leap, but it's nevertheless fundamental to understanding object-oriented development and, in turn, Java programming. Don't rush through this. You really need to fully grasp the nature of an object before you move onit's fundamental to doing anything in Java.

So What Is an Object Anyway?

An object, like any program, is an abstract representation of something. When I talk about what an object is, all I'm really saying is what an object can represent abstractly. The great thing about objects is that unlike normal program code, object representations can be of both action and statean object encapsulates both in one self-contained little package. In programming terms, an action is your code and state is your data (or variables). So why is this cool? Consider a game-programming example, as depicted in Figure A.1.

Figure Figure A.1. An object encapsulates both state and actions. In this case, a ship is represented abstractly by the data of its position and the various actions available as program code.

graphic/apaicon01.gif


In a typical space shooter, you use objects to represent everythingthe player's space cruiser, the enemy ships, the meteorites ...everything.Each ofthese objects encapsulates all of the states and actions they need. For example, the ship object has state data to represent its position, direction, and velocity, along with actions to keep it moving in the right direction (in other words, code to adjust its position over time) or to make it explode if it is hit by weapons fire. The important point is that the ship object contains all of these in one unit.

This is one of the great things about object-oriented coding. When you code objects, you code in terms of the things you're trying to represent. Your code and data are inherently divided into the sections that best represent what you're trying to achieve. This makes object-oriented programming a natural process. You can think and code in terms of the abstracts that make up your game.

I want to take this a little further. If you want the ship object to fire, all you need to do is adjust your object to include a fire action, right? Here's a good question, though: What does it fire? It isn't a ship object; that's just silly (or pretty cool, depending on your point of view). What you need is another object to represent a missile.

Your new missile object is quite similar to a ship. They both have speed and direction, for instance, but missiles also have distinct characteristics (state and actions) that apply only to a missile object. I know this all sounds obvious (at least I hope it does), but the important lesson is how you've encapsulated the various functionalities into object boundariesmissiles are one type of object, and ships are another.

I hope you have a lot of questions at this point, even if they're just mental itches. Hopefully you'll get to the answers soon. In the meantime, take a look at how to create an object using Java.

Java Objects

In Java, you create an object using the class keyword. Here's an example of code for a basic ship:

class Ship
{
    int x;
    int y;
    int color;

    void move(int newX, int newY)
    {
        x = newX;
        y = newY;
    }

    void setColor(int newColor)
    {
        color = newColor;
    }
}

This class represents your ship data (in Java these are called the fields of a class) in the form of three integers. The class also represents the actions in the form of the two methods move and setColor.

Instantiation

In Java, each new class becomes a new type in the language. So you can use the Ship class as the type of a new variable you create. Think of this as something like being able to rewrite the language as you go. Here's how you create a new instance of the Ship class in memory:

Ship myShip = new Ship();

What you've done is instantiate an object. You can then call Ship class methods (actions) on the myShip instance. For example:

myShip.move(100, 100);

Notice how I'm using the Ship class as a template for creating new objects of that type. This is an important distinction: Ship is the abstract class of an object, and myShip is one of those objects in existence. You can create as many of these instances of the Ship class as you want, but there can only ever be one type known as Ship.Here's an example in which you create three different Ships:

Ship myShip = new Ship();
Ship mySecondShip = new Ship();
Ship myThirdShip = new Ship();

You can now call the move method on any of these three ships, and they will move independently. You have three quite distinct Ship class objects.

Methods

As you just learned, fields (data) and methods (actions) make up a class. Now take a look at how to add a method to a class.

To create a method (known in other languages as a procedure or function), you first need to define a method header. This definition must contain the return type, method name, and an optional list of parameters. For example, the following header declares a method named move that takes two integers, newX and newY, and returns a boolean (true or false).

boolean move(int newX, int newY)

You can now add the code for the method directly below the header in what's called the method body. Inside the body, you can access the parameters using the names supplied in the header and return a value using the return keyword. You must write all the code for the method body within enclosing braces. For example:

boolean move(int newX, int newY)
{
    // method body
    System.out.println("move called with " + newX + " and " + newY);
    return true;
}

You can optionally set the return type in the method header to type void.In that case, a return statement is not required in your method, although you can use a return statement without a value if you just want to exit the method. For example:

void stop()
{
    if (speed == 0)
        return;

    // this code is never executed if speed is equal to 0
    speed=0;
}

Fields

A field is a variable defined at the class level. It's just like any other variable in Java, but what makes it special is that it lives in the scope of the class. Therefore, every instance of a class has its own set of these fields, which remain independent of any other instance of that class.

To add a field to a class, you simply declare a variable outside of any method. The following example declares three fields for your Ship class.

class Ship
{
    int x;
    int y;
    int color;
}

I'll get into the details of declaring variables a little later; for now, I want to stay on the object track.

Constructors

A constructor is a special method you use when you want to create an object. It lets you initialize the object in different ways depending on your needs. Take another look at your Ship class, for example. Suppose you wanted to set a different position for each Ship object you create. Here's an example of using a constructor to do that:

class Ship
{
    int x;
    int y;
    int color;

    public Ship(int startingX, int startingY)
    {
        x = startingX;
        y = startingY;
    }
}

As you can see, a constructor is just a method with no return type. (The built-in return value is actually the newly instantiated object itself.) You can do anything you would in a normal method; in this case, I just set the position to match the parameter values. To use your shiny new constructor, you need to adjust the call used to instantiate the object.

Ship myShip = new Ship();
Ship mySecondShip = new Ship(100, 200);
Ship myThirdShip = new Ship(300, 400);

As you can see, both of your constructors are in use hereone to create a normal ship and the other to initialize ships at a certain position.

Wait a minute! Did I just say both constructors? I hope you're confused, because if you look back at your class, it's obvious there is only one constructor declared. Where did the other one come from? And come to think of it, how come you were able to construct an object in the previous examples without any constructor at all?

The answer is the default constructor. The compiler automatically generates this special method if you leave it out. It's exactly the same as a constructor with no argumentsit will initialize all fields to their default values. Therefore, you can go ahead and create your own default constructor if you want to. Here's an example where I override the default constructor with my own:

class Ship
{
    int x;
    int y;
    int color;

    // the default constructor
    public Ship()
    {
        x = 100;
        y = 200;

        // color is not initialized so it will default
        // to zero
    }

    // the position constructor
    public Ship(int startingX, int startingY)
    {
        x = startingX;
        y = startingY;
    }
}

You should also note that the compiler will cease to generate a default constructor as soon as you supply any constructor of your own. So, in fact, the code to construct a ship using the default constructor would not have compiled after you added the position constructor, at least until you added the default constructor back in yourself.

One final point before I move on. When you're using multiple constructors you might encounter a case in which you want to call a constructor from another. You can use the this method call to reuse the functionality. For example:

class text
{
    int i;
    int a;

    public text()
    {
        i = 1;
    }

    public text(int b)
    {
        this();          // sets up i for us
        a = b;
    }
}

Objects and Memory

When you instantiate an object, it lives on the Java memory heap. This is a big pool of memory that you don't really need to worry about (although running out of it is not a good thing). The point is that memory management in Java is far simpler than it is many other languages that I won't name here. (Witness a coughing sound unmistakably similar to "C.") You just create objects, and . . . well, that's about it. You just create them, and the JVM will take care of the rest. Specifically, there's no way to free up memory you've already used.

At this point, you might be wondering why you won't eventually run out of memory. If there is no way to free the memory you've previously used, how does the memory get cleared? The answer is JVM's garbage collector. This nifty little bugger periodically sweeps the heap looking for objects that are no longer referenced by anything, and then discards them (thus freeing the memory).

Sounds simple, doesn't it? Well it is, but there are still a few things worth explaining about how this process works. The most important thing I want to mention is the concept of references.

Figure Figure A.2. Java classes are instantiated onto the Java heap.

graphic/apaicon02.gif


A reference is a pointer (eeek!) to a Java object. Whenever you refer to a particular instance in your code, you're inherently maintaining a link to that object. As soon as you let go of that link, the object becomes unreferenced and is therefore a candidate for recycling by the big green garbage muncher. Take a look at an example because I know how confusing this can seem.

Ship myShip = new Ship();
myShip = null;

The first line creates a new Ship class object, allocated onto the heap. At this point the object has one reference to itthe variable myShip.Notice how the Ship class and myShip reference are different things. A reference is not the object; it's just a link to it. On the second line, I changed that reference to point to something elsein this case, nothing. At this point the reference count on the ship object is down to 0. The JVM keeps track of all these references so the next time the garbage collector periodically runs its process, it will know there are no longer any references to the Ship object and that it can go ahead and clear the memory.

Take a look at a slightly more complicated example:

Ship myShip = new Ship();
Ship yourShip = myShip;
myShip = null;

Any idea what's going to happen in this case? The important concept illustrated is the use of another reference to the same objectin this case, the yourShip object. I didn't construct anything; I just made yourShip refer to the same object. At this point the reference count on the object is 2. Even though I then set the original variable to null (thus reducing the reference count by 1), there is still a reference on the object so the garbage collector will pass it. If and when you set the final reference to null, the garbage collector will recycle it. Let's face it, if your code no longer has any reference to an object, then there's no point in keeping it around, is there?

While looking at references, you've also seen how objects really work in Java. To start with, you can only deal with objects through a reference, so there is no way to pass an object around by value, unlike in C++. Once you have the concept of a reference down, a lot of Java code becomes clear. Take a look at another example of object assignment and references.

Ship myShip;
myShip.move(100, 200);   // ERROR! Object not constructed.

In this case I've created a myShip reference to a class of type Ship,but it hasn't been initialized to anything. Thus the move method call will result in the computer exploding, likely taking most of the block with it in the process. Don't forget to take a hanky with you; my mum always told me you need a good hanky when you blow up the neighborhood. All right, so your computer won't explode (but imagining that it will certainly keeps the error rate down).

NOTE

Tip

Another thing you might have noticed in the previous examples is that you assigned objects by reference. This means there is no way to copy an object. For example:

Ship yourShip = myShip;

This code does not create a clone of the original Ship object; it just creates another reference to the same object. If you want to create a copy of the original object, you need to use the Clonable interface.

    Table of ContentsThe Nature of a ProgramBasic Syntax