Chapter Five

Java Basics: Classes and Methods

Copyright (c) 1999 by Charlie Calvert

It's time to start digging into some of the details of the Java syntax. You will begin that process in this chapter, and continue it over the next three chapters. This chapter will also introduce you to working with Java applications rather than Java applets.

Overall, Java is an admirably clean and logical language. If you have some experience programming, it's easy to pick up most of the syntax of the language. However, there are few peculiarities in Java, and it is easy to be thrown by them if you don't know what to look for.

It happens that most of these peculiarities have to do with the way Java sets up the scope of the various regions of the code you write and the way that it allows you to package your code when you want to save it to file or share it with others. In short, you have to understand the role that classes, packages and jar files play in java or you won't be able to understand the structure of the programs you create.

The purpose of the next three chapters is to get these basic syntactical elements out of the way so that we can proceed to look at the language and JBuilder itself in more depth. I want to try to put most of the curves that the language is likely to throw at you in these chapters, thereby opening up the road ahead.

In particular, this chapter will cover classes and methods, the next chapter will cover types and operators, and the third chapter in the series will cover packages, scoping and jar files. Most of the tricky stuff will be in this chapter and the one on packages and jar files.

By the time you finish reading this chapter you should be able to do the following:

  • Create a simple java class with either default or public scope
  • Add a method to the class
  • Create an instance of your class,
  • Call the method that you added to your class from a standard JBuilder application.

The Governing Analogy of the Next Three Chapters

Analogies are not meant to be rigorously logical. Instead, they are a mental trick we can play to help understand new concepts by setting up parallels between the elements of a familiar idea and the elements of an unfamiliar idea. In this case I want to develop some analogies between the act of writing code and the act of writing a book.

The basic elements in a written work are, from smallest to largest: sentences, paragraphs, chapter sections, chapters, and books. Likewise, code is made up of statements, methods, classes, packages and jar files. My analogy, which is quite rough, even somewhat arbitrary, sets up the following parallels:

Written Word Code
sentences statements
paragraphs methods
chapter sections classes
chapters packages
books jar files

Analogies like this can be tricky. Don't take them too literally, particularly if you are relatively new to programming.

For instance, I don't mean to imply that a statement in code and a sentence in a book are the same thing. I mean only to suggest that they share some things in common.

A programming statement has the same relative importance to an entire program as a sentence does to an entire book. A statement's a relatively small and detail oriented syntactical element in a program. A sentence plays the same relative role in a book. Certainly the syntax for a sentence and the syntax for a statement are quite different. I'm only suggesting that are some rough similarities between the relative importance of sentences and statements.

Note: We can usually hold all the specifics of a simple programming statement in our mind at one time. Similarly, we can usually hold all the specifics of a single sentence in our mind at one time. Very bright people can hold the specifics of even relatively complex paragraphs in their mind at one time, just as bright people can think or imagine a complete method all at one time. But larger chunks, such as a complete class or a complete section of a chapter, are grasped only in rather a general sense by most people.

It's actually interesting to note that you can literally see the limits of the average human mind when you read quotations from extemporaneous public speakers in a magazine or newspaper. Several recent US Presidents, for instance, spoke in sentence fragments. When speaking off the cuff, they usually couldn't quite manage to put a whole sentence together without losing their way. Other US Presidents, on the other hand, speak off the cuff in not only complete sentences, but complete paragraphs. A facility like this is quite unusual. It is equally unusual to find programmers who can really think clearly and specifically in terms of entire classes. In fact, most programmers have trouble holding the entire contents of a ten or fifteen line method in their head at one time. One of the major reasons we break programs up into sections is to help overcome this problem. Most of us can't keep a large number of complex ideas in our heads at one time. As a result, we attempt to conquer the problem by dividing our code up into relatively small syntactical elements.

