Basic Program Structure of Java
This chapter provides an overview of the structure of a Java program. Although there may be some value in the simplicity of a basic "Hello, world" program, I think that because they show something you basically wouldn't ever write code to do, they are unhelpful. So I'm going to begin with a more complicated program. As of this writing, I'm part way through my doctoral dissertation in biblical studies. I've thought about what to use for examples, and I really wanted to find something that I could use in lots of coding situations to help make examples consistent in terms of domain. Since the library is near and dear to me as a grad student, and libraries are complex objects that allow for lots of different approaches in Java, I've decided to build a lot of examples around a library object. Plus, most people know what libraries are about so there's no difficulty in understanding what I'm using as an example. Here's the code, which I'll discuss later. Just one note before I begin is necessary. Java, like UNIX, is strictly case-sensitive. That means that a Date object called Today is totally different and unrelated to a Date object called today.
I grant that this is a bit more complex than most programming books start off with, but I'd rather present an example that covers most of the main features at once.
Code Details
Comments
The first few lines of this program are comments, indicated by //. Besides comments, the first thing you can have in a .java file is a package name. The package name is optional, but if it is present, it must be first, not counting comments. Like all statements in Java, the package statement is terminated with a semicolon, ;. Packages are used to organize related classes together. They affect issues of access and inheritance but I'll discuss that later. If you don't have a package statement, you still end up with a package; it's simply unnamed.
Import Statements
After the package statement comes an import statement. An import statement is kinda sorta like a C include statement. The import statement tells the compiler where to look to find classes that you refer to in your code. Unlike a C include statement for a header file, Java does not add to your code the definition for every class in the package that you import. Instead, it only includes the definition for the class(es) you actually need. That means that you can have all the import statements you like, but the size of your program may not increase at all. It depends upon whether or not Java needs a class in one of the imported packages. Let's analyze briefly what a package name consists of. Consider the package name gradschool.library. Each piece of a package name, delimited by periods, ".", represents the name of a directory. So, if it helps, you can mentally (but not in your code!) replace the periods with file separator characters, like so \gradschool\library. This indicates also that the package name describes a directory structure relative to a parent directory, even if the parent is c:\ or /. You would never put in your Java code
import C:\gradschool\library // DON'T EVER TRY THIS. IT'S WRONG!!!
Class Signature
This is followed by the line public class Library
There are several items here of interest. First, we are giving the class an access modifier, in this case "public". The access level of "public" means that any class can access this class from any package. In any given .java file, there may be at most one class that is marked "public" that is an outermost, non-static class. I'll unpack what that all means as we go along. For right now, suffice it to say that you should have only one public class in a .java file, unless you're already a Java guru, in which case you may wish to skip this section.
Next comes the keyword "class". There are two main kinds of things you can define in Java: classes and interfaces. An important difference between Java and C, for example. No data elements or code exists outside the context of a class. There is no such thing as declaring a global constant outside of a class or interface. To get any work done, or define any data, you need to put it inside a class definition.
Now, what exactly is a class? Classes and the objects you get from classes can be compared to cookie cutters and cookies, respectively. You use cookie cutters to make cookies. There's a very important difference between cookie cutters and cookies. Cookies are not cookie cutters and cookie cutters are not cookies. Cookie cutters define how a cookie will look. Similarly, a blue print for a house tells you what the house will look like, but you can't move into a blueprint. You need to use the blueprint to build a house and then move into the house to live. So when you look at the class definitions I have here, what you are seeing is the cookie cutter. You can't actually interact with this definition. You have to make a cookie to interact with it, and I'll discuss how to do that below. You'll save yourself a lot of grief if you always remember this simple rule. You have to make an object from a class definition before you can use the methods or data members in the class. There are some exceptions to this that I'll cover later, but for right now, assume this unqualified rule is in effect. So, a class definition tells you what an object would look like if you had an object of that type but the definition is not an object itself. It is only a blueprint for such an object. So here, merely defining the class "Library" doesn't cause a Date object called entryTime to exist. It only says that if I had a Library object, part of its data would be this item. So merely compiling the code above just creates class definitions. When I run the code, it will then make objects from the class definitions.
Class Definition
The scope of a class definition is indicated by opening and closing curly braces, { and }. While it is common in K & R style coding to put curly braces on the same line as a line of code, so that you would have something like
public class Library {
I personally dislike that approach for two reasons. First, I find it very unreadable. It makes it hard to find and match braces easily. The second problem flows from the first. If you get a compiler error for mismatched curly braces, I think it's really hard to solve it with braces done this way. So instead, my code always aligns the curly braces vertically so you can always, easily see where the opening and closing curly braces for a class, method or block of code are. End of soapbox.
Data Members
The next three lines, Date entryTime; Date exitTime;String libraryName; define data members of this class. Data members specify the attributes of the object. In the object model, which is not unique to Java, all objects have three properties: identity, state and behavior. Data members or more generically, attributers, capture or reflect the state of the object. Java is a strongly-typed language. All data members or local variables are required to have a data type.
There are three kinds of variables in Java: instance, class and local. Here's the basic scope of each of these. Instance variables, such as those above, have one copy created per object that you instantiate (make an "instance"). So if I make five hundred Book objects, there are five hundred instances of title variables, one for each Book object. An instance variable is any variable declared in a class definition that is declared outside of a method and does not have the modifier "static" in its declaration. It is important to recognize that instance variables belong to instances of the class. Going back to the cookie cutter example, you don't have chocolate chips just because you have a cookie cutter. You have to actually cut out a cookie from chocolate chip cookie dough. Instance variables in this sense are like chocolate chips. The are attributes of real cookies, but not of the cookie cutter. The only way then to have a Date object called entryTime is to have an instance of the class Library. I emphasize this because I regularly have students who have trouble wih the difference betjween variables ina class definition and the existence of the instance varable in an instance of the class.
Local Variables
The next kind of variables I'll discuss are local variables. Any variable declared inside a method or constructor is a local variable. Its scope is from its creation until the code block it is defined in is exited. Suppose, for example, you have the following method:
public boolean verify() { Int I=0; Panel p = new Panel(); int j =1; int k = I + j;
}
When you exit this method, that is, reach the closing curly brace, }, the variables I, j, k and p all go out of scope. They can no longer be used.
Class or Static Variables
The third kind of variable is called a class variable. Unlike instance variables of which there is one copy for every instance of the class, there is only one copy of a class variable no matter how many instances there are of the class. Here's a small example of when you might want to use this.
Class Networking
{ public static int portNumber = 6534; public String serverName; public Networking(String hostName) { serverName = hostName; }
}
Although this class doesn't do much, it is a complete class definition. If you make an instance of the Networking class, the instance gets its own version of serverName. No matter how many instances of the class Networking you create, there is still only one copy of the variable portNumber in memory. This one copy is shared by all the instances of the Networking class. The reason to do this is that there's no need to have multiple copies of portNumber if the port number is always supposed to be the same for all Networking objects. In this current form of declaration, if any instance of the Networking class changes the value of portNumber, it will be "changed" for all instances, since they all have a reference to the same copy in memory. Later we'll see how to prevent the value of a static, shared class variable from being modified. You may wish to think of a static variable as a global if it has "public" access; the variable can be referred to by the name of the class, Networking.portNumber. Static variables are the only kind of variable that can exist without an instance of the class being created. So if you need to have a data member in your class that needs to be shared among instances, and needs to exist whether or not there are any instances, use a static variable. Let me stress this as strongly as I can. You should not, must not, indeed cannot reference an instance variable without creating an instance of the class that the variable occurs in. New Java programmers often try to reference instance variables without instances of their containing class. This happens especially in "main", because so many Java books do so much code in "main" that it just must seem natural to refer to data members in this method. Resist the temptation. The compiler will give you an error for making a static reference to a non-static variable.
The "main" Method
These variable declarations are followed by the "main" method I've mentioned several times above. Like C, Java programs are entered through a main method. Without a main method, Java will not be able to execute your code, period. It is the entry point to a Java program. Unlike main in a C program, however, the signature of this method must not be changed in any way. Let's examine the method signature.
public static void main(String[] args) // Entry point to an application
The access modifier "public' means that this method can be accessed from anywhere. This method must be public so that the JVM can access this method. The "static" modifier means that, like a static variable, there is a copy of this method available in memory after the class is located, even if no instances of the class have been created. This is vital because the JVM calls this method before anything else in the program happens, so you can't create an instance first. Therefore this method must be static, that is, not dependent upon any instances of any class being created.
Next comes the return type "void". This return type means that this method does not return any value when it is done executing. All methods must have a return type. Let me mention in passing that since Java has no pointers, it certainly (blissfully) does not have any void pointers nor "void" object references.
The method name, as implied above, is "main". As noted above, in the object model all objects have behaviors. Methods are the way Java expresses behaviors. The main method accepts one parameter, a String array. I'll talk about String objects and arrays later. For now, what is important to notice is how this main method signature differs from the main function in a C program. Unlike C, Java's main method has only one parameter. It does not have a parameter that contains a count of the number of parameters. This value can be easily obtained by accessing the length data member of the array. In this method, "args" contains the command line parameters, but with one key difference from C. This array does not contain the name of the class that was used on the command line. Suppose, for example, that you invoked the class this way,
java Library Bristol
This would make the args String array one element long, and it would contain the String "Bristol." There is no way to send anything but Strings to the program via the command line. This array would not contain a String with "Library" in it. After all, you ought to know what class contains the main method that is being called. If you don't, you can use reflection to find out. In this simple example, since I know that "Bristol" will be in the first array element, I can write the line of code
lib.libraryName = args[0]; // Accept a command line parameter
Here, I've created an instance of the Library class called lib. The Library class has an instance data member called libraryName. So, since it is an instance variable, I have to have an instance of the Library class for the variable libraryName to exist. Here I'm setting this variable equal to the value of the first (and only) element of the args String array. Just as a pointer to what I'll talk about further along, if I had typed nothing on the command line besides
java Library
the code would have failed when I tried to assign args[0] to lib.libraryName. It would have caused an ArrayIndexOutOfBoundsException exception, because there would be no elements in this array. Here we can see one of Java's strengths. C would have just punted here. Java sees that this is wrong and the program throws an exception, rather than proceed with clearly bogus data, in this case a Null object reference.
The line
creates a new Book object. We'll talk more later about constructors, which are used to create instances of classes.
The final line the main method is
System.exit(0); // End the application and stop the JVM
which tells Java to exit the main thread and shut down the virtual machine. Don't call this unless you intend to exit the program at that point. So you would use this when the user selects "Exit" on the main menu of your application, but not use it when the user presses "Cancel" in a dialog box (unless perhaps choosing "Cancel" in the login dialog).
Methods
Unlike C, Java doesn't require anything like a function prototype. The compiler can encounter a method that uses a variable declared at the bottom of the class definition and find them, as well as methods farther down in the class that the current method calls. Here's the basic format of a method definition:
Let's look at each piece of the method signature. First, there is an optional access modifier. There are four access modifiers: private, protected, public and package-default. The main alternatives are public and private. You should use public as the access modifier for methods that the rest of the planet can access (call). Such methods are generally going to be constructors, factory methods, and getters and setters. That is, high-level public interfaces to your object to get data values or to set data value. You would use private as the access modifier for methods that define the implementation of your class, that is, how your object actually gets work done. Suppose, for example, that you have a VisaAccount object. Suppose also that the VisaAccount class defines a method called
public boolean charge(float chargeAmt)
Another object, say in an e-commerce system, would call this method thusly:
This might be the way this e-commerce order object asks the VisaAccount object to process a credit card charge. What you want to have happen here, however, is to have the public charge() method call private methods that first validate the data and then actually call the private methods to process the charge. Hopefully, by making the real methods that do the work private, plus any related data members private, the order object that calls the VisaAccount object to do work can't directly change the charge amount and skip the validation code. In this example, one would hope that the chargeAmt would be rejected as invalid. That will only work, though, if the VisaAccount object has its own validation code and there's absolutely no way to modify the data or call the method that actually processes the charge from outside the VisaAccount object. You can get that if charge() is public but virtually everything else in the class, besides the constructor, is private. This makes sense and is similar to the real world. Your objects should be composed of public interfaces, methods to ask for data or ask for services from your object, and private implementations, data and methods, that define how your object really behaves. This greatly eases software maintenance, becuaes you can modify the internals of your class and no other class is affected.
Another choice is to use the package default for access. You get this by typing nothing. I don't mean the word "noting". I mean you don't supply any value for the access modifier. It is optional. If you use the package default, the consequences are that your data members and methods are visible to all other classes in the same package, but not to any other classes. So if I create the gradschool.library package, and put the Book class in that package, and define the Book class' constructor and methods as having package default access, any other class in the gradschool.library package can create and use Book objects but no classes outside the gradschool.library package can use the Book class at all, not even a subclass of Book. This leads me to the final choice, which is protected. The use of protected as the access modifier means hat this method or data member is accessible by other classes in the package and by subclasses. In other packages. This is an important consideration for use of your package by other developers. If you want to let other developers use your class as a base class and subclass it in their own packages, you need to provide an access level that allows this level of access, which means public or protected. If this is what you intend to do, public is the most flexible and therefore probably the best choice most of the time. Below is a chart that summarizes the access to your class by other parties based on the access modifier you choose. The left hand column shows the access level you put in your code. The other columns show whether a given group of classes can access data members or methods with the given access level.
FIGURE 3.1
So choose carefully which access level to use. Here's my rule of thumb: if you plan on using your classes but not having others subclass them, make the methods and data members public that need to be used by other classes outside the package or protected (if you want only other classes in the same package or subclasses to access the class) and everything else private.
Next come other modifiers. There are a number of possibilities here, such as synchronized, final, static or native. I'll talk about synchronized and native in thechaper on methods. A static method, like a static data member, a class variable, is created in memory when the class is loaded and does not need an instance to exist. We've already seen the most important static method, main. There are other static methods in the JDK. Sometimes a static method is handy if all you really want to do is take some values, put them through a formula and get a result out. This is the basis of the java.math package. Suppose you want to compute a square root or a cosine. You don't need a math object as such. You just want to use a function to compute the number. So if you don't really need an object to use later, it may make sense to use a static method. Or, you may have a method you want available to other objects to access before an object of the relevant class has been instantiated. Here's an example of when you might want such a thing. Let's say you have an application with many JInternalFrame objects (similar to a Windows MDI application). If you do something in any of the internal frames, you want to update a status line on the outer JFrame. One way you could do this is pass an object reference to the constructor of each JInternalFrame that points to the JFrame. Then they could use that object reference to call a setStatus(String s) method to update the status message. This could be a hassle, especially if you can't easily subclass a class whose constructor parameter list you want to modify. So, instead, you might declare the JLabel for the status message as static and declare the setStatus method as static. By doing so, you can access the status line from any place without an object reference, just by knowing the name of the class that the static method and JLabel belong to. Let me illustrate this with some code:
class MainWindow extends JFrame { public static JLabel staticLabel; public static setStatus(String statMessage) { staticLabel.setText(statMessage);
}
You can call this from anywhere and don't even have to instantiate an object of type MainWindow for this JLabel to exist. Since, however, the JLabel needs to appear on a JFrame object, you do still need to give the staticLabel a value and add it to a MainWindow object. Making this method and data member static primarily serves the purpose of being able to refer to the method without having to have an object reference. Applets in a browser can do this to the status line of the browser through a static method as well. It is important to note, as I said above, that staticLabel needs to be static to be referred to without being preceded by an object reference. Let me put this in the form of a rule: an instance variable can never exist without an instance of the class. This seems to be a very common error among new Java programmers, who are probably used to variables simply existing and being accessible from anywhere, any time.
The keyword final prevents a definition, either of a data member or a method or a class, from being overridden. For example, the String class is final. Before it was made a final class, a number of nasty security breaches were possible that are not possible now. If the class wasn't final, it might be possible to override it, steal passwords, or change code to send the passwords somewhere else. A final method, likewise, cannot be overridden or redefined. So, you might have a method that validates a user id and password. A hacker might not be able to change your class file, but if he can override your method in a subclass he or she can change the validation routine to also send a copy of the id and password to the hacker's screen. Or, suppose that you have a specific set of business rules for how something needs to be done and you don't want that process changed. You can make the method final and no one can override the method to do anything else.
You can also make variables final. Going back to our portNumber example, you might decide that you want a port number for all instances of the networking class to share. However, since port numbers generally should not change, you probably want to be sure that no instance of the Networking class can change the value of the port number. So you can declare it as final. This also means that if the data member is public, objects from other classes can also see it but not change it. Now, if you combine static and final and public like this
public static final String version "Version 2.0";
you have the closest thing that Java provides to a global constant. It cannot be changed at runtime. It is accessible from everywhere and it does not require that you instantiate an instance of its class in order for the version data member to exist. My reading of the JDK 2.0 documentation is that the JVM will create one copy of the static final data member that is shared by all objects. This is an improvement over JDK 1.02, in which declaring such a variable in one class resulted in it being put in-line in other classes where it was used. The result of that is that if you changed the definition, but didn't recompile everything, you would have multiple versions of the same data member in use at runtime. The change in JDK 2.0 should hopefully fix this problem. If you are using a previous version of the JDK, be sure that if you have several classes that use the same public static final data member that you make sure to recompile all dependencies when you change the constantThis is still a good idea, even if this problem has been fixed in JDK 1.2. So making something final can be very handy for convenience or very important for security.
Return Types
As I said above, Java has two kinds of data: objects and primitives. You may put any object or primitive in a method as the return type. Since Strings, to be discussed later, are objects, and not simply pieces of contiguous memory as in C, you can put an array for the return type. You can also specify void for a return type, even though there is no such data type as void. I'm a big believer in always returning something, even if it's only a boolean value. Why? There are a lot of things that can go wrong when you call another method. If something goes wrong, and the method you called doesn't cause the program to abort, but doesn't tell you there's a problem, and your code can't work correctly without the other method succeeding, you're in trouble. The way to avoid this is to require as a coding standard, that each and every method must return a resultEven in a trivial method where you're sure nothing could go wrong, I recommend you follow this practice of returning a boolean value. Of course, since it's not required syntactically to test the return value, be sure that you test the return value every time as well, unless you're really confident that nothing can possibly go wrong.
Method Name
By convention, all variable and class names start with a lower case letter and then the first letter of every word in the method name are capitalized, such as extractGifFromZipFile, but not Extractgiffromzipfile. This convention comes from Smalltalk and is also often used in C. Also, be sure that you don't use a name that is the same as a keyword or class name in Java, like instanceof or math.
Source Files
Source code is stored in a .java file. It is a requirement that Java source code occurs in a file that ends in .java. So how many classes can I put in a .java file, or how many should I put there? Above I said that you could not have more than one public non-static, outermost class in a .java file. Suppose that you have several classes that each need to have public access. You'll have to put each one in its own .java file. If a .java file contains a class that is public, it is a requirement that the .java file have the same name as the public class. So for example, if I have this class definition
public class Library
in a .java file, Java requires that the file name be Library.java. You may have any number of other classes or interfaces in the same file, but you may not have another public, non-static, outermost class. If you are starting to wonder why I'm repeating some things I've already said before, it's in part because I can't count the number of students I've taught in classes who, not ten minutes after I said you can't have more than one public class in a file, or the like, try to do that very thing and get a compile error and don't understand what's wrong. This particular error occurs almost weekly no matter what subject in Java I'm teaching. So now that I've belabored this point, you're not gong to try this, right?
Should you then go ahead and stuff fifty classes into one file because it's possible? I'd recommend that you don't. Instead, I recommend that one file contain at most one public class and other classes that are directly dependent upon it. For example, a class that implements the ActionListener interface for the okayButton in a Frame, should probably be in the same file as the GUI class that defines the Frame and okayButton. The same might be true of an application specific dialog that is instantiated by that ActionListener object. On the other hand, if you have a package like gradschool.library, that contains related classes, like LibraryCard, Library, Book, Patron and so forth, all these sound like independent classes that you should be able to deal with independent of the other classes, so each should be defined in its own .java file. When you are picking that class name and deciding on a file name, be aware that some platforms have limitations on the length of file names. So, for example, a Mac limits file names to twenty-eight characters. So if you want your code to be platform-neutral, don't give your class a forty-five letter name. That was an issue for Swing being ported to the Mac. So avoid this problem by choosing file names that are compatible in size with multiple platforms that your code might need to run on .
Comments
You've already seen one kind of comment in Java:
// This is a single-line comment.
The comment starts with the double slash, //, and continues to the end of the line. Java also uses the same notation for multi-line comments that C does:
/* This is how you make a multi-line comment: You put a /* and follow it, when you want to end the comment, with a matching */
*/
Finally, as suggested above, there is also a javadoc comment that you can put in your code to create HTML-based documentation. It looks like this:
following parameters: Book, LibraryCard, Library.
Now when you run the javadoc utility, it will list the class this is in, the checkOutBook method, its parameters and the comment "Method: checkOutBook is the driver method to check out a book and uses the following parameters: Book, LibraryCard, Library." Given how much developers love to write documentation, I highly recommend using javadoc as an easy way to kill two birds with one stone: documenting your code internally and providing on-line, HTML-based documentation.
Coding Conventions
I've covered most of these conventions already. Classes start with a capital letter and every first letter of the other words in the name begin with a capital letter. Everything else is lower case. This applies to interface names as well. On the other hand, method and data member names begin with a lower-case letter and the first letter of every other word begins with a capital letter. For example,
public class LibraryCard { private String PatronID; public renewCard(String renewalPeriod) { // Code goes here }
} // End class definition LibraryCard
By convention, the names of "constants" are all capital letters with underscores between words, like
public String LIBRARY_SERVER_NAME = "Milton";
These are only conventions, but if you don't follow them, you make life harder for yourself as well as others who need to read your code.
Since we are talking about naming, here's a rule, not a convention. You may start identifiers, like data members, with one of three things: an underscore, _; a letter, like a, A, or Z; or a dollar sign, $. Since other languages and many operating systems have names that use underscores and $, and since Java uses dollar signs when it creates inner class names, I recommend you avoid using either of these in your identifier names for the sake of clarity to all.
Summary
That about covers the minimal basics. Source code is placed ihn a.java file. All the code has to go inside a class or interface definition. All applications need a main mehtod, which serves as an entry point to your program. The nam of the .java file must match the name of a class or interface in the file. If a class has a main method, that class is the source of the name for the file. You can put multiple class definitions in the same .ajva file, but only one public, non-satic outermost class can exist in a given .java file. A class definition is a blueprint. It tells you what an object of the classs type would be like if you had such an object, but classes and ojects are very different things. Class definitions consist of data memers and mehtods. Mehtods may contain lcoal variables. Classes, data members and methods have an access level, which is public, protcted, private or package level (the default).