This chapter lays the foundation for learning Java. It provides an overview of the Java Developer's Kit (JDK), the Java language, and the Java API from the perspective of a software developer.
You will download and install the JDK, and take a quick tour of its contents. You will then learn the features of the Java language that set it apart from its predecessors, C++ and C. You will be introduced to the Java API and learn how Java programs are built from and extend the API. So grab yourself a cup of you-know-what and let's begin.
Java is distributed as the JDK. It is available from Sun's Java home page at http://java.sun.com or http://www.javasoft.com. Figure 2.1 shows the Java home page. From there, you can click on the Products and Services link to download a version of the JDK for your computer and operating system.
Figure 2.1 : The Java home page.
Figures 2.2 and 2.3 show some of the pages you are likely to encounter on the way to finding the JDK that is right for you. Sun makes earlier versions of the software available for download. Always download the latest version that is compatible with your hardware and operating system. The examples in this book use JDK 1.0. As long as you are using this version, or later, you will be able to work through these examples. I will be running Java under Windows 95. If you are using another operating system, follow the installation instructions for that operating system.
Figure 2.2 : JacaSoft products and services.
Figure 2.3 : The binary code license.
The JDK is distributed as a self-extracting executable file. Move it to a temporary directory and then execute it. It will extract itself and set up its directory structure-a single top-level directory, java, with several subdirectories. Move the java directory tree from your temporary directory to a permanent home. I suggest c:\java. That's where I keep my JDK.
Now that you have the latest version of the JDK installed on your computer, you're probably wondering what's inside. Let's take a quick look.
Figure 2.4 shows the contents of the java directory. It consists of four subdirectories and four files, which are
Figure 2.4 : The java directory.
The java\bin directory (see Figure 2.5) contains all the executable programs and dynamic link libraries (DLLs) for the JDK toolset. The major software development tools provided with the JDK are the compiler (javac), interpreter (java), debugger (jdb), disassembler (javap), documentation generator (javadoc), applet viewer (appletviewer), and C header file tool (javah). We're going to examine each of these tools in Chapter 3, "Using the Java Developer's Kit." If you absolutely can't wait to get your hands on Java, go ahead to Chapter 3, but make sure you come back and browse through the rest of this overview.
Figure 2.5 : The Java toolset.
The java\demo directory, shown in Figure 2.6, contains lots of nifty demos that highlight Java's finer features. I'll show you how to run these demos in Chapter 3. If you can't control the urge to run some of the demos now, click on the HTML files in the demo folders. Be sure to use a Java-enabled browser, such as Netscape 2.0.
Figure 2.6 : Java demos.
The java\include directory (see Figure 2.7) contains C header files that are used to write C programs, called native methods, that extend the Java API. We won't be getting involved with native methods until Chapter 38, "Creating Native Methods."
Figure 2.7 : C header files for writing native methods.
Finally, the java\lib directory, shown in Figure 2.8, contains the class library files for the Java API. The file classes.zip contains all the compiled library files. The Java compiler and interpreter are able to work with the library files, in compressed form, which saves you some disk space and provides more efficient operation.
Figure 2.8 : Class library files.
Now that you know a little bit about what's inside the JDK, let's quickly cover the Java language and application programming interface so we can get started using the JDK tools.
The Java language is a remarkable example of programming language evolution. Java builds on the familiar and useful features of C++ while removing its complex, dangerous, and superfluous elements. The result is a language that is safer, simpler, and easier to use. The following subsections describe Java in contrast to C++. Appendix B, "Differences Between Java and C++," provides a detailed identification of the differences between the two languages.
If you have ever programmed in C++, you will find Java's appeal to be instantaneous. Since Java's syntax mirrors that of C++, you will be able to write Java programs within minutes. Your first programs will come quickly and easily, with very little programming overhead.
You will have the feeling that you have eliminated a lot of clutter from your programs-and you will have. All the cryptic header files and preprocessor statements of C and C++ are gone. All the arcane #define statements and typedefs have been taken away. You will no longer have to delve through several levels of header files to correctly reference API calls. And no one will have to suffer to figure out how to use your software.
Java programs simply import the software packages they need. These packages may be in another directory, on another drive, or on a machine on the other side of the Internet. The Java compiler and interpreter figure out what objects are referenced and supply the necessary linkage.
If you think C++ is an object-oriented programming language, you are in for a big surprise. After using Java to write a few programs, you'll get a better feeling for what object-oriented software is all about. I know I did.
Java deals with classes and objects, pure and simple. They aren't just more data structures that are available to the programmer-they are the basis for the entire programming language.
In C++, you can declare a class, but you don't have to. You can declare a structure or a union instead. You can declare a whole bunch of loosely associated variables and use them with C-style functions. In Java, classes and objects are at the center of the language. Everything else revolves around them. You can't declare functions and procedures. They don't exist. You can't use structures, unions, or typedefs. They're gone, too. You either use classes and objects or you don't use Java. It's that simple.
Java provides all the luxuries of object-oriented programming: class hierarchy, inheritance, encapsulation, and polymorphism-in a context that is truly useful and efficient. If you are new to object-oriented software, you can find a complete introduction to these topics is provided in Chapter 5, "Classes and Objects." The main reason for developing object-oriented software, beside clarity and simplicity, is the desperate hope that somehow the objects you develop will be reused. Java not only encourages software reuse, it demands it. To write any sort of Java program, no matter how simple, you must build on the classes and methods of the Java API.
Once you have begun developing software in Java, you have two choices:
With Java, the temptation to start from scratch is no longer appealing. Java's object-oriented structure forces you to develop more useful, more tailorable, and much simpler software the first time around.
Java is safer to use than C++ because it keeps you from doing the things that you do badly, while making it easier to do the things that you do well.
Java won't automatically convert data types. You have to explicitly convert from one class to another. C++, under the most undesirable conditions, will automatically convert one type to another. It has all the flexibility of assembly code. Java doesn't assume that you know what you are doing. It makes sure that you do.
C++ pointers don't exist in Java. You can no longer access objects indirectly or by chance. You don't need to. You declare objects and reference those objects directly. Complex pointer arithmetic is avoided. If you need an indexed set of objects, you can use an array of objects. The concept of "the address of an object" is eliminated from the programming model, and another assembly language dinosaur is laid to rest. As a result, it becomes much easier to do things correctly in Java.
Java's reliability extends beyond the language level to the compiler and the runtime system. Compile-time checks identify many programming errors that go undetected in other programming languages. These checks go beyond syntactic checking to ensure that statements are semantically correct.
Runtime checks are also more extensive and effective. Remember your teacher or mom telling you to "Check your work twice to make sure it's right"? The Java linker understands class types and performs compiler-level type checking, adding redundancy to reliability. It also performs bounds checking and eliminates indirect object access, even under error conditions.
If you gave a skilled hacker a program written in C or C++ and told him to find any security flaws, there are half a dozen things that he would immediately look for: gaining access to the operating system, causing an unexpected return of control, overwriting critical memory areas, acquiring the ability to spoof or modify other programs, browsing for security information, and gaining unauthorized access to the file system.
Why is C or C++ more vulnerable than Java? When a programmer develops software, he or she usually focuses on how to get the software to work correctly and efficiently. C and C++ do not constrain the programmer from meeting these goals and provide a number of flexible features that enable the programmer to meet his end. The hacker is also able to take advantage of these features and use them in ways that weren't originally intended, causing the undesirable consequences identified in the previous paragraph. In short, C and C++ provide a great offense, but no defense. Java, on the other hand, is defensive by nature. Every time a Java-enabled browser downloads a compiled Java class, such as an applet, it runs the risk of running Trojan horse code. Because of this ever-present threat, it subjects the code to a series of checks that ensure that it is correct and secure.
The Java runtime system is designed to enforce a security policy that prevents execution of malicious code. It does this by remembering how objects are stored in memory and enforcing correct and secure access to those objects according to its security rules. It performs bytecode verification by passing compiled classes through a simple theorem prover that either proves that the code is secure or prevents the code from being loaded and executed. The class is Java's basic execution unit and security is implemented at the class level.
The Java runtime system also segregates software according to its origin. Classes from the local system are processed separately from those of other systems. This prevents remote systems from replacing local system software with code that is less trustworthy.
Java-enabled browsers, such as HotJava, allow the user to control the accesses that Java software may make of the local system. When a Java applet needs permission to access local resources, such as files, a security dialog box is presented to the user, requesting explicit user permission. This "Mother may I?" approach ensures that the user always has the final say in the security of his system.
Java security is covered in detail in Chapter 39, "Java Security."
Java, like Ada, and unlike other languages, provides built-in language support for multithreading. Multithreading allows more than one thread of execution to take place within a single program. This allows your program to do many things at once: make the Duke dance, play his favorite tune, and interact with the user, seemingly all at the same time. Multithreading is an important asset because it allows the programmer to write programs as independent threads, rather than as a convoluted gaggle of intertwined activities. Multithreading also allows Java to use idle CPU time to perform necessary garbage collection and general system maintenance, enabling these functions to be performed with less impact on program performance.
Writing multithreaded programs is like dating several people concurrently. Everything works fine until the threads start to interact with each other in unexpected ways. Java provides the support necessary to make multithreading work safely and correctly. Java supports multithreading by providing synchronization capabilities that ensure that threads share information and execution time in a way that is thread safe. These capabilities are illustrated with several programming examples in Chapter 8, "Multithreading."
While it is true that compiled code will almost always run more quickly than interpreted code, it is also true that interpreted code can usually be developed and fielded more inexpensively, more quickly, and in a more flexible manner. It is also usually much more portable.
Java, in order to be a truly platform-independent programming language, must be interpreted. It does not run as fast as compiled native code, but it doesn't run much slower, either. Chapter 36, "The Java Source Code," provides some Java performance benchmarks. For the cases where execution in native machine code is absolutely essential, work is underway to translate Java bytecode into machine code as it is loaded.
The advantages of being interpreted outweigh any performance impacts. Because Java is interpreted, it is much more portable. If an operating system can run the Java interpreter and support the Java API, then it can faithfully run all Java programs.
Interpreted programs are much more easily kept up-to-date. You don't have to recompile them for every change. In Java, recompilation is automatic. The interpreter detects the fact that a program's bytecode file is out-of-date with respect to its source code file and recompiles it as it is loaded.
Because of Java's interpreted nature, linking is also more powerful and flexible. Java's runtime system supports dynamic linking between local class files and those that are downloaded from across the Internet. This feature provides the basis for Web programming.
Java is also evolving beyond the Web and becoming a key component in distributed application development. Sun's release of the NEO and JOE products emphasizes Java's importance to distributed object-based software development. Several other vendors have introduced products that enable Java to be integrated into the Common Object Request Broker Architecture (CORBA), which is the framework for distributed object communication.
The Java API is what makes Java attractive and useful. It consists of a set of packages that are distributed with the JDK as class libraries. These packages provide a common interface for developing Java programs on all Java platforms. The Java API furnishes all the capabilities needed to develop console programs, window programs, client and server networking software, applets, and other applications. It is the difference that takes Java from being a really good programming language to making it a very powerful and efficient programming environment.
The Java API consists of eight major development packages and a supporting debug package, as shown in Figure 2.9. Packages are collections of related objects. For example, there are separate packages for developing window programs, applets, and networking software.
Figure 2.9 : The organization of the Java API.
Java packages contain classes, interfaces, and exceptions, as illustrated in Figure 2.10.
Figure 2.10 : How Java packages are organized.
Classes form the basis for object-oriented software development in Java. They contain variables and methods. Variables are data containers. Methods implement operations on the class and its variables. For example, there is a class in the java.awt package called Rectangle. It consists of variables that specify the position and dimensions of a rectangle, and methods, such as move and resize, that enable operations to be performed on rectangles. Chapter 5 provides an introduction to classes.
Interfaces are collections of related methods. An example of an interface is the DataInput interfacee of the java.io package. It specifies a collection of methods that must be defined for a class to implement the DataInput interface. Exceptions are events that alter the normal course of program execution. Chapter 6, "Interfaces," introduces interfaces, and Chapter 7, "Exceptions," covers exceptions.
The Java API is used to develop Java programs. Figure 2.11 summarizes this process.
Figure 2.11 : Developing software using the Java API.
You write your Java programs using the Java API as a template and building block. You use the API to construct objects that are instances of API classes, implement API interfaces, and respond to API exceptions. These objects are used by your application program, which is itself an instance of a Java API class. Think of your program as a collection of objects that work together to support a common set of operations.
You can also create your own classes, interfaces, and exceptions, building on those that are defined in the API. You can collect them into custom packages that are integrated within and extend the Java API. These API extensions can then be used to develop other programs or even more sophisticated packages and API extensions.
This building-block approach to software development is the essence of object-oriented programming and software reuse. The Java API supports platform-independent software reuse by providing a powerful set of components from which to start.
In order to learn Java, you have to learn the Java language, learn to use the Java API, and learn how to use the JDK toolset. In this chapter, you have explored the JDK software and learned the tools it contains. In Chapter 3 you will learn how to operate those tools.
This chapter highlights the key features of the Java language. In Part II, "Programming in Java," you will focus on learning Java's syntax and application by developing a series of sample programs. These programs will also familiarize you with using the JDK tools and relevant parts of the Java API.
You have been introduced to the Java API and shown how it is used to construct Java programs. In Part III, "Using the Java API," you will focus on learning the Java API. You will do this by studying the components contained in the API packages and using these components to build Java programs.
By the time you have finished Part III, you will be a competent Java programmer. The rest of the book will show you how to extend your skills by focusing on specific areas of Java software development.