Everything is an object, Part 2
Build your first Java program
There are several issues you must understand before seeing your first Java program.
TEXTBOX: TEXTBOX_HEAD: Everything is an object: Read the whole series!
- Part 2. Build your first Java program
-
:END_TEXTBOX
Name visibility
A problem in any programming language is the control of names. If you use a name in one module of the program, and another programmer uses the same name in another module, how do you distinguish one name from another and prevent the two names from “clashing?” In C, this is a particular problem because a program is often an unmanageable sea of names. C++ classes (on which Java classes are based) nest functions within classes so they cannot clash with function names nested within other classes. However, C++ still allowed global data and global functions, so clashing was still possible. To solve this problem, C++ introduced namespaces using additional keywords.
Java was able to avoid all of this by taking a fresh approach. To produce an unambiguous name for a library, the specifier used is not unlike an Internet domain name. In fact, the Java creators want you to use your Internet domain name in reverse since those are guaranteed to be unique. Since my domain name is BruceEckel.com, my utility library of foibles would be named com.bruceeckel.utility.foibles
. After your reversed domain name, the dots are intended to represent subdirectories.
In Java 1.0 and Java 1.1, the domain extensions com
, edu
, org
, net
, and so forth were capitalized by convention, so the library would appear as COM.bruceeckel.utility.foibles
. Partway through the development of Java 2, however, it was discovered that this caused problems, and so now the entire package name is lowercase.
This mechanism means that all of your files automatically live in their own namespaces, and each class within a file must have a unique identifier. So you do not need to learn special language features to solve this problem — the language takes care of it for you.
Using other components
Whenever you want to use a predefined class in your program, the compiler must know how to locate it. Of course, the class might already exist in the same source code file that it’s being called from. In that case, you simply use the class — even if the class doesn’t get defined until later in the file. Java eliminates this forward referencing problem so you don’t need to think about it.
What about a class that exists in some other file? You might think that the compiler should be smart enough to simply go and find it, but there is a problem. Imagine that you want to use a class of a particular name, but more than one definition for that class exists (presumably these are different definitions). Or worse, imagine that you’re writing a program, and as you’re building it you add a new class to your library that conflicts with the name of an existing class.
To solve this problem, you must eliminate all potential ambiguities. This is accomplished by telling the Java compiler exactly what classes you want using the import
keyword. import
tells the compiler to bring in a package, which is a library of classes. (In other languages, a library could consist of functions and data as well as classes, but remember that all code in Java must be written inside a class.)
Most of the time you’ll be using components from the standard Java libraries that come with your compiler. With these, you don’t need to worry about long, reversed domain names; you just say, for example:
import java.util.ArrayList;
to tell the compiler that you want to use Java’s ArrayList
class. However, util
contains a number of classes and you might want to use several of them without declaring them all explicitly. This is easily accomplished by using *
to indicate a wild card:
import java.util.*;
It is more common to import a collection of classes in this manner than to import classes individually.
The static keyword
Ordinarily, when you create a class you are describing how objects of that class look and how they will behave. You don’t actually get anything until you create an object of that class with new
, and at that point data storage is created and methods become available.
But there are two situations in which this approach is not sufficient. One is if you want to have only one piece of storage for a particular piece of data, regardless of how many objects are created, or even if no objects are created.
The other is if you need a method that isn’t associated with any particular object of this class. That is, you need a method that you can call even if no objects are created. You can achieve both of these effects with the static
keyword. When you say something is static
, it means that data or method is not tied to any particular object instance of that class. So even if you’ve never created an object of that class you can call a static
method or access a piece of static
data. With ordinary, non-static
data and methods you must create an object and use that object to access the data or method, since non-static
data and methods must know the particular object they are working with. Of course, since static
methods don’t need any objects to be created before they are used, they cannot directly access non-static
members or methods by simply calling those other members without referring to a named object (since non-static
members and methods must be tied to a particular object).
Some object-oriented languages use the terms class data and class methods, meaning that the data and methods exist only for the class as a whole, and not for any particular objects of the class. Sometimes the Java literature uses these terms too.
To make a data member or method static
, you simply place the keyword before the definition. For example, the following produces a static
data member and initializes it:
class StaticTest {
static int i = 47;
}
Now even if you make two StaticTest
objects, there will still be only one piece of storage for StaticTest.i
. Both objects will share the same i
. Consider:
StaticTest st1 = new StaticTest();
StaticTest st2 = new StaticTest();
At this point, both st1.i
and st2.i
have the same value (47) since they refer to the same piece of memory.
There are two ways to refer to a static
variable. As indicated above, you can name it via an object, by saying, for example, st2.i
. You can also refer to it directly through its class name, something you cannot do with a non-static
member. (This is the preferred way to refer to a static
variable since it emphasizes that variable’s static
nature.)
StaticTest.i++;
The ++
operator increments the variable. At this point, both st1.i
and st2.i
will have the value 48.
Similar logic applies to static
methods. You can refer to a static
method either through an object as you can with any method, or with the special additional syntax ClassName.method()
. You define a static
method in a similar way:
class StaticFun {
static void incr() { StaticTest.i++; }
}
You can see that the StaticFun
method incr()
increments the static
data i
. You can call incr()
in the typical way, through an object:
StaticFun sf = new StaticFun();
sf.incr();
Or, because incr()
is a static
method, you can call it directly through its class:
StaticFun.incr();
While static
, when applied to a data member, definitely changes the way the data is created (one for each class versus the non-static
one for each object), when applied to a method it’s not so dramatic. An important use of static
for methods is to allow you to call that method without creating an object. This is essential, as we will see, in defining the main()
method that is the entry point for running an application.
Like any method, a static
method can create or use named objects of its type, so a static
method is often used as a “shepherd” for a flock of instances of its own type.
Your first Java program
Finally, here’s the program. It starts by printing a string, and then the date, using the
Date
class from the Java standard library. Note that an additional style of comment is introduced here: the
//
, which is a comment until the end of the line:
// HelloDate.javaimport java.util.*;
public class HelloDate {public static void main(String[] args) {
System.out.println("Hello, it's: ");System.out.println(new Date());
} }
At the beginning of each program file, you must place the import
statement to bring in any extra classes you’ll need for the code in that file. Note that I say “extra”; that’s because there’s a certain library of classes that are automatically brought into every Java file: java.lang
.
Start up your Web browser and look at the documentation from Sun. (If you haven’t downloaded it from Java.sun.com or otherwise installed the Java documentation, do so now). If you look at the list of the packages, you’ll see all the different class libraries that come with Java.
Select java.lang
. This will bring up a list of all the classes that are part of that library. Since java.lang
is implicitly included in every Java code file, these classes are automatically available. There’s no Date
class listed in java.lang
, which means you must import another library to use that. If you don’t know the library where a particular class is, or if you want to see all of the classes, you can select “Tree” in the Java documentation. Now you can find every single class that comes with Java. Then you can use the browser’s “find” function to find Date
. When you do, you’ll see it listed as java.util.Date
, which lets you know that it’s in the util
library and that you must import
java.util.*
in order to use Date
.
If you go back to the beginning, select java.lang
and then System
; you’ll see that the System
class has several fields, and if you select out
you’ll discover that it’s a static
PrintStream
object. Since it’s static you don’t need to create anything. The out
object is always there and you can just use it. What you can do with this out
object is determined by the type it is: a PrintStream
.
Conveniently, PrintStream
is shown in the description as a hyperlink, so if you click on that you’ll see a list of all the methods you can call for PrintStream
. There are quite a few. For now all we’re interested in is println()
, which in effect means “print what I’m giving you out
to the console and end with a new line.” Thus, in any Java program you write you can say System.out.println("things")
whenever you want to print something to the console.
The name of the class is the same as the name of the file. When you’re creating a stand-alone program such as this one, one of the classes in the file must have the same name as the file. (The compiler complains if you don’t do this.) That class must contain a method called main()
with the signature shown:
public static void main(String[] args) {
The public
keyword means that the method is available to the outside world (described in detail in Chapter 5 [of Thinking in Java]). The argument to main()
is an array of String
objects. The args
won’t be used in this program, but the Java compiler insists that they be there because they hold the arguments invoked on the command line.
The line that prints the date is quite interesting:
System.out.println(new Date());
Consider the argument: a Date
object is being created just to send its value to println()
. As soon as this statement is finished, that Date
is unnecessary, and the garbage collector can come along and get it anytime. We don’t need to worry about cleaning it up.
Compiling and running
To compile and run this program, you must first have a Java programming environment. There are a number of third-party development environments, but in this [article] we will assume that you are using the JDK from Sun, which is free. If you are using another development system, you will need to look in the documentation for that system to determine how to compile and run programs.
Get on the Internet and go to https://java.sun.com. There you will find information and links that will lead you through the process of downloading and installing the JDK for your particular platform.
Once the JDK is installed, and you’ve set up your computer’s path information so that it will find javac
and java
, download and unpack the source code for [Chapter 2 of Thinking in Java] (at ). This will create a subdirectory for each chapter in Thinking in Java. Move to subdirectory c02
and type:
javac HelloDate.java
This command should produce no response. If you get any kind of an error message it means you haven’t installed the JDK properly and you need to investigate those problems.
On the other hand, if you just get your command prompt back, you can type:
java HelloDate
and you’ll get the message and the date as output.
This is the process you can use to compile and run each of the programs in Thinking in Java. However, you will see that the source code also has a file called makefile
in each chapter, and this contains “make” commands for automatically building the files for that chapter. See for details on how to use the makefiles.
Comments and embedded documentation
There are two types of comments in Java. The first is the traditional C-style comment that was inherited by C++. These comments begin with a /*
and continue, possibly across many lines, until a */
. Note that many programmers will begin each line of a continued comment with a *
, so you’ll often see:
/* This is a comment
* that continues
* across lines
*/
Remember, however, that everything inside the /*
and */
is ignored, so there’s no difference in saying:
/* This is a comment that
continues across lines */
The second form of comment comes from C++. It is the single-line comment, which starts at a //
and continues until the end of the line. This type of comment is convenient and commonly used because it’s easy. You don’t need to hunt on the keyboard to find /
and then *
(instead, you just press the same key twice), and you don’t need to close the comment. So you will often see:
// this is a one-line comment
Comment documentation
One of the thoughtful parts of the Java language is that the designers didn’t consider writing code to be the only important activity — they also thought about documenting it. Possibly the biggest problem with documenting code has been maintaining that documentation. If the documentation and the code are separate, it becomes a hassle to change the documentation every time you change the code. The solution seems simple: link the code to the documentation. The easiest way to do this is to put everything in the same file. To complete the picture, however, you need a special comment syntax to mark special documentation, and a tool to extract those comments and put them in a useful form. This is what Java has done.
The tool to extract the comments is called javadoc. It uses some of the technology from the Java compiler to look for special comment tags you put in your programs. It not only extracts the information marked by these tags, but it also pulls out the class name or method name that adjoins the comment. This way you can get away with the minimal amount of work to generate decent program documentation.
The output of javadoc is an HTML file that you can view with your Web browser. This tool allows you to create and maintain a single source file and automatically generate useful documentation. Because of javadoc we have a standard for creating documentation, and it’s easy enough that we can expect or even demand documentation with all Java libraries.
Syntax
All of the javadoc commands occur only within
/**
comments. The comments end with
*/
as usual. There are two primary ways to use javadoc: embed HTML, or use
doc tags.
Doc tags are commands that start with a
@
and are placed at the beginning of a comment line. (A leading
*
, however, is ignored.)
There are three types of comment documentation, which correspond to the element the comment precedes: class, variable, or method. A class comment appears right before the definition of a class; a variable comment appears right in front of the definition of a variable, and a method comment appears right in front of the definition of a method. As a simple example:
/** A class comment */
public class docTest {
/** A variable comment */
public int i;
/** A method comment */
public void f() {}
}
Note that javadoc will process comment documentation for only public
and protected
members. Comments for private
and “friendly” members (see Chapter 5 [of Thinking in Java]) are ignored and you’ll see no output. (However, you can use the -private
flag to include private members as well.) This makes sense, since only public
and protected
members are available outside the file, which is the client programmer’s perspective. However, all class
comments are included in the output.
The output for the above code is an HTML file that has the same standard format as all the rest of the Java documentation, so users will be comfortable with the format and can easily navigate your classes. It’s worth entering the above code, sending it through javadoc, and viewing the resulting HTML file to see the results.
Embedded HTML
Javadoc passes HTML commands through to the generated HTML document. This allows you full use of HTML; however, the primary motive is to let you format code, such as:
/** **System.out.println(new Date());
**/
You can also use HTML just as you would in any other Web document to format the regular text in your descriptions:
/** * You can even insert a list: * <ol> * <li> Item one * <li> Item two * <li> Item three * </ol> */
Note that within the documentation comment, asterisks at the beginning of a line are thrown away by javadoc, along with leading spaces. Javadoc reformats everything so that it conforms to the standard documentation appearance. Don’t use headings such as
<h1>
or<hr>
as embedded HTML because javadoc inserts its own headings and yours will interfere with them.All types of comment documentation — class, variable, and method — can support embedded HTML.
@see: referring to other classes
All three types of comment documentation (class, variable, and method) can contain
@see
tags, which allow you to refer to the documentation in other classes. Javadoc will generate HTML with the@see
tags hyperlinked to the other documentation. The forms are:@see classname @see fully-qualified-classname @see fully-qualified-classname#method-name
Each one adds a hyperlinked “See Also” entry to the generated documentation. Javadoc will not check the hyperlinks you give it to make sure they are valid.
Class documentation tags
Along with embedded HTML and
@see
references, class documentation can include tags for version information and the author’s name. Class documentation can also be used for
interfaces
(see Chapter 8 [in
Thinking in Java
]).
@version
This is of the form:
@version version-information
in which
version-information
is any significant information you see fit to include. When the-version
flag is placed on the javadoc command line, the version information will be called out specially in the generated HTML documentation.@author
This is of the form:
@author author-information
in which
author-information
is, presumably, your name, but it could also include your email address or any other appropriate information. When the-author
flag is placed on the javadoc command line, the author information will be called out specially in the generated HTML documentation.You can have multiple author tags for a list of authors, but they must be placed consecutively. All the author information will be lumped together into a single paragraph in the generated HTML.
@since
This tag allows you to indicate the version of this code that began using a particular feature. You’ll see it appearing in the HTML Java documentation to indicate what version of the JDK is used.
Variable documentation tags
Variable documentation can include only embedded HTML and
@see
references.
Method documentation tags
As well as embedded documentation and
@see
references, methods allow documentation tags for parameters, return values, and exceptions.
@param
This is of the form:
@param parameter-name description
in which
parameter-name
is the identifier in the parameter list, anddescription
is text that can continue on subsequent lines. The description is considered finished when a new documentation tag is encountered. You can have any number of these, presumably one for each parameter.@return
This is of the form:
@return description
in which
description
gives you the meaning of the return value. It can continue on subsequent lines.@throws
Exceptions will be demonstrated in Chapter 10 [of Thinking in Java], but briefly they are objects that can be “thrown” out of a method if that method fails. Although only one exception object can emerge when you call a method, a particular method might produce any number of different types of exceptions, all of which need descriptions. So the form for the exception tag is:
@throws fully-qualified-class-name description
in which
fully-qualified-class-name
gives an unambiguous name of an exception class that’s defined somewhere, anddescription
(which can continue on subsequent lines) tells you why this particular type of exception can emerge from the method call.@deprecated
This is used to tag features that were superseded by an improved feature. The deprecated tag is a suggestion that you no longer use this particular feature, since sometime in the future it is likely to be removed. A method that is marked
@deprecated
causes the compiler to issue a warning if it is used.Documentation example
Here is the first Java program again, this time with documentation comments added:
//: c02:HelloDate.javaimport java.util.*;
/** The first Thinking in Java example program. * Displays a string and today's date. * @author Bruce Eckel * @author www.BruceEckel.com * @version 2.0 */ public class HelloDate { /** Sole entry point to class & application * @param args array of string arguments * @return No return value * @exception exceptions No exceptions thrown */public static void main(String[] args) {
System.out.println("Hello, it's: ");System.out.println(new Date());
} } ///:~The first line of the file uses my own technique of putting a
:
as a special marker for the comment line containing the source file name. That line contains the path information to the file (in this case,c02
indicates Chapter 2) followed by the file name. The last line also finishes with a comment, and this one indicates the end of the source code listing, which allows it to be automatically extracted from the text of [Thinking in Java] and checked with a compiler.Coding style
The unofficial standard in Java is to capitalize the first letter of a class name. If the class name consists of several words, they are run together (that is, you don’t use underscores to separate the names), and the first letter of each embedded word is capitalized, such as:
class AllTheColorsOfTheRainbow { // ...
For almost everything else: methods, fields (member variables), and object reference names, the accepted style is just as it is for classes except that the first letter of the identifier is lowercase. For example:
class AllTheColorsOfTheRainbow { int anIntegerRepresentingColors; void changeTheHueOfTheColor(int newHue) { // ... } // ... }
Of course, you should remember that the user must also type all these long names, and so be merciful.
The Java code you will see in the Sun libraries also follows the placement of open-and-close curly braces that you see used in [Thinking in Java].
Conclusion
In this [article] you have seen enough of Java programming to understand how to write a simple program, and you have gotten an overview of the language and some of its basic ideas. However, the examples so far have all been of the form “do this, then do that, then do something else.” What if you want the program to make choices, such as “if the result of doing this is red, do that; if not, then do something else”? The support in Java for this fundamental programming activity [is covered in Chapter 3 of
Thinking in Java
].