Classes are as integral a part of good programming as sections of a chapter are of good technical writing. Some people write code that is, in effect, nothing more than one long paragraph, or at best, a series of paragraphs that have no subheadings to aid the reader in finding the text's structure. These programmers make the mistake of failing to use classes to break their code up into coherent and reasonable sections. Code that looks like this will still work, just as you could still understand my text if I wrote it all in one long paragraph or if I didn't use subtitles to break up the various sections of my text. However, code without classes is often not well structured code: it's hard to understand!

Adding section titles to my text helps me, as an author, to organize my text. In the same way, adding classes to a program helps us all, as programmers, add structure to our programs. Classes benefit both the writer and the reader of a program.

Object oriented programming has many benefits. However, the primary benefit that it gives you is simply to help you break your code up into manageable chunks. Though hopefully better off than the politicians who can't quite manage to speak in complete sentences, we programmers are nonetheless struggling with a similar problem. Writing code is complex, and our minds have limited abilities. By dividing our code up into discreet syntactical elements, we can help overcome that complexity.

You can view the history of programming as little more than a struggle to discover the correct syntax for dividing programs up into manageable bits. Structured programming gave us functions, procedures and modules. Object oriented programming has brought us classes. Later in this text, we will look at even more modern advance called components or javabeans.

Java fully embraces object oriented programming. In particular, it uses classes to help us divide our code up into meaningful chunks. These chunks have the same relative significance to an entire program as the sections of a chapter have to a larger work such as a chapter or a book. Syntactically, they are quite different from the sections of a chapter, but in terms of their relationship to a larger work, they have a similar importance and play a similar role.

Understanding Java Classes

For the sake of clarity and readability, I will not make this examination of classes exhaustive. Instead, I will cover only the basic facts that you need to know. Other texts tend to cover the entire subject of classes in one chapter, or in two or three contiguous chapters. The problem with this approach, from my point of view, is that it mixes up beginning level programming issues with advanced programming issues. That can be useful for advanced programmers who just want a quick primer on a new language, but it is not helpful to the newcomer who is trying to understand the basic facts he or she needs to know to start writing code. As a result, I will selectively choose to cover only the key facts about classes in this chapter.

Almost everything in Java is a class. The exceptions to this rule are for a few operators, a few basic types such as integers, booleans, characters and floating point numbers, and for a few stray elements such as the package and import statements. But overall, classes play a very big role in Java programming. Java's heavy reliance on classes is a very good thing. It's one of the great strengths of the language.

Clearly, if we are going to get anywhere with Java, the first thing we need to understand is classes. In fact, it is difficult to talk sensibly even about simple types until we first understand the basic facts about the setting in which the types are placed. It's my contention that you can't effectively use Java types until you understand the classes in which they must reside. So I cover classes first, then types.

Classes are usually considered a relatively advanced feature. In the case of Java, however, they are fundamental to the language. Classes simply must be understood from the beginning or it is impossible to write even the simplest example programs.

Basic Class Syntax

At this stage its time to start drilling down into some specifics. Here is the basic syntax for declaring a class:

class MyClass
{
}

This class doesn't do anything, but it is syntactically correct. It is the minimum code you need to write to declare a class. You need to write more code to use the class, but the declaration I show here will compile on its own without error.

Some people prefer to put the first brace at the end of the first line of a class declaration:

class MyClass {
}

Others prefer the style I show in my first example. Both syntaxes are correct. I use the first technique simply because I find it easiest to read. If you find the other technique simpler to read, then you should use it. Good editors, such as Visual SlickEdit, contain "source beautifiers" that will switch your code back and forth between the two styles at the press of a button.

The Scope of a Class: Default vs Public

I will discuss scope in more detail in the next two chapters. However, I need to at least introduce the topic here.

The scope of a piece of code determines its visibility. A class with very wide scope can be seen throughout an entire program. A class with more limited scope can be seen only within a particular package. When I say that a class can be "seen," I mean that it can be called. If you can't "see" a class because it has too narrow a scope, then you will not be able to use the class, you will not be able to create an instance of it or call its methods.

