The Internet is the place where the little dynamo called Java was first set free. Now thousands of programmers, Internet developers, Web publishers, and software houses around the world are racing to learn everything they can about this tool for revolutionizing the Internet and the way programming is done. Anyone not connected to the Internet may be wondering what all the fuss is about. After all, C++ was supposed to revolutionize the software industry too, yet as you will soon learn, the major difference between C++ and Java is that Java delivers on all its promises. Java promises to bring revolutionary changes to the software industry and to the Internet; this chapter tells you how.
For Internet developers, programmers, and Web publishers, now is the time to get in on the inside track to Java. Throughout much of 1995, Java was in Alpha and Beta testing. During this time, Java development was limited to the Solaris and Windows NT environments, but all this quickly changed as word about Java spread like wildfire. In January 1996, Sun Microsystems officially released Java 1.0, and you can now obtain free developers kits for every major operating system, including Solaris, AIX, Windows 95/NT, OS/2, and Macintosh.
For nonprogrammers, using a programming language such as Java may seem impossible, yet nothing could be further from the truth. If you can create an HTML, an SGML, or a VRML document, you should be able to create Java-powered documents and applications as well. You will find that Java is easy to learn and use because it eliminates or automates many of the problem areas of earlier programming languages.
JavaSoft, an operating company of Sun Microsystems, spent years developing a high-powered programming language for the '90s and beyond. Java delivers on this promise by being the most robust, easy-to-use, and versatile programming language available today. It includes the best aspects of earlier programming languages such as C and C++, allows you to create powerful applications, has features such as built-in multimedia capabilities that make creating multimedia presentations easier than ever, and leaves out those things we all hated about C and C++ like multiple inheritance, operator overloading, and pointers.
The best news about Java is that it is object oriented and architecture neutral. The promise of object-oriented programming (OOP) is the capability to reuse code. But, as C++ programmers will tell you (and if you are a C++ programmer, you probably already know this), good intentions do not mean a whole lot when it comes to reuse of C++ code. With Java, on the other hand, you can realize the benefits of code reuse immediately. You no longer have to develop separate applications fordifferent platforms. With Java, you can develop a single application that is immediately usable on multiple platforms. Imagine the countless hours you will save by being able to develop a singleapplication usable on Windows, UNIX, and Macintosh systems.
Considering that large corporations can use Java's platform independence to save millions of dollars on a single project, there is little wonder that Java is a buzzword in the software and Internet technology industries. Java has captivated much more than the imaginations of the techies. Companies from every business sector you can imagine-from finance to shipping-are examining ways to use Java.
For the entrepreneur or individual programmer, Java's platform independence allows you to develop powerful applications for operating systems you may never have worked with. This means that if you own a software-development or Internet-related business, whether it is a one-person operation or a conglomerate, you will be able to reach new customers and new markets. In an age when everyone is looking at the bottom line, a technology that allows you to sell more, do more, and reach larger audiences (potentially everyone who owns a computer) is certainly something worth investigating.
Furthermore, by allowing you to use the programming environment you are the most comfortable with, Java empowers you, the programmer. This is true whether you have limited technical skills or expert knowledge of computers. If you have a working knowledge of another programming language, you will find that Java is surprisingly easy to learn.
The developers of Java thought very carefully about the structure of their new language and by no mere coincidence modeled Java after C and C++. C is a favorite language for programmers doing procedural programming. C++ is a favorite language for programmers writing object-oriented programs. C and C++ have user and developer bases many times greater than their nearest competitors and could, in fact, be considered to be their own best competition.
Therefore, to ensure that Java is easy to understand and use, Java is modeled after C and C++. Java also borrows extensions from Objective C. These extensions allow for extremely dynamic method resolution. This makes it very easy for current C, Objective C, and C++ developers to transition to Java.
Any programmer who has ever had problems with pointers and memory management should rush to embrace Java with open arms. Java gets rid of pointers, automatically manages memory for you, and even features a garbage-collection routine that runs in the background.
In distributed environments, such as the World Wide Web, strict security mechanisms are essential-businesses simply cannot risk compromising their systems. The developers of the Java programming language knew this. They developed Java to be the most secure programming environment you will find anywhere. Java doesn't just fix security loopholes-it eliminates them, which makes Java the perfect language for programming on the Web.
Pointers are the biggest security problem with C/C++ programs. System crackers can use seemingly benign programs to forge pointers to memory, steal information from your system, and crash your system permanently. In Java, you can't forge pointers to memory because there are no pointers. Java eliminates many other security loopholes as well. For example, when Java programs are compiled and run, they are checked with a dynamic code verifier to ensure that the program has no malicious coding. Additionally, the Java runtime environment provides strict rules for programs started from remote hosts. These programs cannot access the local network, cannot access files on your local system, and cannot start programs on your systems either.
As with many breakthroughs in science and technology, the Java programming language is the result of a concerted effort from a group of forward thinkers. Yet what you may find surprising-and perhaps shocking-about Java is that this truly ingenious technological development is not the result of a project that went perfectly from day one. Amazingly, if the project that began with the code name Green in the spring of 1991 had proceeded according to plan, Sun Microsystems would be in the commercial electronics business and the world would be without its jolt of Java. To understand the evolution and the true breakthrough Java represents, you have to roll the clock back to 1991.
In 1991 Sun Microsystems, Inc. was just beginning its climb to the position as the top producer of UNIX workstations. The company had revenues of nearly $2.5 billion for the previous fiscal year, up from a mere $210 million in 1986, and it seemed that the company was unstoppable. Sun's rise to fame was largely due to its pioneering efforts in open systems that enable businesses to build and maintain open network computing environments. Corporations raced to embrace Sun's open systems because they were fed up with the high costs and fees associated with closed network environments. Sun was climbing to the top of the mountain, and its executives knew it. Figure 1.1 shows Sun's site on the Web at http://www.sun.com/.
A movement began within Sun to develop new technologies that would sustain the corporation's phenomenal growth rate over the long term. A key area the company focused on was the commercial electronics market; the Green project was born as part of a larger project to develop advanced software for this market. The goal of the Green group was to establish Sun Microsystems as a player in the commercial electronics market. To achieve this goal, Sun's engineers and developers looked to microprocessors that would run on a variety of machines, particularly distributed real-time embedded systems that were both reliable and portable.
The key to Sun's success in this market would be the capability to easily port the system to multiple platforms. The plan was to develop the project in C++, but the developers ran into many problems as they tried to extend the C++ compiler. The developers ran into other problems as they tried to work in the constrictive framework of C++. Soon the developers realized that to succeed, they would have to try something bold and new. It was then that James Gosling began work on a new language he called Oak. Later, the new language would be called Java because in another twist of fate, Oak failed a trademark search.
Eventually, the developers created a PDA-like device to show off their efforts. Although the device used an early form of the Java programming language and a basic operating system and user interface, it was good enough to dazzle the executives at Sun. Around this time, the Green group developers incorporated under the name FirstPerson, Inc., which would later become JavaSoft. Figure 1.2 shows JavaSoft's site on the Web at http://www.javasoft.com/.
Figure 1.2 : JavaSoft's Web site.
After that, it was a series of wrong turns for the Green group. A deal fell through with Time-Warner to develop set-top boxes that would be used for interactive television and video-on-demand. A deal fell through to develop an operating system for the 3DO. The public launch of the project was canceled, and much of the team left the Green group. By now it was early 1994, and the group of developers from Sun began looking to new areas once again.
It was about this time that a mass migration from the National Center for Supercomputing Applications (ncSA) to Silicon Valley began. A group of upstarts from ncSA created the company now called Netscape Communications Corporation. Silicon Valley was buzzing with thoughts of cyberspace, and this thing called the World Wide Web was starting to catch on like wildfire. By no coincidence, the Green group developers turned to the Internet and the Web as the answer to their problems. The Internet's distributed and multiplatform environment was perfect as a test bed for their project.
The rest, as they say, is history. Four years after the project began, those who hung in there got the gold ring. Java is currently the hottest topic on the Internet. Thousands of Web publishers and Internet developers want to learn how they can create high-powered Web documents complete with animation and multimedia. Millions of Web users want to learn where they can check out the latest Java-powered Web pages.
Sun Microsystems has done a wonderful job of keeping pace with this demand. They licensed Java technology to companies such as IBM, Microsoft, Silicon Graphics, Adobe, and Netscape. They continue to diligently update the Java language. And true to the ideal that made Sun Microsystems who they are today, Java and the Java Developer's Kit are provided free of charge to developers.
As we look back on the evolution of Java and the evolution of the World Wide Web, it seems that the two technologies were on a parallel course. After all, Java was meant to be used in distributed environments and on open systems. The World Wide Web is an open-ended information system designed to be used in the Internet's distributed environment. Both Java and the Web are designed with portability, robustness, and ease of use in mind. Java also provides solutions for important security issues on the Web.
But how do the pieces fit together and why is Java so important to Internet development? To better understand how Java, the Internet, and the World Wide Web fit together, let's take a brief look at the history of the Internet and the World Wide Web.
Although it may be hard to believe today, the Internet began as a U.S. government project. In 1969, four computers were linked over a long-distance connection in order to prove that such an outlandish concept could work. This early network was called the ARPANET (or Advanced Research Projects Agency Network). The ARPANET slowly grew; by 1972, 50 universities and research facilities with military projects had connections. By the late 1980s, more than 80,000 computers were connected through a series of networks. Eventually, this collection of networks became the Internet.
From 1969 to 1991, the Internet was largely a private entity-the realm of researchers, scholars, and the military. Although commercial enterprises could connect to the Internet, the acceptable use policies pertaining to the use of the Internet prohibited them from conducting business. This all changed in 1991, when the ban on business activities was lifted. The ban was lifted primarily because of the formation of a parallel network backbone that allowed commercial transactions to flow separately from noncommercial transactions. This provided a way for businesses to conduct commercial activities without using areas restricted to research and education.
The Internet has been growing at a phenomenal rate ever since. Today, millions of computers and more than 50 million users are connected to the global Internet.
As we look back now, it's hard to believe that the Web was born only a few short years ago. Development on the World Wide Web project began at the European Laboratory for Particle Physics (CERN) in 1989. The Web is the brainchild of Tim Berners-Lee, who proposed the Web as a way for physicists around the world to collaborate using a networked information system based on hypertext.
The structure of hypertext documents was defined by a new language called the Hypertext Markup Language (HTML). Tim Berners-Lee based his new markup language on a subset of the Standard Generalized Markup Language (SGML). To transfer HTML documents to remote locations anywhere in the world, a new protocol was devised. This protocol, called the Hypertext Transfer Protocol (HTTP), offers a means of easily and quickly finding, retrieving, and displaying documents.
Hypertext allows you to navigate through networked resources at the touch of a button. Using a client application called a browser, you can select highlighted keywords or specified hot areas within a document to quickly and automatically navigate to a new document. The first browser was a text-only browser with limited capabilities, and it was because of these limitations that the Web did not catch on quickly in the Internet community.
In fact, in early 1993 there were only about 50 Web sites worldwide. Compare this tiny number to the thousands of Web sites available today, and it seems that the Web literally sprang to life overnight. Currently, there are more than 100,000 Web sites. The catalyst for this exponential growth rate was a browser called Mosaic. This browser, developed by ncSA, allowed users to exploit the Web's graphical capabilities, and that was exactly what the world wanted. Today, the Web is the fastest-growing segment of the Internet, and the browser that started it all, Mosaic, is only one of the dozens of available browsers.
The wild success of Mosaic inspired the 1994 migration of ncSA developers to Silicon Valley. A group of these developers formed the company now known as Netscape Communications Corporation. Netscape released its first browser, Netscape Navigator, which supported many proposed extensions to the HTML standard. These new features brought the Web one step closer to being a fully interactive multimedia feast for users and helped Netscape fuel another period of explosive growth for the Web.
1995 was a year of many firsts for the Web. Microsoft brought the world inline video as well as documents with soundtracks. Netscape delivered a new version of Navigator that supported frames, plug-ins, and many more unique features. Gavin Bell, Anthony Parisi, Mark Pesce, and others delivered the final 1.0 specification of the Virtual Reality Modeling Language (VRML), and Sun Microsystems delivered Java to the world on a silver platter.
In Java, Internet developers and Web publishers saw the means to finally create fully interactive multimedia presentations for the Web. This important step in the evolution of the Web was greeted with fanfare from the Internet community and is currently responsible for another period of explosive growth in Web development.
If you have seen Java in action, you should have little doubt of its importance to the development of the Web. Java is also important to the software industry. The Java programming language has many features that make it unique, powerful, and versatile. For example, most programming languages are either compiled or interpreted. Java is both, which is why it is so versatile. To understand how Java can be both compiled and interpreted, let's look at the basics of compiled and interpreted programming languages.
Although only a few programming languages are interpreted, they are generally the easiest to learn and use. An interpreted programming language that most people, even nonprogrammers, are familiar with or have at least heard of is BASIC. The BASIC programming language got its name because it is so rudimentary and easy to use.
You create a BASIC program using a simple, high-level language structure. When you are finished with the BASIC program, you can run it immediately. The BASIC interpreter reads the instructions in your code line by line. The BASIC interpreter translates these individual lines into sets of instructions the computer can understand. Because the lines of code must be translated into a form the computer understands as the program is executing, interpreted programs generally run more slowly than other programs and require more processor time.
Compiled programming languages are generally more difficult to learn and use than interpreted programming languages. However, most programming languages are compiled. Compiled programming languages you may recognize include COBOL, FORTRAN, C, C++, and Pascal.
You create a program in a compiled language using a high-level language structure. When you are finished with the source code for the program, you compile it to a machine-readable and machine-executable form with a compiler. When you execute the program, the computer can directly interpret the instructions. Because the lines of codes do not have to be translated into a form the computer understands as the program is executing, compiled programs run very quickly compared to interpreted programs.
However, there is a trade-off to be made between speed and portability. Your code is compiled to such a low-level form that it can only be run on the platform for which it was compiled. This means that your code is not directly portable to other platforms.
As stated before, Java is both interpreted and compiled. You create a Java program using a simple, high-level language structure. When you are finished creating the Java program, you compile the source code to an intermediate level called bytecode. You can then run the compiled bytecode, which is interpreted by the Java runtime environment.
Bytecode is very different from machine code. Machine code is represented as a series of 0s and 1s. Bytecodes are sets of instructions that look a lot like assembler code. Although your computer can directly execute machine code, bytecodes must be interpreted before they can be executed. The trade-off between machine code and bytecode goes much deeper than what you may think. Machine code is usable only on the specific platform for which it was compiled. On the other hand, your program in bytecode form can run on any platform capable of using the Java runtime environment. This capability is what makes Java architecture neutral.
The Java runtime interpreter translates the bytecode into sets of instructions the computer can understand. Because the bytecode is in an intermediate form, there is only a slight delay in translating it to a form the computer understands. If you are familiar with how intermediate-level languages such as Assembler are used, you may see the true beauty in Java. Here's a language that allows you to compile the source code to a machine-independent and intermediate form that will execute nearly as quickly as if it were fully compiled.
If you are wondering how Java's architecture neutrality is achieved, you are not the only one; all compilers, even the Java compiler, compile source code for a specific machine. The trick to creating Java bytecode is that the source code is compiled for a machine that does not exist. This machine is called the Java Virtual Machine and it exists only in nanospace, or within the confines of your computer system's memory. As amazing as creating a machine within the memory of your system is, Java is living proof that this concept is not only possible but powerful.
Fooling the Java compiler into creating bytecode for a nonexistent machine is only half of the ingenious process that makes Java architecture neutral. The Java Interpreter must also make your computer and the bytecode file believe they are running on a Java Virtual Machine. It does this by acting as the intermediary between the Virtual Machine and your real machine.
Figure 1.3 illustrates how Java works on a typical computer. As you can see, the Virtual Machine is layered between your operating system and the Java object framework. Above the object framework are the user applications written in Java. (See Chapter 24, "The Java Virtual Machine," for detailed information on how the Java Virtual Machine works.)
Figure 1.3 : The layers of interaction for java programs.
The C programming language has been popular ever since it was introduced in the early 1970s. The popularity of C stems largely from its relative ease of use, friendliness, and advanced features, which at the time appealed to both programmers and nonprogrammers. Considering that C's major competitors in those days were outdated and difficult-to-use programming languages such as COBOL and FORTRAN that ran primarily on mainframes, it is little wonder that C was called friendly and attracted a large following rather quickly.
Today's programmers would probably not find C to be the friendliest and most advanced programming language available. Primarily this is because even the best C programmers sometimes have problems tapping into C's advanced functions. If you are a C programmer and have ever had problems with pointers and memory management, you know what I am talking about. Pointers and memory management are difficult concepts for novices and experienced programmers alike. A single line of code pointing to the wrong location in memory can cause the application and the computer running the application to crash.
In the early 1980s, the personal-computer boom was beginning to hit the marketplace. To keep pace with the growth of the pc industry, software houses were developing programs as fast as they could. Key constraints for getting new applications to market were development time and the costs associated with the length of the development cycle. To cut costs and development time, software developers and programmers looked at ways to reuse existing code in future projects.
Although you can take segments of C code out of one project and use it in another project, code reuse in C is difficult and not always possible. To be successful, a section of code would have to pertain to a specific function or set of related functions such as file I/O or screen display. The section of code would also have to be generalized and contain no possibly conflicting assignments. However, depending on the complexity and type of new project you plan to code in C, it is often best to simply start from scratch. This is primarily because conflicts in the C code you are trying to reuse can take just as long to work out as it would to simply create new code.
The creative team at AT&T Bell Labs developed a possible solution to the problem of code reuse. They called this solution C++. C++ is an extension of C that allows you to create objects. Objects are separately defined code modules that are used to perform specific functions. Bjarne Stroustrup was the mastermind who had the creative vision to develop this extension of C that allows programmers to separate the functions specified within an application into generalized and reusable object modules. A decade after the introduction of C++, we can see it clearly as a logical evolution of C that was designed to address the needs of programmers, which is why C++ is the most widely used programming language.
Although C++ is undoubtedly a powerful and popular programming language, it has its faults. These faults are rooted in its past as an extension of C. Like C, the most-difficult-to-understand-and-use aspects of C++ pertain to memory management and pointers. Furthermore, because C++ is an extension of C, it is very easy for C++ programmers to follow procedural coding habits they learned in other languages, especially in C. When you code a C++ application using procedural programming methods, you lose the benefits that object-oriented programming languages offer. This is where Java comes in.
Java is to programming in the '90s what C++ was to programming in the '80s-a giant leap forward. Like C++, Java is the next logical progression for programming languages and is strongly based in the most popular programming language of its day. With Java, you get the look and feel of C++ and the power of a language specifically designed for object-oriented programming. Unlike C++, Java completely severs the ties with procedural coding and forces you to follow sound object-oriented programming concepts.
The Java programming language features automated boundary checking that eliminates many of the problem areas of C and C++. With Java, there are no pointers, and memory management is automatic. The obvious benefits of this are that pointer problems and memory leaks are a thing of the past. No longer can you point to the wrong area of memory and crash the program. No longer can you make errors when freeing memory and cause a slow memory leak that will eventually cause the system to run out of memory.
Java has many other features that make it a joy to program in and a refuge for programmers who are tired of the difficulties associated with developing in C++. With Java, arrays are encapsulated in a class structure, which is another feature that facilitates Java's built-in boundary checking. Java performs automatic garbage collection, which is another feature that facilitates Java's built-in memory management.
The automatic garbage-collection routine also showcases Java's built-in multithreading capability. By running in the background routines that free up memory and provide general system clean-up functions, Java programs run more quickly and more efficiently.
Many first-time programmers and even experienced programmers who use procedural programming languages have problems grasping the basic concepts in object-oriented programming because OOP concepts are rather abstract and are designed under a different philosophy than traditional procedural programming languages. Concepts related to object-oriented programming include
The fundamental unit in object-oriented programming is the object. Languages that follow object-oriented concepts describe the interaction among objects. All objects have a state and a behavior.
The state of an object pertains to data elements and their associated values. Everything the object knows about these elements and values describes the state of the object. Data elements associated with objects are called instance variables.
The behavior of an object depends on the actions the object can perform on the instance variables defined within the object. In procedural programming, such a construct would be called a function. In object-oriented terminology, this construct is called a method. A method belongs to the class it is a member of, and you use a method when you need to perform a specific action more than once.
Thus, the state of an object depends on the things the object knows, and the behavior of the object depends on the actions the object can perform. If you create a software object that models your television, the object would have variables describing the television's current state, such as it is on, the current channel setting is 8, the current volume setting is 23, and there is no input coming from the remote control. The object would also have methods that describe the permissible actions, such as turn the television on or off, change the channel, change the volume, and accept input from the remote control.
Tip |
If you are having a hard time grasping what an object is, think of it as a chunk of code that performs a specific and generally related set of actions called methods. |
Objects encapsulate instance variables and related methods into a single, identifiable unit. Therefore, objects are easy to reuse, update, and maintain. You can quickly and easily do the following:
Objects are as dynamic as you make them. An object can invoke one or more methods to accomplish a task. You initiate a method by passing a message to an object. A message must contain the name of the object you are sending the message to, the names of the methods to perform, and the values needed by those methods. The object receiving the message uses this information to invoke the appropriate methods with the specified values.
The benefit of encapsulation of instance variables and methods is that you can send messages to any object without having to know how the object works. All you have to know is what values a method will accept. Therefore, the software object describing your television could be extremely complex, but all you or the end user have to know to use the television is how to press the appropriate buttons on the remote control. The press of a button on the remote control sends a message to the television's software object, telling it which method to perform and the new input values for the method.
Classes encapsulate objects. A single class can be used to instantiate multiple objects. This means that you can have many active objects or instances of a class. The object describing the functions of your television is an instance of a class of objects called television.
Keep in mind that each object within a class retains its own states and behaviors. By encapsulating objects within a class structure, you can group sets of objects by type. The Java Application Programming Interface (API) describes many classes. Each class in the API specifies a set of objects that perform related functions and share common characteristics. Classes you create can serve a similar purpose.
Tip . |
Think of a class as a unit of code that contains a set of specific and generally related code modules called objects |
In C++ and other programming languages, a collection of related classes or functions is called a library. Java puts a twist on the concept of libraries by using the term package to describe a collection of related classes. Just as classes encapsulate objects, packages encapsulate classes in Java. As you will see in the section "Access Modifiers," this additional layer of encapsulation makes it easy to control access to methods.
Inheritance is a powerful aspect of object-oriented programming that allows you to easily reuse code and extend the functionality of existing classes. If you created a class to draw a shaded rectangle on the screen, you could extend the class to move the rectangle to specific locations on the screen without having to rewrite the original class. You could also extend the class for the shaded rectangle to display a series of user-selectable rectangles. In either case, the new class would inherit the methods that created the shaded rectangle and then extend the methods to perform the appropriate action.
Using this aspect of object-oriented programming, you can create a new class that inherits the functionality of an existing class. You can then extend the functions of the old class in ways that suit your current needs. The television class could have subclasses for black-and-white televisions, color televisions, and home-theater-style televisions. The new television subclass is not limited by the instance variables or methods of the superclass and can include instance variables and methods not defined in the superclass. The new subclass can also override inherited methods.
In object-oriented programming, access to methods and variables is controlled through access modifiers. The Java programming language defines four levels of access controls:
Methods and variables that are controlled by an associated object and are not accessible to objects of different classes are generally considered to be private. The advantage of this is that only objects in a particular class can access the methods or variables without limitation. Java's private methods and variables are likewise accessible only by objects within the same class.
Methods and variables that are controlled by an associated object and are accessible to objects in the current class or a subclass of the current class are generally considered to be protected. The advantage of this is that only objects in specific classes can access the variables without limitation. Java's protected methods and variables are likewise accessible only by methods in the same class or subclass.
Methods and variables that are accessible to other objects in most circumstances are considered to be friendly. By default, methods and variables you declare in Java are assumed to be friendly and are accessible by any class and objects in the same package. The advantage of this is that objects in a particular package (generally a set of related classes) can access each other without limitation.
Methods and variables that are accessible to all objects, even those outside the current class and package, are considered to be public. Java's public methods and variables are accessible by any object or class. Therefore, public methods and variables can be accessed without limitation.
Peter's Principle |
Understanding the various access controls is easy if you think in terms of scope:
|
Java is first and foremost an object-oriented programming language. Many programmers are surprised when they discover how easy it is to follow sound object-oriented design practices with Java. The following sections give you a better understanding of what Java offers.
The ease with which you can transition to Java from C/C++ and Java's object-oriented capabilities are only the icing on the cake. Java has many powerful characteristics, most of which are discussed in previous sections of this chapter. Java is
Architecture-neutral
Distributed
Dynamic
Interpreted and compiled
Multithreaded
Network-ready and compatible
Object-oriented
Portable
Robust
Secure
These characteristics are the source of Java's power and the reason for Java's widespread popularity. As you begin to develop with Java, you will find that many of these characteristics are interrelated and are a direct outgrowth of Java's development for the following:
A key ingredient for a successful programming language designed for an environment as complex as the Internet is the capability to run on heterogeneous and distributed platforms. Java is able to do this because it is
Another key ingredient for a successful programming language designed for complex network environments is performance. Java has many features that make it a high-performance language, including its compiler and runtime system. Java's interpreter is able to execute bytecode at speeds approaching that of code compiled to a purely machine-readable format because it is multithreaded.
Unlike many other programming languages, Java has built-in multithreading capabilities. Multithreading is the capability to run more than one process thread at a time. Multithreading allows Java's interpreter to run processes such as garbage collection and memory management in the background. Processes that run in the background take advantage of idle time for your computer's CPU. In the real world, many things occur simultaneously: The door bell rings, the phone rings, and your child runs into the kitchen screaming. You cannot answer the phone and the door and give Johnny a hug all at the same time. So what you do is grab Johnny with one arm, grab the phone with the other, and tell the person at the door to wait a moment.
To accomplish all three tasks in successive order, you prioritized. Your child was priority one. The phone call you have been waiting for all afternoon was priority two. The mail carrier delivering a package was priority three. Programs that are multithreaded are capable of prioritizing as well. When the computer is waiting for input from the user, background processes can be busily cleaning up memory, or when the computer pauses for an instant after crunching a number, a background process can squeeze in a few clock cycles to prepare a section of memory for use. Being able to run background processes while a foreground process waits for input from a user or pauses momentarily is essential for optimal performance.
Although Java's object-oriented design is the key feature that makes code reuse possible, Java's designers knew that complex network environments tend to change rapidly. Therefore, to ensure that Java developers could easily reuse code even if the environment changed, Java was designed to be dynamic and robust. Java accomplishes this by delaying the binding of objects and through dynamic linking of classes at runtime, which avoids errors if the environment has changed since the program was compiled. Another way Java avoids errors is that it checks data structures at compile time and runtime.
Robustness and reliability go hand in hand. For Java to be robust, it must be reliable as well. As stated before, pointers and memory management are the source of many problems in C/C++ programs. Therefore, Java ensures robustness and reliability by not using pointers; by using dynamic boundary checking, which ensures that memory boundaries cannot be violated; and by providing for automatic memory management, which guards against memory leaks and memory violations.
Security features in distributed networked environments are essential, especially in an automated world where computer viruses, trojan horses, and worms abound. Many of Java's characteristics ensure that it is extremely secure. For example, malicious programmers cannot access system heaps, stacks, or protected sections of memory because Java does not use pointers to memory and only allocates memory at runtime. This prevents malicious programmers from reaching restricted sections of the system.
Java also ensures system security at runtime by making the Java interpreter pull double duty as a bytecode verifier. Before the Java interpreter executes a program, it performs a check to make sure the program is valid Java code. Java proves the validity of code using a theorem prover that guards against the following:
The structure of the Java language is just as important as its characteristics. The following sections provide an overview of concepts related to the structure of Java programs.
Whether you first learned about Java through your excursions into cyberspace or by reading about it in the latest edition of Dr. Dobbs' Journal, you have probably seen references to both Java applets and Java applications. Unfortunately, technical writers both in cyberspace and in the real world sometimes assume that you know the difference between the two terms.
The term Java applet generally refers to a small application that is designed for use on the World Wide Web. Java applets require an external viewer program, so to use an applet, you need a Web browser or an applet viewer. Keep in mind that the smallness of an applet is entirely relative and that the key to an applet is its design for use with an external viewer.
The term Java application generally refers to an application that is designed for stand-alone use. A frequently used slang term for application is app. Java applications do not require an external viewer program. This means that you can execute a Java application directly using the Java interpreter. Keep in mind that some Java programs can run both as applets requiring an external viewer and as stand-alone applications.
The more complex the programs you create, the easier it is to accidentally reuse a variable or parameter name. In C++, a namespace conflict can take hours or days to fix, especially when you have large class libraries. Java has a unique naming system that avoids namespace conflicts by nesting the name at various levels.
Each component of a name is nested according to the following namespace levels:
The Java interpreter is responsible for maintaining and translating the namespace. The interpreter resolves object names by looking successively in each of the known namespaces. Each namespace is considered in precedence order from the highest level, the package namespace, to the lowest level, the nested local block namespace. Java generally uses the first match found.
The levels in the namespace represent a hierarchy that mirrors the actual structure associated with Java packages and classes. Names associated with each level are separated from the names in other levels by a period. The concept of namespace and levels within the namespace makes more sense when you see how they are actually used.
Java packages in the original package library have the java package name prepended and are generally followed by a class name within the package. The following is a declaration for the BorderLayout class type in the Abstract Windowing Toolkit (AWT) package:
java.awt.BorderLayout
The naming of function calls in Java programs follow the namespace conventions as well. The following is a declaration for a method called println:
System.out.println(str);
The full path to the println method within Java's namespace is as follows:
java.lang.System.out.println
Java resolves the location of the println method by searching for the unique occurrence of the System class in the currently defined namespace. When Java finds an occurrence of the System class, it looks for an occurrence of the out subclass, and finally it finds the println method.
The program file containing the actual instructions in the Java programming language is called the source or source code. You name source code files for Java with the .java extension. These files should be plain text files. When you compile the source using the Java compiler, javac, you compile the source to bytecode that can be executed.
In a procedural language such as Pascal, the complete executable code for a program is generally stored in one file. In an object-oriented language such as Java, the executable code is generally stored according to the class or library structure. After you compile your Java source code, you will have one file for each class you declared in the source. Each of these files will be named with the .class extension. These individual files are called compilation units.
Java compilation units contain package and import statements and declarations for classes and interfaces. These four components form the basic structure of Java programs.
The Java API includes a group of packages under the core java package. All classes and objects you create are assumed to be under this default package. Therefore, unless you state otherwise, Java uses the current path and generally assumes that your compiled code is in the current directory when you run a Java program. To tell Java where to look for packages, you use package statements.
Anyone experimenting with Java and not planning on full-scale Java development will probably want to follow the default package structure. However, if you plan to create applications in Java and want the classes and objects you create to follow a package-naming structure other than the default, you must include a package statement in the source code:
package PackageName
When defining new packages, you must follow Java's hierarchical naming structure. This means that levels within the package-naming structure should be separated from the package names in other levels by a period. This is a sample package statement for a multilevel package namespace:
package MyPackages.PackageSubName;
Your package names at each level of the namespace must mirror the actual directory structure on your file system. This is because Java transforms package names into pathnames to locate classes and methods associated with a package. It does this by replacing the periods with file system separators. So the package name MyPackages.Gizmos would be transformed into the following pathname for a UNIX system:
MyPackages/Gizmos
On a Windows 95/NT system, the package name MyPackages.Gizmos would be transformed into the following pathname:
MyPackages\Gizmos
Java finds the classes associated with a package using the pathname. Java would look for the MyPackages.Gizmos package and its associated classes and methods in the \MyPackages\Gizmos directory.
The Java language specification recommends that you use globally unique package names that pertain to your Internet domain when your packages will be available to nonlocal users. It is further recommended that you always capitalize the first component for the major domain, such as COM, EDU, or GOV.
Keeping in mind Java's precedence order, you reverse the order of the domain name, component by component. Thus, a globally available package called zoom associated with mcp.com would be named COM.mcp.zoom. This package name is transformed into the following pathname for a UNIX system:
COM/mcp/zoom
On a Windows 95/NT system, the package name COM.mcp.zoom is transformed into the following pathname:
COM\mcp\zoom
As with other languages, Java includes a core functionality that is globally accessible. In Java, these core functions are in the java.lang package. To access packages, classes, and objects that are not declared in this package library, you use import statements. Import statements help to define and resolve the current namespace. They do this by allowing an imported package to be resolved using the name of its class component.
Note |
If you do not use import statements, you must specify the full package reference before each class name in your source code. Having to specify full package references can get tedious rather quickly, especially in long programs. Therefore, it is strongly recommended that you use import statements. |
Import statements should appear before other declarations in the source code and generally follow package statements if they are used. The idea behind import statements is to help Java find the appropriate methods and to avoid namespace conflicts. To make Java's AWT class types available, you could use this import statement in your source code:
import java.awt;
This import statement allows Java to resolve the method awt.Button to java.awt.Button. Java also allows you to import only the class type you need. You can do this using a class type import statement such as
import java.awt.Button;
This import statement allows Java to resolve the method Button to java.awt.Button. A more efficient way to import packages is to import them on demand. You do this as follows:
import java.awt.*;
An asterisk in the last element of the import statement allows Java to import classes as necessary. This lets you dynamically add public types to the namespace, and as with class type import statements, Java can resolve the method Button to java.awt.Button.
Tip |
You will find that most Java programmers import classes on demand. Although this saves you a lot of typing, you should be as specific as possible about the packages you actually need. Specifically, you should rarely use an import statement that will make all classes in the Java language available. When two classes in two different packages have the same name, there will be a conflict unless you prepend the package name to the class name. |
In Java, all classes are derived from the system class named Object. This makes Object the root of the class hierarchy and means that all methods and variables in the Object class are available to all other classes. It is this class structure that makes code reuse in Java possible. All classes are by default private unless declared to be public.
Class declarations without modifiers follow this general format:
class name {
//methods and variables associated with the class
}
Java supports single inheritance of classes. Therefore, each class except Object has only one superclass. This means that any class you create can extend or inherit the functions of only a single class. Although this may seem like a limitation if you have programmed in a language that allows for multiple inheritance of classes, Java supports multiple inheritance of class methods, which is accomplished through the class interface. As you will learn in the next section, you define the class interface with an interface declaration.
Interfaces are abstract classes. Through an interface, you can define the protocols for methods and final variables without having to worry about the specific implementation. This allows you to create what could be called outlines for programming structures that you will later define. Interfaces can also be extensions of one or more interfaces. While interfaces are by default private unless declared to be public, an interface's methods and constants are public.
Note |
Final variables are similar to the named constants used in other programming languages. The values associated with constants and final variables do not change. |
Because you do not have to work out the full inner workings of methods associated with an interface, interfaces allow for rapid development. You can later implement the interface in a class declaration. Because a single class can implement more than one interface, it is possible to share the same interface with several classes or any instance of a class. This not only provides considerable flexibility, but it allows a class to inherit the properties of all method calls associated with multiple interfaces, and in turn with multiple classes.
A major difference between a class and an interface is that an interface cannot store data. Further, an interface does not provide an implementation for the methods; it only provides the declaration. Interface declarations without modifiers follow this general format:
interface name {
//methods and static variables associated with the interface
}
Class declarations that use interfaces follow this general format:
class classname implements interfacename {
//class body
}
Or they can take this format:
class classname implements interfacename1, interfacenameN {
//class body
}
The only bad thing about interfaces is that they require dynamic method binding, which reduces runtime performance. However, you should note that using interfaces to accomplish multiple inheritance actually reduces runtime overhead compared to the method of multiple inheritance used in C++.
Java was formally introduced to the world in May 1995 at SunWorld '95. Since then, Java has undergone an evolution of purpose and, as a result, the current specification for the Java programming language is a dramatically different language than what was first introduced.
The first version of Java released for general use on the Internet was Java Alpha. Alpha versions of software applications and programming languages are generally released to developers for review, comments, and bug fixes. The final Alpha implementation of Java is Java Alpha 3, which is used by the Alpha version of the HotJava Web browser.
HotJava was developed by Sun to showcase the features of Java and is written in the Java language. Despite the fact that the Alpha version of Java and HotJava have limited features, they enjoyed widespread use long after the release of Java Beta and Java 1.0. The Java Alpha release included HotJava, which put Java and HotJava in the hands of anyone who wanted to do Java development for the Internet and anyone who wanted to view Java-powered Web pages. Until late 1995, HotJava was the only browser available for viewing Java-powered Web pages.
Development for Java was in full swing by the time Sun released Java Pre-Beta 1. Java Pre-Beta 1 represented a major change in the structure of the Java language, which included the introduction of the applet AWT superclass. The AWT superclass is used to display graphical objects such as buttons and pop-up windows. These changes to the structure of the Java API made this revision and all future revisions incompatible with the Java Alpha. Pre-Beta 1 also introduced new Java tools such as the applet viewer and the Java debugger.
A few months after the release of Java Pre-Beta 1, Sun released Java Beta. Beta versions of software applications and languages are generally made available to wider audiences and generally concentrate on bug fixes. Although Java Beta had bug fixes and security improvements, the major changes to the Java language were again in the applet AWT superclass.
The final Beta version of Java was Java Beta 2. Java Beta 2 added functionality to all the Java packages. Although this in itself represented a major change to the Java API, Java Beta 2 was also a move to make the Java API compatible with the way the Netscape Navigator Web browser used Java Beta applets.
Looking Ahead |
Chapter 4, "The Java Language: A Primer," features a section on making the transition from Java prerelease versions to Java 1.0. Current Java Alpha and Beta programmers will find this section to be very helpful. |
Because all versions of the Netscape Navigator since version 2.0 Beta 4 were able to display Java Beta applets, there was a major initiative by Internet developers to support and start creating Java Beta applets. For this reason, the Java Beta 2 API supports the Netscape <APPLET> tag and not the <APP> tag used previously. The <APPLET> tag is the standard for the official release of the Java 1.0 and later versions of the API.
Another far-reaching change to the Java language that Java Beta 2 introduced was the capability to load classes from zip files. Before this, when you installed Java on your file system, Java created a directory, subdirectory, and file structure that mirrored the structure of the Java API. Earlier discussions on how Java searches the namespace by translating the names into pathnames make clear why this was necessary. For example, to find the println method in previous versions of Java, Java would search the namespace along the full path to java.lang.System.out.println. It would do this by replacing the periods with the appropriate file system separator for your system. Java relied on the directory structure of your file system, and thousands of files were installed on your hard drive.
Support for loading classes from zip files makes it possible to compress the entire contents of the Java API into a single file, which saves space and gets rid of the clutter on your file system. When you install the current version of Java, you will find this single file, called classes.zip, in Java's lib subdirectory. So now when the Java runtime class loader and the Java compiler search the namespace, they first look along the appropriate file path. If the class file is not found, they look for the corresponding zipped file in classes.zip.
Looking Ahead |
Java allows you to zip packages and classes you create as well. Setting up the Java environment and creating zipped packages is discussed in Chapter 2, "Getting Started with the JDK." |
In January 1996, Sun officially released Java version 1.0. The changes from Java Beta 2 to Java 1.0 are very minor and primarily relate to bug fixes. This means Java Beta 2 applets and Java 1.0 applets are compatible. It also means that the Netscape Navigator can display Java 1.0 applets as well as Java Beta applets.
Initially, Sun froze the Java API when they released the 1.0 version of Java. The Java API consists of pre-developed code that you can use in your applications. The code is organized into package libraries filled with useful classes and methods designed to make it easy to program with Java. The great thing about these packages is that they have all been thoroughly tested. You will find that these packages provide every core function you can think of and thus save you time and allow you to start developing applications in Java without having to reinvent the wheel.
To ensure that Java's security model was the best possible for the Internet, Sun asked the world to test it. Several months after the release of Java 1.0, the implementation of the security model in the Java bytecode verify was found to have a flaw. This flaw, identified by researchers at Princeton University, allowed sophisticated crackers to spoof an Internet Protocol address that allowed an applet to access a machine other than the one on which it was executing. Sun fixed the problem and immediately released Java 1.0.1.
Other security problems were found a short while later. In May 1996, Sun released Java 1.0.2. Not only did this release fix minor security problems, it also fixed minor bugs in the Java packages and introduced class interface changes. Another security bug found in June 1996 made it possible to manipulate the way objects are assigned and the way they work together in order to undermine the Java type system. After this bug was discovered by a researcher in the United Kingdom, Sun did a full security review to check for any bugs that may be related and again released an update to the JDK.
Because Sun and its partners for Java development have proclaimed that they intend to support the current API, one can reasonably expect that the Java programming language has finally reached a level of standardization. This is good news for anyone who wants to start developing with Java.
The progression of the Java language has not stopped. Sun will continue to develop Java and has already announced the next major release of Java. You may see the full release for JDK 1.1 late in 1996. Thankfully, the introduction of standardization ensures that programs you create today will be usable tomorrow.
The Java Virtual Machine (JVM) is at the heart of the Java programming language. It is because of the Java Virtual Machine that Java is architecture neutral, dynamic, interpreted and compiled, network ready and compatible, portable, robust, and secure. The JVM makes these features possible by providing an abstract specification for which developers can design interpreters and programmers can design applications.
This abstract specification is a virtual machine that exists only in nanospace. Because the Java Virtual Machine exists only in memory, the Java developers were able to use object-oriented methodology to pass information-parameters, method calls, and other types of data-back and forth between the real machine and the virtual machine. After the developers mapped out the necessary interaction between the real machine and the virtual machine for things like standard I/O, file I/O, and memory management, they could create additional Java runtime environments for other systems.
Because the specification for the Java Virtual Machine is fully described for all to use and thus open for development, the Java programming language is free from the restrictions of proprietary languages. This means that any developer can create an interpreter for the Java Virtual Machine. (Chapter 24 provides a detailed look at the Java runtime system and the Java Virtual Machine.)
As you have seen in this chapter, the developers at Sun's JavaSoft division poured their hearts into the creation of a revolutionary programming language. No other programming language offers the power and versatility that Java offers. Java is the programming language for the '90s and beyond.
The Java language offers an easy-to-use structure that is modeled after two of the most widely used programming languages, C and C++. However, Java was engineered so that it does not have the problem areas inherent in C and C++. If you plan to develop Java applications, you will find that Java's object-oriented design is both friendly and familiar. You will also find that the Java API saves you hours of work and will help you to create better programs without having to reinvent the wheel.