The Genius of Java

In this first chapter from the book The Art of Java by Herbert Schildt and James Holmes, the authors highlight certain features of the Java programming language that separate it from other languages. The chapter also covers: memory management, Java’s built-in support for multithreading, Java’s approach to exceptions as compared to C++, Java’s support of polymorphism, and how bytecode enables Java’s “Write Once, Run Anywhere” ability and provides security. (ISBN 0-07-222971-3, McGraw-Hill/Osborne, 2003).

The Art of JavaHistory in the large view is mirrored on a smaller scale by the history of programming. Just as the first societies sprang from simple beginnings, so too did programming. Just as great civilizations rose, flourished, and declined, so too have programming languages. Yet, throughout the rise and fall of nations, mankind progressed. In similar fashion, as each new language replaced its predecessor, the ongoing refinement of programming proceeded. Throughout history, there have been pivotal events, such as the fall of the Roman Empire, the invasion of Britain in 1066, or the first nuclear explosion, which transformed the world. The same is true for programming languages, albeit on a smaller scale. For example, the invention of FORTRAN changed forever the way that computers would be programmed. Another such pivotal event was the creation of Java.

Java is the milestone that marks the beginning of programming’s Internet age. Designed expressly for creating applications that would run anywhere there was an Internet connection, Java’s “write once, run anywhere” philosophy defined the new programming paradigm. What James Gosling, et al., initially saw as the solution to a relatively small class of problems became a force that defined the programming landscape for the next generation of programmers. Java so fundamentally altered how we thought about programming that the history of computer languages can be divided into two eras: Before Java and After Java.

Programmers in the Before Java world created programs that ran on a stand-alone machine. Programmers in the After Java world create programs for a highly distributed, networked environment. No longer does a programmer think in terms of a single computer. Instead, the network is the computer, and today we programmers think in terms of servers, clients, and hosts.

Although the development of Java was driven by the needs of the Internet, Java is not simply an “Internet language.” Rather, it is a full-featured, general-purpose programming language designed for the modern, networked world. This means that Java is suitable for nearly all types of programming. Although sometimes overshadowed by its networking capabilities, Java also incorporated many innovative features that advanced the art of programming. These innovations still ripple through computing today. For example, several aspects of C# are modeled on elements first mainstreamed by Java.

Throughout this book we will demonstrate the wide-ranging capabilities of Java by applying it to a varied cross section of applications. Some of the applications demonstrate the power of the language, independent of its networking attributes. We call these “pure code” examples because they show the expressiveness of the Java syntax and design philosophy. Others illustrate the ease with which sophisticated networked programs can be developed using the Java language and its API classes. Collectively, the applications show the power and scope of Java.

Before we begin our exploration of Java, we will take some time in this first chapter to point out several of the features that make it a remarkable programming language. These are features that reflect what we call the “genius of Java.”

Remember: this is chapter one of The Art of Java, by Herbert Schildt and James Holmes (McGraw-Hill/Osborne, ISBN 0-07-222971-3, 2003). Check it out at your favorite bookstore today.  
Buy this book now.

{mospagebreak title=Simple Types and Objects – The Right Balance}

One of the greatest challenges facing a designer of an object-oriented computer language is how to handle the object vs. simple type dilemma. Here is the problem. From a conceptually pure point of view, every data type should be an object, and every type should descend from a universal parent object. This makes all data types work the same, with each sharing a common set of inherited traits. The trouble is that making the simple types, such as int or double, into objects can cause a decrease in performance because of the added overhead incurred by the object mechanism. Because the simple types are often used to control loops and conditional statements, this extra overhead would have wide-ranging, negative consequences. The trick is to find the right balance between the “everything is an object” desire and the “performance counts” reality.

Java solves the object, simple type problem in an elegant manner. First, it defines eight simple types: byte, short, int, long, char, float, double, and boolean. These types translate directly into binary values. Thus, a variable of type int can be operated on directly by the CPU without any added overhead. The simple types in Java are as fast and efficient as they are in any other language. Therefore, a for loop controlled by an int runs at full speed, unencumbered by any object-related issues.

Aside from the simple types, all other types in Java are objects that inherit the universal superclass Object. Thus, all other types share inherited functionality. For example, all objects have a toString( ) method because toString( ) is a method defined by Object.

Because simple types are not objects, Java is free to treat objects and nonobjects a bit differently. This is where the real genius of Java’s design becomes apparent. In Java, all objects are accessed through a reference, rather than directly, as is the case for the simple types. Thus, your program never operates on an object directly. By using this approach, several benefits follow, not the least of which is garbage collection. Because all objects are accessed via a reference, garbage collection can be efficiently implemented: when there is no reference to an object, it can be recycled. Another benefit is that an object reference of type Object can refer to any object in the system.