The class I have named MyClass has a default scope; in other words, it is not declared private, and it is not declared public. By default, classes can be seen only inside the current package.

I will talk more about packages later, but in general, you can think of a package and a directory as being synonymous. Classes with default scope are visible throughout a single package. That means any other source file in the current directory will be able to see classes declared in this manner. If you have a source file in another directory, then it will not be able to see a class in the current directory if that calss is declared with default scope.

Here is another declaration for a class:

public class MyClass
{
}

This class has the word public proceeding it. Classes declared this way can be seen by files in the current package, and in other packages. Once again, I'm aware that I haven't defined the word package yet, but recall that it is roughly synonymous with the word directory. If you are in directory A, then you can see pubic classes declared not only in your current directory, but also in directories B, C, D, and etc. You can also see any methods in those classes that are declared public.

Public classes must go in their own Java source file, and that file must have the same name as the class. For instance, the class we have declared, called MyClass, must go in a source file called MyClass.java.

You can't have two public classes in the same source file. You can, however, have more than one class in the same source file. If you have one public class and one class with default scope in the same file, and you compile that source file, then the result will be two compiled files with a .class extension. There is one .class file for each class you declare, even though they are both declared in the same java source file.

Nested Class: Not Covered in this Chapter

Java allows you to nest classes within other classes:

class Foo
{
  int i;

  static class NestedFoo
  {
    int j;
  }
}

Several variations on this type of syntax are available, each having its own fine shade of meaning. However, I do not expect to find occasion to explore this colorful subject in this book since I don't think it will be generally useful to my target audience.

There are certain advanced programming situations in which a nested class syntax might be useful in the hands of a talented programmer, but beginning and intermediate level programmers will probably find few occasions when it will prove useful to them. As a result, I will probably cover this subject either not at all, or in one of the more advanced chapters of this text.

Creating and Destroying Classes

Like Delphi, Java insists that you create an instance of most classes before you use them. Here is the syntax for creating a class:

MyClass myClass = new MyClass();

With one notable exception, you are never going to be able to do much with a class unless you first create it with the operator new. What you are really doing in cases like this is creating an object on the heap, that is, you are allocating memory for your object. But just as in Delphi, you don't have to use pointer syntax when addressing this object. Instead, you use dot syntax:

myClass.doSomething;

Unlike Delphi programmers, Java programmers don't have to free the instances of the classes they create. Instead, the system will automatically free them. In fact, Java will always automatically free all memory allocations. This admirable system is called garbage collection.

Sometimes when you are running a Java program it will seem to "go away for a second," in other words, it will appear to pause. In a standard Windows program written in C or Pascal, that usually means that the Window's swap file is busy. In a Java program, that often means that the garbage collector is running. Of course, on Java programs running on Windows, it could mean either that the swap file is busy, or that the garbage collector is busy. Take your pick!

Declaring Methods in a Class

In Java, there is no such thing as a stand alone function, procedure or sub-routine. All the code you write must be part of a class. Here is what that looks like in practice:

class MyClass
{
  String getString()
  {
    return "This is a string";
  }
}

Here you can see the standard declaration for a class with default scope. Remember, a class with default scope can be seen from anywhere inside our current directory.

The new declaration for MyClass contains one method called getString. If you call this method, it will return a string containing the words "This is a string." In other words, the method getString is a little machine whose purpose it is to return four words. More explicitly, the words that it returns are: "This is a string." The syntactical element return tells the compiler that you are about to state the value that a function "returns" to the user.

In the last paragraph, I used the word string. What is a string? In general terms, a string is a piece of text embedded in a program. If you want to use the written word to say something to the user, then you create a string.

Of course, the string you create could contain not only written words, but numbers, nonsense syllables, or other content. All of which makes strings seem a bit amorphous. To help you get a better grip on what a string is, it might help to talk purely in terms of the syntax of the Java language.

