Few programming languages generate the kind of interest that Java has, but then few languages redefine, as Java does, what programs are and what programmers can do. While the programs of other languages are confined to a particular platform, Java is platform independent. While you must always virus scan normal software that you download from the Internet-or put your trust in the company or person who wrote it the Java language is designed for writing programs that can be downloaded and run safely.
Before Java, software always came in a shrink-wrapped box. You had to give it a permanent home on your hard drive, put it on speaking terms with your network, and upgrade it again and again. Java programs can come on a wire for cordial visits. When you are done with them, they disappear. They are always up-to date and they have no problem talking to the network.
In addition to platform independence and strong networking capabilities, Java offers the benefits of object orientation and multithreading. These capabilities allow your code to more closely model the real-world problems you are trying to solve. The language is also dynamic: small pieces of Java code are assembled at runtime into the program, rather than being assembled at the time you write the code.
On the Internet these days, there's no lack of hype about Java, and a lot of it sounds like what we've just said. But you will find that there is substance behind the hype. Parts of Java are, admittedly, still in rough draft form, but we believe that the more you learn about Java, the more you will like it.
A lot of the current excitement has been generated by applets - small programs - that can be embedded into Web pages. But Java isn't just a means that ends in a clever Web page. First and foremost, it is a powerful, general, platform-independent programming language. Before you finish this book, you may find yourself writing stand-alone applications in Java purely because you don't have to port your Java code from platform to platform. And applets themselves are far more powerful than Web page dressings.
Figure 1-1: Meeting scheduler applet.
For example, Figure 1-1 shows an applet we develop fully in the last chapter of this book. It is your standard meeting scheduler, with a few very powerful twists. You and your colleagues can schedule meetings through your Java-capable Web browsers. You needn't be in the same local area network, on the same platform, or even in the same country- the only requirement is that you are connected to the Internet. In this book, our aim is to build applications that are distributed across the Internet and use the Web as a programming platform. Besides the meeting scheduler, we'll show you how to hook up to servers on the Web by writing a client for the Internet Chess Server, how to start your own store, and how to write highly configurable, interactive applets. Along the way, we'll cover the basics you need to write powerful stand-alone applications and any applet that you could dream up.
In this chapter, we start off by examining how all Java programs are run and why these characteristics are advantageous for network computing. Next, we focus on applets and how they are changing the Web. To back up our claim that Java is good for more than just cute Web pages, we briefly look at the history of Java. Then, we examine the features of Java that make it an easy-to-use, easy-to-learn, general programming language.
The Java language is object-oriented, threaded, dynamic, and all that, but these aspects aren't what sets it apart as the best language available for networking. What makes the difference is how Java programs are executed. Java programs are executed inside virtual machines that sit inside the computer on which they are running.
A Java program has no contact with the actual computer; it only knows about the virtual machine. This arrangement has several important implications.
First, as we noted earlier, Java programs are platform-independent. Have you ever had to develop for multiple operating systems? Chances are that you didn't do it for pleasure. When you were done, you probably knew a lot more nuances of the various platforms than you really cared to. When you write a Java program and compile it, it is ready to run on any computer that contains the Java virtual machine. In a sense, you are just writing for one platform, the virtual machine.
Second, the virtual machine decides what Java programs can and can't do. Programs written in compiled languages, like C or C++, are run directly by the operating system. Therefore, they have direct access to all of the system's resources, including memory and the file system.
Since Java programs are run from within the virtual machine, the people who create the virtual machine get to decide what a program can and can't do. The environment that is created for Java programs is called the runtime environment. The virtual machine acts as a firewall between the host computer and the Java program. A Java program never accesses your computer's input and output devices, file system, or even memory. Instead, it asks the virtual machine to access it.
When we run applets, we are downloading them into a virtual machine that prohibits access to the file system entirely. Like all virtual machines that run Java programs, it only allows indirect access to the system resources, which is why we can trust applets not to delete our files or propagate viruses.
Java's runtime architecture also allows Java programs to assemble themselves at runtime. Suppose someone only uses a very small percentage of a program you wrote. Wouldn't it be nice to load the most important parts of the program into memory, and only load the bulky, seldom-used parts if they are needed? Java programs can do that, through a process called dynamic binding.
If you're only loading your programs from the hard drive, and your computer is nice and fast, dynamic binding isn't really that important. But when you are downloading programs from the Internet, the biggest factor in program speed is going to be the rate of network transfer. Your Java programs can quickly download the parts they need to get started, and then download the other parts as they begin to run. Dynamic binding also makes Java code easier to maintain, as we will see later in this chapter.
Java's runtime environment solves several basic problems of Internet programming. Since the Internet consists of many different platforms, it is beneficial to be able to write platform-independent programs. Java programs can be expected to do no more than the virtual machine allows. And finally, the runtime environment allows us to write programs that can download and start executing speedily.
All Java programs need a virtual machine in which to run. A special type of Java program, called an applet, is run in a virtual machine inside Java-capable Web browsers such as Netscape Navigator +2.0 (+2.0 means 2.0 or later version) or Internet Explorer +3.0. This virtual machine has been adapted so that applets can't damage the computer to which they are downloaded.
Figure 1-2: How applets are run.
Notice that the applet in Figure 1-2 is run on the client computer. Before Java, most Web-related programs had to be run on the Web server machine. The client side execution of applets is a major breakthrough for Web programming. Before Java, Web pages were static. Now that applets can be embedded in Web pages, they can be interactive. They can also talk back to the machine they come from and can be parts of larger systems. As we progress through each chapter, we'll explore more and more of the possibilities of applets. But first, lets take a high-level view of applets and how they work.
The Applet Runtime Environment
As we have said, the applet virtual machine, or runtime environment, exists inside a Web browser. It is built to run applets-and only applets. In the course of running the applet, it acts as a firewall between the local computer and the applet. Like all runtime environments, it services memory requests and controls access to input and output devices.
But that role as firewall is much more important for the applet runtime environment than it is for the standard runtime environment. For instance, we don't want an applet to download and have access to our local file system. The Java language itself doesn't prohibit access to the file system. If we want to, we can write a Java program that deletes our entire hard drive. If we run it, then we have to expect the consequences just as if we wrote and ran a C program to do it, or if we just told the operating system to wipe out the drive directly. But even though we can write a Java program that has access to the file system, we certainly don't want applets to download from the Internet and wipe out our drive.
So our applet runtime environment needs to protect the file system. We'll cover how it does this, and things applets can't do first. Protecting the file system prevents much of the potential damage from viruses, but not quite enough. We still need to make sure that our applets are downloaded in a safe manner-we'll cover that second.
It's possible to write completely valid Java code that could delete the entire file system. So why can't a hacker with evil intentions just stick this code into an applet, embed the applet in a Web page, and tell potential victims to check it out? Well, he can, but when the applet downloads to his victims' Web browsers, the applet will crash, never touching the local file system. The reason is simple: the applet runtime environment doesn't know how to access the file system. This is why the runtime architecture of Java is so powerful. The creators of the runtime environment have the final say as to what a program can or can't do. For instance, if they don't want Java programs to print out offensive words, they can keep it from happening. Less prudently, but more importantly, the runtime environment can determine what files, if any, Java programs are allowed to access, what input and output devices they can deal with, and any other effects a program can have on the system.
Like all Java runtime environments, the applet runtime environment doesn't allow direct access to memory. A Java program can only deal with the memory the runtime environment hands to it, and even then it is limited in exactly what it can do with that memory.
The Safe Downloading of Applets
So far, we have seen that applets don't have access to the local system's memory or to its files. However, a hacker has still another chance, when the applet downloads, to overcome any obstacles that might be in the way. The applet runtime environment performs two more steps to ensure that applets aren't trying to do anything destructive.
First, it verifies the .class file that is being downloaded. The .class file contains extra information that guarantees that the program is following all of Java's rules. The applet runtime environment carefully scrutinizes the .class file to make sure that information is there. If it didn't do that, a hacker with an in-depth knowledge of a particular platform could get access to the system's memory.
Second, it loads the Java program into its own memory space. Why is this important? If it isn't loaded into its own memory space, a hacker could replace part of the runtime environment with his own functionality! Then, he could use that class to access the file system or to do a number of other devious things.
On May 23, 1995, Sun Microsystems formally released Java to the world as an Internet programming language. But Java wasn't part of a long range plan to solve the problems of Internet programming. Nor was it a quick hack to capitalize on the popularity of the Web. Java originated as part of a consumer electronics project that was started in 1990, years before the Web or the Internet gained widespread popularity Let's look at the origins of Java and how the lessons the originators learned from dealing with consumer electronics affected the language we know today.
The intent of the consumer electronics project was not to create a network-ready language. It was to build a network out of all the small computers you use every day, such as the chips in your VCR, television, and microwave. In 1990, Sun saw this as an emerging market and to explore its opportunities, it created a skunkworks-a separate, nearly autonomous division-within Sun Microsystems.
In the early 1980s, a similar skunkworks was created within IBM to explore personal computing, and it created the IBM PC. Sun's consumer electronics skunkworks, code-named "Green", didn't revolutionize consumer electronics in the way IBM's skunkworks changed the microcomputing landscape forever. Two years after its inception, it lost out on a bid to get into the interactive television market, and shortly thereafter it dissolved. In the words of Java creator James Gosling (as quoted in the Sun World Online article we cited earlier), they discovered that the "consumer electronics market wasn't real. People had hyped things beyond reason."
But despite this hindsight revelation, they fulfilled their mission as a skunkworks. Separated from the corporate bureaucracy, but with the resources of a large company available to them, a talented group of computer professionals was able to intensely study and solve the problems of networking appliances. They were technically, if not commercially, successful.
Part of that technical success was a computer language named Oak that was designed to work in appliances. In 1995, Sun realized that this language could provide solutions to Internet programming. Unfortunately, somebody else had already trademarked the name Oak, so they renamed it Java.
Lessons Learned From Consumer Electronics
Unbeknownst to the team, the problems that they were attacking in the domain of consumer electronics would be the same problems the tremendous growth of the Web would reveal about the Internet. Until the Web became popular, the Internet was mostly used to connect research centers and universities. Though it was a vast and time-tested network, it wasn't ready for widespread consumer and business use. Let's see how some of the challenges of consumer electronics are also found on the Internet.
Architectural Heterogeneity
Your coffee maker and your television both have microchips, but it is highly unlikely that they are the same type. The Green team couldn't build its system with a particular type of architecture in mind. As the Web introduced Macs and PCs to the Internet, this same problem would emerge. For its network of household appliances, the Green team had to solve this problem up front.
Real-time Software Portability
Not only did the language of the network need to be portable across various platforms, but the programs written in those languages also needed to be runnable on a variety of platforms. Before Java, Internet programmers solved this by compiling different programs for each architecture. For instance, there were separate Mosaic browsers for Mac, Windows, and the various flavors of UNIX.
The Green team couldn't take this approach for two reasons. First, the number of possible platforms was directly related to the number of possible appliances; porting code for each platform would be too time-consuming. Second, consumers aren't going to put up with incompatibility problems. Though personal computer users accept software upgrades as a matter of course, coffee machine users just want their coffee. Neither appliance users nor manufacturers would put up with the difficulties that are a matter of course in the sphere of personal computing.
The solution? All Java programs are run inside the virtual machine we talked about earlier. The virtual machine is layered on top of the microprocessor, so that the Java programs don't have to be concerned about what platform they are running on. Of course, this solution is also directly applicable to Internet programming.
Simplicity & Compactness
Your coffee machine may contain a little computer, but it isn't a Pentium or PowerPC chip with tons of RAM! For their system to work, it had to be designed to function in very small spaces. The Green team solved this problem by keeping the virtual machine small-in the range of kilobytes, not megabytes-and simple. Keeping the virtual machine simple meant also keeping the language simple. Though the software that can be built with Java is quite complex, the language itself is very straightforward. The Green team had to keep the core of the language separated from what could be done with its functionality
Inherent Software Downloadability
Appliances don't have hard drives, either. The software to run in all those appliances had to be stored elsewhere, and only stored by the appliance's computer when absolutely necessary-at runtime. Thus, Java evolved as a language of the network, not the computer.
Network Safety
Once you start bouncing software over a network, you have to be concerned with what harm the software might cause to a host. The Green team was developing the environment in which to develop software; not the software itself. Since the software was ultimately going to be developed by third parties, they had to ensure that a piece of code couldn't be downloaded to an appliance and effectively destroy it. This is identical to the worries computer users have about software downloaded over the Internet. We don't want viruses to erase our hard drives!
Before Java, these problems were solved by checking downloaded programs for viruses. The Green team adopted a much more direct solution-incapacitate the programs from doing any harm in the first place. They accomplished this by letting the virtual machine determine what downloaded software could and couldn't do. As we described earlier, this solution is why we can be confident that our computers won't be harmed by Java applets we download from the Web.
Quite by coincidence, the Green team solved the problems of Internet programming. The Java language was architectureneutral and safe for networks, and by the time Web started to take off, it was functional. In 1994, Sun realized that their aborted foray into the consumer electronics market had produced a valuable product-Java.
At the time of Java's development, the Internet was the domain of workstations and supercomputers. Only computer engineers and scientists had any interest in it, and if they wanted to use it, they had to have a pretty thorough knowledge of the UNIX operating system. For the millions of users sitting behind the graphical user interfaces of their Macs and Windows machines, the Internet, and its huge capacity for information storing and communication, was completely foreign. In April 1993, the first graphical Web browser, NCSA Mosaic 1.0, was released, and the Internet was added to the buzzword lexicon.
The Green team created a Web browser named HotJava, and released it to the Internet in the spring of 1995. As a Web browser, HotJava was clunky in many ways. It didn't support all of the latest HTML extensions, and it was quite slow. But it had a powerful feature that had no precedent on the Web; it supported executable content. Unlike other Web browsers, it could download small Java programs called applets and run them inside the browser. It ran them in a virtual machine, the same scenario originally intended for your appliances.
Within weeks of the formal release of Java, the maker of the most popular Web browsers, Netscape Communications Corporation, announced support of Java and Java applets. Netscape licensed Java from Sun and began work on incorporating a Java virtual machine into its next line of browsers, Netscape Navigator +2.0 or Internet Explorer +3.0. Early versions of these browsers were released in October 1995, thus making Java applets accessible to a much wider range of Web surfers than HotJava was able to. In the meantime, Sun had made improvements to the Java language, changes that included making applets easier to program. Sun released version 1.0 of Java in January 1996.
Since the early HotJava days, Sun has made the inner workings of Java freely available to the Internet community. This helps encourage the porting of the virtual machine to the various platforms of the Internet, including the platforms of Sun's many competitors in the workstation market. Sun's strategy is puzzling to many industry observers. Why invest millions in a technology and then give it away?
Bill Joy, one of the founders of Sun, framed the answer this way in the Forbes ASAP article we cited earlier: "Most of the bright people don't work for you-no matter who you are. You need a strategy that allows for innovation occurring elsewhere." Java is Sun's attempt to make the Internet a level playing field, where hackers like us provide the innovative software. To do this, they are even willing to give control of the Java language specification to a standards body eventually.
What does Sun stand to gain? As one of the major vendors of high-end Web servers, it gains as the market for Web servers grows. There aren't any guarantees here for Sun. The company still has to compete and still has to make good products. It's a cocky strategy, one that most computer companies don't have the confidence to adopt.
Sun is also developing pioneering computers for Java programs to run on, including the Internet appliance, a simple computer costing a few hundred dollars which will function as a hardware Web client. There is also talk of Java's becoming the tool that will move interactive television from the snake-oil shelf to the living room. Java may yet return to its roots-consumer electronics.
All this means that the Java skills you learn today will probably serve you well in whatever path the Information Superhighway takes. In many ways, the Internet is quite lucky to have Java. The Web was ripe for a scripting language of some sort. The first halfway decent one to come along would probably have become a standard, even if it wasn't platform independent, safe for the network, and completely open to third-party development. Instead, we got a language that is close to being custom-designed for the Internet. Now, let's look more closely at Java and the features that you will soon come to love.
We hope our discussion of Java's history has reassured you about its future. Now, let's examine what actually emerged from the vaporware of consumer electronics. Our buzzword density is going to be pretty high over the next few pages, but we'll try to stay well below the acceptable standards of hype. But Java isn't perfect-we will also point out some of its weaknesses along the way
Probably one of the most feared phrases in computerese is "legacy systems." As changes in the world of computers take place at a dizzying pace, it's sometimes hard to comprehend that we are moving into the third decade of widespread computing. Unfortunately, the early programming languages had to follow the rules of what is, today, primitive computing. They will probably go down in intellectual history as significant turning points, but they have also propagated problems that existed in those early computing environments. Despite our blazing processors and tons of system resources, the ghosts of those early computers continue to haunt our programming languages.
This is the demand of backward compatibility, but Java doesn't answer the call. Because it was developed from scratch, it doesn't have to be able to compile on computers only found in museums. We could compare some of the "features" of older programming languages to the human appendix; it no longer serves a purpose and can become infected. If we were to design a new revolutionary species, we could drop it out of the plan. However, if we take an evolutionary approach-as language designers often do to ensure backward compatibility-we would be stuck with it.
Java is revolutionary in the sense it avoids incorporating the problems of decades of computing for the sake of backward compatibility. At the same time, it doesn't demand that we learn tons of esoteric new concepts. Java represents a synthesis of many programming languages that came before it. It borrows the time-tested concepts of previous languages, but eliminates the problems that would be required for backward compatibility's sake.
The same reasoning can be applied to the creation of programming languages. There is a lot of wisdom stored in their 30-year evolution. Luckily, the creators of Java didn't go too far adrift in the design. For instance, the basic syntax is pretty much the same as the C programming language. In fact, Java has the basics of most languages-types, variables, and subroutines.
Java isn't about radically changing the way people are supposed to think and adding tons of exotic features. Mostly, Java is a simplified C++, with some additions from other languages. The arcana inherited from those 1960s era computers is gone, along with C++ "features" that are hard to learn and make code harder to maintain. In the words of Bill Joy, quoted in Forbes ASAP, "What we have taken away is mind-boggling complexity." Let's look at some of the complexity and arcana of C++ that has been left out of Java. The next few pages will certainly make more sense if you have C or C++ experience. But, as we do throughout the book, we have attempted to describe the differences between C++ and Java so that anyone with some programming background can understand.
For those of you not familiar with C and C++, the preprocessor performs global substitutions on your code before it goes to a compiler. This results in the compiler seeing an entirely different set of code than is written, and the person responsible for maintaining that code has to figure out what the preprocessor is doing. The designers of Java saw the preprocessor as performing magic on your code, so they discarded it.
No Makefiles & Library Linking Worries
When you program in C or C++, often one of the biggest challenges is creating your Makefile, a small program that tells the compiler how to build your executable file. Usually your source code is spread across many files and requires the use of libraries of code that have already been compiled. The purpose of the Makefile is to make sure that all the right information is fed to the preprocessor, that source code that hasn't changed isn't compiled needlessly, and that the library is linked in correctly
Java takes care of the Makefile's first purpose by not having a preprocessor. The manifestation of the second purpose is built directly into the compiler. If you have a bunch of source code files in your project and you only change one, the compiler won't bother to update the ones that haven't changed.
The last problem is taken care of because Java is a dynamic language. The virtual machine links Java programs together at runtime, thus eliminating the need to link to libraries at compile time. We will look at this property of Java shortly, in the section entitled "Dynamic."
No Direct MemoryAccess or PointerArithmetic
In C and C++, a pointer is an integer that represents a memory address on the computer. When you use pointers in C or C++ programs, you are actually telling the computer to look at that specific memory address and deal with whatever resides there. If you want, you can perform arithmetic on the memory address and then tell the computer to act on whatever is there.
This is part of C's heritage as a systems programming language. When you are doing very low-level programming for a particular platform, it is valuable. But for high-level programming, it's bad programming practice and usually leads to confusing code. Because it represents bad programming style and can lead to unsafe programs, Java doesn't have direct memory access or pointer arithmetic.
If you're an experienced programmer, you may be wondering how
useful a language can be without direct memory access. Although
Java doesn't allow you to directly access memory, it does have
reference variables that play the same role as C and C++
pointers you can make a linked-list or a stack, for instance.
The difference is
that you can't access the memory address directly or cast the
memory address to an integer.
Many programming languages allow the programmer to define what some of the operators-like the + sign-mean in relation to certain data types. They define the meaning with a subroutine that is called whenever the operator is seen, which is called operator overloading. Here's an example where SetA and SetB are a programmer-defined type representing a set of integers:
SetA=SetA+SetB;
What is the programmer attempting to do here? We don't really know. We would have to ask the programmer, who is probably doing something intuitive, like adding together each value of the two vectors. But ultimately, the overloaded operator raises more questions than it answers: What happens if one vector has more numbers than another? As people who are trying to understand this code, we are not helped by operator overloading. We still have to look at the subroutine defining the actions of the overloaded operator to know what is going on. Also, the language has to be more complex to allow operator overloading. Because operator overloading inhibits the readability of the source code and makes the language more complex, Java's designers declined to put it in.
For those of you who don't have a background in object-oriented programming, the concept of inheritance will be easier to understand after reading Chapter 3. For now, we'll look at what you may think of as a childish example-complete with children. Let's assume we have a society in which every family has only one parent, and the children in one family do things in the following way: If they have learned how to do something themselves, they do it their way; if not, they ask their parent. In turn, if the parent doesn't know how to do something, he or she asks his/her parent. This is a very simple model of single inheritance. Each child can only inherit properties from one parent, who in turn can only inherit from one parent.
In multiple inheritance, the child can inherit ways of doing things from multiple parents. This makes the life of our child more complicated. Different parents could define differently how the child should perform a certain action, or the child could have inherited from the same parent twice. Even without these ambiguities occurring, the child would have to ask all of the parents involved in order to figure out how to do something.
When we program in object-oriented languages, modules within our programs can inherit ways of doing things just like the child in our example. When a language allows multiple inheritance, it must be more complex because the problems become more complicated. Why do any languages use multiple inheritance? We will discuss this in depth in Chapter 3, but the short answer is that our modules need to take on the characteristics of more than one parent. As we will see, Java supports this design concept without complicating the entire language with multiple inheritance.
We've stated that Java is good partly because it is new. One of the most important advantages of starting from the ground up is that Java was created to be an object-oriented language. Since object orientation is perhaps the most popular trend in modern software development, we can put a check in the buzzword column for Java. But before we proceed down our buzzword checklist, let's look briefly at what object orientation is and how Java implements it.
To understand the importance of object orientation, it helps to remember a simple fact: computers don't think the way we do. They store 1s and 0s in registers. The antithesis of intuition is assembly language-a very narrow way to view the problems of the universe. Computers live in a world so simple that it's difficult for us to comprehend it, and our world is too complicated for computers to grasp. Something mechanically simple, such as adding a thousand numbers together, can take us an hour, while computer scientists are still trying to teach computers how to write grammatically correct sentences.
In our early interactions with computers, we had to play by their rules. As computer research progressed, computer languages were developed that allowed us more sanity when telling our computers what to do. The first major breakthrough was procedural languages. Instead of just passing the computer a long list of very simple instructions, procedural languages allowed us to build a short list that could be called again and again-a subroutine. With subroutines, we could represent discrete blocks of action that we could relate to, like finding the minimum value of a set of values. We are able to build on subroutines in the creation of our program.
Object orientation gives us a level of abstraction about the actions of our programs. Still, it is quite distant from how we intuitively attack problems. Try to visualize the following directive: "Go to the store, get milk, go home." We have directed you to perform three actions, but chances are that your first step in thinking about the problem is thinking about the nouns, not the verbs, of our directive. For instance, you don't want to get milk that's sour, and you don't want to waste time going to a store that doesn't have milk. If we were to ask you how you planned to attack the problem, you may say, "Starting from my current location, I am going to use an available source of transportation and proceed to a store that sells milk, buy milk that isn't sour, and proceed to the place where I live."
The crux of our milk-buying problem has to do with the properties of the objects involved-the milk, the store, and even the house. Procedural languages force us to focus entirely on the actions involved in solving the problem. Object-oriented languages allow us to solve our problem by defining objects. Instead of thinking about checking each carton of milk to see if any are sour, we can think about milk having the condition of being sour. Table 1-1 illustrates each object in our problem, the information inherent to it, and the questions we would wish to ask it.
Object | Data | Questions |
---|---|---|
Transportation | Range | What stores are in range? |
Milk | Expiration | How long until expired? |
Price | How expensive is milk? | |
Store | Location | Does this store have milk |
House | Location | Is the store within rage of transportation |
Owner | Is this my house? | |
Table 1-1: Objects of our problem
In Java, we can write our program by creating a representation of each of these objects. As you will see in Chapter 3, our objects can very closely model the approach we took in Table 1-1. We still write subroutines. For instance, to code our example above, we would write subroutines to answer all of the questions in the third column and to set the values in the second column. The difference is that all of our subroutines are associated to an object. This is the point of object-oriented languages-to describe our problems for the computer to solve in terms that we would naturally use.
Unfortunately, object orientation often fails to achieve this enlightened goal. The reasons are many, but let's generalize three of them. First, object orientation is a still maturing methodology. Some early attempts at implementing object-oriented languages led to such levels of abstraction that mere mortals were lost. Second, procedural languages force programmers to think procedurally. As B. L. Whorf once said, "Language shapes the way we think, and determines what we can think about." Even though an object-oriented approach more closely models most real-world problems, many programmers will prefer the more familiar approach learned for procedural languages. The computer language has shaped the problem solving process!
But perhaps most importantly, the advance of object orientation has been impaired by hybrid object-oriented languages; languages that are both procedural and object oriented. C++ is the chief culprit here, with Object Pascal close on its heels. Hybrid languages make it particularly easy for the object-oriented programmer to routinely create code that is not object oriented. Since they can still write procedural programs, they probably will, throwing in objects occasionally when they feel daring. Also, hybrid languages introduce tons of special cases that pure object-oriented languages eliminate. They not only make it easier for people not to adopt an object-oriented methodology, they make it harder to use object-oriented features in the first place!
Java works to solve all three of the problems listed here. As we mentioned before, it is a synthesis of languages that preceded it, and it solves many of the problems exposed by the early object-oriented languages. It solves the latter two problems by being completely object oriented. This eliminates the complexity of hybrid languages, while forcing procedural programmers to use object-orient programming.
Java was developed from the start to be a language of the network. We have already looked at a couple of advantages this gives us that involve the virtual machine. The virtual machine keeps programs from harming the computer they are downloaded to, allows programs to download quickly, and runs the programs so that they aren't dependent on the underlying operating system.
These advantages are inherent to the Java language. In day-today programming, we never have to worry about them. But since Java was born to be networked, we have an extensive set of functionality included in the API to allow us to converse with the Internet. Using the API, we can use high level abstractions like Uniform Resource Locators (URLs) or communicate on very low levels by just passing packets back and forth.
Because the networking support is so strong, we can write applets that communicate back to the computer they came from in ways we define. In fact, this is exactly what we do with our meeting scheduler, the applet and server we develop in Chapter 19. The applet downloads via the HyperText Transfer Protocol (HTTP). But HTTP is really only meant for retrieving information, not communication. So the client applet then opens a connection with the schedule server on the Web server machine. All of the actual communication occurs on that connection.
We didn't put encrypted data transfer into our scheduler system, but if you wanted to, you could. If you figure out a better way to compress video, just write an applet that knows how to interpret the compression and a server that knows how to transfer the video. Instead of having to write a massive client program and then convince people to install it, you can just write an applet that downloads to their Web browsers and becomes the client. The API gives you the ability to define your own way of transferring data, while the platform independence and safety inherent to the language means that you can get client programs to the users' computers.
A C or C++ program, when compiled, is a monolithic file of machine instructions. For large programs, the size of this executable file can be measured in megabytes, such as Microsoft's Word for Windows 6.0, which is 3.2 megabytes. But when you develop a truly massive project, you usually use code that others have written previously. The original source code is compiled and stored in a library. When a program is compiled, the new source code that has been written is linked to this existing library, and the whole image is dumped into a big executable file.
But what if a bug is found somewhere in the library, or for some other reason you want to change one of the modules? Then you get to relink each and every program that uses that library. Java programs don't have this problem because they assemble themselves at runtime, as we discussed in the first part of this chapter. This means that the modules exist independently of the programs into which they are compiled.
Have you ever wanted to be in two places at the same time? If you have, then multithreaded programming is for you. Like object orientation, threads are abstractions designed to make your life as a programmer easier. Their purpose is to allow you to easily describe sets of actions that happen concurrently. Let's say you write a program to draw a circle on the screen that starts in the middle and grows out. It takes you days to figure out how to do it. When you're all done, your program could be condensed to the following pseudocode:
//pseudocode, not Java!! set_center set_the_color radius=1 do { draw circle(radius) radius=radius+1 ) while (radius<final circle_size)
You show your program to your boss, who is ecstatic, but now asks you to make the program draw two circles on the screen at the same time. Back to the drawing board! After a couple of weeks, you come back with a program that could be represented as follows:
//pseudocode, not Java!! set_center_for_Circle1 set_center_for_Circle2 set_color_for_Circle1 set_color_for_Circle2 Circle1_radius=1 Circle2_radius=1 do{ if (Circle1_radius<final_circle1_size) draw circle1(Circle1_radius) if (Circle2_radius<final_circle2_size) draw circle2(Circle2_radius) if (Circle1_radius<final circle1 size) Circle1_radius=Circle1_radius+1 if (Circle2_radius<final circle2_size) Circle2_radius=Circle2_radius+1 } _ while (Circle1_radius<final circle1_size AND Circle2_radius<final_circle2_size)
If you look at the pseudocode above, you'll see that all we are doing is repeating each instruction for circle 1 to circle 2. This repetition is something very mechanical that a computer can do well, and it is also what threading is all about. Instead of having to write new code to draw the second circle, we can make our first example a thread. Then, we can run two threads at the same time. The processor would run an instruction first from one thread, and then another.
If you have been looking at the applets on the Web, you've probably seen threads in action in the animations that are dressing up so many Web pages these days. In Chapter 5, "How Applets Work," we'll show you how to use threads to easily create your own animated applets. In Chapter 11, "Advanced Threading," we'll cover how to pass information back and forth between multiple threads.
Now that we have introduced you to Java and applets, the real fun begins. In the next chapter we'll install the Java Developers Kit (JDK) and write a couple of basic programs. After your first experiences as a Java programmer, we'll look at Java's object orientation in Chapter 3 and then fully explain its syntax and semantics in Chapter 4. With those basics down, we'll walk you through all of the steps of writing simple applets in Chapter 5. From there, we're off-exploring the API, writing applets with powerful user interfaces, and creating applets that converse with other programs on the Internet.