Of course, accessing every object through a reference adds overhead. The reason is that a reference is, essentially, an address (i.e., a pointer). Thus, every object access occurs indirectly, through that address. Although modern CPUs handle indirect accesses efficiently, indirect accesses are not as fast as operating directly on the data itself, as is the case with the simple types.

Although the simple types are quite efficient, there are still times when an object equivalent of a simple type is needed. For example, you might want to create a list of integers at runtime and have those integers recycled (garbage collected) when no longer needed. To handle this type of situation, Java defines the simple type wrappers, such as Integer and Double. These wrappers enable the simple types to participate in the object hierarchy when necessary.

Java’s resolution to the object vs. simple type problem captures the right balance. It allows efficient programs to be written, but at the same time it allows the object model to be implemented without concern about negatively impacting the performance of the simple types.

Remember: this is chapter one of The Art of Java, by Herbert Schildt and James Holmes (McGraw-Hill/Osborne, ISBN 0-07-222971-3, 2003). Check it out at your favorite bookstore today.  
Buy this book now.

{mospagebreak title=Memory Management Through Garbage Collection}

Garbage collection as a memory management technique has been around a long time, but in Java it took on a new life. In languages such as C++, memory must be managed manually, with the programmer explicitly releasing unused objects. This is a source of problems because it is common to forget to release a resource after it is no longer needed, or to release a resource that is still being used. Java prevents these problems by managing memory for you. This can be done in an efficient manner because all objects in Java are accessed through a reference. Thus, when the garbage collector finds an object to which there is no reference, it knows that the object is unused and can be recycled. Had Java allowed objects to be operated on directly (in a fashion similar to the simple types), then such an efficient means of garbage collection would not have been possible.

Java’s use of garbage collection reflects the philosophy of Java in general. The Java designers took great pains to create a language that would prevent some of the problems typical of other programming languages. By using garbage collection, it is not possible for the programmer to forget to release a resource or to mistakenly release a resource that is still in use. Thus, garbage collection heads off an entire class of problems.

Remember: this is chapter one of The Art of Java, by Herbert Schildt and James Holmes (McGraw-Hill/Osborne, ISBN 0-07-222971-3, 2003). Check it out at your favorite bookstore today.  
Buy this book now.

{mospagebreak title=A Wonderfully Simple Multithreading Model}

Java’s designers saw early on that the future of programming involved language-level support for multithreaded multitasking. Recall that there are two basic types of multitasking: process-based and thread-based. In process-based multitasking, the smallest schedulable unit is a process.

A process is, essentially, a program that is executing. Thus, process-based multitasking is the feature that allows a computer to run two or more programs at the same time. In thread-based multitasking, a thread is the smallest schedulable unit. A thread defines a path of execution within a program. Thus, one process can contain two or more threads of execution, and a multithreaded program can have two or more parts of itself executing simultaneously.

Although process-based multitasking is mostly a function of the operating system, thread-based multitasking benefits greatly from language-level support. For example, C++, which has no built-in support for multithreaded programming, must rely completely on operating system functions to handle multithreading. This means that to create, begin, synchronize, and end threads requires numerous calls to the operating system. As a result, multithreaded code in C++ is not portable. It also makes multithreading unwieldy in a C++ program.

Because Java builds in support for multithreading, much of what must be done manually in other languages is handled automatically in Java. One of the most elegant parts of Java’s multithreading model is its approach to synchronization. Synchronization is based on two innovative features. First, in Java, all objects have built-in monitors that act as mutually exclusive locks. Only one thread can own a monitor at a given time. The locking feature is turned on by modifying a method with the synchronized keyword. When a synchronized method is called, the object is locked and other threads wanting access to the object must wait.

The second part of Java’s support of synchronization is found in Object, the universal superclass of all other classes. Object declares the following synchronization methods: wait( ), notify( ), and notifyAll( ). These methods support interthread communication. Thus, all objects have built-in support for interthread communication. When used in combination with a synchronized method, these methods allow a high-level of control over the way threads interact.

By making multithreading an easy-to-use, built-in part of the language, Java changed the way that we thought about the fundamental architecture of a program. Before Java, most programmers conceptualized programs as monolithic structures that had a single path of execution. After Java, we think of programs as collections of parallel tasks that interact with one another. This change to parallelism has had a wide-ranging effect on computing, but perhaps its greatest impact has been to facilitate the use of software components.

Remember: this is chapter one of The Art of Java, by Herbert Schildt and James Holmes (McGraw-Hill/Osborne, ISBN 0-07-222971-3, 2003). Check it out at your favorite bookstore today.  
Buy this book now.