Any time you put two full quotes together in a java source file you are creating a string. Even if you put two quotes together with nothing between them, you are still creating a string; It just happens to be an empty string. Whenever you write one quote, you must also include the closing quote. The pairs of quotes you create must be on the same line of code. If you need to go to a second line, then use the plus operator to concatenate your strings:

  String getString()
  {
    return "She walks in beauty, like the night/n" +
      " Of cloudless climes and starry skies";
  }

Note how I was careful to append a '/n' to the end of the string on the first line. This ensures that the second line I wrote does not appear on the same line as the first. In the same spirit, you sometimes must add a space at the end of one line, so the beginning of the next line does not run up against the end of the first:

  String getString()
  {
    return "This is a string. " +
      "Yes it is.";
  }

Without the space, your string will look like this: "This is a string.Yes it is." If you put the space in, the string is printed as we expect: "This is a string. Yes it is."

We know the getString method returns a String because it is declared to do so:

String getString()

If we had written the method to return an integer, it would have looked like this:

int getString()

In this example I have removed the word String and put in its place the word int. This means the function returns a integer rather than a string.

I capitalize the word String because it is a class, and I don't capitalize the word int because it is a simple type. I will talk more about simple types and the String class in the next chapter.

I capitalize the word MyClass because by convention the names of all classes start with a capital letter in Java. If you create a name for a class by combining multiple words, then by convention you captialize the first letter in each word: MyClass.

The word getString starts with a small letter because, by convention, all the names for methods in Java start with a small letter. If the name you choose for your method or variable contains more than one word, then the second and all subsequent words should begin with a capital letter: myMethod, myVariable, myFancyVariable. If you are unclear as to what variables are, don't worry, as I will explain the subject in more depth in the next chapter.

One last point needs to be made about the getString method. Consider the following class declaration:

public class MyClass
{
  public String getString()
  {
    return "This is a string";
  }
}

As you can see, I declare this method to be public. That means it can be seen in both this directory and in other directories. In other words, it can be seen in both this package and in other packages. I also declare the method getString to be public. If I did not declare it to be public, then I could not call it from a class in another directory. I could create an instance of the class, because the class is declared public. But if the method getString was declared with default scope, then I could not call it from a class in another directory. In other words, if MyClass had public scope and getString had default scope, then I could create an instance of MyClass, but I could not call the method getString. By declaring getString public, I make it possible to call the method from a class that resides outside the current directory, that is, from a class in another package.

Using a Class in an Application

Supposing that we have a class that does something useful such as return a string. What can we do with that class?

Listing 5.1 shows the frame, or form, from a simple JBuilder application that uses the class we have created. Take a look at the listing, and then I will explain how to create it. And don't worry, the only code you have to type in is the declaration for our short class, and one line to call it. All the other code that you see is strictly boilerplate, and will be created automatically by JBuilder. (This is one of the main reasons to use JBuilder: It knows how to perform a lot of the routine tasks for you automatically!)

Lising 5.1: The source to the MethodTest program

package methodtest;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
    
public class Frame1 extends JFrame
{
  JPanel contentPane;
  JButton jButton1 = new JButton();
  MyClass myClass = new MyClass();
  JTextArea jTextArea1 = new JTextArea();

  //Construct the frame
  public Frame1()
  {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try
    {
      jbInit();
    }
    catch(Exception e)
    {
      e.printStackTrace();
    }
  }

  //Component initialization
  private void jbInit() throws Exception
  {
    jButton1.setText("jButton1");
    jButton1.setBounds(new Rectangle(113, 124, 155, 29));
    jButton1.addActionListener(new Frame1_jButton1_actionAdapter(this));
    contentPane = (JPanel) this.getContentPane();
    contentPane.setLayout(null);
    this.setSize(new Dimension(400, 300));
    this.setTitle("Frame Title");
    jTextArea1.setText("jTextArea1");
    jTextArea1.setBounds(new Rectangle(70, 27, 248, 88));
    contentPane.add(jButton1, null);
    contentPane.add(jTextArea1, null);
  }

