Most computer bookstores today carry more Java programming books than any other language. Even so, many software developers are still unfamiliar with Java as a programming language much less the overall Java environment and all it encompasses. Java's popularity has been fueled by its adoption as a de facto standard for programming Internet and intranet applications at a time when both of these areas are seeing exponential growth. There are a number of different Java environment subsets and APIs; however the Java language is common to all of these. This section starts by discussing the Java language and then provides an overview of the four primary Java environment subsets : Java Card, Embedded Java, Personal Java, and the complete Java environment. While the Java language is very stable in its current state, many of the Java APIs continue to evolve . Our discussion of Java APIs is thus limited to some of the more popular APIs that were defined as of late 1998 when this book was written.
Java was developed in the early 1990s at Sun Microsystems Labs by a team led by James Gosling. At the time, Gosling was part of a team developing a prototype hand-held controller for consumer electronics projects. The team wanted a simple, object-oriented, and familiar language for their project. They started with C++ but after several weeks decided its complexity was excessive, given the goals of their project, internally referred to as the "Green" project. A number of other languages were considered and rejected as alternatives. In the end, Gosling and his team decided to develop a new language which they called "Oak." A working prototype of their first device, the "Star 9," was developed to test the language but never saw its way into production. In late 1993, however, as the world wide web was just starting to become popular, Gosling reconsidered Oak as a language that could be used for Internet applications. By early 1995, Sun had developed a web browser, called WebRunner, capable of executing small Java programs, called applets, that were downloaded when referenced on a web page. In May of 1995, the language and browser were renamed and introduced to the public as the Java language and HotJava browser.
Many early uses of Java were to create "applets," small applications that ran within a web browser (Java also supports the creation of complete stand-alone applications.) More recently, Java has become popular for server side programming leading to the creation of "servlets." A servlet is akin to a Java applet except it executes within a web server, versus an applet which executes within a web browser. Java's component technology, JavaBeans, has also been extended for server-side usage, now called Enterprise JavaBeans.
From its roots as a language for programming the "Star 9," simplicity has always been one of the overriding design goals of the Java language. Java was designed such that it could be programmed without extensive programmer training while staying roughly attuned to current software practices. The fundamental concepts of the Java language can be grasped quickly and programmers can be productive from the start.
The Java language was also designed to be object-oriented from the ground up. After 30 years of research use, object-oriented technology has finally found its way into the programming mainstream. The needs of distributed client-server based systems coincide with the packaged, message-passing paradigms of object-based software. To function within increasingly complex heterogeneous, network-based environments, programming systems must adopt object-oriented concepts. The Java language provides a clean and efficient object-based development environment.
While Java's design makes it perhaps the simplest object-oriented language to use, the combination of "simplicity" with "object-oriented" must be taken carefully . To make the most of an object-oriented language, a developer must start with an object-oriented architecture. One of the reasons object-oriented technology has been so slow to catch on is that creating a good object-oriented architecture for a software project remains a relatively difficult task. Not all software architects have the necessary experience with object-oriented technology to do so. While the Java language simplifies the implementation of object-oriented architectures, it does not necessarily simplify the design of such architectures. We have seen very large Java projects, some over 50,000 lines of code, whose architecture is not at all object-oriented. Without proper training in and understanding of object-oriented design, many C and FORTRAN programmers have developed Java code whose structure bears a strikingly familiar resemblance to programs they may have written in C or FORTRAN.
The simplicity of the Java language owes much to its similarity with C and C++. Even though C++ was rejected as an implementation choice for Gosling's "Star 9", Java's syntax was kept as close as possible to that of C++. At the same time, many of what Gosling and his team felt were the unnecessary complexities of C++ were removed from Java. Making the Java language a minimal "subset" of C++ while simultaneously retaining its "look and feel" means programmers can migrate easily to programming in Java. The Java learning curve can be as low as a couple of days for an experienced C++ programmer.
Java is most often used as an interpreted language. When you "compile" Java source code into a.class file, you are not converting it to a machine specific executable. Instead, compiled Java code is represented in the.class file as architecture neutral "bytecode." The bytecode is simply a compact representation of the original Java syntax that has been checked for static (compile time) errors. To execute the bytecode, it must first be interpreted by a Java Virtual Machine (JVM), which translates the bytecode into the underlying hardware architecture instructions. This process is outlined in Figure 14-1. As an interpreted language, Java's development cycle is much faster than traditional compiled languages. The old edit-compile-link-debug cycle is reduced to just compile and run. When you are satisfied with the application, you can obtain maximum performance by using a built in, just-in-time compiler to compile the Java intermediate code into machine code.
The popularity of Java and the almost universal availability of JVMs for every operating system have led to bytecode cross compilers for other languages. For instance, there are now compilers available that can generate Java.class files from Ada code.
Java applications are portable across multiple platforms. While basic portability is a result of the Java bytecode and Java Virtual Machine design, portability considerations extend down to the language level. For instance, the primitive data types are all well defined. Integer primitives include an 8-bit byte , a 16-bit short , a 32-bit int , and a 64-bit long . There is no ambiguity in the length of integer types as is present in different implementations of C and C++. Real numeric types and their arithmetic operations are defined by the IEEE 754 specification. The char data type is based on sixteen bit Unicode characters . Boolean is also a primitive data type as it is in modern C++, where it is called bool . The preciseness of these primitive data type definitions help to keep Java applications portable across a wide range of platforms.
For most programmers, the Java language presents two major and very obvious departures from C and C++. First, in Java, all pointer manipulation is implicit and programmers do not directly deal with pointers or pointer arithmetic. Secondly, Java's robust run-time system manages memory for the programmer. These two features of Java remove some of the most common C and C++ bugs , memory leaks, and invalid pointers. The Java language completely removes the memory management load from the programmer. C-style pointers, pointer arithmetic, and C memory management functions such as malloc and free do not exist. Automatic garbage collection is an integral part of the Java language. Once you have allocated an object, the Java run-time system keeps track of the object's status and automatically reclaims memory when objects are no longer in use, freeing memory for future use.
The Java language's memory management model is based on objects and references to objects. Because the Java language has no implicit pointers, all references to objects are through symbolic "handles." The Java memory manager keeps track of references to objects. When an object has no more references, the object is a candidate for garbage collection. While the Java language has a "new" operator to allocate space for objects, there is no explicit "free" operator.
One of the common criticisms of previous garbage collection schemes is that they tend to run at inappropriate times, creating poor interactive response or interrupting time-critical server code. In Java, this problem is largely solved by running the garbage collector in a low priority thread. In the 1.1 release of Java, the garbage collection scheme was expanded to include a distributed garbage collector for Java objects created through the Java RMI (remote method invocation) API. Much additional work on garbage collection performance is now being completed and will be incorporated into the 1.2 release of the Java Development Kit (JDK).
Java's built-in garbage collection is just one example of the use of language level multithreading in Java. Chapter 19 of this book describes multithreading in more detail. While multithreading in general is not new, Java is one of the first languages (besides Ada) to support multithreading at the language level. Java's multithreading features make it easy for programmers to directly implement multiple concurrent threads of activity into their program. With Java, there is no longer any reason for a user interface to display an hourglass cursor while it waits for a database query to execute, or for any other asynchronous action, for that matter.
Java is dynamically adaptable and can load new code modules as needed from multiple sources, even across a network. Java's widespread use in networked applications has often raised questions about its security. Java's security beckons from its original design as a language for programming networked applications. Security is built in at the language level. For instance, while pointers are the cause of many common C bugs, they are also the starting point of many viruses and other network security breaches. The lack of arbitrary pointers in the Java language eliminates a whole class of potential security holes. Such language level features form Java's first defense against malicious use. The second security barrier stems from Java's interpreted nature.
Before Java bytecode is interpreted and executed by the Java Virtual Machine, it must first pass through a bytecode verifier. Because the bytecode preserves the structure and syntax of the original code, the bytecode verifier can check for illegal type manipulations, parameters, and other potential security breaches. Thus even a malicious compiler cannot create insecure Java bytecode because this would be caught at run time by the bytecode verifier. The Java run time environment can also implement additional security constraints by limiting which hosts a Java applet downloaded over the network can communicate with.
The original Java release contained a basic set of class libraries, called packages, used by most Java programs. The java.lang package contained the basic language foundation classes. These classes implement wrappers for the primitive types, threads, exceptions, string, and a variety of other fundamental classes. The I/O package implemented basic input and output classes. The AWT class library (Abstract Windowing Toolkit) implemented basic functionality found in graphical user interfaces such as buttons , scrollbars, fonts, color , and events. A utility package provided a variety of encoder and decoder techniques, date and time, hash table, vector, and stack classes. The network interface class library extended the functionality of the I/O class library with network communication classes such as sockets.
These class libraries, plus others defined since, have become know as the "core" Java APIs. Any full Java implementation must implement the complete set of core Java APIs. Besides the core APIs, a number of extended Java APIs have also been defined, such as the Java3D API. Java implementations have the option of supporting the extended APIs. Over time, some extended APIs have moved into the core set and programmers should check the documentation on the http://java.sun.com/products/ web page for the latest status of any API.
Besides being extended with new APIs, several "subsets" of the Java core APIs have been defined for specific application environments. These include JavaCard for smart cards, Embedded Java for embedded devices, and Personal Java for devices such as PDAs. Each of these Java environments supports the full Java language with the difference being simply in the set of class libraries that are guaranteed to exist in the implementation.