{mospagebreak title=Fully Integrated Exceptions}

The conceptual framework for exceptions pre-dates Java. So, too, does the incorporation of exceptions into other programming languages. For instance, exceptions were added to C++ several years before Java was created. What makes Java’s approach to exceptions important is that they were part of the original design. They were not added after the fact. Exceptions are fully integrated into Java and form one of its foundational features.

A key aspect of Java’s exception mechanism is that its use is not optional. In Java, handling errors through the use of exceptions is the rule. This differs from C++, for example, in which exceptions are supported but are not fully integrated into the entire programming environment.

Consider the common situations of opening or reading from a file. In Java, when an error occurs during one of these operations, an exception is thrown. In C++, the methods that open or read from a file report an error by returning a special error code. Because C++ did not originally support exceptions, its library still relies on error return codes rather than exceptions, and your program must constantly check for possible errors manually. In Java, you simply wrap the file-handling code within a try/catch block. Any errors will automatically be caught.

Remember: this is chapter one of The Art of Java, by Herbert Schildt and James Holmes (McGraw-Hill/Osborne, ISBN 0-07-222971-3, 2003). Check it out at your favorite bookstore today.  
Buy this book now.

{mospagebreak title=Streamlined Support for Polymorphism}

Polymorphism is the attribute of object-oriented programming that allows one interface to be used by multiple methods. Java supports polymorphism with a variety of features, but two stand out. The first is the fact that every method (other than one marked final) can be overridden by a subclass. The second is the interface keyword. Let’s examine each a bit closer.

Because methods in a superclass can be overridden by those in a derived class, it’s trivially easy to create class hierarchies in which subclasses are specializations of the superclass. Recall that a superclass reference can be used to refer to any subclass of that superclass. Furthermore, a call to a method on a subclass object, through a superclass reference, automatically executes the overridden version of that method. Thus, a superclass can define the form of an object and provide a default implementation. This default implementation can then be customized by a subclass to better meet the needs of a specific situation. Thus, the same interface, in this case the one defined by the superclass, can be the basis for multiple implementations.

Of course, Java takes the concept of “one interface, multiple methods” a step further. It defines the interface keyword, which allows you to fully separate a class’ methods from their implementations. Although an interface is abstract, you can still declare a reference of an interface type. This reference can then be used to refer to any object that implements the interface. This is a very powerful concept because it streamlines and facilitates the use of polymorphism. As long as a class implements an interface, an object of that class can be used by any code that requires the functionality provided by the interface. For example, assuming an interface called MyIF, consider the following method:

void myMeth(MyIF ob) {
// ...


Any object that implements the MyIF interface can be passed to myMeth( ). It doesn’t matter what other capabilities (if any) that object has. If it implements MyIF, then myMeth( ) can operate on it.

Remember: this is chapter one of The Art of Java, by Herbert Schildt and James Holmes (McGraw-Hill/Osborne, ISBN 0-07-222971-3, 2003). Check it out at your favorite bookstore today.  
Buy this book now.

{mospagebreak title=Portability and Security Through Bytecode}

Despite all of its powerful features, Java may not have been much more than a footnote in programming history if it were not for one important but nearly transparent part of the language: bytecode. As all Java programmers know, the output of the Java compiler is not machine code that can be directly executed by a CPU. Instead, it is a highly optimized set of portable instructions, called bytecode, which are executed by the Java Virtual Machine (JVM). The original JVM was simply an interpreter for bytecode. Today, the JVM also applies on-the-fly compilation of bytecode into executable code. Whatever process is used to execute bytecode, its advantages are enormously important to the success of Java.

The first advantage is portability. By compiling a Java program into bytecode, it can be executed on any computer, with any type of CPU (and operating system) as long as a JVM is available for that environment. In other words, once a JVM has been implemented for a specific environment, any Java program can run in that environment. It is not necessary to create a separate executable for each different environment. The same bytecode can be run in all environments. Therefore, through the use of bytecode, Java offered programmers the ability “to write once, run anywhere.”

The second advantage achieved by bytecode is security. Because execution of the bytecode is under the control of the JVM, the JVM can prevent a Java program from performing malicious acts that affect the host machine. The ability to ensure the security of the host computer was crucial to the success of Java because it enabled the creation of the applet. Because an applet is a small, dynamically downloaded program that comes across the Internet, some mechanism to prevent applets from doing harm was necessary. The combination of bytecode and the JVM provided the mechanism by which applets could be downloaded safely. Frankly, without bytecode, the Web would be a much different place today.

Remember: this is chapter one of The Art of Java, by Herbert Schildt and James Holmes (McGraw-Hill/Osborne, ISBN 0-07-222971-3, 2003). Check it out at your favorite bookstore today.  
Buy this book now.

{mospagebreak title=The Richness of the Java API}

Conceptually, computer languages consist of two parts. The first is the language proper, defined by the keywords and syntax. The second is the standard library, which contains a set of classes, interfaces, and methods that are available to the programmer. Although all of the major languages today provide large libraries, the one defined by Java stands out because of the richness and diversity it offers to the programmer. When Java was first created, its library contained a set of core packages, such as java.lang,, and With each new release of Java, classes and packages have been added. Today, Java gives the programmer access to a truly amazing array of functionality.

Since the beginning, one of the key elements that differentiated the Java library from that provided by other languages was its support for networking. At the time of Java’s creation, other languages, such as C++, did not (and still do not) provide standard library elements that handle networking. By providing classes that easily handled connecting to and using the Internet, Java helped spark the Internet revolution. With Java, the Internet was open to all programmers, not just those that specialized in networking. The functionality in transformed computing.

Another key package of the core Java library is java.awt, which supports the Abstract Window Toolkit (AWT). The AWT enables the programmer to create portable, GUI-based code. That is, by using the AWT classes, it is possible to create a windowed application that uses the various standard GUI elements, such as scroll bars, check boxes, and radio buttons. Because of the AWT, it is possible to create a GUI application that can run in any environment that supports the Java Virtual Machine. This level of GUI portability was unknown prior to Java.

Java’s inclusion of the AWT revolutionized the way programmers thought about the application environment. Before Java, GUI-based programs had to be specifically written for their execution environments. This meant that a Windows program, for example, would need to be substantially recoded to run in an Apple computer. After Java, a programmer could write one program that would execute in both environments. By defining a portable GUI, Java unified the programming environment.

In later years, a lightweight alternative to the AWT was added to Java: Swing. The Swing components are contained in javax.swing and its subpackages. Swing offers the programmer a rich set of GUI components that have enhanced portability. As many of the examples in this book show, both the AWT and Swing give the programmer the ability to produce highly effective, portable GUI-based applications.

Today, the Java library has grown substantially from its initial core. Each new release of Java has been accompanied with additional library support. New packages have been added, and new functionality has been added to existing packages. The Java library has been in a constant state of transformation because it has been responsive to the rapidly evolving computing environment. This ability to adapt and change in short order is part of the genius of Java.

Remember: this is chapter one of The Art of Java, by Herbert Schildt and James Holmes (McGraw-Hill/Osborne, ISBN 0-07-222971-3, 2003). Check it out at your favorite bookstore today.  
Buy this book now.

{mospagebreak title=The Applet, and The Continuing Revolution}

The Applet

Although taken for granted today, the applet is one of Java’s more revolutionary features because it allowed the creation of portable, dynamically downloaded programs that could safely execute within the confines of a browser. In the Before Java world, executable content was always suspect because of the harm a malicious program could do to the client’s computer. Furthermore, code compiled for one type of CPU and operating system would not work on another type of system. Because there are a wide variety of CPUs and operating systems connected to the Internet, it was not practical to create a unique version of a program for all environments. The Java applet provided a solution to both problems. With the applet, the Web programmer was able to easily add dynamic content to the rather static world of HTML. Java applets made the Web move, and there was no going back.

In addition to changing the way that we thought about Web content, the applet had another important effect—or perhaps side effect. It helped propel the move to component software. Because applets are small programs, they usually represent small units of functionality, which is the same thing that a software component does. Once we began to think in terms of applets, it was a small step to Beans, and beyond. Today, the component-oriented architecture, in which an application consists of an interacting set of components, has largely replaced the monolithic model that typified the past.

The Continuing Revolution

There is one more aspect of Java that reflects its genius, although it isn’t actually part of the language. Java brought with it a culture of innovation that welcomed new ideas, and a process by which these new ideas could be rapidly assimilated. Whereas many other computer languages change slowly, Java is constantly evolving and adapting. Furthermore, this process is open to the entire Java community through the Java Community Process (JCP). The JCP offers a mechanism by which users of Java help influence the future direction of the language, tools, and associated technologies. Thus, the people that actually use the language have input into its ongoing development.

From the start, Java revolutionized programming—and the revolution hasn’t stopped. Java is still at the forefront of computer language development. It is a language that has earned a lasting place in the history of computing.

Remember: this is chapter one of The Art of Java, by Herbert Schildt and James Holmes (McGraw-Hill/Osborne, ISBN 0-07-222971-3, 2003). Check it out at your favorite bookstore today.  
Buy this book now.

Google+ Comments

Google+ Comments