  //Overridden so we can exit when window is closed
  protected void processWindowEvent(WindowEvent e)
  {
    super.processWindowEvent(e);
    if (e.getID() == WindowEvent.WINDOW_CLOSING)
    {
      System.exit(0);
    }
  }

  void jButton1_actionPerformed(ActionEvent e)
  {
    jTextArea1.setText(myClass.getString());
  }
}

class MyClass
{
  public String getString()
  {
    return "She walks in beauty like the night\n" +
      "Of cloudless climes and starry skies";
  }
}

//Recall that in my JBuilder environment I chose Project | Default Options,
//turned to the code style page, and chose Standard adaptors for event handling
class Frame1_jButton1_actionAdapter implements java.awt.event.ActionListener
{
  Frame1 adaptee;

  Frame1_jButton1_actionAdapter(Frame1 adaptee)
  {
    this.adaptee = adaptee;
  }

  public void actionPerformed(ActionEvent e)
  {
    adaptee.jButton1_actionPerformed(e);
  }
}

      

To create this program you should first open JBuilder and close any currently open projects. Choose File | New | Application from the menu.

In step 1 of the project wizard, you will, by default, see a string that looks something like this in the Project File edit control:

/home/myname/jbproject/untitledx/untitledx.jpr

To create an application called MethodTest, change the string so that it looks something like this:

/home/myname/jbproject/MethodTest/MethodTest.jpr

Press the Finish button twice to generate your project.

Scroll down to the bottom of Frame1.java, and insert the declaration for MyClass:

class MyClass
{
  String getString()
  {
    return "She walks in beauty like the night\n" +
      "Of cloudless climes and starry skies";
  }
}

You also need to add code to your poject to declare an instance of your class, and to initialize it. Go to the beginning of the declaration for Frame1 and add the declaration for your class:

public class Frame1 extends JFrame
{
  JPanel contentPane;
  MyClass myClass = new MyClass();

In this code fragment I want you to focus on the last line. The other lines are included just so you can see where in your program you should insert the line.

The code I show you first declares an instance of your object:

MyClass myClass 

It then creates the instance:

myClass = new MyClass(). 

The act of using the new operator allocates memory for your class. So the process involves two steps: first declare your instance of the class, and then create it.

Compile the project once to make sure you have typed in the class declaration correctly. To do this, open the Project menu, and select either Make project methodtest or Make frame1.java. In the first case you will make the entire application, in the second, you will make only frame1.java. either action suits our current needs.

If your code compiles correctly, then click on the design page at the bottom of the editor. You will be placed in design mode. This time, I don't want you to turn to the AWT page. We are creating an application now, not an applet. As a result we don't need to worry about compatibility with some older versions of the JDK. Instead, you can select your controls from the Swing page of the component palette. (You can, of course, use swing controls in an applet. The only problem is that you might not be able to use that applet in most contemporary HTML browsers.)

In this particular case, you want to select a jButton or jToggleButton and a jTextArea. Arrange them as shown in Figure 1.

 

Figure 1: The main frame for your application as it appears at design time. Note that the contentPane is selected in the structure pane, and the layout is set to null.

In order to get your controls to look like the ones shown in the picture, it is probably best for you to switch from the border layout to the null layout. To do this, click on the contentPane in the JBuilder structure pane, and then use the Inspector to select the null layout. (That's confusing, isn't it? Recall that the structure pane is the second of the two windows on the left of your screen. As you can see from a glance at Figure 1, the contentPane is the highlighted third item in the hierarchical list of items shown in the structure pane.)

Recall that I said we were using the null layout only as a temporary measure until we had time to discuss layouts in more depth. Use the null layout now, because it is simple to use and requires no explanation. Keep in mind, however, that I'm going to discuss layouts in more depth later in this text. At that time, I will show how to avoid using the limited null layout in your final code.

Now double click on the button to create an event handler. When you are done, the following code, or something like it, should have been added to your program:

  void jButton1_actionPerformed(ActionEvent e)
  {

  }

Change the code so that it looks like this:

  void jButton1_actionPerformed(ActionEvent e)
  {
    jTextArea1.setText(myClass.getString());
  }

That's it! Your program is finally done. Now you should be able to select the green "run" arrow to compile and launch your program. When it is loaded, press the button you created, and you should see the text from your class in the jTextArea component.

Constructors

If you can stand swallowing one last bit of syntactical jargon in this chapter, I would like to add a quick explanation of constructors. Constructors are methods added to your class that will be called automatically when the class is created.

Consider the following declaration:

package Sammy;

public class MyClass
{
  String myString;

  public MyClass()
  {
    myString = "She walks in beauty like the night\n" +
      "  Of cloudless climes and starry skies\n" +
      "And all that's best of dark and bright\n" +
      "  Meet in her aspect and her eyes:\n" +
      "Thus mellowed to that tender light\n" +
      "  Which heaven to gaudy day denies.\n";
  }

  public String getString()
  {
    return myString;
  }
}

This class contains a constructor called MyClass. The constructor for you class should always have the same name as the class itself.

The constructor will be called automatically when you create an instance of your class. As a result, it is a great place for you to perform initialization for a class.

In this case, note that I have declared a variable called myString. I initialize that string in my constructor. Then in the getString method, all I need to do is return my initialized string.

In Java, any variables that you do not initialize in your constructor will be zeroed out. Thus if you declare an int as variable of your class, it will be automatically set to zero when the class is created. Strings, on the other hand, are not set to an empty string, but instead they are set to null. All classes that have not been explicitly initialized are said to contain the value null, which is really a fancy way of saying zero.

Since Java automatically initializes all the variables in your class to 0, null, or to some similar default value, you need not bother initializing variables in your constructor if you just want to "zero them out." Only initialize the variable explicitly in your constructor if you want to set it to some explicit value other than zero, null, etc. In our case, we indeed want to do that, so I have created a constructor.

Public Classes, Your First Package

Notice also that I have declared MyClass to be public. Furthermore, I have declared both the constructor and the getString method to be public. As a result, you can place this file in a separate directory and call it from your current directory.

I have declared the package for this file to be "Sammy." This means that this file (which has to be called MyClass.java) must be placed in a directory called Sammy. For instance, you could create a directory beneath the directory where Frame1.java is stored and call it Sammy. You could then copy this file into that directory. Now add the file to your current project by choosing the Add to project speed button in the IDE. This speed button shows a picture of a folder with a green cross on it. (Or, if you prefer, choose Project | Add to Project from the menu.

Now you need to make some changes to your Frame1.java source file. At the very top of this file add an import statement for the Sammy package:

package untitled7;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import Sammy.*;

Now remove the initial declaration for MyClass that you had written near the bottom of Frame1.java:

class MyClass
{
  public String getString()

 {  
   return "She walks in beauty like the night\n" +<
    "Of cloudless climes and starry skies";
 }
}

You no longer need this declaration because the class is now declared in MyClass.java, which is stored in the Sammy directory.

Now you can save your work and run the program. You may find that with the new, larger string returned by the getString method, that you will have to resize the jTextArea while in design mode to make the program look right at runtime.

Don't worry if you had trouble understanding some of the concepts mentioned in this last section of the chapter. I will talk more about variables and more about packages in the next two chapters. I pushed the envelope a bit here in this last section in order to give you a foretaste of some of the subjects being covered in the next two chapters.

Summary

In this chapter you learned the basic facts about classes and methods. You should now know enough to begin using classes in your programs. Additional important information about classes will be presented in the next two chapters.

Back to Java Madness Index