100% found this document useful (1 vote)
2K views1,191 pages

Special Edition Using Java 2 Platform - Que

Special Edition Using Java 2 Platform - Que

Uploaded by

Sandeep Londhe
Copyright
© Attribution Non-Commercial (BY-NC)
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
100% found this document useful (1 vote)
2K views1,191 pages

Special Edition Using Java 2 Platform - Que

Special Edition Using Java 2 Platform - Que

Uploaded by

Sandeep Londhe
Copyright
© Attribution Non-Commercial (BY-NC)
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 1191

Release Team[oR] 2001 [x] java

Special Edition Using Java 2 Platform by Joseph L. Weber Que 1998, 1414 pages

ISBN: 0789720183

A broad resource for those beginning to program in Java or expanding their skills.

Table of Contents Back Cover

Colleague Comments

Synopsis by Rebecca Rohan Billed as a "tutorial reference," Special Edition Using Java 2 Platform is an unusual hybrid that's neither a typical course book nor an end-to-end glossary-style reference. Instead, the large volume is laid out in 13 broad Java topic areas, such as User Interface, Databases, and IO, plus additional chapters for JavaScript and Java Resources. Information on a topic usually starts with very basic information, then progresses to examples, though the book doesn't claim to cover every possibility, such as every stream class. If Special Edition has the information you need, it will be served in an unintimidating way. Tables and screen grabs are put to use throughout.

Table of Contents Special Edition Using Java 2 Platform - 4 Introduction - 8


Part I Introduction to Java

Chapter 1 Chapter 2 Chapter 3 Chapter 4


Part II

- What Java Can Do for You - 10 - Java Design - 19 - Installing The JDK and Getting Started - 37 - JDK Tools - 49
The Java Language

Chapter 5 Chapter 6 Chapter 7 Chapter 8 Chapter 9

- Obejct-Oriented Programming - 61 - HelloWorld!: Your First Java Program - 70 - Data Types and Other Tokens - 81 - Methods - 101 - Using Expressions - 112

Chapter 10 - Control Flow - 122 Chapter 11 - Classes - 135 Chapter 12 - Interfaces - 165 Chapter 13 - Threads - 178 Chapter 14 - Writing an Applet - 195 Chapter 15 - Advanced Applet Code - 222 Chapter 16 - JAR Archive Files - 233

-2-

Chapter 17 - Applets Versus Applications - 247 Chapter 18 - Managing Applications - 268


Part III User Interface

Chapter 19 - java.awt: Components - 276 Chapter 20 - Exceptions and Events in Depth - 313 Chapter 21 - Containers and Layout Managers - 352 Chapter 22 - Graphics - 377 Chapter 23 - JFCJava Foundation Classes - 409 Chapter 24 - Advanced JFC - 441 Chapter 25 - Images - 471 Chapter 26 - Java 2D Graphics - 501
Part IV IO

Chapter 27 - Files, Streams, and Java - 531 Chapter 28 - Using Strings and Text - 570 Chapter 29 - Using Internationalization - 593 Chapter 30 - Communications and Networking - 604 Chapter 31 - TCP Sockets - 623 Chapter 32 - UDP Sockets - 641 Chapter 33 - java.net - 661 Chapter 34 - Java Security in Depth - 688 Chapter 35 - Object Serialization - 710 Chapter 36 - Remote Method Invocation - 722 Chapter 37 - Management API - 739
Part V Databases

Chapter 38 - Databases Introduced - 762 Chapter 39 - JDBC: The Java Database Connectivity - 777 Chapter 40 - JDBC Explored - 800
Part VI Component-Based Development

Chapter 41 - JavaBeans - 817 Chapter 42 - JavaIDL: A Java Interface to CORBA - 838 Chapter 43 - JavaCOM Integration - 863
Part VII Advanced Java

Chapter 44 - Java Media Framework - 875 Chapter 45 - Commerce and Java Wallet - 901 Chapter 46 - Data Structures and Java Utilities - 936 Chapter 47 - java.lang - 964 Chapter 48 - Reflection - 1013 Chapter 49 - Extending Java with Other Languages - 1027 Chapter 50 - Java Versus C(++) - 1041
Part VIII Debugging Java

Chapter 51 - Debugging Java Code - 1060 Chapter 52 - Understanding the .class File - 1103 Chapter 53 - Inside the Java Virtual Machine - 1123

-3-

Part IX

JavaScript

Chapter 54 - Java Versus JavaScript - 1147 Chapter 55 - Starting with JavaScript - 1157
Part X Java Resources

Chapter 56 - Java Resources - 1185


Part XI Appendix

Appendix A - Whats on the CD-ROM - 1191

Back Cover The most comprehensive Java 2 tutorial reference available Upgrade to JFC, the Swing Toolkit, and other new Java 2 technologies Learn how to use all the core Java APIs, including the new Collection interface Save time with professional programming techniques and proven code Create network applications Master object serialization, RMI, and the Management API Build powerful database applications using JDBC Learn JavaBeans, IDL, and COM integration Make your Java application secure About the Author Joe Weber is a frequent contributor to a variety of Java books, magazines, and other resources. He has been working with Java full-time since its early alpha stages and has helped advise a number of Fortune 500 companies on the goals of Java. He has also helped to generate adoption in these organizations. Mr. Weber is a VP of MagnaStar, Inc., a Java consulting firm; serves as the senior technical advisor to Soren Technologies, a medical software company whose systems are written in Java; and currently is the director of the DocuLink product division for Xlink Corporation. Joe has also served on advisory committees and taught classes at universities in the Midwest. He continues to be a strong advocate for Java in the educational environment. Mr. Weber is a cofounder of the Javaology Magazine and has contributed articles to several other Java magazines.

Special Edition Using Java 2 Platform


Joseph Weber

Copyright 1998 by Que All rights reserved. No part of this book shall be reproduced, stored in a retrieval system, or transmitted by any means, electronic, mechanical, photocopying, recording, or otherwise, without written permission from the publisher. No patent liability is assumed with respect to the use of the information contained herein. Although every precaution has been taken in the preparation of this book, the publisher and author assume no responsibility for errors or omissions. Neither is any liability assumed for damages resulting from the use of the information contained herein.

-4-

International Standard Book Number: 0-7897-2018-3 Library of Congress Catalog Card Number: 98-68732 Printed in the United States of America First Printing: January 1999 00 99 98 4 3 2 1

Trademarks
All terms mentioned in this book that are known to be trademarks or service marks have been appropriately capitalized. Que Publishing cannot attest to the accuracy of this information. Use of a term in this book should not be regarded as affecting the validity of any trademark or service mark. Java is a trademark of Sun Microsystems, Inc.

Warning and Disclaimer


Every effort has been made to make this book as complete and as accurate as possible, but no warranty or fitness is implied. The information provided is on an "as is" basis. The authors and the publisher shall have neither liability or responsibility to any person or entity with respect to any loss or damages arising from the information contained in this book or from the use of the CD or programs accompanying it.

Credits
Executive Editor Tim Ryan Acquisitions Editor Jeffrey W. Taylor Development Editor Benjamin Milstead Managing Editor Patrick Kanouse Project Editor Andrew Cupp Copy Editors Geniel Breeze Kelli Brooks Michael Brumitt Cheri Clark Keith Cline Dana Lesh Theresa Mathias San Dee Phillips Heather Urschel Indexer

-5-

Erika Millen Technical Editors Joe Carpenter Jodi Cornelius Software Development Specialist Dan Scherf Production Carol Bowers Mona Brown Michael Dietsch Ayanna Lacey Gene Redding

Dedication
To my parents, Emmet and Ruth, who taught me faith and dedication. I love them dearly.

About the Authors


Joe Weber is a frequent contributor to a variety of Java books, magazines, and other resources. He has been working with Java full-time since its early alpha stages and has helped advise a number of Fortune 500 companies on the goals of Java. He has also helped to generate adoption in those organizations. Mr. Weber is a V.P. of MagnaStar Inc., a Java consulting firm; serves as the senior technical advisor to Soren Technologies, a medial software company whose systems are written in Java; and currently is the director of the DocuLink product division for XLink Corporation. Joe has also served on advisory committees for and taught classes at universities in the Midwest. He continues to be a strong advocate for Java in the educational environment. Mr. Weber is a cofounder of the Javaology Magazine and has contributed articles to several other Java magazines. Mr. Weber loves to hear from his readers and can be reached via email at [email protected]. Mark Wutka is a senior systems architect who refuses to give up his programming hat. For the past three years he has worked as the chief architect on a large, object-oriented distributed system providing automation for the flight operations division of a major airline. Over the past nine years, he has designed and implemented numerous systems in Java, C, C++, and Smalltalk for that same airline. He is currently Vice President of Research and Development for Pioneer Technologies, a consulting firm specializing in distributed systems and legacy system migration. He can be reached via email at [email protected]. He also claims responsibility for the random bits of humor at www.webcom.com/wutka.

Acknowledgments
I would like to thank and acknowledge the huge numbers of individuals who have worked on this book. A volume like the one that you hold in your hands right now is not the work of a single individual, but is a collaboration of the efforts of the writers, editors, and the developer. So many people contribute to a work like this behind the scenes, and unfortunately I don't even know all of their names, but their efforts are greatly appreciated. In particular I would like to thank Ben Milstead, who has developed this work and, along with Joe Carpenter and Jodi Cornelius, helped to insure that what you read is accurate. It would be impossible for this book to have the degree of accuracy that it has with out

-6-

these people's efforts. I would like to thank Jeff Taylor, who was the last in a string of acquisition editors on this book, and who has stuck through it and made life so much easier. I would be remiss if I did not single out the efforts of Mark Wutka. Mark has helped to write portions of this book since its first edition and his skills and work have helped to add volume and understanding to this book. Mark deserves my immense gratitude and thanks for his contributions. I would also like to acknowledge Stephanie Gould, my first Acquistions Editor, who convinced me to work on my first book and showed me that I like writing. Mark Arend and Gene deGroot who, when I was not so much younger, each taught me perseverance and creativity. Shawn Gubine, my oldest and dearest friend, for reasons not even he probably knows. Scott Morris, who taught me that the correct answer to why most software works the way it does is, "because they didn't ask me," and that confidence is 99 percent of success. David and Dorothy, my siblings, who have added humanity. Finally, last, but most importantly, I would like to thank my wife, Kim, whose patience, understanding, and love have allowed this book to come into existence. Kim deserves as much credit as I for making this book happen.

Tell Us What You Think!


As the reader of this book, you are our most important critic and commentator. We value your opinion and want to know what we're doing right, what we could do better, what areas you'd like to see us publish in, and any other words of wisdom you're willing to pass our way. As the Executive Editor for the Java team at Macmillan Computer Publishing, I welcome your comments. You can fax, email, or write me directly to let me know what you did or didn't like about this bookas well as what we can do to make our books stronger. Please note that I cannot help you with technical problems related to the topic of this book, and that due to the high volume of mail I receive, I might not be able to reply to every message. When you write, please be sure to include this book's title and author as well as your name and phone or fax number. I will carefully review your comments and share them with the author and editors who worked on the book. Fax: Email: Mail: 317-817-7070 [email protected]

Tim Ryan, Executive Editor Java Team Macmillan Computer Publishing 201 West 103rd Street

-7-

Indianapolis, IN 46290 USA

Introduction
Overview
Welcome to the amazing and dynamic world of Java! If you are brand new to Java, you're in for a treat. Java is an extremely rich language that is simple and easy to learn. Java gives the programmer unprecedented access to even the most complex of tasks. What is Java? Java is a revolutionary programming language that was introduced by Sun Microsystems in June 1995. Since then, hundreds of thousands of programmers have picked up books just like the one you hold in your hands now and have realized just how powerful the language is. Java is an object-oriented programming language, which means that people programming in Java can develop complex programs with great ease. In addition, Java has built-in support for threads, networking, and a vast variety of other tools. A note about version numbers: The final release of Java in December 1998 was called Java 2. At that time, however, the JDK was still being called JDK 1.2. Don't be confused; JDK 1.2 is part of Java 2, and this book covers both.

This Book Is for You


If you're new to Java, this book is for you. Don't be intimidated by the size of this book. It contains a vast amount of rich information about every facet of the Java programming language, along with easy-to-follow chapters that are designed to get you started. If you're already a Java expert, this book will become a treasured item on your shelf. Actually, it may never leave your desk. This book puts into one source the most complete reference and set of examples on every aspect of the Java programming language ever compiled. No currently available API has gone unexplored; no programming method has gone undocumented. Between the covers of this book, you find examples and explanations that will make your life as a programmer immensely easier.

How This Book Is Organized


This book is organized into 11 parts. Each part covers a large chunk of information about how the Java programming language is organized. Part I, "Introduction to Java," introduces you to the design of the Java language and the Virtual Machine. It shows you what Java can do for you, and how it's being implemented in some programs today. Clear instructions have been included to help you get started by downloading the Java Development Kit and installing it. Finally, this part teaches you how each of the free tools included in the Java Development Kit (JDK) work. Part II, "The Java Language," shows how Java's syntax is developed. The fundamental aspects of Java are found in its language syntax. Every program is built using the fundamentals of the language, and this part walks you through each segment. The second half of this part talks about building specific Java programs, such as applets and applications. For the beginner, each of the chapters has been structured to help you become familiar with Java programming. For the expert, the individual aspects of the language are explored in great detail, making Part II a great reference as well as a learning tool. Part III, "User Interface," teaches you the details of building a graphical user interface in Java. It shows you how to do this using the traditional AWT interfaces, and then

-8-

demonstrates the new features of Java 1.2 with the Java Foundation Classes (also know as Swing). In addition, this part explores how to build and manipulate images, and then discusses Java 1.2's 2D graphics system. Part IV, "IO," walks you through reading and writing data into your Java application. The part begins by teaching you the fundamental components and techniques of streaming and reading files. Then you learn how to build networked applications. You'll find priceless information about the internet's TCP/IP protocol. The part finishes by teaching you about the more advanced features, such as making sure your data transfers are secure. It covers using Java's serialization for sending and retrieving whole Java objects, and using Remote Method Invocation to run entire Java programs on remote machines. Finally, the part wraps up by discussing the new management API in Java 1.2 that allows you to talk to advanced devices, such as routers. Part V, "Databases," walks you through the details of one of the most important aspects of building modern business applications. Databases are the core to almost all business applications, and Java's JDBC (Java DataBase Connectivity) eases the burden of communicating between your Java applications and the database. In this part, you are introduced to how databases work, given a bit of history, and then you learn the terminology required to go on. Next, you explore Java's JDBC interface, which allows you to connect, send, and store data to any JDBC-compliant database. Welcome to the world of platform-independent and DBMS-independent systems! Part VI, "Component-Based Development," will be fascinating to anyone interested in learning how to make the development cycle faster and easier. Component-based development has been around for many years now, but it has never been as easy to do as with Java. In this part, you will learn how to use three different component models: Java's own JavaBeans specification, CORBA (which is rapidly becoming an industry standard, and maps very nicely to JavaBeans), and COM (Microsoft's interface for talking to Windows). Part VII, "Advanced Java," teaches you about some very complex technologies surrounding Java when you're ready to take the next step. Part VII shows you advanced techniques. You learn how to take advantage of the server-side capabilities of Java and how to use the Java Wallet for building commerce applications. You also learn about Java's built-in data structures and utilities, and how to build native applications. This part finishes with a comparison of Java to C++. Part VIII, "Debugging Java," teaches you all the tricks of the trade. This part will quickly become invaluable as you learn how important good debugging technique is when developing applications. You will find great references on every aspect of the sun.tools.debug package, as well as on the op-codes for Java's Virtual Machine. Part IX, "JavaScript," talks about the distant cousin to Java, JavaScript, which can help you do tasks with great ease. Because it can control the browser, it can even do some things Java can't. This part teaches you JavaScript programming, so you'll be multilingual. Part X, "Java Resources," is a perfect source for additional material beyond this book. You'll find some terrific Web sites and other material to help you stay up to date and on top of the Java community. Part XI, "Appendix," gives you an overview of all of the resources on the CD-ROM included with this book.

Conventions Used in This Book


This book uses various stylistic and typographic conventions to make it easier to use. Note When you see a note in this book, it indicates additional information that may

-9-

help you avoid problems or that should be considered in using the described features. Tip Tip paragraphs suggest easier or alternative methods of executing a procedure. Tips can help you see that little extra concept or idea that can make your life so much easier. Caution Cautions warn you of hazardous procedures (for example, activities that delete files). Special Edition Using Java 2 uses cross-references to help you access related information in other parts of the book. See "The Object Class."

Part I: Introduction to Java


Chapter List
Chapter 1: What Java Can Do for You Chapter 2: Java Design Chapter 3: Installing the JDK and Getting Started Chapter 4: JDK Tools

Chapter 1: What Java Can Do for You


The Many Types of Java Applications
By now you have probably heard enough hype about Java to go out and buy this book. The good news is that the hype is well-justified. Java is probably everything you have heard that it is and more. In this chapter, you examine the various possibilities provided by the Java language by taking a look at the different types of applications you can develop with it. To drive the point home, you then take a look at several examples of Java applets that are currently on the Web. You also examine examples of a Java Graphical User Interface (GUI) application and a Java command line application. By the end of this chapter, you should have a fairly good idea of what you can accomplish with Java and be excited about this language, the incredible new enhancements with JDK 1.2, and how Java is changing the computing world. Java is not used only to create applets or servlets. The amazing thing about Java is that it can be used to create a huge variety of applications. The following are a few of the types of applications you can build in Java: Applets (mini applications) GUI applications Command line applications Servlets (server side applications)

- 10 -

Packages (libraries) Embedded applications (such as oscilloscopes and other embedded computers) Pen-based programs Applets are essentially applications that run inside a Java-enabled browser, such as Netscape Navigator, Microsoft Internet Explorer, or HotJava. GUI applications developed in Java have graphical interfaces and stand on their own. They operate like any other GUI application, for instance the Windows Notepad application, which does not require a Web browser to execute it. Command line applications can be run from an MS-DOS command prompt or a UNIX shell prompt, just like the xcopy command in MS-DOS or the ls command in UNIX. Packages are not applications per se. Rather, packages are more like a collection of classes (portable Java-bytecode files) that belong to one package (similar to a C++ class library). There is no custom format for packages like those used with static and dynamic libraries on the various operating systems. The implementation in Java is much simpler and more portable. Basically, all classes belonging to a package are placed in one directory. For example, all classes belonging to Java's Abstract Window Toolkit (AWT) package, java.awt, are placed in a directory called AWT under the C:\jdk1.2\src directory. This is a directory tree of various packages provided with the Java Development Kit: c:\java\classes |___applet |___awt | |___Button.class | |___Color.class | |___Event.class |___io |___lang |___net |___util A few examples of class files under the AWT directory are also shown to illustrate the point here (in actuality, there are several dozen class files under the AWT directory).

Learning About the Java Language


When Java was first created, Sun Microsystems released a white paper that described Java with a series of buzzwords to make your head spin: Java is a simple, object-oriented, robust, secure, portable, high-performance, architecturally neutral, interpreted, multithreaded, dynamic language. Phew! Try saying all that in one breath. Anyway, the language itself is discussed in more detail in the remainder of this book, but the one buzzword you need to learn for this chapter is interpreted. Java source code compiles into portable bytecodes that require an interpreter to execute them. For applets, this task is handled by the browser. For GUI and command line applications, the Java interpreter program is required to execute the application. The

- 11 -

examples shown in the section "Java Command Line Applications" later in this chapter illustrate both methods.

The Java Development Kit


The reason Java is so popular is not simply because of the benefits of the language itself. The rich sets of packages (or class libraries to you C++ programmers) that come bundled with the Java Development Kit (JDK) from Sun Microsystems also contribute to its popularity. These prewritten objects get you up and running with Java quickly, for two main reasons: You do not need to develop the functionality they provide. The source code is available for all. Here is a brief description of some of the more significant packages provided with Java: Package java.applet java.awt Description Classes for developing applets. Abstract Window Toolkit (AWT) classes for the GUI interface, such as windows, dialog boxes, buttons, text fields, and more. Classes for networking, URLs, client/server sockets. Classes for various types of input and output. Classes for various data types, running processes, strings, threads, and much more. Utility classes for dates, vectors, and more.

java.net java.io java.lang

java.util

java.awt.image Classes for managing and manipulating images.

Java Applets
As mentioned previously, Java applets run within a Java-enabled Web browser. Because Web browsers were primarily developed for displaying HTML documents, incorporating Java applets inside a Web browser requires an HTML tag to invoke an applet. This HTML tag is the <APPLET> tag, as shown in the following example: <applet code=TextEdit.class width=575 height=350></applet> You will explore all the details of Applets in Chapters 14 and 15.

Real-World Examples of Java Applets on the Web


Because pictures truly say more than a thousand words, you will enjoy taking a look at some examples of real-world Java applets on the Web today. Figures 1.2 through 1.11 are examples of these applets. Figure 1.1 shows a Java application called NetProphet. NetProphet is a wonderful utility that allows you to chart and graph all of your stocks. It is a wonderful example of how having a Java client interacting with a server (client/server) can be used to create

- 12 -

dynamic information. Netprofit is available from Neural Applications at http://www.neural.com/NetProphet/NetProphet.html.

Figure 1.1: NetProphet is a wonderful example of client/server Java.

Figure 1.2 shows how Eastland Data Systems's Internet Shopping Applet (http://www.eastland.com/shoptech.html) has been applied by Blossom Flowers (http://www.blossomflowers.com/shopping_frame.html).

Figure 1.2: Internet shopping by Eastland.

This applet is unique because it implements drag-and-drop features on the Internet. Java has been shown to be a great language to write Internet games in. Figure 1.3 shows the famous Rubik's Cube that amused everyone a few years ago. This is a fully functional Rubik's cube developed in Java. You can play with it live on the Internet at http://www.tdb.uu.se/~karl/java/rubik.html.

- 13 -

Figure 1.3: Rubik's Cube.

Figure 1.4 below shows another game that uses 3D graphics. Palle Pedalpost (http://www.zapper.kd/postpil/postgame.html) performs with smooth animation, and is definitely worth a look.

Figure 1.4: Pelle Pedalpost.

Lotus has been very innovative in its use of the Java language with the eSuite program. eSuite is a collection of tools for building groupware applications, and is shown in Figure 1.5.

- 14 -

Figure 1.5: Lotus eSuite.

One of the wonderful enhancements with JDK 1.2 is the capability to have applications display multimedia. Figure 1.6 shows an MPG movie playing within a Java program.

Figure 1.6: This MPG movie is playing in a Java program.

The Chicago Tribune has used Java Servlets to create a wonderful site called Metromix. Metromix, shown in Figure 1.7, is a source of entertainment in the Chicago area.

Figure 1.7: Metromix Web site.

- 15 -

A group of students from Harvard has created a truly innovative system for scheduling classes. This system, shown in Figure 1.8, can be viewed from http://www.digitas.harvard.edu.

Figure 1.8: Digitas Course Decision Assistant.

Java GUI Applications


While Java applets have stolen most of Java's thunder, Java goes a lot further than applets. Java can be used to develop portable GUI applications across all supported platforms. In fact, the same Java source code can be used for both an applet and an application. To illustrate this, look at an application called Text Editor that was developed for demonstration purposes. As the name implies, this application is used for editing text files, similar to the Windows Notepad application. Figure 1.9 shows the applet version of the Text Editor, Figure 1.10 shows the application version on Windows 95, and Figure 1.11 shows the application version under Solaris.

Figure 1.9: The Text Editor application running as an applet.

- 16 -

Figure 1.10: The Text Editor application on Windows 95 runs using the Java interpreter.

Figure 1.11: The Text Editor application on Solaris.

All three versions of the Text Editor were generated using the same Java source files. In fact, all three versions are executed using the same bytecode files that were compiled only once under Windows 95 and copied to Solaris without requiring a recompilation. Notice how the Java interpreter is used on the MS-DOS prompt to execute the application. Notice the File dialog box in Figures 1.10 and 1.11. If you are a Windows 95 or Solaris user, you know they are the standard File dialog boxes used on these operating systems. As a developer, you do not need to custom code anything to get the native look and feel. All you have to do is ensure that the class (bytecode) files are available from where the applet or application needs to be invoked. The rest (the native look and feel, systemspecific features, and so on) is handled by Java's dynamic link libraries.

Java Command Line Applications


Even in today's world, where GUI applications have become a standard on practically every type of computer, there are times when you might need to drop down to the command line to perform some tasks. For these times, Java provides the capability to develop command line applications.

- 17 -

The only difference between command line and GUI applications is that command line applications do not use any of the GUI features provided in Java. In other words, command line applications do not use the java.awt package. Figure 1.12 shows an example of a command line application, copyURL, which essentially is a copy utility for copying files from the Internet to a local disk. This application uses the java.net package to obtain information about a resource (file) on the Internet. Then copyURL uses the java.io package to read the bytes of data from the file on the Internet and write them to a local file.

Figure 1.12: copyURL.class is an Internet command line copy utility.

Java Is Client/Server
In today's computing world, client/server technology has found a place in most corporations. The biggest benefit of this technology is that the processing load is shared between the client and the server. A client can be any program (GUI application, Telnet, and so on) that requests services from a server application. Examples of server applications include database servers, application servers, communication (FTP, Telnet, Web) servers, and more. In this chapter, you have seen several examples of Java client-side applets and applications. However, Java provides classes for server-side processing as well. Java applications can be used as clients or servers, whereas applets can only be used for client-side processing. The java.net package provides classes necessary for developing client/server applications. Figure 1.13 shows a Java applet, javaSQL, that sends free-form SQL queries typed in by the user to a server application, javaSQLd. javaSQLd in turn queries a database and returns the query results to the javaSQL applet.

- 18 -

Figure 1.13: javaSQL client applet.

Figure 1.14 illustrates the relationship between javaSQL and javaSQLd. Imagine querying a database at work from home via a Java-enabled browser. With Java, the possibilities are endless!

Figure 1.14: javaSQL and javaSQLd.

How to Stay Current


Web-related technology is progressing so rapidly that it is difficult to stay on top of new events. The pace of innovation on the Internet is extremely rapid, and Java has been growing at a rate at least as astounding as the rest of the technology. About the only way to stay current is to visit certain Web sites that post the latest news and Java examples. While there are dozens of Java-related Web sites that provide timely information, you will find a list of some of those that have a history of providing great information in Chapter 56, "Java Resources."

Chapter 2: Java Design


Java Is Interpreted
Before you write any applets or programs with Java, it is important to understand how Java works. This chapter introduces you to the actual language, the limitations of the language (intentional and unintentional), and how code can be made reusable. Strictly speaking, Java is interpreted, although in reality Java is both interpreted and compiled. In fact, only about 20 percent of the Java code is interpreted by the browser, but this is a crucial 20 percent. Both Java's security and its ability to run on multiple platforms stem from the fact that the final steps of compilation are handled locally. A programmer first compiles Java source into bytecode using the Java compiler. These bytecodes are binary and architecturally neutral (or platform-independentboth work equally well). The bytecode isn't complete, however, until it's put together with a Java runtime environment, usually a browser. Because each Java runtime environment is for a specific platform, the bytecodes can be interpreted for the specific platform and the final product will work on that specific platform. This platform-specific feature of Java is good news for developers. It means that Java code is Java code is Java code, no matter what platform you're developing for or on. You could write and compile a Java applet on your UNIX system and embed the applet into your Web page. Three different people on three different machines, each with different environments, can take a peek at your new applet. Provided that each of those people runs a Java-capable browser, it won't matter whether he or she is on an IBM, HP, or Macintosh. Using Java means that only one source of Java code needs to be maintained for the bytecode to run on a variety of platforms. One pass through a compiler for multiple platforms is good news for programmers. The one drawback that comes with interpretation, however, is that there is a performance

- 19 -

hit. This is caused by the fact that the browser has to do some work with the class files (interpret them) before they can be run. Under traditional programming, such as with C++, the code that is generated can be run directly by the computer. The performance hit that interpretation causes means that Java programs tend to run about 1/2 to 1/6 the speed of their native counterparts. This deficiency is largely overcome using a tool called a just-in-time (JIT) compiler. A justin-time compiler compiles Java methods to native code for the platform you're using. It is embedded with the Java environment for a particular platform (such as Netscape). Without the JIT compiler, methods are not translated to native code but remain in the original machine-independent bytecode. This bytecode is interpreted on any platform by the Java Virtual Machine. A Java application is portable, but the just-in-time compiler itself cannot be portable because it generates native code specific to a platform, exactly as you need a different version of the virtual machine for each new platform. Generally, you don't even need to concern yourself with JITs. Both the Netscape Navigator and Microsoft's Internet Explorer browsers have JIT compilers in them. Why is this combination of compilation and interpretation a positive feature? It facilitates security and stability. The Java environment contains an element called the linker, which checks data coming into your machine to make sure it doesn't contain deliberately harmful files (security) or files that could disrupt the functioning of your computer (robustness). More importantly, this combination of compilation and interpretation alleviates concern about version mismatches. The fact that the final portion of compilation is being accomplished by a platform-specific device, which is maintained by the end user, relieves you of the responsibility of maintaining multiple sources for multiple platforms. Interpretation also enables data to be incorporated at runtime, which is the foundation of Java's dynamic behavior.

Java Is Object Oriented


Java is an object-oriented language. Therefore, it's part of a family of languages that focuses on defining data as objects and the methods that may be applied to those objects. As explained, Java and C++ share many of the same underlying principles; they just differ in style and structure. Simply put, object-oriented programming languages (OOP, for short) describe interactions among data objects. See Chapter 50, "Java Versus C(++)," to learn more about the similarities of Java with C++. Many OOP languages support multiple inheritance, which can sometimes lead to confusion or unnecessary complications. Java doesn't. As part of its less-is-more philosophy, Java supports only single inheritance, which means each class can inherit from only one other class at any given time. This type of inheritance avoids the problem of a class inheriting classes whose behaviors are contradictory or mutually exclusive. Java enables you to create totally abstract classes, known as interfaces. Interfaces allow you to define methods you can share with several classes, without regard for how the other classes are handling the methods. See Chapter 5, "Object-Oriented Programming," to learn more. Note Although Java does not support multiple inheritance, Java does allow a class to implement more than one interface. Each class, abstract or not, defines the behavior of an object through a set of methods. All the code used for Java is divided into classes. Methods can be inherited from one class to the next, and at the head of the class hierarchy is

- 20 -

the class called Object. The Object class belongs to the java.lang package of the Java Core API. You are introduced in the last section of this chapter to the Java Core API. See Chapter 11, "Classes," to learn more about classes and objects. Objects can also implement any number of interfaces (or abstract classes). The Java interfaces are a lot like the Interface Definition Language (IDL) interfaces. This similarity means it's easy to build a compiler from IDL to Java. That compiler could be used in the Common Object Request Broker Architecture (CORBA) system of objects to build distributed object systems. Is this good? Yes. Both IDL interfaces and the CORBA system are used in a wide variety of computer systems and this variety facilitates Java's platform independence. See Chapter 42, "JavaIDL: A Java Interface to CORBA," to learn more about CORBA. As part of the effort to keep Java simple, not everything in this object-oriented language is an object. Booleans, numbers, and other simple types are not objects, but Java does have wrapper objects for all simple types. Wrapper objects enable all simple types to be implemented as though they are classes. It is important to remember that Java is unforgivingly object oriented; it simply does not allow you to declare anything that is not encapsulated in an object. Even though C++ is considered an OOP language, it enables you to develop bad habits and not encapsulate types. See Chapter 7, "Data Types and Other Tokens," to learn more about types. Object-oriented design is also the mechanism that allows modules to "plug and play." The object-oriented facilities of Java are essentially those of C++, with extensions from Objective C for more dynamic method resolution.

The Java Virtual Machine


The heart of Java is the Java Virtual Machine, or JVM. The JVM is a virtual computer that resides in memory only. The JVM enables Java programs to be executed on a variety of platforms as opposed to only the one platform for which the code is compiled. The fact that Java programs are compiled for the JVM is what makes the language so unique, but in order for Java programs to run on a particular platform, the JVM must be implemented for that platform. See Chapter 53, "Inside the Java Virtual Machine," to learn more about the JVM. The JVM is the very reason that Java is portable. It provides a layer of abstraction between the compiled Java program and the underlying hardware platform and operating system. The JVM is actually very small when implemented in RAM. It is purposely designed to be small so that it can be used in a variety of consumer electronics. In fact, the whole Java language was originally developed with household electronics in mind. Gadgets such as phones, PCs, appliances, television sets, and so on will soon have the JVM in their firmware and allow Java programs to run. Cool, huh?

Java Source Code


Java source code is compiled to the bytecode level, as opposed to the bitcode level. The JVM executes the Java bytecode. The javac program, which is the Java compiler, reads

- 21 -

files with the .java extension, converts the source code in the .java file into bytecodes, and saves the resulting bytecodes in a file with a .class extension. The JVM reads the stream of bytecode from the .class file as a sequence of instructions. Each instruction consists of a one-byte opcode, which is a specific and recognizable command, and zero or more operands (the data needed to complete the opcode). The opcode tells the JVM what to do. If the JVM needs more than just the opcode to perform an action, then an operand immediately follows the opcode. See Chapter 52, "Understanding the .class File," to learn about opcodes. There are four parts to the JVM: Stack Registers Garbage-collection heap Method area

The Java Stack


The size of an address in the JVM is 32 bits. Therefore, it can address up to 4G of memory, with each memory location containing one byte. Each register in the JVM stores one 32-bit address. The stack, the garbage-collection heap, and the method area reside somewhere within the 4G of addressable memory. This 4G of addressable memory limit isn't really a limitation now, because most PCs don't have more than 32M of RAM. Java methods are limited to 32K in size for each single method.

Java Registers
All processors use registers. The JVM uses the following to manage the system stack: Program counter Keeps track of where exactly the program is in execution. Optop Points to the top of the operand stack. Frame Points to the current execution environment. Vars Points to the first local variable of the current execution environment. The Java development team decided that Java would only use four registers because if Java had more registers than the processor it was being ported to, that processor would take a serious reduction in performance. The stack is where parameters are stored in the JVM. The JVM is passed to the bytecode from the Java program and creates a stack frame for each method. Each frame holds three kinds of information: Local variables An array of 32-bit variables that is pointed to by the vars register. Execution environment Where the method is executed and is pointed to by the frame register. Operand stack Acts on the first-in, first-out principle, or FIFO. It is 32 bits wide and

- 22 -

holds the arguments necessary for the opcodes. The top of this stack is indexed by the optop register.

Garbage-Collection Heap
The heap is the collection of memory from which class instances are allocated. Any time you allocate memory with the new operator, that memory comes from the heap. You can call the garbage collector directly, but it is not necessary or recommended under most circumstances. The runtime environment keeps track of the references to each object on the heap and automatically frees the memory occupied by objects that are no longer referenced. Garbage collections run as a thread in the background and clean up during CPU inactivity.

The Java Method Area


The JVM has two other memory areas: Method Constant pool There are no limitations as to where these memory areas must actually exist, making the JVM more portable and secure. The fact that memory areas can exist anywhere makes the JVM more secure in the fact that a hacker couldn't forge a memory pointer. The JVM handles the following primitive data types: byte (8 bits) float (32 bits) int (32 bits) short (16 bits) double (64 bits) char (16 bits) long (64 bits)

Security and the JVM


This section is organized into six parts. You will explore the issue of security of networked computing in general and define the security problem associated with executable content. I propose a six-step approach to constructing a viable and flexible security mechanism. How the architecture of the Java language implements security mechanisms will also be covered. As with any new technology, there are several open questions related to Java security, which are still being debated on the Net and in other forums.

Executable Content and Security


In this section, you will analyze the concept of security in the general context of interactivity on the Web and security implementation via executable content.

- 23 -

Let's examine the duality of security versus interactivity on the Web and examine the evolution of the Web as a medium in the context of this duality. To do this, let's create a definition of the security problem in the context of executable content. The Security Problem Defined A program arriving from outside the computer via the network has to be greeted by the user with a certain degree of trust and allowed a corresponding degree of access to the computer's resources to serve any useful purpose. The program is written by someone else, however, under no contractual or transactional obligation to the user. If this someone is a hacker, the executable content coming in could be a malicious program with the same degree of freedom as a local program. See Chapter 34, "Java Security in Depth," to learn more about Java Security. Does the user have to restrict completely the outside program from accessing any resource whatsoever on the computer? Of course not. This would cripple the ability of executable content to do anything useful at all. A more complete and viable security solution strategy would be a six-step approach: 1. Anticipate all potential malicious behavior and attack scenarios. 2. Reduce all such malicious behavior to a minimal orthogonal basis set. 3. Construct a programming environment/computer language that implicitly disallows the basis set of malicious behavior and, hence, by implication, all potential malicious behavior. 4. Logically or, if possible, axiomatically prove that the language/environment is indeed secure against the intended attack scenarios. 5. Implement and allow executable content using only this proven secure language. 6. Design the language such that any new attack scenarios arising in the future can be dealt with by a corresponding set of countermeasures that can be retrofitted into the basic security mechanism. Working backwards from the previous solution strategy, the security problem associated with executable content can be stated as consisting of the following six subproblems: What are the potential target resources and corresponding attack scenarios? What is the basic, minimal set of behavioral components that can account for the previous scenarios? How should a computer language/programming environment that implicitly forbids the basis set of malicious behavior be designed? How can you prove that such a language/environment is, indeed, secure as claimed? How can you make sure that incoming executable content has, indeed, been implemented in and originated from the trusted language? How can you make the language future proof (extensible) to co-opt security strategies to counter new threats arising in the future? As you will learn, Java has been designed from the ground up to address most (but probably not all) of the security problems as defined here. Before you move on to Java security architecture itself, the attack targets and scenarios are identified next.

- 24 -

Potential Vulnerability In this subsection, I list the various possible attack scenarios and resources on a user's computer that are likely to be targeted by a potentially malicious, external, executable content module. Attack scenarios could belong to one of the following categories and have one of the following goals (this is not an exhaustive list): Damage or modify integrity of data and/or the execution state of programs. Collect and smuggle out confidential data. Lock up resources, making them unavailable for legitimate users and programs. Steal resources for use by an external, unauthorized party. Cause nonfatal but low-intensity unwelcome effects, especially on output devices. Usurp identity and impersonate the user or the user's computer to attack other targets on the network. Table 2.1 lists the resources that could be potentially targeted and the type of attack they could be subject to. A good security strategy assigns security/risk weights to each resource and designs an appropriate access policy for external executable content. Table 2.1 Potential Targets and Attack Scenarios

Targets

Damage Integrity

Smuggle Information

Lock Up/ Deny Usage

Steal Resource

Nonfatal Distraction

Impersonate

File system Confidential data Network CPU Memory Output devices Input devices

X X

X X

X X

X X X

X X

X X X X

X X X X X

X X

X X X

X X

OS, program X state

- 25 -

Java Approach to Security


This following discussion is in reference to the six-step approach outlined in the previous section. Step 1: Visualize All Attack Scenarios Instead of coming up with every conceivable attack scenario, the Java security architecture posits potential targets of a basic set of attack categories very similar to the previous attack scenario matrix. Specifically, the Java security model covers the following potential targets: Memory OS/program state Client file system Network against the following attack types listed in Table 2.1: Damage integrity of software resources on the client machine. Achieved by what is usually called a virus. A virus is usually written to hide itself in memory and corrupt specific files when a particular event occurs or on a certain date. Lock up/deny usage of resource on the client machine. Usually achieved by a virus. Smuggle information out of the client machine. Can be done easily with UNIX SENDMAIL, for example. Impersonate the client machine. Can be done through IP spoofing. This style of attack was brought to the attention of the world by Kevin Mitnick when he hacked into one of computer security guru Tsutumo Shimura's personal machines. The whole incident is well-documented in the New York Times best-selling book Takedown by Tsutumo Shimura. Step 2: Construct a Basic Set of Malicious Behavior Instead of arriving at a basic set of malicious behavior, Java anticipates a basic set of security hotspots and implements a mechanism to secure each of these: Java language mechanism and compiler. Java-compiled class file. Java bytecode verifier and interpreter. Java runtime system, including class loader, memory manager, and thread manager. Java external environment, such as Java Web browsers and their interface mechanisms. Java applets and the degrees of freedom allowed for applets (which constitute executable content).

- 26 -

Step 3: Design Security Architecture Against Previous Behavior Set Construct a programming environment/computer language that implicitly disallows the basic set of malicious behavior and hence, by implication, all potential malicious behavior. You guessed itthis language is Java! Step 4: Prove the Security of Architecture This step involves logically or, if possible, axiomatically proving that the language/environment is indeed secure against the intended attack scenarios. Security mechanisms built into Java have not (yet) been axiomatically or even logically proven to be secure. Instead, Java encapsulates all its security mechanism into distinct and well-defined layers. Each of these security loci can be observed to be secure by inspection in relation to the language design framework and target execution environment of Java language programs and applets. Step 5: Restrict Executable Content to Proven Secure Architecture The Java class file checker and bytecode verifier achieve this objective. Step 6: Make Security Architecture Extensible This step requires that the language be designed. Design the language such that any new attack scenarios arising in the future can be dealt with by a corresponding set of counter-measures, which can be retrofitted into the basic security mechanism. The encapsulation of security mechanisms into distinct and well-defined loci, combined with the provision of a Java SecurityManager class, provides a generic mechanism for incremental enhancement of security.

Security at the Java Language Level


The first tier of security in Java is the language design itselfthe syntactical and semantic constructs allowed by the language. The following is an examination of Java language design constructs with a bearing on security. Strictly Object Oriented Java is fully object oriented, with every single primitive data structure (and, hence, derived data structure) being a first-class, full-fledged object. Having wrappers around each primitive data structure ensures that all the theoretical security advantages of OOP permeate the entire syntax and semantics of programs written in Java: Encapsulation and hiding of data behind private declarations. Controlled access to data structures via public methods only. Incremental and hierarchical complexity of program structure. No operator overloading. Final Classes and Methods Classes and methods can be declared as final, which disallows further subclassing and method overriding. This declaration prevents malicious modification of trusted and verified code. Strong Typing and Safe Typecasting Typecasting is security checked both statically and dynamically, which ensures that a declared compile-time type of an object is strictly compatible with eventual runtime type, even if the object transitions through typecasts and coercions. Typecasting prevents malicious type camouflaging. No Pointers This is possibly the strongest guarantor of security that is built right into the Java language. Banishment of pointers ensures that no portion of a Java program is ever

- 27 -

anonymous. Every single data structure and code fragment has a handle that makes it fully traceable. Language Syntax for Thread-Safe Data Structures Java is multithreaded. Java language enforces thread-safe access to data structures and objects. Chapter 13, "Threads," examines Java threads in detail, with examples and application code. Unique Object Handles Every single Java object has a unique hash code that is associated with it. This means that the state of a Java program can be fully inventoried at any time.

Security in Compiled Java Code


At compile time, all the security mechanisms implied by the Java language syntax and semantics are checked, including conformance to private and public declarations, typesafeness, and the initialization of all variables to a guaranteed known value. Class Version and Class File Format Verification Each compiled class file is verified to conform to the currently published official class file format. The class file is checked for both structure and consistency of information within each component of the class file format. Cross-references between classes (via method calls or variable assignments) are verified for conformance to public and private declarations. Each Java class is also assigned a major and minor version number. Version mismatches between classes within the same program are checked. Bytecode Verification Java source classes are compiled into bytecodes. The bytecode verifier subjects the compiled code to a variety of consistency and security checks. The verification steps applied to bytecode include: Checking for stack underflows and overflows. Validating of register accesses. Checking for correctness of bytecode parameters. Analyzing dataflow of bytecode generated by methods to ensure integrity of a stack, objects passed into and returned by a method. Namespace Encapsulation Java classes are defined within packages. Package names qualify Java class names. Packages ensure that code which comes from the network is distinguished from local code. An incoming class library cannot maliciously shadow and impersonate local trusted class libraries, even if both have the same name. This also ensures unverified, accidental interaction between local and incoming classes. Very Late Linking and Binding Late linking and binding ensures that the exact layout of runtime resources, such as stack and heap, is delayed as much as possible. Late linking and binding constitutes a road block to security attacks by using specific assumptions about the allocation of these resources.

Java Runtime System Security


The default mechanism of runtime loading of Java classes is to fetch the referred class from a file on the local host machine. Any other way of loading a classincluding from across the networkrequires an associated ClassLoader. A ClassLoader is a subtype of the standard Java ClassLoader class, which has methods that implement all the consistency and security mechanisms and applies them to every class that is newly loaded.

- 28 -

For security reasons, the ClassLoader cannot make any assumptions about the bytecode, which could have been created from a Java program compiled with the Java compiler. The bytecode could also have been created by a C++ compiler modified to generate Java bytecode. This means the ClassLoader kicks in only after the incoming bytecode has been verified. ClassLoader has the responsibility of creating a namespace for downloaded code and resolving the names of classes referenced by the downloaded code. The ClassLoader enforces package-delimited namespaces. Automatic Garbage Collection and Implicit Memory Management In C and C++, the programmer has the explicit responsibility to allocate memory, deallocate memory, and keep track of all the pointers to allocated memory. This often is a maintenance nightmare and a major source of bugs that result from memory leaks, dangling pointers, null pointers, and mismatched allocation and deallocation operations. Java eliminates pointers and, with it, the programmer's obligation to manage memory explicitly. Memory allocation and deallocation are automatic, strictly structured, and fully typesafe. Java uses garbage collection to free unused memory instead of explicit programmer-mediated deallocation. Garbage collection eliminates memory-related bugs as well as potential security holes. Manual allocation and deallocation allows unauthorized replication, cloning, and impersonation of trusted objects, as well as attacks on data consistency. SecurityManager Class SecurityManager is a generic and extensible locus for implementing security policies and providing security wrappers around other parts of Java, including class libraries and external environments (such as Java-enabled browsers and native methods). The SecurityManager class itself is not intended to be used directly (each of the checks defaults to throwing a security exception). It is a shell class that is intended to be fleshed out via subclassing to implement a specific set of security policies. Among other features, SecurityManager has methods to determine whether a security check is in progress and also checks the following: To prevent the installation of additional ClassLoaders. If dynamic libraries can be linked (used for native code). If a class file can be read from. If a file can be written to. If a network connection can be created. If a certain network port can be listened to for connections. If a network connection can be accepted. If a certain package can be accessed. If a new class can be added to a package. The security of a native OS system call.

Security of Executable Code


- 29 -

The major source of security threats from and to Java programs is Java code that comes in across the network and executes on the client machine. This class of transportable Java programs is called the Java applet class. A Java applet has a very distinct set of capabilities and restrictions within the language framework, especially from the security standpoint. File System and Network Access Restrictions Applets loaded over the network have the following restrictions imposed on them: They cannot read or write files on the local file system. They cannot create, rename, or copy files and directories on the local file system. They cannot make arbitrary network connections, except to the host machine they originally came from. The host machine would be the host domain name specified in the URL of the HTML page that contains the <APPLET> tag for the applet, or the host name specified in the CODEBASE parameter of the <APPLET> tag. The numeric IP address of the host does not work. The previous strict set of restrictions on access to a local file system applies to applets running under Netscape Navigator. The JDK AppletViewer slightly relaxes the restrictions by letting the user define a specific, explicit list of files that can be accessed by applets. Now, as you will learn in Chapter 16, "JAR," it is possible to overcome the limitations on applets in 1.1-compliant browsers by "signing" the files. This enables applets that need to perform one of these functions this capability while maintaining a security framework. External Code Access Restrictions Applets cannot do the following: Call external programs via such system calls as fork or exec. Manipulate any Java thread groups except their own thread group that is rooted in the main applet thread. System Information Access Applets can read some system properties by invoking System.getProperty (String key). Applets under Netscape have unrestricted access to these properties. Sun's JDK AppletViewer enables individual control over access to each property. Table 2.2 lists the type of information returned for various values of key. Table 2.2 System Variable Availability

Key

Information Returned

java.version java.vendor java.vendor.url java.class.version

Java version number Java vendor-specific string Java vendor URL Java class version number

- 30 -

os.name os.arch file.separator path.separator line.separator

Operating system name Operating system architecture File separator (such as /) Path separator (such as :) Line separator

Inaccessible System Information The information provided in Table 2.3 is not accessible to applets under Netscape. AppletViewer and the HotJava browser enable user-controllable access to one or more of these resources. Table 2.3 System Variables Restricted from Applets

Key

Information Returned

java.home

Java installation directory

java.class.path Java classpath user.name user.home user.dir User's account name User's home directory User's current working directory

Applets Loaded from the Local Client There are two different ways that applets are loaded by a Java system (note: this applies only to AppletViewer). An applet can arrive over the network or be loaded from the local file system. The way an applet is loaded determines its degree of freedom. If an applet arrives over the network, it is loaded by the ClassLoader and is subject to security checks imposed by the ClassLoader and SecurityManager classes. If an applet resides on the client's local file system in a directory listed in the user's CLASSPATH environment variable, then it is loaded by the file system loader. From a security standpoint, locally loaded applets can: Read and write the local file system. Load libraries on the client. Execute external processes on the local machine.

- 31 -

Exit the JVM. Skip being checked by the bytecode verifier.

Open Issues
Having examined the issue of security of executable content both in general and specifically in the framework of Java, you now examine some aspects of security that are not fully addressed by the current version of the Java architecture. You also learn if, for some types of threats, 100 percent security can be achieved. The following components of the Java architecture are the loci of security mechanisms: Language syntax and semantics. Compiler and compiled class file format and version checker. Bytecode verifier and interpreter. Java runtime system, including ClassLoader, SecurityManager, memory, and thread management. Java external environment, such as Java Web browsers and their interface mechanisms. Java applets and the degrees of freedom allowed for applets (which constitute executable content). Security provided by each of these layers, however, can be diluted or defeated in some ways with varying degrees of difficulty: Data layout in the source code can be haphazard and exposed despite hiding and control mechanisms provided by Java syntax. This situation can lead to security breaches if, for instance, access and assignment to objects are not thread safe or data structures that ought to be declared private are instead exposed as public resources. The runtime system is currently implemented in a platform-dependent, non-Java language, such as C. The only way to ensure the system is not compromised is by licensing it from Sun or comparing it with a reference implementation. Using runtime systems written in non-Java languages can lead to a security compromise if, instead of using Sun's own runtime system or a verified clone, someone uses a home-brew or no-name version of the runtime that has diluted versions of the class loader or bytecode verifier. The interface between Java and external non-Java environments, such as Web browsers, may be compromised. Security issues that cannot easily be addressed within Java (or any other mechanism of executable content, for that matter) include: CPU resources on the client side can be stolen. A user can send an applet to your computer that uses your CPU to perform some computation and returns the results back to the user. Applets can contain nasty or annoying content (images, audio, or text). If this happens often, users have to block applets on a per-site basis. User-definable content filtering should be integrated into the standard Java class library.

- 32 -

An applet can allocate an arbitrary amount of memory. An applet can start up an arbitrary number of threads. Security compromises can arise out of inherent weaknesses in Internet protocols, especially those that were implemented before Java and executable content burst on the scene. One generic way to deal with security problems is for Java applet classes to be sent encrypted and digitally signed. The ClassLoader, SecurityManager, and even the bytecode verifier can include built-in decryption and signature verification methods. Note These and other open issues related to Java security are topics of ongoing debate and exploration of specific and involved security breach scenarios, especially on online forums. The next and final section of this chapter points to references and sources of further information on this topic.

The Java API


The Java Application Programming Interface, or API, is a set of classes developed by Sun for use with the Java language. It is designed to assist you in developing your own classes, applets, and applications. With these sets of classes already written for you, you can write an application in Java that is only a few lines long, as opposed to an application that would be hundreds of lines long if it were written in C. Which would you rather debug? The classes in the Java API are grouped into packages, each of which may have several classes and interfaces. Furthermore, each of these items may also have several properties, such as fields and/or methods. Although it is possible to program in Java without knowing too much about the API, every class that you develop will be dependent on at least one class within the API, with the exception of java.lang.Object, which is the superclass of all other objects. Consequently, when you begin to develop more complex programs that deal with strings, sockets, and graphical interfaces, it is extremely helpful for you to know the objects provided to you by Sun, as well as the properties of these objects. Tip I suggest downloading the Core API in HTML format from JavaSoft and reading through it to really get a good feel of how the language works. As you go through each package, you will begin to understand how easy to use and powerful an object-oriented language like Java can be.

Java Core API


The Core API is the API that is currently shipped with Java 1.1. These packages make up the objects that are guaranteed to be available, regardless of the Java implementation, so long as the implementation supports at least version 1.1: java.lang java.lang.reflect java.bean java.rmi, java.rmi.registry, and java.rmi.server

- 33 -

java.security, java.security.acl, and java.security.interfaces java.io java.util java.util.zip java.net java.awt java.awt.image java.awt.peer java.awt.datatransfer java.awt.event java.applet java.sql java.text Note Those packages that were added under 1.1 are only guaranteed to be available on machines supporting the 1.1 API. java.lang The java.lang package consists of classes that are the core of the Java language. It provides you not only with the basic data types, such as Character and Integer, but also the means of handling errors through the Throwable and Error classes. Furthermore, the SecurityManager and System classes supply you with some degree of control over the Java Runtime System. See Chapter 47, "java.lang," to learn more about java.lang. java.io The java.io package serves as the standard input/output library for the Java language. This package provides you with the ability to create and handle streams of data in several ways. It provides you with types as simple as a String and as complex as a StreamTokenizer. java.util The java.util package is composed essentially of a variety of useful classes that do not truly fit in any of the other packages. Among these handy classes are: Date class, designed to manage and handle operations with dates. Hashtable class. Classes to develop ADTs, such as Stack and Vector. See Chapter 46, "Data Structures and Java Utilities," to learn more about the java.util packag. java.net The java.net package is the package that makes Java a networked-based

- 34 -

language. It provides you with the capability to communicate with remote sources by creating or connecting to sockets or using URLs. You can write your own Telnet, Chat, or FTP clients and/or servers, for example, by using this package. java.awt The java.awt package is also known as the Java Abstract Window Toolkit (AWT). It consists of resources that enable you to create rich, attractive, and useful interfaces in your applets and standalone applications. The AWT not only contains managerial classes, such as GridBagLayout, but it also has several concrete interactive tools, such as Button and TextField. More importantly, however, is the Graphics class that provides you with a wealth of graphical abilities, including the ability to draw shapes and display images. java.awt.image The java.awt.image package is closely related to the java.awt package. This package consists of tools that are designed to handle and manipulate images coming across a network. java.awt.peer java.awt.peer is a package of interfaces that serve as intermediaries between your code and the computer on which your code is running. You probably won't need to work directly with this package. java.applet The java.applet package is the smallest package in the API, but it is also the most notable as a result of the Applet class. This class is full of useful methods, as it lays the foundation for all applets and is also able to provide you with information regarding the applet's surroundings via the AppletContext interface. 1.1 Packages The following packages were added to Java during the 1.1 upgrade: java.awt.datatransfer java.awt.datatransfer provides classes for dealing with the transfer of data. This includes new classes for clipboards and the capability to send Java strings. java.awt.event Under JDK 1.0, all events used a single class called java.awt.event. This mechanism proved to be fairly clumsy and difficult to extend. To combat this, the java.awt.event package provides you the ability to use events any way you want.

JavaBean API
The JavaBean API defines a portable, platform-neutral set of APIs for software components. JavaBean components are also able to plug into existing component architectures, such as Microsoft's OLE/COM/ActiveX architecture, OpenDoc, and Netscape's LiveConnect. The advantage of JavaBean is that end users are able to join JavaBean components using application builders, such as the BeanBox. A button component could trigger a bar chart to be drawn in another component, for example, or a live data feed component could be represented as a chart in another component. java.rmi, java.rmi.registry, and java.rmi.server The java.rmi, java.rmi.registry, and java.rmi.server packages provide all the tools you need to perform Remote Method Invocation (RMI). Using RMI you can create objects on a remote computer (server) and use them on a local computer (client) seamlessly. See Chapter 36, "Remote Method Invocation," to learn more about RMI. java.lang.reflect The java.lang.reflect package provides the tools you need to reflect objects. Reflection enables you to inspect a runtime object to determine what its constructors, methods, and fields are. See Chapter 48, "Reflection," to learn more.

- 35 -

java.security, java.security.acl, and java.security.interfaces The java.security packages provide the tools necessary for you to use encryption in your Java programs. By using the java.security packages, you can securely transfer data back and forth from a client to a server. See Chapter 34, "Java Security in Depth," to learn more about the java.security packages. java.sql The java.sql package encompasses what is known as JDBC, or the Java DataBase Connectivity. JDBC enables you to access relation databases, such as Microsoft SQL Server or Sybase SQL Anywhere. See Chapters 38 to 40 to learn more about JDBC. Note Printed documentation for all the APIs is available from the JavaSoft Web site at http://www.javasoft.com.

New to JDK 1.2


The following packages were added during the upgrade to 1.2: Java Enterprise API The Java Enterprise API supports connectivity to enterprise databases and legacy applications. With these APIs, corporate developers are building distributed client/server applets and applications in Java that run on any OS or hardware platform in the enterprise. Java Database Connectivity, or JDBC, is a standard SQL database access interface that provides uniform access to a wide range of relational databases. You have probably heard of ODBC. Sun has left no stone unturned in making Java applicable to every standard in the computing industry today. Java IDL is developed to the OMG Interface Definition Language specification as a language-neutral way to specify an interface between an object and its client on a different platform. Java RMI is a remote-method invocation between peers or the client and server when applications at both ends of the invocation are written in Java. Java Commerce API The JavaCommerce API brings secure purchasing and financial management to the Web. JavaWallet is the initial component, which defines and implements a client-side framework for credit card, debit card, and electronic cash transactions. Just imaginesurfing the Internet will take up all of your spare time...and money! Java Server API Java Server API is an extensible framework that enables and eases the development of a whole spectrum of Java-powered Internet and intranet servers. The Java Server API provides uniform and consistent access to the server and administrative system resources. This API is required for developers to quickly develop their own Java servletsexecutable programs that users upload to run on networks or servers. Java Media API The Java Media API easily and flexibly allows developers and users to take advantage of a wide range of rich, interactive media on the Web. The Media Framework has clocks for synchronizing and media players for playing audio, video, and MIDI. Two-D and 3D provide advanced imaging models. Animation provides for motion and transformations of 2D objects. Java Share provides for sharing of applications among multiple users, such as a shared white board. Finally, Telephony integrates the telephone with the computer. This API is probably the most fun of all to explore. Java Security API The Java Security API is a framework for developers to include security functionality easily and securely in their applets and applications. This

- 36 -

functionality includes cryptography with digital signatures, encryption, and authentication. Java Management API Java Management API provides a rich set of extensible Java objects and methods for building applets that can manage an enterprise network over the Internet and intranets. It has been developed in collaboration with SunSoft and a broad range of industry leaders including AutoTrol, Bay Networks, BGS, BMC, Central Design Systems, Cisco Systems, Computer Associates, CompuWare, LandMark Technologies, Legato Systems, Novell, OpenVision, Platinum Technologies, Tivoli Systems, and 3Com.

Java Embedded API


The Java Embedded API specifies how the Java API may be subsetted for embedded devices that are incapable of supporting the full Java Core API. It includes a minimal embedded API based on java.lang, java.util, and parts of java.io. It then defines a series of extensions for particular areas, such as networking and GUIs.

Chapter 3: Installing The JDK and Getting Started


Why You Need Sun's Java Development Kit to Write Java
This chapter intends to help you install Java, give you a basic introduction to the Java Development Kit, and give you several Java-enabled browsers. By the end of the chapter, you will have installed what you need to get going and you'll have compiled and run your first Java application. The Java Development Kit (JDK) is a software package that Sun has made available to the public for free. This package gives you all the tools you need to start writing and running Java programs. It includes all the basic components that make up the Java environment, including the Java compiler, the Java interpreter, an applet viewer that lets you see applets without opening a Java-compatible Web browser, as well as a number of other programs useful in creating Java programs. The JDK represents the bare minimum of what you need to work with Java. If there's no such thing as a free lunch, then JDK is more of a free light snack. Although it does contain all the tools you really need to work with Java, it isn't the integrated development environment many programmers are used to working with. The tools that come with the JDK are command-line driven and they don't have a nice graphical user interface like those of Visual C++ or Borland C++. The tools are intended to be executed from the command prompt (the DOS prompt, for Windows 95 and NT systems). The files that contain your source code are plain ASCII text files you create with a text editor (which you need to supply), such as the NotePad (for Win32 systems), vi (on UNIX), or BBEdit (on the Macintosh). Note A growing number of integrated development environments (IDEs) are available from various third-party companies, each with various features that make life easier on the programmer. If you decide to do your Java development with an IDE, you will probably get a code editor that can colorize Java code, a project file manager, and a faster compiler. Most of the major development companies have IDEs for Java. Microsoft (Visual J++), Borland (JBuilder), Symantec (Cafe), IBM (Visual Age for Java), Metroworks (CodeWarrior), and Aysmetrix (SuperCede) are just a few of the commercial Java development environments available. Each has strengths and weaknesses. If you plan on doing serious Java development, check them out and see which fits your programming needs the best. Even if you plan to use an integrated development environment (IDE) like Visual J++, Visual Caf or Visual Age for Java, you will want to learn about the JDK because it's the reference by which all others are compared.

- 37 -

More on How Java Is Both Compiled and Interpreted


A C++ compiler takes high-level C++ code and compiles it into instructions a computer's microprocessor can understand (Machine Code). This means that every different type of computer platform will need a separate compiling of a given C++ program in order to be able to run it. Taking a C++ program and compiling it on different types of computers is not an easy task. Because different computers do things in different ways, the C++ program has to be able to handle those differences. This is a significant problem when dealing with the wide variety of computer platforms available today. The Java environment overcomes this problem by putting a middleman between the compiler and the computer called the Java Virtual Machine (JVM). Instead of compiling directly for one type of computer, the Java compiler, javac, takes the high-level, humanreadable Java source code in a text file and compiles it into lower-level Java bytecodes that the JVM understands. The JVM then takes that bytecode and interprets it so that the Java program runs on the computer the JVM is running on. The only platform-specific program is the JVM itself. Similarly, Web browsers that support Java applets all have JVMs built into them. The JVM concept provides a number of advantages, the main one being cross-platform compatibility. Java programmers don't need to worry about how a computer platform handles specific tasks and they don't need to worry about how to compile different versions of their program to run on different platforms. The only platform that programmers need to worry about is the JVM. Programmers can be reasonably confident that their program will run on whatever platforms have JVMs, such as Windows 95, Solaris, and Macintosh. Caution Even with Java, there are slight differences between platforms. When working with Java, it's a good idea to test a program on as many different types of computers as possible. On the other hand, languages like Basic are not compiled. In order to run the program, you need a basic interpreter, which reads each line of code, parses out what you've written, and figures out all the machine-code necessary to run the program. The major disadvantage of this type of interpreter is that it requires a lot of processing power, so inevitably it is very slow. Because Java is compiled, it meets you halfway. The amount of interpretation is therefore greatly reduced. The main disadvantage of this system is that interpreting code is still slower than running a program that is native to the host computer. For each instruction in the Java bytecode, the JVM must figure out what the equivalent is for the system it is running on. This creates a slowdown in processing a Java program. To overcome the speed limitation of Java, a number of Just-In-Time compilers (JITs) are available. JITs make the Java system even more confusing, but they make it run much faster by taking the already compiled Java bytecode and compiling it into instructions that are native to a given computer. It's all done transparently to the user from within the JVM. The JIT, because it's part of the JVM, is also platform-specific but runs any Java bytecode, regardless of what type of machine it comes from. Using a JIT, a Java program can achieve speeds close to that of a native C++ program.

Getting and Installing Sun's JDK


Now that you know a little bit more about what Java and the JDK are, you're now ready to get going on actually installing and using it. If you haven't done so already, sit down at your computer, turn it on, and load the CDROM from the back of the book. On the CD-ROM is a directory called JDK. Inside the directory "JDK" are three subdirectories: MACINTOSH, SOLARIS, and WINDOWS. Each of these subdirectories contains the complete installation of Sun's Java Developer's Kit for

- 38 -

each of those three platforms. Table 3.1 shows what those refer to. Table 3.1 Contents of the JDK Folder on the CD-ROM

Directory

Contents

MACINTOSH

Contains the JDK for the Macintosh platform, both 68k and PowerPC. Contains two subdirectories, one for the SPARC Solaris JDK and one for the x86 Solaris JDK. Contains the JDK for x86 32-bit Windows systems, namely Windows 95 and Windows NT.

SOLARIS

WINDOWS

Note Alternately, you can use a Web browser and a connection to the Internet to receive the JDK. If you are going to download it, see the section "Downloading the JDK" later in this chapter. What if you're not using one of those three platforms? You may or may not be in luck. A number of other JDKs exist for other platforms, but you may need to look around the Internet for them. The three previous ones are supported by Sun; any other platforms are not. There are ports for systems such as Linux, DEC Alpha, Amiga, OS/2 and many others. The best place to look for information on those releases is the list of third party ports on Sun's list: http://www.javasoft.com/products/jdk/1.2/. Now you'll look at how to install the JDK onto 32-bit Windows systems from the CD-ROM. The setup is fairly easy, but you should be familiar with the Windows and DOS environments before attempting to install the JDK.

Installing the JDK Off the CD-ROM for Windows 95 and NT


Step 1: Remove Previous Versions of the JDK There should not be any copies of previous versions of the Java Developers Kit on your computer. If you have stored any additional Java source code files (files you have written or files you have received from someone else) in a directory under the main JDK Java directory, you should move those files to a new directory before deleting previous versions of the JDK. You can delete the entire Java directory tree using Windows Explorer or the File Manager. Step 2: Unpacking the JDK After removing the previous version of the JDK, execute the self-extracting archive to unpack the JDK files. You should unpack the file in the root directory of the C drive to create C:\JDK1.2. If you want the JDK in some other directory, unpack the archive file in that directory. Unpacking the archive creates a Java parent directory and all the necessary subdirectories for this release. If you look through the files that are installed with the JDK you will find a several files in the lib and jre\lib files with the extension .jar. The .jar files contain the runtime API classes necessary for the Java VM to operate successfully. Note: prior to JDK 1.2 the setup program created a file called lib/classes.zip instead of the various .jar files. DO NOT UNZIP THE CLASSES.ZIP FILE.

- 39 -

Step 3: Update Environment Variables After unpacking, you should add the JAVA\BIN directory onto the path. The easiest way to accomplish this is to edit the AUTOEXEC.BAT file and make the change to the path statement there. If you have set the CLASSPATH environment variable, you may need to update it. For instance, you may have to make a CLASSPATH entry that points to the jdk1.2\jre\lib\rt.jar file. Again, the easiest way to accomplish this is to edit the AUTOEXEC.BAT file and make the change to the CLASSPATH environment variable there, or you can let the setup program make the changes for you. After completing these changes to AUTOEXEC.BAT, save the file and reboot so the changes take effect. The next section covers the installation of the JDK for x86 and SPARC Solaris UNIX Systems. This installation procedure is similar to some of the other UNIX operating system installations. For more information about getting ports of the JDK for other UNIX systems (such as Linux) see Chapter 56, "Java Resources."

Installing the JDK Off the CD-ROM for x86 and SPARC Solaris
The setup for installing the JDK onto a 32-bit Windows system is fairly easy, but you should be familiar with the Windows and DOS environments before attempting to install the JDK. Step 1: Copy the Directory to Your Hard Drive Copy the appropriate directory (either the x86 or Sparc Solaris release directory) onto your hard drive. Depending on how your file system is configured and the privileges on your system, you might want to either copy the directory into a public area, such as /usr/local/ or into your home directory. The command to copy the Sparc release from the Solaris directory on the CD-ROM to your home directory is >cp -r sparc
~/

Step 2: Set Your Environment Variables The CLASSPATH variable is an environment variable that defines a path to the rt.jar file. Most of the tools that come with the JDK use the CLASSPATH variable to find that file, so having it set correctly is fairly important. You can set the CLASSPATH variable at the command prompt by entering the following: % setenv CLASSPATH .:/usr/local/jdk1.2/jre/lib/rt.jar Or you can put this line of text in your .login or .profile files, so it's called every time you log in: setenv CLASSPATH .:/usr/local/jdk1.2/jre/lib/rt.jar Note If you are using a version of Java prior to JDK 1.2, you will need to substitute jre/lib/rt.jar with lib/classes.zip in all of the examples through out this book.

Downloading the JDK


You can download the JDK off the Internet instead of getting it from the CD-ROM in the back of the book. When you download the JDK off the Internet, you can be fairly certain that you're getting the latest version of it. What You Need to Download the JDK The first item you need to download the JDK is

- 40 -

a computer with a connection to the Internet that can use a Web browser. The particular browser doesn't really matter all that much, but the Netscape Navigator browser is used for these examples. The second item you need is some (well, actually, quite a bit) of free hard disk space on the machine to which you are planning to download the JDK. Table 3.3 contains the amounts of disk space you need to download and uncompress the JDK for each platform. Table 3.3 Disk Space Requirements for the JDK 1.1

Platform

Disk Space Compressed

Disk Space Uncompressed

Solaris Windows

13.7 MB 5.77 MB

16.5 MB 12.1 MB

Starting Your Download If you have some free disk space and a browser handy, you're ready to download. Now you can get started! 1. Launch your Net connection (if you need to do that) and your Web browser. If you are unsure of how to do this, consult your system administrator, your friends who know how to use computers, the manuals, or a book on using the Web, such as Que's Special Edition Using the World Wide Web. 2. Point your browser at the JavaSoft JDK download site at http://www.javasoft.com/products/jdk/1.2/ 3. Scroll down to the pop-up menu that says "Download JDK Software" lists the various operating systems on which the JDK is available from Sun. Pick your operating system of choice in that pop-up menu. 4. Click the "Download Software" button just below the pop-up menu. 5. You'll hit a page that has a number of restrictions on the distribution of the JDK. Read each and, if you comply to all the restrictions, click the "Yes" button to go to the download page. 6. The page that now comes up has a list of various sites the JDK is available to download from. If there are options available, use the one closest to your location. Click the link to start the download. The JDK is a pretty big file and downloading is going to take a while. How long it takes depends on how fast your connection is, the user load on the FTP server at that particular moment, the network load on the Internet at the time of day you are downloading the file, the beating of a butterfly's wings somewhere on the planet, sunspots, blind luck, and a large number of other factors that are even more difficult to predict. If the file transfer is going too slow for your taste, try connecting at another time. Depending on where you are on the planet, good times to connect will vary, again depending on many of the same factors that control the transfer rate.

- 41 -

Installing a Downloaded JDK


Now that you have the appropriate installer file for your computer somewhere handy on your hard drive, it is time to actually install the software so you can get to work programming. Each platform has its own standard installation procedures and the 1.2 release of the JDK is pretty good at following them to make installation a simple and straightforward procedure.

Solaris x86 and SPARC Platforms


For Solaris, the JDK 1.2 is normally distributed as a self-extracting shell script (a file with a .sh extension); the name of the file indicates its version. Caution Use tar or your standard system backup process to back up any previous releases of the JDK before beginning installation of a new version. You don't want to lose all that work you put into it and you'll have a copy of the previous release in the event something goes wrong with your new copy. Installing the JDK on a Solaris machine can be done in one of two ways. It can either be installed into a user's home directory for individual use or it can be installed into a public bin directory, such as /usr/local/bin/, so that all users on a system can use it. The installation process is the same for both. 1. Choose a directory for the installation. These instructions assume an installation location of /usr1/JDK1.2. If you choose a different base directory, simply replace USR with the name of your installation directory. For example, if you choose to install under your home directory, everywhere you see usr, replace it with ~ or $HOME. 2. Verify that you have write permissions for the installation directory. Use this command to check the current permissions: ls -ld /usr1 The options to the ls command specify a long listing, which includes information about ownership and permission, and also specifies to ls to not list the contents of the directory, which is the default. For more information about the ls command, see your system manuals. The output of the command should be similar to the following: drwxr-xr-x root other 512 Feb 18 21:34 /usr

In this case, the directory is owned by root (the system administrator) and neither the group nor the general user community has permission to write to this directory. If you run into this situation and you are not root, you need the assistance of your system administrator to install in that directory. 3. Move or copy the JDK distribution file to /USR1. 4. Extract the JDK by typing a period, a space, and then the jdk.sh filename (such as jdk1.2-solaris2-sparc.sh). > . jdk1.2-solaris2-sparc.sh This executes the shell script, which then automatically uncompresses the file you need into the directories that you need them in.

- 42 -

5. Verify that the following subdirectories were created under /USR1: jdk1.2 jdk1.2/bin jdk1.2/classes jdk1.2/demo jdk1.2/lib jdk1.2/src 6. Set your PATH environment variable. For the C shell and its derivatives, use: setenv PATH $PATH:/usr1/jdk1.2/bin For the Korn shell and its derivatives, use: PATH= $PATH;/usr1/jdk1.2/bin export PATH 7. Set your CLASSPATH environment variable. For the C shell and its derivatives, use: setenv CLASSPATH /usr1/jdk1.2/jre/lib/rt.jar For the Korn shell and its derivatives, use: CLASSPATH = CLASSPATH /usr1/jdk1.2/jre/lib/rt.jar export CLASSPATH Tip Rather than set these variables from the command line each time, you probably should add the commands to set the PATH and CLASSPATH variables in your shell resource file.shrc, .cshrc, .profile, and so on. If you are a system administrator installing the JDK as a network development tool, you may want to add these parameters to the default configuration files.

Windows Installation
You need Windows 95 or Windows NT to run Java. For Windows 3.1, see "Installing IBM's Applet Developer's Kit for Windows 3.1" later in this chapter. Installing the JDK is a fairly simple procedure, but you should know your way around the Windows and DOS environments. For Windows, the JDK is provided in a standard windows setup format; the name of the file indicates its version. 1. Choose a directory for the installation. These instructions assume an installation location of C:\JDK1.2. If you choose a different base directory, simply append the appropriate path (and change the drive letter, if appropriate). If you want to install to E:\TOOLS\JAVA, for example, replace C: with e:\tools whenever it shows up in the instructions. Caution Rename the JAVA directory (for example, to OLDJAVA) using the Explorer in Windows 95 or Windows NT. If the installation fails for any reason, you can restore the previous version directly from OLDJAVA. Otherwise, after the installation is complete, you can move any additional files, such as documentation, from your old installation into your new installation before removing it from your system.

- 43 -

2. If you plan on installing to a networked drive, make sure you have permission to write to the desired directory. 3. Extract the JDK by running the self-extracting program (double-clicking the icon in Explorer or File Manager works just fine). 4. Verify that the following subdirectories were created on drive C:\. C:\JDK1.2 C:\JDK1.2\BIN C:\JDK1.2\CLASSES C:\JDK1.2\DEMO C:\JDK1.2\LIB Tip For Windows NT 4.0 and later, you can skip steps 6, 7, and 8, and set the CLASSPATH from a properties sheet. You do not need to reboot, but you may have to close any DOS Prompt windows that you had open to use the new variable. 6. Add C:\JDK1.2\BIN to your PATH statement in your autoexec.bat file: set PATH=c:\windows;c:\dos;...;c:\java\bin 7. Set your CLASSPATH environment variable in your autoexec.bat file: set CLASSPATH=c:\java\jre\lib\rt.jar 8. Reboot your computer for the environment variables to take effect.

Macintosh Installation
For Macintosh, the JDK is normally distributed as a stuffed, bin-hexed archive (a file with a HQX.SIT extension). The file version is indicated in its name. Caution Make sure to archive your current version of the JDK before installing a newer version. You don't want to lose all that work you put into it and you'll have a copy of the previous release in the event something goes wrong with your new copy. To install the JDK for Macintosh, follow the following steps. 1. After following the instructions earlier in this chapter for downloading the MacJDK 1.2, you should have an installer titled MacJDK.SEA. Double-click this installer so that it launches into a fairly standard Macintosh installer dialog box. Caution The Macintosh enables you to name directories and files in a manner that choke UNIX. Filenames that UNIX can't handle include the naming of directories with slashes (/). This causes problems with the JDK because it uses a mixed UNIX/Mac method of tracking paths when the JDK attempts to locate your files. Thus, a slash in the name of a directory is interpreted as a change of directory. UNIX also has a few problems with names that include spaces. As of this release, you should follow the UNIX file and directory naming conventions used by the developers. This means you shouldn't use spaces, slashes, asterisks, and most other punctuation characters in your file and directory

- 44 -

names. You can, however, use as many periods as you want, and the filename can be as long as you want it (as long as it's less than 32 characters). For example, the following is a perfectly good Macintosh filename but will not work under UNIX: /../..../Stuff \/\/..java To work under UNIX and the Mac, the filename should look like this: Stuff.java 2. In the lower-left corner of the installer dialog box in the Install Location area, you can specify where you want to install the JDK. After selecting the appropriate drive and directory, click the Install or hit "return" button to run the installer. It puts all the Mac JDK in a directory called MACJDK at whatever location you specify in the installer. The default installation location is the root level of your startup disk. You now have a working copy of the JDK on your hard drive folder. This includes two essential programs: the Java compiler and the AppletViewer. You are now ready to move onto the next (and much more fun) parts of Java development.

Testing the Java Compiler and JVM


Now you're ready to write a small Java application to test your installation of the JDK.

Creating a New Java Project


Somewhere on your hard drive, create a new directory to store your projects. I call mine PROJECTS and I keep it out of the JDK directory, so that I don't need to move it around whenever I install a new version of the JDK. Inside that directory, create another directory called HELLOWORLD. Now, using your favorite text editor (such as the NotePad, vi, emacs, SimpleText, or something else), create a file called HelloWorld.java (double-check your capitalizationJava is case-sensitive), and type into it: public class HelloWorld { public static void main(String[] args) { System.out.println("Hello, World!"); } }; Don't worry about the details of syntax right now; just type that in, save it, and exit your text editor. Make sure it's saved as a standard ASCII text file.

Running a Java Application for UNIX or Windows


If you're on a UNIX or Windows machine, at the command (DOS) prompt, type the following: javac HelloWorld.java Your system should pause for a moment, then return you to your prompt.

- 45 -

Get a directory listing in a DOS window to make sure you have the following files: >dir HelloWorld.class

HelloWorld.java

Or, in UNIX, get a directory listing to make sure you have the following files: >ls HelloWorld.class

HelloWorld.java

If you get any errors, check the HelloWorld.java code to make sure it looks exactly as it does here. If you get an error that javac was not found, you didn't set the JAVA/BIN directory in your PATH variable. Go back and check your installation. Now you're ready to run your first Java program! At your command prompt, type the following: >java HelloWorld You should see the following: Hello, World! If you did, congratulations. You've run your first Java application, but more importantly, you've correctly and successfully installed the JDK. If you didn't see "Hello, World!", there is something wrong with your installation. Check to make sure your CLASSPATH variable is set to point at both the current working directory (a period ".") and to the rt.jar file. Check to make sure you typed the name of the file correctly, keeping in mind that Java is case-sensitive. If none of that works, you may need to reinstall the JDK.

Running a Java Application for the Macintosh


The procedure for compiling and running a Java application is a bit different for a Macintosh because it doesn't have a command prompt. 1. On your Mac, open your HELLOWORLD folder so that your HelloWorld.java file appears. 2. Then open the MACJDK folder so that the Java compiler icon appears (it should be a little "Duke" with a "C" on his chest). Drag the HelloWorld.java file onto the Java compiler icon. The Java compiler then launches and begins compiling the program. When it's finished, a file called HelloWorld.class should appear in your HELLOWORLD folder. 3. If you received compile time errors, check the HelloWorld.java code to make sure it looks exactly the same as the previous code. 4. Double-click the HelloWorld.class file. The java runner application launches, loads the HelloWorld program, and runs the program. A window titled stdout should appear, with the words Hello, World! in them. If it did, congrats. You've installed the JDK and run your first Java program.

- 46 -

If you didn't see Hello, World!, there is something wrong with your installation. Check to make sure you are running System 7, that the JDK installed completely, and that the filename and the name of the class generated match, keeping in mind that Java is casesensitive. If you still can't get it to work, you may need to reinstall the JDK. Note The authors of the Macintosh Java Runner application have cleverly hidden the Quit command in the Apple menu. Why they did that isn't known. If you want to free up the memory that the Java Runner is taking up after it's finished running your program, choose Apple, Java Runtime, Quit. Not very Mac-like, but at least it's not a command line. To quit, you can just hit command-Q, like any other normal Mac program.

Installing IBM's Applet Developer's Kit for Windows 3.1


Why isn't there a Sun JDK for Windows 3.1? Well, a number of technical issues make porting the JDK tools to Windows 3.1 difficult, and with the release of Windows 95, Windows 3.1 was seen as a dying platform, so the decision was made to not directly support it. Some of these issues include the fact that Java needs long filenames such as the ".java" and ".class" filenames. The eight-character file name and three-character extension of Window's 3.1 naming system just couldn't fully support Java file names. A more difficult problem to solve, however, is the fact that Java is a multi-threaded language, meaning it can run more than one process at the same time, but Windows 3.1 doesn't support multithreading. In order to support Java in Windows 3.1, several groups undertook projects to port the JDK to 3.1, the most successful of which is IBM's ADK. With IBM's release of their ADK, Windows 3.1 users now have a way to develop Java applets and applications without upgrading to Windows 95 or NT. It includes a number of programs that help get around the problems previously described, as well as improving upon the tools that come with the JDK.

Downloading the ADK


To get to the main ADK Web page, you first need to launch your Web browser and go to http://www.alphaworks.ibm.com/. This is the main Web page for a number of IBM's projects that are currently under development. To get to the ADK Web page, you'll need to pick the "ADK for Win 3.1" entry in the pop-up menu in the "Select" selection. To completely install the ADK and use all its features, you need three components: the ADK itself, the Windows 32-bit extension Win32s, and the WinG graphics extension. To download and install the two windows components, ftp to ftp://ftp.microsoft.com/softlib/mslfiles/ and get the following two files: pw1118.exe wing10.exe The WinG extension file name is wing10.exe and it is about 830k. The Win32s file name is pw1118.exe and it is about 2.4 MB. You need to get and install both of these before installing the ADK. To install these two system enhancements, make a temporary directory for each of the two and put the .exe files into them. Use either a DOS prompt or the Run command in the File menu of the program manager, to execute the .exe files. If you put the wing10.exe file in a directory called wingtemp on your C: drive, for example, the DOS prompt

- 47 -

command would look like: C:\wingtemp\>wing10.exe This decompresses all the files to do the complete install. Each should decompress to a large number of files with an executable called setup.exe. After it is done decompressing, execute the setup program, again using either a DOS prompt or the File, Run menu. The setup program prompts you for some information and then installs all the needed files. After you are done installing these, you can delete the temporary directories you put the installer programs in. When you have WinG and Win32s installed, you can proceed with the installation of the ADK itself. You will first need to read the ADK license agreement at http://www.alphaWorks.ibm.com/ADK. At the bottom of the page is a button labeled "I Agree." If you read the license and agree to its terms, you can click that button, which takes you to the download page where you can download the ADK installer. The actual ADK file is rather large, about 4 MB, and will take a while to download, especially over a modem connection. Once you've gotten the ADK installer, you can then execute it from the Windows program manager File, Run menu. It asks you for an installation directory (for example: C:\java\) and then it does its stuff, installing all the files you'll need to get up and running with the ADK. When the ADK is completely installed, it creates a program group with the items in Table 3.4. Table 3.4 Files in the ADK Program Group

Name

Description

Configure AppletViewer ADK.WRI

This runs the AppletViewer and displays a license document.

The ADK User Guideread this for more information on the ADK. A file manager type application that lets you manipulate files with long file names, rather than the Win 3.1 standard 8.3 file names. A small editor that integrates the ADK tools into one program, so you can work with Java code without having to switch between a number of other programs. The guts of the ADK, this is the program that runs all the Java environment-based tools, such as AppletViewer and javac.

ADK File

ADK Edit

ADK Console

To set up the ADK, run the "Configure AppletViewer" program, agree to the license agreement, follow the instructions to configure the AppletViewer, and then close the applet.

- 48 -

To test your installation, follow these steps: 1. Launch the "ADK Console" program. 2. Select AppletViewer from the Tools menu. 3. Type C:\java\demo\Animator\ into the Working Directory Field (or whatever directory you installed the ADK). 4. Type example1.html into the Command Options field. 5. Press OK. This should launch the Animator applet and put a dancing Duke on your screen. If it did, then you're all set to develop Java programs on your Windows 3.1 machine. If it didn't, make sure that the path you put in the Working Directory field is actually the path that has the Animator applet and that there is a example1.html file in that directory. If not, you may need to go back through the installation process and try again.

Chapter 4: JDK Tools


JDK Tools Reference
This chapter is intended to cover all the tools that are included in the Java Developer's Kit. You'll learn about each tool, what it does, all its associated options, and the environment variables it references. If you're just beginning programming in Java, this chapter serves as an introduction to the tools of the JDK. If you're a hard-core Java hacker, this chapter is more of a reference tool, so you don't have to waste precious CPU cycles bringing the rather ugly man page reference materials. Either way, reading this chapter gives you a pretty good idea of what the JDK tools can do and how to make them do it.

AppletViewer
Applets are programs written in Java that are designed to run embedded in an HTML document, just like a Web page. Under most circumstances, they don't have the ability to run by themselves. The AppletViewer tool is a small program that lets you run applets without the overhead of launching a system that hogs the Web browser. It's a quick and easy way to test your applets as you're developing them. You call the AppletViewer with the following command: AppletViewer [ options ] URLs... The URLs in the command line are the Uniform Resource Locators to HTML files that contain applet tags (such as http://www.javasoft.com/index.html). Alternatively, if you're in a directory that has an HTML file that references an applet, you can call AppletViewer simply by typing in the name of the HTML file that contains the applet tag. The following option is available: Option Description -debug Starts the AppletViewer in the Java debugger, jdb, thus allowing you to debug the applets in the HTML document. The AppletViewer also has an Applet menu in the AppletViewer window that enables you

- 49 -

to set a number of different functions of the AppletViewer. Those menu options are as follows: Restart Restarts the applet using the current settings. Reload Reloads the applet. Changes in the class file are applied upon reload. Stop Causes the stop() method of the applet to be called and halts the applet. Note the applet is not destroyed in this example as it is with Reload. Save Saves the serialized state of the applet. Start Starts the applet. This is useful when the Stop option has been utilized. If the applet has not been stopped, it has no action. Clone Clones (duplicates) the current applet, using the same settings to create another AppletViewer instance. Tag Shows the HTML applet tag that is used to run the current applet, as well as any parameters that are passed to the applet from the HTML tag (see Figure 4.1).

Figure 4.1: The AppletViewer's Tag window.

Info Shows special information about the applet, which is set within the applet's program (see Figure 4.2).

- 50 -

Figure 4.2: The AppletViewer's Applet Info window.

Edit This doesn't appear to do anything; it has been grayed out since the first beta. Print Causes the applet's PrintGraphics to be sent to a printer. Properties Shows the AppletViewer security properties. These settings enable you to configure AppletViewer for a network environment that includes a firewall proxy, or an HTTP proxy, using the relative proxy server and proxy port boxes. The Network Access box allows you to select the type of network access that AppletViewer is allowed. The choices are No Network Access, Applet Host (default), and Unrestricted. The Class Access box enables you to choose what kind of accessRestricted or Unrestrictedyou would like AppletViewer to have on other classes (see Figure. 4.3)

Figure 4.3: The AppletViewer's Properties window.

Close Closes the AppletViewer window and terminates the applet. Quit Closes the AppletViewer window and terminates the applet.

java, The Java Interpreter


The Java interpreter is what you use to run your compiled Java application. The syntax for the interpreter is: java [options] classname

- 51 -

where classname only includes the name of the class and not the extension (.class). The Java interpreter options are listed in Table 4.1. Table 4.1 Java Interpreter Options

Option

Description

-help -version

Displays all the options. Displays the version of the JDK that is used to compile the source code. Displays all the classes as they are loaded. (Performs the same functions as in the javac tool.) Checks to see if the source code is newer (not yet compiled) than its class file. If this is the case, then the new version of source is compiled. Used with remote Java files that are to be debugged later with the jdb tool. The interpreter generates a password for you, which is used in the jdb's password option (see the section "jdb, The Java Debugger" later in this chapter.) Output profiling information to file \JAVA.PROF. java looks for class files in the specified directories, DIRS. For multiple directories, a colon (in UNIX) or semicolon (in DOS) is used to separate each directory. For example, on a DOS machine, the classpath might look like set CLASSPATH=.;C:\users\dac\classes;C:\tools\java\classes. Turns off asynchronous garbage collection. Prints out a message each time a garbage collection occurs. Disables class garbage collection. Verifies all classes that are loaded. Verifies classes that are imported or inherited. This is the default setting. Turns off class verification. Sets the maximum Java heap size to the value specified by val. The minimum heap size is 1K (-mx 1k) and the default is 16M(mx 16m). (Use the letters m and k to specify megabytes or kilobytes for the value of val.) Sets the initial Java heap size to the value specified by val. The minimum heap size is 1K (-mx 1k) and the default is 1M (-mx

-v (also -verbose)

-cs (also checksource)

-debug

-prof -classpath dirs

-noasyncgc -verbosegc -noclassgc -verify -verifyremote

-noverify -mx val

-ms val

- 52 -

1m). (Use the letters m and k to specify megabytes or kilobytes for the value of val.) -ss val Sets the value of the stack size for a C process to the value specified in val. The stack size must be greater than 1K (-ss 1k). (Use the letters m and k to specify megabytes or kilobytes for the value of val.) Sets the stack size of a Java process to the specified value in val.(Use the letters m and k to specify megabytes or kilobytes for the value of val.)

-oss val

javac, The Java Compiler


The javac program is the tool you use to convert .java files into class files that can be run by the interpreter. Table 4.2 lists the Java compiler options. Table 4.2 Java Compiler Options

Option

Description

-O -classpath <path>

Displays the current version of the JDK. Overrides the default CLASSPATH environment variable and specifies a new path to look up classes. Make certain you always include library classes, such as jdk1.2\jre\rt.jar. Specifies the directory to place the resulting class files in. Note the directory specifies the root location. Using this option causes debugging tables to be generated with the class files. This information is necessary to provide complete debugging information when you use jdb. Turns off warnings. When this is turned out, the Compiler does not generate any warning messages. Note: this option is available in JDK 1.1 and above, but not in JDK 1.0 Turns optimization on. This causes all static, final, and prive methods to be placed inline. Although this can result in faster performance, it may also cause your class files to become larger. Turn verbose compilation on. This causes the compiler to print out the source files that are being compiled and loaded. Using the depend option causes the compiler to consider recompiling class files that are referenced from other class files. Ordinarily, recompilation is only done based on file dates. Note: this is JDK 1.2 and is not available in JDK 1.0 This option can be used to pass a single argument through to the Java interpreter that is actually running the compiler. The javaoption should not contain any spaces; if spaces are required, multiple -J parameters should be used. This option can be used to enable you to pass options

-d <directory>

-g

-nowarn

-O

-verbose

-depend

-Jjavaoption

- 53 -

like mx or ms to alter the amount of memory used during the compiler's execution.

javap, The Java Disassembler


The Java disassembler is used to disassemble Java bytecode that has already been compiled. After disassembling the code, information about the member variables and methods is printed. The syntax for the Java disassembler is: javap [options] classnames Multiple classes can be disassembled. Use a single space to separate each class. The options available for the disassembler are shown in Table 4.3. Table 4.3 javap Options

Option

Description

-version -c

Displays the version of the JDK that javap is being executed from. Disassembles the source file and displays the bytecodes produced by the compiler. Prints the local variable tables. Shows only public classes and members. Shows protected and public classes and members. Prints out private, protected, and public member variables and methods. (By default, javap uses this option.) Shows all classes and members. Print internal type signatures. Prints stacks, local variables, and member methods as the javap works.

-l -public -protected -package

-private -s -verbose

-classpath dirs Looks for class files in the specified directories, _DIRS. For multiple directories, a colon (UNIX) or semicolon (DOS) is used to separate each directory. For example, on a DOS machine the classpath might look like set CLASSPATH=.;C:\users\dac\classes;C:\tools\java\ classes. -verify Runs the verifier on the source, and checks the classes being loaded.

javah C-Header and Stub File Creation


The javah tool creates C-header and stub files needed to extend your Java code with the

- 54 -

C language. The syntax of the javah tool is: javah [options] classname where classname is the name of the Java class file without the .class extension. See Table 4.4 for a list of javah options. Table 4.4 javah Options

Option

Description

-version -help -jni -td -trace -classpath -stubs -d dir

Prints out the build version. Prints out the help screen. This is the same as typing javah by itself. Creates a header file for use in JNI. Identifies the temporary directory for javah to use. Causes trace information to be added to the stub files. Specifies the classpath for use with javah. Creates stub files instead of the default header files. Tells the javah tool in what directory to create the header or stub files. Prints out the status as it creates the header or stub file. Puts both the stub and header files into the file specified by file name. This file could be a regular text file or even a header (FILENAME.H) or stub (FILENAME.C) file.

-v -o filename

The javadoc Tool (Documentation Generator)


The javadoc tool creates an HTML file based on the tags that are embedded in the /** */ type of comments within a Java source file. These HTML files are used to store information about the classes and methods that you can easily view with any Web browser. Javadoc was actually used by the creators of the JDK to create the Java API Documentation (refer to http://www.javasoft.com/doc for more information). You can view the API online and you can also see the source code used to generate it in your \JDK1.2\SRC\JAVA directory. See Tables 4.5 and 4.6 for information regarding options and tags. Table 4.5 javadoc Options

- 55 -

Option

Description

-verbose

Displays more information about what files are being documented. Specifies the directory where javadoc stores the generated HTML files. For example, javadoc -d C:\usrs\dac\public_html\doc java.lang. Looks for class files, included in the source file, in the specified directories, DIRS. For multiple directories, a colon (UNIX) or semicolon (DOS) is used to separate each directory. For example, on a DOS machine, the classpath might look like set CLASSPATH=.;C:\users\dac\classes;C:\tools\java\classes. Specifies in colon-separated directories the list of files to use. Specifies the type of file to output the information in. The default is HTML, but it can be set to MIF. Causes javadoc to ignore @depreciated paragraphs. Causes javadoc to utilize the @author paragraphs. Javadoc does not create an index file. Javadoc does not create a tree file. The specified flag is passed directly to the Java runtime.

-d directory

-classpath dirs

-sourcefile dirs -doctype

-nodepreciated -author -noindex -notree -J<flag>

Table 4.6 javadoc Tags

Tag

Description

@see class

Puts a See Also link in the HTML file to the class specified by class. Puts a See Also link in the HTML file to the method specified by method. Describes method arguments.

@see class#method @param param descr

- 56 -

@version ver @author name @return descr @exception class

Specifies the version of the program. Includes the author's name in the HTML file. Describes a method's return value. Creates a link to the exceptions thrown by the class specified by class.

jdb, The Java Debugger


The Java debugger is the debugging tool for the Java environment and is completely command-line driven. You can use the debugger to debug files located on your local system or files that are located on a remote system. For remote Java files, the jdb must be used with the -host and -password options described in the table of options. The jdb also consists of a list of commands that are not covered in this chapter. See Table 4.7 for information regarding jdb options. Table 4.7 jdb Options

Options

Description

-host hostname

Tells the jdb where the remote Java program resides. hostname is the name of the remote computer (such as well.com or sun.com). Passes to the jdb the password for the remote Java file, issued by the Java interpreter using the -debug option.

-password password

Now that you've covered the JDK tools, look at the one variable upon which they all dependthe CLASSPATH variable.

The CLASSPATH Environment Variable


There is really only one environment variable used by the various tools of the JDK, which is the CLASSPATH variable and it is essential that it is set correctly. If it is not, the compiler, interpreter, and other JDK tools will not be able to find the .class files they need to complete their tasks. The CLASSPATH variable points to the directories where all the classes that are available to import from reside. CLASSPATH lets you put your own class files in various directories and lets the JDK tools know where they are. On UNIX machines, the CLASSPATH variable is a colon-separated list of directories in the form: setenv CLASSPATH .:/users/java/:/usr/local/jdk1.2/classes/ This command can be put in your .login file, so it's set properly every time you log in.

- 57 -

In DOS land, it's a semicolon-separated list of directories in the form: set CLASSPATH=.;C:\users\dac\classes;C:\tools\jdk1.2\classes This line can be put in your AUTOEXEC.BAT file so that the CLASSPATH is set properly every time you boot your machine. The first period points the CLASSPATH at the current working directory, which is quite helpful if you don't feel like typing in full path names every time you want to do something with the Java program you're working on at a given moment. The UNIX and Win32 versions of the JDK are quite similar and most of the commands that work for one work for the other. The Macintosh version of the JDK has some significant differences, however.

Macintosh Issues
Because the Mac doesn't have a command-line interface, the tools for the JDK are slightly different on the Mac than they are on other platforms. Note The most notable difference is that fewer tools come with the Mac JDK than for other platforms. Hopefully, this will change soon, but until then, Mac users have to make due without some of the most basic tools, such as the Java debugger, javadoc, and the Java disassembler. The Mac JDK includes four tools: AppletViewer The applet viewer program to run applets outside of a browser. Java Compiler Compiles the .java files into .class bytecodes. Java Runner The Java interpreter, basically the "java" described previously. JavaH C-header creator, with stub file creation, otherwise known as javah. For the most part, these do the same things as their non-GUI counterparts but have some interface issues that make them different. Some tools, like the AppletViewer, are quite similar to the versions on other platforms. Other tools, like the Java Runner, are completely different. Here's the basic information on those tools and where they differ from their cross-platform counterparts.

AppletViewer for the Macintosh


When opened, the Mac AppletViewer has the standard Mac File and Edit menus. There is also a status box, which shows the current amount of memory allotted to the Appletviewer's Java Virtual Machine, and how much of that memory is taken. That box also shows progress bars indicating the status of any information being loaded into the AppletViewer, like .class files or GIF image files. Note If you are running a Mac that supports drag and drop (supported in Mac OS 7.1 and above), you can launch applets off your hard drive by simply dragging the HTML file that contains the <applet> tag onto the little Duke icon of the AppletViewer. You can also double-click the AppletViewer Duke icon and use one of the two Open menus to open an applet. The AppletViewer File menu contains the following options:

- 58 -

Open URL Opens a URL to a Web page that contains an applet. Open Local Brings up a standard Mac Open dialog box that lets you open an HTML file on your local hard drive. Save Doesn't do anything; it's there to comply with the Mac human interface guidelines. Close Closes the topmost window, if that window can be closed. Properties Shows the AppletViewer security properties. These settings enable you to configure AppletViewer for a network environment that includes a firewall proxy, or an HTTP proxy, using the relative proxy server and proxy port boxes. The Network Access box allows you to select the type of network access that AppletViewer is allowed. The choices are No Network Access, Applet Host (default), and Unrestricted. The Class Access box enables you to choose what kind of accessrestricted or unrestricted you would like AppletViewer to have on other classes. Quit Closes all the open applets and exits the AppletViewer. The AppletViewer also has an Edit menu, but this is not enabled as of this writing. Hopefully, it will be enabled soon, at the very least, so you don't have to type in long URLs in the Open URL dialog box. When an applet is running, an Applet menu also appears. The commands available in that menu are as follows: Restart Restarts the applet using the current settings. Reload Reloads the applet. Changes in the class file are applied upon reload. Clone Clones (duplicates) the current applet, using the same settings to create another AppletViewer instance. Tag Shows the HTML applet tag that is used to run the current applet, as well as any parameters that are passed to the applet from the HTML tag (refer to Figure 4.1). Info Shows special information about the applet, which is set within the applet's program (refer to Figure 4.2). Properties Shows the AppletViewer security properties. These settings enable you to configure AppletViewer for a network environment that includes a firewall proxy, or an HTTP proxy, using the relative proxy server and proxy port boxes. The Network Access box allows you to select the type of network access that AppletViewer is allowed. The choices are No Network Access, Applet Host (default), and Unrestricted. The Class Access box enables you to choose what kind of accessRestricted or Unrestrictedyou would like AppletViewer to have on other classes (refer to Figure 4.3). Quit Closes the AppletViewer window and terminates the applet.

Java Runner, The Mac Java Interpreter


The Mac Java Runner is the Mac equivalent of the java command described earlier. Because the Mac has no command line, it has a very rudimentary GUI to set the various options. To make matters slightly worse, that GUI doesn't quite follow the Apple Human Interface Guidelines, which means there's a menu where you wouldn't normally expect it.

- 59 -

You normally launch the Java Runner by double-clicking a .class file that has a main() method. You use the Java compiler to create that .class file, and so it appears on the desktop, or in the folder from which it was launched, as a document icon with Duke in the middle, and 1s and 0s in the upper-left corner of the icon. Alternatively, you can drag the .class file onto the Java Runner icon, or double-click the Java Runner icon and select the .class file in the Open File dialog box that appears. The Java Runner's menus are cleverly hidden as a submenu in the Apple, Java Runtime menu so that they don't interfere with any menus created by the Java application that is running: Edit Mem Lets you set the maximum and minimum heap sizes and disable asynchronous garbage collection (to speed things up). Edit Classpath This option is not currently enabled. Redirect Stderr Redirects error messages to a file that you specify in the Create File dialog box that appears after selecting this menu option. Redirect Stdout Redirects program messages to a file that you specify in the Create File dialog box that appears after selecting this menu option. Save Options Saves your other menu settings. Save Text Window Saves the frontmost text window (for example, the output window of the HelloWorld program) to a file. Close Text Window Closes the topmost text window. Quit Quits the Java Runner and kills any running Java applications.

The Java Compiler


The Java compiler has a basic GUI that lets you set the options that are available as command-line arguments to the other systems. You can compile files by either dragging the .java files onto the compiler, or by choosing File, Compile File. Other menu options are as follows: Close Seems to return an error when selected. Hopefully, this will be fixed in a future release. Caution As of version 1.02 of the MacJDK, the Close menu item appears to have a bug that causes a method not found exception when used. Until that bug is fixed, do not use the Close menu item. Properties Opens a dialog box that lets you setusing check boxes and other itemsmost of the options available to the other systems. It also lets you select an outside editor from a list of popular editors. The default is simple text. This dialog box also lets you set the CLASSPATH for the compiler, the target folder where .class files will be written, and disable threaded compiles to speed up the compiler in situations where multithreading is slowing things down. Quit Quits the compiler.

JavaH: C-Header File Generator


- 60 -

JavaH is provided so that you can link native methods into Java code. At this time, it only works for PowerPC-based Macs. It has no menus of its own outside of the standard Java Runner in the Apple menu, such as the all-important Quit command. To use JavaH, you need a third-party compiler, such as Metrowerks CodeWarrior, in order to generate the C code to actually link in with the Java.

Part II: The Java Language


Chapter List
Chapter 5: Obejct-Oriented Programming Chapter 6: HelloWorld!: Your First Java Program Chapter 7: Data Types and Other Tokens Chapter 8: Methods Chapter 9: Using Expressions Chapter 10: Control Flow Chapter 11: Classes Chapter 12: Interfaces Chapter 13: Threads Chapter 14: Writing an Applet Chapter 15: Advanced Applet Code Chapter 16: JAR Archive Files Chapter 17: Applets Versus Applications Chapter 18: Managing Applications

Chapter 5: Obejct-Oriented Programming


Object-Oriented Programming: A New Way of Thinking
By now, as a programmer, you have no doubt heard of a marvelous term called OOP object-oriented programming. OOP is truly the hottest method of software development today. It isn't a totally new concept, but it has been a long time in coming to the masses. While Java doesn't impose OOP programming like some languages (such as SmallTalk), it does embrace it and allow you to dance with the technology seamlessly. Object-oriented programming is a completely new way of programming. At the same time, in many ways OOP is much the same as structured programming. After you learn and embrace the new terms and concepts associated with object programming, the switch can be so easy that you might not even notice you are doing it. You see, OOP's goal is to provide you, the programmer, with a few new ways to actually write code and a whole lot of new ways to think about programming.

- 61 -

After you have embraced the new ways OOP teaches you to think about programming, the lexical changes, or how you actually write code grammatically, come quite naturally. Unfortunately, truly embracing these changes can take some time. For others, the realization of how OOP works comes in flashes of inspiration. With each new realization, you open up a whole new set of programming possibilities.

A Short History of Programming


To understand why object-oriented programming is of such great benefit to you as a programmer, it's necessary to take a look at the history of programming as a technology. In the early days of computing, programming was an extremely labored process. Each step the computer needed to take had to be meticulously (and flawlessly) programmed. The early languages were known as Machine Language, which later evolved to Assembly Language. If you have ever tried giving another person directions for how to tie their shoes, you probably found that it was very difficultespecially if they had never seen shoelaces before. As a simple exercise, ask a coworker (one that won't think this is too weird) to take his or her shoes off. Ask that person to do exactly what you tell him or her to do, and no more. You find that it is necessary to give very precise, step-by-step directions. "Lift up the left shoelace, move it to the right side below the right shoelace. Pick up the right shoelace," and so on. If you can grasp the number of instructions you need to teach someone how to tie a shoe, you might be able to grasp what this type of programming was like. For programmers, the instructions were a bit more cryptic (and the computer was much less forgiving about imprecise directions). It was necessary to give directions such as "Push the contents of register 1 onto the stack," "Take the contents of the accumulator and place them in register 1," and so on.

Procedural Languages
Programmers soon saw the need for more stylized procedural languages. These procedural languages placed code into blocks called procedures or functions. The goal of each of these blocks was to act like a black box that completed one task or another. For instance, you might create a procedure to write something to the screen, like writeln in Pascal or printf in C. The purists of this type of programming believed that you could always write these functions without modifying external data. In the example of printf or writeln, the string that you print to the screen is the same string before and after you print the string out. In essence, the ideal was not only to build a black box, but to weld the box shut when you were done testing it. One of the problems with this method, though, is to write all functions in such a way that they actually do not modify data outside their boundary. This can be very difficult. For instance, what if you want to pass in a value that you want to have updated while it "lives" inside the method (but not one that is returned)? Frequently, constraining a procedure in this manner turns out to be too difficult a restriction. So, as functions began changing data outside their scope (in C this is done by passing a pointer), a problem called coupling began to surface. Because the functions were now changing data outside of their scope, testing became more and more difficult. Coupling meant that each method had to be testednot only individually, but also to make sure that it wasn't used in such a way that a value it changed wasn't corrupted as a result. In addition, it meant that each black box had to be tested with all of its black boxes in place. If any of those boxes where changed, the parent box had to be retested because the other box may have changed a value and the parent box may not work any longer. (Starts to sound pretty complicated doesn't it?) As large programs were developed, the problem of coupling reared its ugly head. Testing

- 62 -

these programs begot a whole sub-industry, and software managers lost most of their hair. If they were lucky enough to keep their hair, you could spot them just as easily because they never cut it.

Structured Development
The next solution was to try structured development. Structured development didn't necessarily change the languages that were being used, but rather provided a new process. Using structured development, programmers were expected to plan 100 percent of their program before ever writing a single line of code. When a program was developed, huge schematics and flow charts were developed showing the interaction of each function with every other and how each piece of data flowed through the program. This heavy pre-code work proved to be effective in some cases, but limiting for most. This pitfall might have come in large part because the emphasis in programming became good documentation and not necessarily great design. In addition, when programmers were pushed to predesign all of their code before actually writing any of it, a bad thing happened. Programming became institutionalized. You see, good programs tended to be as much experimentation as real development. Structured development pulled at this portion of the development cycle. Because the program needed to be completely designed before anything was implemented, programmers were no longer free to sit and experiment with individual portions of the system.

Ahh...Object-Oriented Programming
Finally, along came object-oriented programming. Object-oriented programming did require a few language changes, but also changed the way that programmers think about programming. The resulting programming technique goes back to procedural development by emphasizing black boxes, embraces structured development (and actually pushes it further), and most importantly, encourages creative programming design. Objects under an OOP paradigm are represented in a system, not just their acquainted data structures. Objects aren't just numbers, like integers and characters; they are also the methods that relate and manipulate the numbers. In OOP programming, rather than passing data around a system openly (such as to a function), messages are passed to and from objects. Rather than taking data and pushing it through a function, a message is passed to an object telling it to perform its task. Object-oriented programming really isn't all that new; it was developed in the 1970s by the same group of researchers at Xerox Parc that brought us GUI (graphical user interfaces), EtherNet, and a host of other products that are commonplace today. Why has OOP taken so long to enter into the masses? OOP requires a paradigm shift in development. In addition, because the computer ends up doing much more work, programs developed using OOP do tend to require a bit more computing horsepower to obtain the same performance resultsbut what a difference those little breaks can make. Objects themselves are the cornerstone of object-oriented programming. The concept of objects is perhaps the first and most significant change each programmer who wants to do OOP design must understand. Objects are robust packages that contain both data and methods. Objects can be replicated and adjusted without damaging the predefined code. Instead of being trapped under innumerable potential additional uses, a method's purpose is easily definable, as is the data upon which it will work. As the needs of new programs begin to grow, the method can be replicated or adjusted to fit the needs of the new system taking advantage of the current method, but not necessarily altering it (by overloading or overriding the method). Objects themselves can be expanded and, by deriving new objects from existing ones,

- 63 -

code time is greatly reduced. Equally important, if not more important, debug time is greatly reduced by localizing bugs, because coupling changes are limited, at worst, to new classes.

A Lesson in Objects
As you work, you are familiar with objects all the time: calculators, phones, computers, fax machines, and stereos are all examples of objects in the real world. When you deal with these objects, you don't separate the object from its quantities and methods. For example, when you turn on your stereo, you don't think about the quantities (such as the station number) from the methods (such as turning the dial or making sound). You simply turn it on, select a station, and sit back to listen to the music. By using object-oriented programming, you can approach the same simplicity of use. As a structured programmer, you are used to creating data structures to hold data and to defining methods and functions to manipulate this data. Objects, however, take and combine the data with the code. The synergistic relationship that comes out is one object that knows everything necessary to exist and work. Take a look at an example using your car. When you describe a car, there are a number of important physical factors: the number of people a car can hold, the speed the car is going, the amount of horsepower the engine has, the drag coefficient, and so on. In addition, the car has several functional definitions: It accelerates, decelerates, turns, and parks. Neither the physical nor the functional definitions alone embody the definition of your carit is necessary to define them both.

Traditional Program Design


In a traditional program, you might define a data structure called MyCarData to look like this: public class MyCarData { int weight; float speed; int hp; double dragCoef; } } Then you would create a set of methods to deal with the data: public class RunCar { public void speedUp(MyCarData m){ ... } public void slowDown(MyCarData m){ ... } public void stop(MyCarData m){ ... } }

- 64 -

The OOP Way


In OOP programming, the methods for the car to run and the actual running of the car are combined into one object: public class Car{ int weight; float speed; int hp; double dragCoef; public void speedUp(){ speed += hp/weight; } public void slowDown(){ speed -= speed * dragCoef; } public void stop(){ speed=0; } } Within each of the new methods, there is no need to either reference the variables using dot notation (such as m.speed) or pass in a reference to variables (such as (MyCarData m)). The methods implicitly know about the variables of their own class. (These variables are also known as field variables.)

Extending Objects Through Inheritance


The next step in developing objects is to create multiple objects based on one super object. Return to the car example. A Saturn SL 2 is a car, and yet certainly it has several attributes that not all cars have. When building a car, manufacturers don't typically start from scratch. They know their cars are going to need several things: tires, doors, steering wheels, and more. Frequently, the same parts can be used between cars. Wouldn't it be nice to start with a generic car, build up the specifics of a Saturn, and from there (because each Saturn has its own peculiarities) build up the SL 2? Inheritance is a feature of OOP programming that enables you to do just this. By inheriting all the common features of a car into a Saturn, it's not necessary to reinvent the object (car) every time. In addition, by inheriting a car's features into the Saturnthrough an added benefit called polymorphismthe Saturn is also a car. Now that might seem obvious, but the reach and scope of that fact is enormous. Under traditional programming techniques, you would have to separately deal with each type of carFords here, GMCs there, and so on. Under OOP, the features all cars have are encapsulated in the car object. When you inherit car into Ford, GMC, and Saturn, you can then polymorph them back to car, and much, if not all, of this work is eliminated. For instance, say you have a race track program. On the race track, you have a green light, yellow light, and red light. Now, each race car driver comes to the race with a different type of car. Each driver has accessible to him each of the peculiarities of his individual car (such as some fancy accelerator in your Volvo). As you put each car on the track, you give a reference of your car to the track itself. The track controller doesn't need access to any methods that access that fancy accelerator of yours or the CD player;

- 65 -

those methods are individual to each of the cars. However, the person sitting in the control tower does want to be able to tell both drivers to slow down when the yellow light is illuminated. Because the makes are cars, the control tower program has received them as cars. Take a look at this hypothetical code. Here are two cars: class Lamborghini extends Car{ public void superCharge(){ for (int x=0;x<infinity;x++) speedUp(); } } class Volvo extends Car{ CDPlayer cd; public void goFaster(){ while(I_Have_Gas){ speedUp(); } } public void jam(){ cd.turnOn(); } } Here is the race track itself: class RaceTrack { Car theCars[] = new Car[3]; int numberOfCars = 0; public void addCar(Car newCar){ theCars[numberOfCars]=newCar; numberOfCars++; } public void yellowLight(){ for (int x=0;x<numberOfCars;x++) theCars[x].slowDown(); } } Here is the program that puts it all together: class RaceProgram{ Lamborghini me = new Lamborghini(); Volvo you = new Volvo(); RaceTrack rc = new RaceTrack();

- 66 -

public void start(){ rc.addCar(me); rc.addCar(you); while(true){ if (somethingIsWrong) rc.yellowLight(); } } } How can this work? In the RaceProgram class, you created two different objects: me (of type Lamborghini) and you (of type Volvo). How can you call rc.addCar, which takes a Car as a parameter type? The answer lies in polymorphism. Because both of the cars extended Car, they can be used as Cars as well as their individual types. This means that if you create yet another type of car (Saturn), you could call rc.addCar (the Saturn) without having to make any changes to RaceTrack whatsoever. Notice that this is true, even though Volvo effectively is a different structure, because it now also contains a CDPlayer variable!

Objects as Multiple Entities


One of the pitfalls you have probably fallen into as a procedural programmer is thinking of the data in your program as a fixed quantity. A perfect example of this is the screen. Usually procedural programs tend to write something to the (one) screen. The problem with this method is that when you switch to a windowing environment and have to write to multiple screens, the whole program is in jeopardy. It takes quite a bit of work to go back and change the program so that the right data is written to the appropriate window. In contrast, OOP programming treats the screen not as the screen but as a screen. Adding windows is as simple as telling the function it's writing to a different screen object. This demonstrates one of the aspects of OOP that saves the most real programming time immediately. When you become an OOP programmer, you begin thinking of dealing with objects. No matter if there's 1 or 100 of them, it doesn't affect the program in any way. If you're not familiar with OOP programming, this might not make sense. After all, what you are saying to yourself is, "If I have two screens, when I go to print something to the screen, I need to be sure to position it correctly on the correct screen, and pay attention to user interaction to each different window." Believe it or not, under OOP the need to do this is washed away. After the elements of a window or screen are abstracted sufficiently, when you write the method, it's irrelevant which screen you're writing to. The window object handles all of that for you. This is actually the flip side of polymorphism, because all you care about is that the item is a screen, and not any of the extra capabilities any one particular screen has.

Organizing Code
OOP organizes your code elegantly because of two key factors: When used correctly, OOP forces you to organize your code into many manageable pieces. By using OOP, each piece is organized naturally, without you having to actually think about the organization. Given that you are forced to organize your code and the organization is natural, this is an amazingly powerful feature.

Objects and How They Relate to Java Classes


- 67 -

At the heart of Java is support for these objects you have been hearing about. They come in a form called a class. (Actually, there is a Java class called Object, which all classes inherit from, so all classes literally are Objects.) Objects are instances of classes. In this sense, classes can be thought of as a template for creating an object. Take a rectangle as an example. A rectangle you want to create should have an x,y location, height, width, move method, and resize method (for shrinking or enlarging the rectangle). When you write the code for the rectangle, you create it in a class. However, to take advantage of the code, you need to create an instance of that class. The instance is a single Rectangle object.

Building a Hierarchy: A Recipe for OOP Design


When setting out to develop an OOP program for the first time, it is often helpful to have a recipe to follow. Developing good OOP structures is a lot like baking a pie. It's first necessary to gather all the ingredients, then begin assembling each portion of the pie.

Break Down Code to Its Smallest Entities


When writing an OOP program, it's first necessary to figure out which ingredients are needed. For instance, if you were writing an arcade game, it would be necessary to figure out everything that would be in that game: creatures, power pieces, the main character, bullets, and so on. After you have assembled these pieces, you need to break them down into all of their entities, both data and functional. For this example, if you were setting out to write the arcade game, you might create a list like this for the four items: Piece Creatures Power Pieces Bullets Main Character Entity Location, size, power level, attack capability to, and maneuver-ability Must be drawn, location, power level

Capability to be fired, size, and quantity Capability to receive commands from the user, capability to move around the maze according to these commands, capability to attack, location, and size

Look for Commonality Between the Entities


The next phase of developing an OOP structure is to look for all the common relationships between each of the entities. For instance, right away you might recognize that the primary difference between the creatures and the main character (aside from how they look) is who controls each. Namely, the creatures are controlled by the computer, and the main character is controlled by the user. Wouldn't it be great if you could write most of the code for both the creatures and the main character once, and then just write separate code for moving them? If that's how you feel, but you really don't think it could be that easy, keep reading. Treating objects this way is exactly what the OOP paradigm is all about.

Look for Differences Between Entities


- 68 -

The next step is to find the differences between the entities. For instance, the bullets move and the power pieces stay put. Creatures are controlled by the computer, and the main character is controlled by the user. You are looking for relationships that unite and separate all of those entities in your program.

Find the Largest Commonality Between All Entities


The third step is to find the largest common relationship between all the entities in your program. Rarely is it impossible to find any common relationships among all objects. It is possible, however, to find one entity so completely different that it doesn't share anything with any other object. Looking at the game example, what do you see that all four objects have in common? A quick list might include size, the capability to move around (the power piece doesn't really need to move, but it wouldn't hurt if it could), and location. Is that all they have in common? Perhaps the most obvious commonality wasn't even (intentionally) listed beforethe capability to be drawn to the screen. This capability is so obvious you might just miss it. Don't forget to look at the obvious. With these entities, you could create a class called Draw_Object. The class would contain all the items just listed.

Put Remaining Common Objects Together and Repeat


The next phase is to put objects that still have things in common together (after you have eliminated the aspects that were just grouped into the previous class). You use these commonalties to produce another level of classes, each of which inherits from the class that contains all the completely common information (Draw_Object). Going back to the example, at this point the power pieces and the bullets probably split from the creatures and the main character. Now, take the remaining objects and repeat the recipe again. Going through the next phase, you find that the only real difference between the power pieces and the bullets is their size and how fast they move (the power pieces at speed 0). Because these are primarily minor differences, you combine them into one class. When you look at the creatures and the main character, you have decided that the main character contains everything that a creature does plus some, so you inherit the Creature class in the Main_Character class. The final class hierarchy is shown in Figure 5.1. Try this on your own. There are countless variations to the chart developed here; see what you come up with.

Figure 5.1: Building a hierarchy for your game enables you to save a lot of coding.

- 69 -

Using Objects to Add As Many As Desired


When writing a game, it is often desirable to be able to add as many attack creatures as a particular board wants. Because the creature class encapsulates, all that you need to create a creature and a new board with more creatures is to add those creatures to the list. Again, this might seem obvious, but it's extremely powerful; it means you don't need to create a string of variables like creature1Speed, creature2Speed, creature1Power, creature2Power, and so on. You can think of this step as if you were creating any other variable. For instance, assuming that you're already a programmer in a different language, you're probably very used to just creating an integer variable any time you need one. Now you can create a whole new creature any time you need one.

Java Isn't a Magic OOP Bullet


The focus of this chapter has been to introduce the concepts of good OOP. The chapter has intentionally avoided complicated coding implementations; the rest of this book should help you fill in that portion. Now that you have seen many of the fundamentals of OOP programming at a surface level, establish why you went through all of this. Java isn't a magic bullet to creating OOP programs. While Java embraces the OOP paradigm, it is still possible (and not unusual) to write structured programs using Java. It's not unusual to see Java programs written without any acknowledgment of some of the OOP tools just covered, like polymorphism and encapsulation. By introducing OOP at this stage, hopefully you can break the bad habits of structured programming before they begin. You need to remember that OOP is as much a different way of thinking as it is a different way of programming. Throughout this book, there are applets and applications written both ways. Look for those programs that are broken into multiple pieces. Then, when you think you understand OOP, reread this chapter and see if any more insights are brought to mind.

Chapter 6: HelloWorld!: Your First Java Program


HelloWorld Application
When learning to program, it is often useful to jump in headfirst, learn how to write a short application, and then step back and learn the rest of the fundamentals. In this chapter you do just that, and by the end you should be able to write your own Java programs. You have already seen the simplest Java program, HelloWorld, in Chapter 3, "Installing the JDK and Getting Started." Take a closer look at each of the components. Listing 6.1 shows the HelloWorld application. Listing 6.1 The HelloWorld Application public class HelloWorld { public static void main(String args[]){ System.out.println("Hello World!!"); } }

- 70 -

As you can see, there really isn't a lot to this program, which may be why it's called the easiest Java application. Nevertheless, you take a close look at the program from the inside out. Before you do that, though, compile the program and run it.

Create the File


The first step to creating the HelloWorld application is to copy the text from Listing 6.1 into a file called HelloWorld.java using your favorite text editor (Windows NotePad, or SimpleText on the Macintosh will work if you don't have another). It is very important to call the file HelloWorld.java, because the compiler expects the filename to match the class identifier (see "Declaring a Class" later in this chapter). Caution If you use a program such as Microsoft Word to type the code, make sure that you save the file as text only. If you save it as a Word document, Word adds a lot of information about formatting the text that simply doesn't apply to your situation, and only causes you grief.

Compile the Code


To compile the program, you need to first install the JDK. Then, use the program javac included with the JDK to convert the text in Listing 6.1 to a form the computer can run. To run javac on a Macintosh, drag the source file over the javac icon. On any other computer, type the following at a command prompt: javac HelloWorld.java. The javac program creates a file called HelloWorld.class from the HelloWorld.java file. Inside this file (HelloWorld.class) are what is known as bytecodes. Bytecodes are special instructions that can be run by the Java interpreter. "Installing a Downloaded JDK."

Run the Program


Now that you have compiled the program, you can run it by typing the following at the command prompt: java HelloWorld. Note The HelloWorld used in the command prompt java HelloWorld is not HelloWorld.class or HelloWorld.java, just the name of the class. After you do this, the computer should print the following to the screen: Hello World!! That may not seem very interesting, but then it's a simple program. If you don't see that on the screen, go back and make sure you have typed in the file exactly as it is shown in Listing 6.1, and make sure that you called the file HelloWorld.java.

Understanding HelloWorld
Now that you have seen the results of the HelloWorld program, go back to the original source code and see if you can understand how it works. As you should begin to see, there are a lot of parts to the HelloWorld program. After you understand all of them, you're a long way to being able to write any program.

Declaring a Class
- 71 -

The first task when creating any Java program is to create a class. Take a look at the first line of the HelloWorld application: public class HelloWorld { This declares a class called HelloWorld. See "Classes in Java." To create any class, simply write a line that looks like: public class ClassName Here, ClassName is the name of the program you are writing. In addition, ClassName must correspond to the filename. It's a good idea to make all your class names descriptive, so that it's easier to remember for what they are used. Note It is an accepted practice that class names should always begin with a capital letter. This is not required, but considered good style. There are also a number of limitations on the names you can assign to a class, but you learn more about that later in Chapter 11, "Classes." Next, notice the brace ({) that is located before the class declaration. If you look at the end of the class, there is also a closing brace (}). The braces tell the compiler where your class will begin and end. Any code between those two braces is considered to be in the HelloWorld class. Don't be confused. Braces are used for a number of things called blocks, which are covered in more detail in Chapter 8, "Methods." The braces are matched in a LIFO (Last In, First Out) format. That means that the next closing brace closes the open brace that was closest to it. In the case of the HelloWorld program, there are two open braces, so the one that closes the class is the very last one.

main Method
The next line in the HelloWorld program reads like the following: public static void main(String args[]){ This line declares what is known as the main method. Methods are essentially miniprograms. Each method performs some of the tasks of a complete program. The main method is the most important one with respect to applications, because it is the place that all Java applications start. For instance, when you run java HelloWorld, the Java interpreter starts at the first line of the main method. When creating any Java application, you need to create a main method as shown. In Chapter 8 you learn more about declaring and using methods.

Writing to the Screen


How does the text Hello World!! appear when you run the HelloWorld program? The answer (as you have probably guessed) lies in the next line of the program: System.out.println("Hello World!!"); You can replace any of the text within the quotation marks ("") with any text you would

- 72 -

like. The System.out line is run because, the interpreter looks at the first line of code (namely the printout) and executes it when the application starts. If you place any other code there, it runs that code instead.

System.out and System.in


You have just seen how System.out.println was used to print text to the screen. In fact, System.out.println can be used at any time to print text to what is known as Standard Out. In almost all cases, Standard Out is the screen. The system.out.println serves approximately the same purpose as the writeln in Pascal. In C, the function is printf, and in C++, cout. println Versus print There is one minor variation on println that is also readily used: print("Hello World!!"). The difference between println and print is that print does not add a carriage return at the end of the line, so any subsequent printouts are on the same line. Strictly speaking, print is the true cousin to printf and cout for C/C++ programmers. To demonstrate this, expand your HelloWorld example a bit by copying Listing 6.2 into a file called HelloWorld2.java and compiling it with the line java HelloWorld2.java. Listing 6.2 A HelloWorld Program with Two Printouts public class HelloWorld2 { public static void main(String args[]){ System.out.println("Hello World!"); System.out.println("Hello World Again!"); } } To run the program, type java HelloWorld2. You should see output that looks like the following: Hello World! Hello World Again! Notice that each phrase appears on its own line. Now, for comparison, try the program again using print instead of println. Copy Listing 6.3 into a file called HelloWorld3, compile, and run it. Listing 6.3 A HelloWorld Output Using print Statements public class HelloWorld3 { public static void main (String args[]){ System.out.print ("Hello World!"); System.out.print ("Hello World Again!"); } } You should notice that the output looks like this: Hello World!Hello World Again!

- 73 -

What caused the change? When you use print, the program does not add the extra carriage return. Extending the String: Writing More Than HelloWorld One of the features Java has inherited from C++ is the capability to add strings together. Although this might not seem completely mathematically logical, it is awfully convenient for a programmer. Revisit your last HelloWorld program and get the same output using one println and the + operator (see Listing 6.4). Listing 6.4 HelloWorld Output Adding Two Strings public class HelloWorld4 { public static void main (String Args[]){ System.out.print ("Hello World!" + "Hello World Again!"); } } When you compile and run HelloWorld4, you should see the same output that was produced from HelloWorld3. This might not seem too interesting, so take a look at one more extensions of the ability to add to stringsyou can also add numbers. For instance, say you want to add the number 43 to the string. Listing 6.5 shows an example of just such a situation. Listing 6.5 HelloWorld with a Number public class HelloWorld5 { public static void main (String args[]){ System.out.print ("Hello World! " + 43); } } Listing 6.5 produces the following: Hello World! 43 Getting Information from the User with System.in System.out has a convenient partner called System.in. While System.out is used to print information to the screen, System.in is used to get information into the program. Requesting Input from the User Use System.in.read() to get a character from the user. This is not covered in too much depth, because System.in isn't used that often in Java programs; that is primarily, because (as you learn in the upcoming section "HelloWorld as an Applet") it really doesn't apply to applets. Nevertheless, Listing 6.6 shows an example of a Java application that reads a letter from the user. Listing 6.6 ReadHello: An Application that Reads Input from the User import java.io.*; public class ReadHello { public static void main (String args[]){ int inChar; System.out.println("Enter a Character:"); try {

- 74 -

inChar = System.in.read(); System.out.println("You entered " + inChar); } catch (IOException e){ System.out.println("Error reading from user"); } } } You've probably already noticed that there is a lot more to this code than there was to the last one. Before that's explained, you should compile the program and prove to yourself that it works: Enter a Character: A You entered 65 First things first. The code you are most interested in is the line that reads: inChar = System.in.read(); System.in.read() is a method that takes a look at the character that the user enters. It then performs what is known as a return on that value. A value that is returned by a method can then be used in an expression. In the case of ReadHello, a variable called inChar is set to the value that is returned by the System.in.read() method. In the next line, the value of the inChar variable is added to the System.out string, just as you did in Listing 6.5. By adding the variable into the string, you can see the results of your work. It's not necessary to use a variable. If you prefer, you can print it out directly in the second System.out line, by changing it to the following: System.out.println("You entered "+ System.in.read()); Notice that the program displays a number instead of a character for what you entered. This is because the read() method of System.in returns an integer, not an actual character. The number corresponds to what is known as the ASCII character set. Converting an Integer to a Character You need to do what is known as a cast to convert the number that is returned from System.in into a character. Casting effectively converts a given datatype to another one. Change ReadHello to look like Listing 6.7. Listing 6.7 ReadHello: An Application that Reads in a Character from the User import java.io.*; public class ReadHello { public static void main (String args[]){ char inChar; System.out.println("Enter a Character:"); try { inChar =(char) System.in.read(); System.out.println("You entered " + inChar); } catch (IOException e){ System.out.println("Error reading from user"); } } }

- 75 -

Notice the characters before System.in.read().The (char) causes the integer to be changed into a character. The Rest of the Extra Codetry and catch What does the rest of all that code do? There is a sequence there called a try-catch block in this code. In some programming languages, when a problem occurs during execution, there is no way for you as a programmer to catch it and deal with the problem. When a problem occurs, the system halts and ends the program (usually with some nasty message like General Protection Fault, or Core Dump). In some languages, it's a bit complicated. In Java, most problems cause what are known as exceptions, which can be handled by you, so your program doesn't stop working. See "Java's Exceptions." See "Java's Events." When a method states that it will throw an exception, it is your responsibility to try to perform that method, and if it throws the exception, you need to catch it. Do you see the line of code right after the catch phase? If there is an error while reading, an exception called an IOException is thrown. When that happens, the code in the catch block is called.

HelloWorld as an AppletRunning in Netscape


If you are reading this book, odds are you are most interested in using Java to write programs called applets. Applets can be run in a browser, such as Netscape Navigator. Several differences exist between applets and applications. The most important is that Java applet classes extend an existing class. This class is called java.applet.Applet. For now, it's enough to say that you have to extend Applet for a class to be usable as such. This is covered in more detail in a later chapter. See "Applets Versus Applications."

The New Source CodeCompiling It


One of the simplest applets is the HelloWorld applet, the source code for which is shown in Listing 6.8. Right away you should see that the applet HelloWorld is quite different from the HelloWorld application in Listing 6.1. You break down the source code to understand it a little later in this chapter. For now, copy Listing 6.8 into a file called HelloApplet.java and compile it. Listing 6.8 HelloWorld as an Applet import java.applet.Applet; import java.awt.Graphics; public class HelloApplet extends Applet { public void paint (Graphics g) { g.drawString ("Hello World!",0,50); } }

Creating an HTML File


- 76 -

When you created the HelloWorld application in Listings 6.1 through 6.5, you ran them using the Java interpreter. Applets, however, don't run from the command line; they are executed within a browserbut how do you tell the browser to open the applet? If you have already written Web pages, you are familiar with HTML. HTML pages are what a browser such as Netscape is used to dealing with. To get the applet into the browser, you need to embed what are known as HTML tags into an HTML file. The HTML file can then be read into a browser. The simplest HTML file for the HelloApplet class is shown in Listing 6.9. Copy this text into a file called HelloApplet.html. See "Including a Java Applet in an HTML Page." Take a look at the third line of Listing 6.9. Notice the <APPLET> tag? The <APPLET> tag is a new HTML tag that is used to include Java applets. When creating your own HTML files, don't forget to include the closing </APPLET> tag as well, or your applets won't appear. Note With Java files, it is necessary that the filename be the same as the class file. This is not necessary with the HTML file. In fact, a single HTML file can contain several <APPLET> tags. Listing 6.9 HelloApp.htmlHTML File to Use for Applet <HTML> <BODY> <APPLET CODE="HelloApplet.class" WIDTH = 200 HEIGHT=200> </APPLET> </BODY> </HTML>

Running the Program in AppletViewer


To run the applet, the JDK includes a very simplified version of a browser called AppletViewer. AppletViewer looks for <APPLET> tags in any given HTML file and opens a new window for each of them. When you run the HTML file in AppletViewer, you see output such as that in Figure 6.1. To run the HelloApplet program using AppletViewer, type appletviewer HelloApplet.html on the command line.

Figure 6.1: AppletViewer opens a new window and runs HelloApplet in it.

Running HelloWorld in Netscape


- 77 -

Another option for running applets is with Netscape Communicator. You're probably already familiar with using the Navigator. To open the HelloApplet program in Netscape, choose File, Open File, then select the HelloApplet.html file, as shown in Figure 6.2.

Figure 6.2: HelloApplet can also be run by using Netscape Navigator.

Understanding the Source Code


Now that you have seen how to run the HelloApplet program, go back and see how the program works. Importing Other Classes The first thing to notice are the top two lines of the code: import java.applet.Applet; import java.awt.Graphics; The import statement is a new one. It is often necessary or easier to use the contents of a class file that have already been created, rather than try to reproduce that work yourself. The import statement enables you to use these other classes. If you are familiar with the C/C++ #include declaration, the import statement works in somewhat the same way. In the case of the HelloApplet program, there are two classes used, other than HelloApplet. The first is the java.applet.Applet class. The Applet class contains all the information that is specific to applets. In fact, any class run in a browser as an applet must extend java.applet.Applet. The second class that is imported into HelloApplet is the java.awt.Graphics class. java.awt.Graphics contains all kinds of tools for drawing things to the screen. In fact, the screen is treated as a Graphics object. Declaring an Applet Class You might have noticed that there is a slight difference between this class declaration for the HelloApplet class compared with the HelloWorld application. HelloApplet extends Applet. Remember in the last chapter how you learned about building a class structure? extends is the keyword that indicates that a class should be entered into that class hierarchy. In fact, a class that extends another class is placed at the bottom of the existing chain: public class HelloApplet extends Applet {

- 78 -

See "Super ClassesExtending Another Class." You might think this harps the issue, but it's important: All applets must extend java.applet.Applet. However, because you imported the Applet class, you can simply call it Applet. If you had not imported java.applet.Applet, you could still have extended it using the full name: public class HelloApplet extends java.applet.Applet { Applet Methodspaint The next item to notice about the HelloApplet class versus HelloWorld is that HelloApplet doesn't have a main method. Instead, this applet only has a paint method. How is this possible? The answer lies in the fact that the applets don't start themselves. They are being added to an already running program (the browser). The browser has a predefined means for getting each applet to do what it wants. It does this by calling methods that it knows the applet has. One of these is paint: public void paint (Graphics g) { The paint method is called any time the browser needs to display the applet on the screen; you can use the paint method to display anything. The browser helps by passing a Graphics object to the paint method. This object gives the paint method a way to display items directly to the screen. The next line shows an example of using the Graphics object to draw text to the screen: g.drawString ("Hello World!",0,50); } }

The Brief Life of an Applet


The paint method is not the only method that the browser calls of the applet. You can override any of these other methods just like you did for the paint method in the HelloWorld example. When the applet is loaded, the browser calls the init() method. This method is only called once no matter how many times you return to the same Web page. After the init() method, the browser first calls the paint() method. This means that if you need to initialize some data before you get into the paint() method, you should do so in the init() method. Next, the start() method is called. The start() method is called every time an applet page is accessed. This means that if you leave a Web page and then click the Back button, the start() method is called again. However, the init() method is not. When you leave a Web page (for example, by clicking a link), the stop() method is called. Finally, the destroy() method is called when the browser exits all together. Note Notice that unlike the paint(Graphics g) method, the init(), start(),stop(), and destroy() methods do not take any parameters between

- 79 -

the parentheses.

Keywords
Before you set off on a more in-depth exploration of each of the topics discussed in this chapter, there are a few other housekeeping matters you need to learn. The most important of these is the use of keywords in Java. There are certain sequences of characters, called keywords, that have special meaning in Java. Some of them are like verbs, some like adjectives, and some like pronouns. Some of them are tokens that are saved for later versions of the language, and one (goto) is a vile oath from ancient procedural tongues that may never be uttered in polite Java. The following is a list of the 56 keywords you can use in Java. When you know the meanings of all these terms, you will be well on your way to being a Java programmer. abstract case class do final future implements int new package rest super throw var boolean cast const double finally generic import interface null private return switch throws void break catch continue else float goto inner long operator protected short synchronized transient volatile byte char default extends for if instanceof native outer public static this try while

The keywords byvalue, cast, const, future, generic, goto, inner, operator, outer, rest, and var are the reserved words that have no meaning in Java. Programmers experienced with other languages such as C, C++, Pascal, or SQL may know for what these terms might eventually be used. For the time being, you won't use these terms, and Java is much simpler and easier to maintain without them. The tokens true and false are not on this list; technically, they are literal values for Boolean variables or constants. The reason you care about keywords is these terms have specific meaning in Java; you can't use them as identifiers for something else. This means that you can't create classes

- 80 -

with any of these names. If HelloApplet had been on the list, the compiler never would have compiled that program for you. In addition, they cannot be used as variables, constants, and so on. However, they can be used as part of a longer token, for example: public int abstract_int; Note Because Java is case sensitive, you can use an initial uppercase letter if you are bent on using one of these words as an identifier of some sort. Although this is possible, it is a very bad idea in terms of human readability, and it results in wasted manhours when the code must be improved later to this: public short Long; It can be done, but for the sake of clarity and mankind's future condition, please don't do it. In addition, there are numerous classes defined in the standard packages. Although their names are not keywords, the overuse of these names can make your meaning unclear to people who work on your application or applet in the future.

API
In this chapter, you learned how to use several classes other than the one you were writing. The most important of these was java.applet.Applet. Why were you told what methods were in java.applet.Applet? The answer is that all the classes in what is known as the Java API are well documented. Although it's unlikely that you will have great success understanding the API until you have finished reading several more chapters, it's important to start looking at it now. As you progress as a Java programmer, the API will probably become one of your best friends. In fact, it may well be that Java's rich API is one of the reasons for its success. You can access a hyperlink version of the API documentation on Sun's site at http://www.javasoft.com/products/JDK/CurrentRelease/. When exploring the API, you should notice how various classes inherit from others using the extends keyword. Sun has done a great deal of work to keep you from having to write nearly as much code; you simply must learn to make good use of the classes.

Chapter 7: Data Types and Other Tokens


Java Has Two Data Types
When working with computerseither for something as simple as writing a college paper or as complex as solving quantum theory equationsthe single most important thing the computer does is deal with data. Data to a computer can be numbers, characters, or simply values. Java has several types of data it can work with, and this chapter covers some of the most important. In Java, there are two categories into which data types have been divided. Primitive types Reference types

- 81 -

Java has eight primitive types, each with its own purpose and use. Boolean char float byte int double short long As you proceed through this chapter, each of these types is covered in detail. For now, take a look at Table 7.1, which shows the numerical limits each type has. Table 7.1 Primitive Data Types in the Java Language

Type

Description

Boolean byte

These have values of either true or false. 7-bit 2s-complement integer with values between -2^7 and 2^7-1 (-128 to 127). 16-bit 2s-complement integer with values between -2^15 and 2^15-1 (-32,768 to 32,767). 16-bit Unicode characters. For alphanumerics, these are the same as ASCII with the high byte set to 0. The numerical values are unsigned 16bit values between 0 and 65535. 32-bit 2s-complement integer with values between -2^31 and 2^31-1 (-2,147,483,648 to 2, 147,483,647). 64-bit 2s-complement integer with values between -2^63 and 2^63-1 (-9,223,372,036,854,775,808 to 9,223,372,036,854,775,807). 32-bit single precision floating-point numbers using the IEEE 754-1985 standard (+/- about 10^39). 64-bit double precision floating-point numbers using the IEEE 754-1985 standard (+/- about 10^317).

short

char

int

long

float

double

- 82 -

Primitive types in Java are unique because, unlike many other languages, the values listed in Table 7.1 are always as shown here, regardless of what type of computer you are working on. This gives you, as a programmer, added security and portability you might not always have in other languages.

Learning About boolean Variables


The simplest data type available to you in Java is that of the boolean. boolean variables have two possible valuestrue or false. In some other languages, Booleans are 0 or 1; or, as in C(++), false is 0 and all other numbers are true. Java has simplified this a bit, and made actual values true and false. boolean variables are used mostly when you want to keep track of the state an object is in. For instance, a piece of paper is either on or off the table. A simple piece of code might say: boolean on_the_table = true;

Declaring a Variable
You should understand what the line of code in the last section means before you go any further. When you create a variable in Java, you must know at least a few things: You must know what data type you are going to use. In this case, that was Boolean. You must know what you want to call the variable (on_the_table). You might also want to know the value with which the variable should start. In this case, assume the paper is on the table initially, so you set the variable to true. If you do not specify a value for the variable, the Java compiler automatically makes your Boolean variables false. You can create any variable in Java in the same way as was just shown: 1. State the data type that you will be using (boolean). 2. State the name the variable will be called (on_the_table). 3. Assign the variable a value (= true). 4. As with every other line of code in Java, terminate the line with a semicolon (;).

Identifiers: The Naming of a Variable


Refer to the first example: boolean on_the_table = true; How does the computer work with the characters that make up on_the_table? on_the_table is called an identifier in programming lexicology. Identifiers are important because they are used to represent a whole host of things. In fact, identifiers are any phrases chosen by the programmer to represent variables, constants, classes, objects, labels, or methods. After an identifier is created, it represents the same object in any other place it is used in the same code block.

- 83 -

There are several rules that must be obeyed when creating an identifier: The first character of an identifier must be a letter. After that, all subsequent characters can be letters or numerals. The characters do not need to be Latin numerals or digits; they can be from any alphabet. Because Java is based on the Unicode, standard identifiers can be in any language, such as Arabic-Indic, Devanagari, Bengali, Tamil, Thai, or many others. The underscore (_) and the dollar sign ($) are considered letters and can be used as any character in an identifier, including the first one. In Java, as in C and most other modern languages, identifiers are case sensitive and language sensitive. This means that on_the_table is not the same as On_The_Table. Changing the case changes the identifier by which the variable is known. Make your identifier names long enough so that they are descriptive. Most application developers are forever walking the line of compromise between choosing identifiers that are short enough to be quickly and easily typed without error and those that are long enough to be descriptive and easily read. Either way, in a large application, it is useful to choose a naming convention that reduces the likelihood of accidental reuse of a particular identifier. It is not generally a good idea to create four variables called x, x1, x2, and x4, because it would be difficult to remember the purpose of each variable. In addition, identifiers cannot be keywords. Table 7.2 shows several legal and illegal identifiers. The first illegal identifier is forbidden because it begins with a numeral. The second has an illegal character (&) in it. The third also has an inappropriate character: the blank space. The fourth is a literal number (216) and cannot be used as an identifier. The last one contains yet another bad character: the hyphen, or minus sign. Java would try to treat this last case as an expression containing two identifiers and an operation to be performed on them. Table 7.2 Examples of Legal and Illegal Identifiers

Legal Identifiers

Illegal Identifiers

HelloWorld counter HotJava$ ioc_Queue3

9HelloWorld count&add Hot Java 65536

ErnestLawrenceThayers non-plussed FamousPoemOfJune1888

Changing Boolean Variables

- 84 -

In Chapter 10, "Control Flow," you see how Boolean variables can be used to change the behavior of a program. For instance, if the paper is on the table, you do nothing, but if it has fallen onto the floor, you can tell the computer to pick it up. There are two ways in which you can change a Boolean variable. Because Booleans are not represented by numbers, you must always set a Boolean to either true or false. The first way to do this is explicitly. For instance, if you have a variable called My_First_Boolean, to change this variable to false, you would type: My_First_Boolean = false; If you compare this line to the declaration of on_the_table earlier, you might notice that they are very similar. The next way to assign a Boolean variable is based on an equation or other variable. For instance, if you want My_First_Boolean to have the same value as on_the_table, you might type a line like this: My_First_Boolean= on_the_table; You can also make the variable have a value based on the equality of other numbers. For instance, the following line would make My_First_Boolean false: My_First_Boolean = 6>7; Because 6 is not greater than 7, the equation on the right would evaluate false. You learn more about this type of equation later in Chapter 10. Note Boolean types are a new feature in Java, not found in C and C++. To some, this stricter adherence to typing may seem oppressive. On the other hand, pervasive ambiguity, which has resulted in countless lost man-hours from the world's intellectual workforce in the form of chasing many hard-to-detect programming errors, may be eliminated.

The Various Flavors of Integer


The next set of primitive types in Java are all known as integer types: byte int char short long As you saw in Table 7.1, each of these types has a different limit to the numbers it can carry. For instance, a byte cannot hold any number that is greater than 127, but a long can easily hold the amount of the national debt. It can actually hold one million times that number. There are different reasons to use each type, and you should not use a long for every variable just because it is the biggest. It is unlikely that most of the programs you write will need to deal with numbers large enough to take advantage of that size. More

- 85 -

importantly, large variables such as longs take up much more space in the computer's memory than do variables like short.

Limits on Integer Values


Integers can have values in the ranges shown in Table 7.3. Table 7.3 Integer Types and Their Limits

Integer Type

Minimum Value

Default Value

Maximum Value

byte short int long

-128 -32,768 -2,147,483,648 9,223,372,036,854,775,808 0

(byte) 0 (short) 0 0 0

127 32,767 2,147,483,647 9,223,372,036,854,775,807

char

65535

Note The maximum number for a long is enough to provide a unique ID for one transaction per second for every person on the planet for the next 50 years. It is also the number of grains in about a cubic mile of sand. Yet, if a project to count the black flies in Maine is undertaken, surely the cry will arise for 128-bit integers. Note If some operation creates a number exceeding the ranges shown here, no overflow or exception is created. Instead, the 2s-complement value is the result. (For a byte, it's 127+1=-128, 127+9 =-120, and 127+127=-2.) However, an ArithmeticException is thrown if the right-hand operand in an integer divide or modulo operation is zero.

Creating Integer Variables


All of the main four integer types can be created in nearly the same way (you learn about char later in this chapter). The following lines show how to create a variable of each of these types: byte My_First_Byte = 10; short My_First_Short = 15; int My_First_Int = 20; long My_First_Long = 25; Notice that the declaration of the integer types is nearly identical to that for the Boolean variable and that it is exactly the same for all integer types. The one main difference is that an integer variable must be assigned a number, not true or false. Also, notice that

- 86 -

an integer must be assigned a whole number, not a fraction. In other words, if you want to have a number like 5.5 or 5 2/3, you cannot do so with an integer. You learn more about these types of numbers in the section "Floating-Point Variables" later in this chapter.

Operations on Integers
You can perform a wide variety of operations on integer variables. Table 7.4 shows a complete list. Table 7.4 Operations on Integer Expressions

Operation

Description

=, +=, -=, *=, /= ==, != <, <=, >, >= +, +, -, *, /, % +=, -=, *=, /= ++, <<, >>, >>>

Assignment operators

Equality and inequality operators Inequality operators Unary sign operators Addition, subtraction, multiplication, division, and modulus operators Addition, subtraction, multiplication, division, and assign operators Increment and decrement operators Bitwise shift operators

<<=, >>=, >>>= Bitwise shift and assign operators ~ &, |, ^ &=, |=, ^= Bitwise logical negation operator Bitwise AND, OR, and exclusive or (XOR) operators Bitwise AND, OR, exclusive or (XOR), and assign operators

Later in Chapter 10 you learn about the equality and inequality operators that produce Boolean results. For now, concentrate on the arithmetic operators.

Operators
Operators are used to change the value of a particular object. For instance, say you want to add or subtract 5 from 10. As you soon see, you would use the addition or subtraction operator. They are described here in several related categories. C and C++ programmers should find the operators in Table 7.4 very familiar.

- 87 -

Arithmetic Operators
Arithmetic operators are used to perform standard math operations on variables. These operators include: + * / % Addition operator Subtraction operator Multiplication operator Division operator Modulus operator (gives the remainder of a division) Probably the only operator in this list that you are not familiar with is the modulus operator. The modulus of an operation is the remainder of the operand divided by the operandi. In other words, in the equation 10 % 5, the remainder is 0 because 5 divides evenly into 5. However, the result of 11 % 5 is 1 because (if you can remember your early math classes), 11 divided by 5 is 2 R 1, or 2 remainder 1. Listing 7.1 shows an example of these operators in use. Listing 7.1 Examples Using Arithmetic Operators int int int int int j = 60; k = 24; l = 30; m = 12L; result = 0L; // set the byte j's value to 60

result result result 7)) result 5)

= j + k; // result gets 84: (60 plus 24) = result / m; // result gets 7: (84 divided by 12) = j - (2*k + result); // result gets 5: (60 minus (48 plus = k % result; // result gets 4: (remainder 24 div by

Assignment Operators
The simplest assignment operator is the standard assignment operator. This operator is often known as the gets operator, because the value on the left gets the value on the right: = Assignment operator The arithmetic assignment operators provide a shortcut for assigning a value. When the previous value of a variable is a factor in determining the value that you want to assign, the arithmetic assignment operators are often more efficient: += Add and assign operator

- 88 -

-= *= /= %=

Subtract and assign operator Multiply and assign operator Divide and assign operator Modulus and assign operator

Except for the assignment operator, the arithmetic assignment operators work as if the variable on the left of the operator were placed on the right. For instance, the following two lines are essentially the same: x = x + 5; x += 5; Listing 7.2 shows more examples of the operators in use. Listing 7.2 Examples Using Arithmetic Assignment Operators byte j = 60; short k = 24; int l = 30; long m = 12L; long result = 0L; result result result 12) result result result div by += j; += k; /= m; -= l; = -result; %= m; 12) // set the byte j's value to 60

// result gets 60: (0 plus 60) // result gets 84: (60 plus 24) // result gets 7: (84 divided by // result gets -23: (7 minus 30)) // result gets 23: (-(-23)) // result gets 11: (remainder 23

Increment/Decrement Operators
The increment and decrement operators are used with one variable (they are known as unary operators): ++ Increment operator Decrement operator

For instance, the increment operator (++) adds one to the operand, as shown in the next line of code: x++; This is the same as: x+=1; The increment and decrement operators behave slightly differently based on the side of the operand they are placed on. If the operand is placed before the operator (for

- 89 -

example, ++x), the increment occurs before the value is taken for the expression. The result of y is 6 in the following code fragment: int x=5; int y=++x;

// y=6 x=6

If the operator appears after the operand, the addition occurs after the value is taken. y is 5 as shown in the next code fragment. Notice that in both examples, x is 6 at the end of thefragment: int x=5; int y = x++;

//y=5 x=6

Similarly, the decrement operator () subtracts one from the operand, and the timing of this is in relation to the evaluation of the expression in which it occurs.

Character Variables
Characters in Java are a special set. They can be treated as either a 16-bit unsigned integer with a value from 0 to 65535, or as a Unicode character. The Unicode standard makes room for the use of many different languages' alphabets. The Latin alphabet, numerals, and punctuation have the same values as the ASCII character set (a set that is used on most PCs and with values between 0 and 256). The default value for a char variable is \u0000. The syntax to create a character variable is the same as for integers and Booleans: char myChar = 'b'; In this example, the myChar variable has been assigned the value of the letter 'b'. Notice the tick marks (') around the letter b ? These tell the compiler that you want the literal value of b rather than an identifier called b.

Floating-Point Variables
Floating-point numbers are the last category of native types in Java. Floating-point numbers are used to represent numbers that have a decimal point in them (such as 5.3 or 99.234). Whole numbers can also be represented, but as a floating point, the number 5 is actually 5.0. In Java, floating-point numbers are represented by the types float and double. Both of these follow a standard floating-point specification: IEEE Standard for Binary FloatingPoint Arithmetic, ANSI/IEEE Std. 754-1985 (IEEE, New York). The fact that these floating-point numbers follow this specificationno matter what machine the application or applet is running onis one of the details that makes Java so portable. In other languages, floating-point operations are defined for the floating-point unit (FPU) of the particular machine the program is executing on. This means that the representation of 5.0 on an IBM PC is not the same as on, for example, a DEC VAX, and the limits on both machines are shown in the following table: Floating- Minimum Positive Point Value Type float 1.40239846e-45f Default Value Maximum Value

3.40282347e+38f

- 90 -

double

4.94065645841246544e324d

1.7976931348623157e+308d

In addition, there are four unique states that floating-point numbers can have: Negative infinity Positive infinity Zero Not a number These states are required, due to how the 754-1985 standard works, to account for number rollover. For instance, adding 1 to the maximum number of a floating point results in a positive infinity result. Many of the operations that can be done on integers have an analogous operation that can be done on floating-point numbers. The main exceptions are the bitwise operations. The operators that may be used in expressions of type, float, or double are given in Table 7.5. Table 7.5 Operations on float and double Expressions

Operation

Description

=, +=, -=, *=, /= Assignment operators ==, != <, <=, >, >= +, +, -, *, / +=, -=, *=, /= ++, Equality and inequality operators Inequality operators Unary sign operators Addition, subtraction, multiplication, and division operators Addition, subtraction, multiplication, division, and assign operators Increment and decrement operators

Arrays
There are three types of reference variables: Classes Interfaces Arrays

- 91 -

Classes and interfaces are so complicated that each gets its own chapter, but arrays are comparatively simple and are covered here with the primitive types. An array is simply a way to have several items in a row. If you have data that can be easily indexed, arrays are the perfect means to represent them. For instance, if you have five people in a class and you want to represent all of their IQs, an array would work perfectly. An example of such an array is: int IQ[] = {123,109,156,142,131}; The next line shows an example of accessing the IQ of the third individual: int ThirdPerson = IQ[3]; Arrays in Java are somewhat tricky. This is mostly because, unlike most other languages, there are really three steps to filling out an array, rather than one. 1. Declare the array. There are two ways to do this: Place a pair of brackets after the variable type or place brackets after the identifier name. The following two lines produce the same result: int MyIntArray[]; int[] MyIntArray; 2. Create space for the array and define the size. To do this, you must use the keyword new, followed by the variable type and size: MyIntArray = new int[500]; 3. Place data in the array. For arrays of native types (like those in this chapter), the array values are all set to 0 initially. The next line shows how to set the fifth element in the array: MyIntArray[4] = 467; At this point, you may be asking yourself how you were able to create the five-element array and declare the values with the IQ example. The IQ example took advantage of a shortcut. For native types only, you can declare the initial values of the array by placing the values between braces ({,}) on the initial declaration line. Array declarations are composed of the following parts: Array modifiers Type name Brackets Initialization Optional The keywords public, protected, private, or synchronized The name of the type or class being arrayed [ ] See Chapter 11 for more details about initialization ;

Required Required Optional

Semicolon

Required

Listing 7.3 shows several more examples of using arrays.

- 92 -

Listing 7.3 Examples of Declaring Arrays long Primes[] = new long[1000000]; assign long[] EvenPrimes = new long[1]; array. EvenPrimes[0] = 2; // Declare an array and // some memory to hold it. // Either way, it's an // Populate the array.

// Now declare an array with an implied 'new' and populate. long Fibonacci[] = {1,1,2,3,5,8,13,21,34,55,89,144}; long Perfects[] = {6, 28}; array. long BlackFlyNum[]; // Creates two element

// Declare an array. // Default value is null. // Array indexes must be

BlackFlyNum = new long[2147483647]; type int.

// Declare a two dimensional array and populate it. long TowerOfHanoi[][]={{10,9,8,7,6,5,4,3,2,1},{},{}}; long[][][] ThreeDTicTacToe; // Uninitialized 3D array.

There are several additional points about arrays you need to know: Indexing of arrays starts with 0 (as in C and C++). In other words, the first element of an array is MyArray[0], not MyArray[1]. You can populate an array on initialization. This only applies to native types and allows you to define the value of the array elements. Array indexes must either be type int (32-bit integer) or be able to be cast as an int. As a result, the largest possible array size is 2,147,483,647. Most Java installations would fail with arrays anywhere near that size, but that is the maximum defined by the language. When populating an array, the rightmost index sequences within the innermost curly braces.

Whitespace
Of some importance to most languages is the use of whitespace. Whitespace is any character that is used just to separate letters on a linea space, tab, line feed, or carriage return. In Java, whitespace can be declared anywhere within the application's source code without affecting the meaning of the code to the compiler. The only place that whitespace cannot be is between a token, such as a variable or class name. This may be obvious, because the following two lines are obviously not the same: int myInt; int my Int;

- 93 -

Whitespace is optional, but because proper use of it has a big impact on the maintainability of the source code for an application or applet, its use is highly recommended. Let's take a look at the ever popular HelloWorld application written with minimal use of whitespace: public class HelloWorld{public static void main(String args []){System.out.println("Hello World!!");}} Clearly, it is a little harder to ferret out what this application does, or even that you have started at the beginning and finished at the end. Choose a scheme for applying meaningful whitespace and follow it. You stand a better chance of knowing which close curly brace (}) matches which open brace ({).

Comments
Comments are an important part of any language. Comments enable you to leave a message for other programmers (or yourself) as a reminder of what is going on in that particular section of code. They are not tokens and neither are any of their contents. Java supports three styles of comments: Traditional (from the C language tradition) C++ style javadoc (a minor modification on traditional comments)

Traditional Comments
A traditional comment is a C-style comment that begins with a slash-star (/*) and ends with a star-slash (*/). Take a look at Listing 7.4, which shows two traditional comments. Listing 7.4 Example Containing Two Traditional Comments /* The following is a code fragment * that is here only for the purpose * of demonstrating a style of comment. */ double pi = 3.141592654 /* close enough for now */ ;

As you can see, comments of this sort can span many lines or can be contained within a single line (outside a token). Comments cannot be nested. Thus, if you try to nest them, the opening of the inner one is not detected by the compiler, the closing of the inner one ends the comment, and subsequent text is interpreted as tokens. Listing 7.5 shows how this can become very confusing. Listing 7.5 An Example of a Single Comment That Looks Like Two /* This opens the comment /* That looked like it opened another comment but it is the same one * This will close the entire comment */

- 94 -

C++ Style Comments


The second style of comment begins with a slash-slash (//) and ends when the current source code line ends. These comments are especially useful for describing the intended meaning of the current line of code. Listing 7.6 demonstrates the use of this style of comment. Listing 7.6 An Example Using Traditional and C++ Style Comments for (int j = 0, Boolean Bad = false; // initialize outer loop j < MAX_ROW; // repeat for all rows j++) { for (int k = 0; // initialize inner loop k < MAX_COL; // repeat for all columns k++) { if (NumeralArray[j][k] > '9') { // > highest numeric? Bad = true; // mark bad } // close if > '9' if (NumeralArray[j][k] < '0') { // < lowest numeric? Bad = true; // mark bad } // close if < '0' } // close inner loop } // close outer loop

javadoc Comments
The final style of comment in Java is a special case of the first. It has the properties mentioned previously, but the contents of the comment may be used in automatically generated documentation by the javadoc tool. Caution Avoid inadvertent use of this style if you plan to use javadoc. The javadoc program will not be able to tell the difference. javadoc comments are opened with /**, and are closed with */. By using these comments in an appropriate manner, you can use javadoc to automatically create documentation pages similar to those of the Java API. Listing 7.7 shows a javadoc comment. Listing 7.7 An Example of a javadoc Comment /** This class is for processing databases * Example use: * xdb myDB = new xdb (myDbFile); * System.out.println(xdb.showAll()); */

Literals: Assigning Values


When you learned about assigning a Boolean variable, there were only two possible values: true and false. For integers, the values are nearly endless. In addition, there are many ways an integer value can be represented using literals. The easiest way to assign a value to an integer value is with its traditional Roman numeral:

- 95 -

int j = 3; However, what happens when you want to assign a number that is represented in a different form, such as hexadecimal? To tell the computer that you are giving it a hexadecimal number, you need to use the hexadecimal literal. For a number like 3, this doesn't make much difference, but consider the number 11. Represented in hexadecimal (0x11), it has a value of 16! Certainly, you need a way to make sure the computer gets this right. The following statements all contain various literals: int j=0; long GrainOfSandOnTheBeachNum=1L; short Mask1=0x007f; static String FirstName = "Ernest"; static Char TibetanNine = '\u1049' Boolean UniverseWillExpandForever = true; Clearly, there are several types of literals. In fact, there are five major types of literals in the Java language: Boolean Integer Character String Floating-point

Integer Literals
Integer literals are used to represent numbers of integer types. Because integers can be expressed as decimal (base 10), octal (base 8), or hexadecimal (base 16) numbers, each has its own literal. In addition, integer numbers can be represented with an optional uppercase L ('L') or lowercase L ('l') at the end, which tells the computer to treat that number as a long (64-bit) integer. As with C and C++, Java identifies decimal integer literals as any number beginning with a non-zero digit (for example, any number between 1 and 9). Octal integer literal tokens are recognized by the leading zero (045 is the same as 37 decimal); they may not contain the numerals 8 or 9. Hexadecimal integer literal tokens are known by their distinctive 'zero-X' at the beginning of the token. Hex numbers are composed of the numerals 0 through 9plus the Latin letters A through F (case is not important). The largest and smallest values for integer literals are shown in each of these three formats: Largest 32-bit integer literal 2147483647 017777777777 0x7fffffff

- 96 -

Most negative 32-bit integer literal

-2147483648 020000000000 0x80000000

Largest 64-bit integer literal

9223372036854775807L 0777777777777777777777L 0x7fffffffffffffffL

Most negative 64-bit integer literal

-9223372036854775808L 01777777777777777777777L 0xffffffffffffffffL

Caution Attempts to represent integers outside the range shown in this table result in compile-time errors.

Character Literals
Character literals are enclosed in single quotation marks. This is true whether the character value is Latin alphanumeric, an escape sequence, or any other Unicode character. Single characters are any printable character except hyphen (-) or backslash (\). Some examples of these literals are 'a', 'A', '9', '+', '_', and '~'. Some characters, such as the backspace, would be difficult to write out like this, so to solve this problem, these characters are represented by what are called escape characters. The escape sequence character literals are in the form of '\b'. These are found within single quotation marksa backslash followed by one of the following: Another character (b, t, n, f, r, ", ', or \) A series of octal digits A u followed by a series of hex digits expressing a nonline-terminating Unicode character The Escape characters are shown in Table 7.6. Table 7.6 Escape Characters

Escape Literal

Meaning

'\b' '\t'

\u0008 backspace \u0009 horizontal tab

- 97 -

'\n' '\f' '\r' '\"' '\'' '\\'

\u000a linefeed \u000c form feed \u000d carriage return \u0022 double quotation mark \u0027 single quotation mark \u005c backslash

Caution Don't use the \u format to express an end-of-line character. Use the \n or \r characters instead. Character literals mentioned in Table 7.6 are called octal escape literals. They can be used to represent any Unicode value from '\u0000' to '\u00ff' (the traditional ASCII range). In octal (base 8), these values are from \000 to \377. Note that octal numerals are from 0 to 7 inclusive. Table 7.7 shows some examples of octal literals. Table 7.7 Octal Values and Their Meaning

Octal Literal Meaning

'\007' '\101' '\141' '\071' '\042'

\u0007 bell \u0041 'A' \u0061 'a' \u0039 '9' \u0022 double quotation mark

Caution Character literals of the type in the previous table are interpreted very early by javac. As a result, using the escape Unicode literals to express a line termination charactersuch as carriage return or line feedresults in an end-of-line appearing before the terminal single quotation mark. The result is a compile-time error. Examples of this type of character literal appear in the Meaning heading listed in the previous table.

Floating-Point Literals
Floating-point numbers can be represented in a number of ways. The following are all legitimate floating-point numbers:

- 98 -

1003.45 1.00345e3

.00100345e6 0.00100345e+6

100.345E+1100345e-2

Floating-point literals have several parts, which appear in the following order as shown in Table 7.8. Table 7.8 Floating-Point Requirements

Part

Is It Required?

Examples

Whole Number

Not if fractional part is present.

0, 1, 2,..., 9, Number Part 12345

Decimal Point Not if exponent is present; must be there if there is a fractional part. Fractional Can't be present if there is no decimal point. Must be there if there is no whole number part. Only if there is no decimal point. No. The number is assumed to be double precision in the absence of a type suffix.

0, 1, 14159, 718281828,41421, 9944

Exponent

e23, E-19,

E6, e+307, e-1

Type Suffix

f, F, d, D

The whole number part does not have to be a single numeral; case is not important for the E which starts the exponent, or for the F or D, which indicate the type. As a result, a given number can be represented in several different ways as a literal: Single precision floating-point literals produce compile-time errors if their values are non-zero and have an absolute value outside the range from 1.40239846e-45f through 3.40282347e+38f. The range for the non-zero absolute values of double precision literals is 4.94065645841246544e-324 through 1.7976931348623157e+308.

String Literals
Strings are not really native types. However, it is also necessary to talk about them to finish the discussion of literals. String literals have zero or more characters enclosed in double quotation marks. These characters may include the escape sequences listed in the "Character Literals" section earlier in this chapter. Both double quotation marks must appear on the same line of the source code, so strings may not directly contain a newline character. To achieve the new line effect, you must use an escape sequence such as \n or \r. The double-quotation mark (") and backslash (\) characters must also be represented

- 99 -

using the escape sequences (\" and \\). One nice feature Java inherits from C++ is that if you need to use a longer string, a string may be created from concatenating two or more smaller strings with the string concatenation operator (+). Caution Although it is often convenient to use the + operator for strings, the current implementation of the String class isn't very efficient. As a result, doing lots of string concatenations can waste memory resources. Some examples of string literals include: "Java" "Hello World!\n" "The Devanagari numeral for 9 is \u096f " "Do you mean the European Swallow or the African Swallow?" "*** *ERROR 9912 Date/Time 1/1/1900 00:01" + " predates last backup: all files deleted!" "If this were an actual emergency"

Creating and Destroying Objects


Memory management is a topic that is very important to all computer languages. Whenever you create a new instance of a class, the Java runtime system sets aside a portion of memory in which to store the information pertaining to the class. However, when the object falls out of scope or is no longer needed by the program, this portion of memory is freed to be used again by other objects. While Java hides most of these operations from the programmer, it does provide you some chances to optimize your code by performing certain additional tasks. While requiring you to allocate memory explicitly for each new object with the new operator, it also enables you to specialize your new object (by using its constructor methods) and ensures that it leaves no loose ends when it is destroyed. Note Unlike C and C++, which provide the programmer with a great deal of control over memory management, Java performs many of these tasks for you. Most notably, in its aptly called garbage collection, Java automatically frees objects when there are no references to the given object, thereby making the C++ free() method unnecessary.

Creating Objects with the new Operator


When creating an instance of a class, it is necessary to set aside a piece of memory to store its data. However, when you declare the instance at the beginning of a class, you are merely telling the compiler that a variable with a certain name will be used in the class, not to actually allocate memory for it. Consequently, it is necessary to create the memory for the variable using the new operator. Examine the following code: public class Checkers { private GameBoard board; public Checkers() { board = new GameBoard("Checkers"); board.cleanBoard(); } ...

- 100 -

You see that although the variable board is declared in the third line, you must also allocate memory for it using the new operator. The syntax of a statement involving the new operator is: instanceofClass = new ClassName(optional_parameters); Quite simply, the line tells the compiler to allocate memory for an instance of the class and points the variable to the new section of memory. In the process of doing this, the compiler also calls the class's constructor method and passes the appropriate parameters to it.

Pointers: Fact or Fiction? Java claims not to possess pointers and, as a result, prevents the programmer from making some of the mistakes associated with pointer handling. Nevertheless, although it chooses not to adopt the pointer-based mindset, Java is forced to deal with the same issues of allocating memory and creating references to these locations in memory. Thus, although assigned a different name, references are Java's version of pointers. Although you cannot perform some of the intrusive operations with pointers as you can with C, there are striking parallels between pointer assignment and object creation. You must first declare a variable (the reference). Then you must allocate adequate memory and assign the reference to it. Furthermore, because you may later decide to set a reference equal to another type of the same variable (or null), Java's reference system is extremely similar to C's system of pointers. While Java's implementation effectively hides the behavior of pointers from the programmer and shields you from their pitfalls, it is nevertheless a good idea to consider what is occurring behind the scenes when you create and refer to a variable.

Chapter 8: Methods
Parts of a Method
Methods are truly the heart and soul of Java programs. Methods serve the same purpose in Java that functions do in C, C++, Pascal. All execution, which takes place in any applet or application, takes place within a method, and only by combining multiple dynamic methods are large-scale quality Java applications written. Like C and C++ functions, Java methods are the essence of the class and are responsible for managing all tasks that will be performed. A method has two parts: a declaration and a body. While the actual implementation of the method is contained within the method's body, a great deal of important information is defined in the method declaration. The simplest method (and least useful) would look like this: void SimpleMethod(){

Declaration
- 101 -

The declaration for a method is similar to the first line in the previous section. At the very least, it specifies what the method will return, and the name the method will be known by. Ordinarily, as you will soon see, more options than these two are used. In general, method declarations have the form access_specifier modifier (parameters) throws ExceptionList where everything in italics is optional. Access Specifiers The first option for a method is the access specifier. Access specifiers are used to restrict access to the method. Regardless of what the access specifier is, though, the method is accessible from any other method in the same class. However, although all methods in a class are accessible by all other methods in the same class, there are certain necessary tasks that you might not want other objects to be able to perform. You learn more about classes in Chapter 11, "Classes." For now you look at how the access modifiers can change a method. Public The public modifier is the most relaxed modifier possible for a method. By specifying a method as public, it becomes accessible to all classes regardless of their lineage or their package. In other words, a public method is not restricted in any way. For example: public void toggleStatus() Protected The second possible access modifier is protected. Protected methods can be accessed by any class that extends the current class. For instance, the class java.awt.Component has a protected method paramString(), which is used in classes such as java.awt.Button, but is inaccessible to any class that you might create that does not extend Component. For example: protected void toggleStatus() See Using Packages to Organize Your Code." Note If you are having a compile-time error caused by an attempt to access a method not visible to the current scope, you might have trouble diagnosing the source of your problems. This is because the error message does not tell you that you are attempting to access a protected method. Instead it resembles the following: No method matching paramString() found in class java.awt.Button. java.awt.Button.paramString() is a protected method in java.awt.Button. This is because the restricted methods are effectively hidden from the non-privileged classes. Therefore, when compiling a class that does not meet the security restrictions, such methods are hidden from the compiler. Also note that you encounter a similar error message when trying to access a private or protected method outside of its range of access, as well as when you attempt to access a field from an unprivileged class. Private Private is the highest degree of protection that can be applied to a method. A private method is only accessible by those methods in the same class. Even classes return_value nameofmethod

- 102 -

that extend from the current class do not have access to a private class. For example: private void toggleStatus() Default Those methods that do not declare their access level have a special accessibility in Java. These methods are accessible to any class in the rest of the current package, but not any classes outside the current package. For example: package abc; public class NetworkSender { void sendInfo(String mes) { system.out.println(mes) } } package abc; public class NetworkSenderTest { String mes = "test"; void informOthers(String mes) { NetworkSender messenger; messenger = new NetworkSender(); messanger.sendInfo(mes); // this is legal } } package xyz; import NetworkSender; public class NetworkSenderTest2 extends NetworkSender{ String mes = "test"; void informOthers(String mes) { NetworkSender messenger; messenger = new NetworkSender(); messanger.sendInfo(mes); // this is NOT legal } }

The first statement invokes sendInfo() as a method belonging to the NetworkSender. This is legal because default methods are accessible to other classes in the same package (both NetworkSender and NetworkSenderTest are in the package abc). However, in NetworkSenderTest2 the statement is illegal because it attempts to invoke sendInfo() on an instance of the NetworkSender class, but NetworkSenderTest2 is in a different package (xyz). Even though NetworkSenderTest2 is a subclass of NetworkSender, it is referencing sendInfo() not as a method belonging to its superclass, but rather as a method belonging to an instance of NetworkSender. Modifiers Method modifiers enable you to set properties for the method, such as where it will be visible and how subclasses of the current class will interact with it. Static Static, or class, variables and methods are closely related. For example: static void toggleStatus() It is important to differentiate between the properties of a specific instance of a class and the class itself. In the following code (see Listing 8.1), you create two instances of the

- 103 -

Elevator class and perform some operations with them. Listing 8.1 Hotel.javaHotel Example with Instance Methods class Elevator { boolean running = true; void shutDown() { running = false; } } class FrontDesk { private final int EVENING = 8; Elevator NorthElevator, SouthElevator; FrontDesk() { // the class constructor NorthElevator = new Elevator(); SouthElevator = new Elevator(); } void maintenance(int time) { if (time == EVENING) NorthElevator.shutDown(); } void displayStatus() { // code is very inefficient, but serves a purpose System.out.print("North Elevator is "); if (!(NorthElevator.running )) System.out.print("not "); System.out.println("running."); System.out.print("South Elevator is "); if (!(SouthElevator.running )) System.out.print(" not "); System.out.println("running."); } } public class Hotel { public static void main(String args[]) { FrontDesk lobby; lobby = new FrontDesk(); System.out.println("It's 7:00. Time to check the elevators."); lobby.maintenance(7); lobby.displayStatus(); System.out.println(); System.out.println("It's 8:00. elevators."); lobby.maintenance(8); lobby.displayStatus(); }

Time to check the

- 104 -

} Both NorthElevator and SouthElevator are instances of the Elevator class. This means that each is created with its own running variable and its own copy of the shutDown() method. Although these are initially identical for both elevators, as you can see from the preceding example, the status of running in NorthElevator and SouthElevator does not remain equal once the maintenance() method is called. Consequently, if compiled and run, the preceding code produces the following output: C:\dev>\JDK1.2\java\bin\java Hotel It's 7:00. Time to check the elevators. North Elevator is running. South Elevator is running. It's 8:00. Time to check the elevators. North Elevator is not running. South Elevator is running. Note In the preceding example, you might notice a rather funny looking method named FrontDesk(). What is it? As you learn in the "Constructors" section in Chapter 11, this is the constructor method for the FrontDesk class. Called whenever an instance of FrontDesk is created, it provides you the ability to initialize fields and perform other such preparatory operations. Variables and methods such as running and shutDown() are called instance variables and instance methods. This is because every time the Elevator class is instantiated, a new copy of each is created. In the preceding example, while the value of the running variable certainly can change because there are two copies of it, changing one does not change the other. Therefore, you can track the status of the NorthElevator and SouthElevator separately. However, what if you want to define and modify a property for all elevators? Examine the example in Listing 8.2 and note the additions. Listing 8.2 Hotel2.javaHotel Example with Static Methods class Elevator { boolean running = true; static boolean powered = true; void shutDown() { running = false; } static void togglePower() { powered = !powered; } } class FrontDesk { private final int EVENING = 8; private final int CLOSING = 10; private final int OPENING = 6; Elevator NorthElevator, SouthElevator; FrontDesk() { NorthElevator = new Elevator();

- 105 -

SouthElevator = new Elevator(); } void maintenance(int time) { if (time == EVENING) NorthElevator.shutDown(); else if ( (time == CLOSING) || (time == OPENING) ) Elevator.togglePower(); } void displayStatus() { // Code is very inefficient, but serves a purpose. System.out.print("North Elevator is "); if (!(NorthElevator.running )) System.out.print("not "); System.out.println("running."); System.out.print("South Elevator is "); if (!(SouthElevator.running )) System.out.print(" not "); System.out.println("running."); System.out.print("The elevators are "); if (!(Elevator.powered )) System.out.print("not "); System.out.println("powered."); } public class Hotel2 { public static void main(String args[]) { FrontDesk lobby; lobby = new FrontDesk(); System.out.println("It's 7:00. Time to check the elevators."); lobby.maintenance(7); lobby.displayStatus(); System.out.println(); System.out.println("It's 8:00. elevators."); lobby.maintenance(8); lobby.displayStatus(); System.out.println(); System.out.println("It's 10:00. elevators."); lobby.maintenance(10); lobby.displayStatus(); } }

Time to check the

Time to check the

In this case, the variable powered is now a static variable, and the method togglePower() is a static method. This means that each is now a property of all Elevator classes, not the specific instances. Invoking either the NorthElevator.togglePower(), SouthElevator.togglePower(), or Elevator.togglePower() method would change the status of the powered variable

- 106 -

in both classes. Consequently, the code would produce the following output: C:\dev>\JDK1.2\java\bin\java Hotel2 It's 7:00. Time to check the elevators. North Elevator is running. South Elevator is running. The elevators are powered. It's 8:00. Time to check the elevators. North Elevator is not running. South Elevator is running. The elevators are powered. It's 10:00. Time to check the elevators. North Elevator is not running. South Elevator is running. The elevators are not powered. Placing the static modifier in front of a method declaration makes the method a static method. While nonstatic methods can also operate with static variables, static methods can only deal with static variables and static methods. Abstract Abstract methods are simply methods that are declared, but are not implemented in the current class. The responsibility of defining the body of the method is left to subclasses of the current class. For example: abstract void toggleStatus(); Caution Neither static methods nor class constructors can be declared to be abstract. Furthermore, you should not make abstract methods final, because doing so prevents you from overriding the method. Final By placing the keyword final in front of the method declaration, you prevent any subclasses of the current class from overriding the given method. This ability enhances the degree of insulation of your classes, and you can ensure that the functionality defined in this method will never be altered in any way. For example: final void toggleStatus() Native Native methods are methods that you want to use, but do not want to write in Java. Native methods are most commonly written in C++ and can provide several benefits such as faster execution time. Like abstract methods, they are declared simply by placing the modifier native in front of the method declaration and by substituting a semicolon for the method body. However, it is also important to remember that the declaration informs the compiler as to the properties of the method. Therefore, it is imperative that you specify the same return type and parameter list as can be found in the native code. Synchronized By placing the keyword synchronized in front of a method declaration, you can prevent data corruption that may result when two methods attempt to access the same piece of data at the same time. Although this might not be a concern for simple programs, after you begin to use threads in your programs, this can become a serious problem. For example: synchronized void toggleStatus()

- 107 -

See "What Are Threads?" Returning Information Although returning information is one of the most important things a method can do, there is little to discuss by way of details about returning information. Java methods can return any data type ranging from simple ones, such as integers and characters, to more complex objects. (This means that you can return things such as strings as well.) Keep in mind that unless you use the keyword void as your return type, you must return a variable of the type specified in your declaration. For example, the following method is declared to return a variable of type boolean. The return is actually accomplished by employing the return (either true or false) statement in the third and fourth lines: public synchronized boolean isEmpty(int x,t y) { if (board[x][y] == EMPTY) return true; return false; } Method Name The rules regarding method names are quite simple and are the same as any other Java identifier: Begin with a Unicode letter (or an underscore or dollar sign) and continue with only Unicode characters. Parameter Lists Simply put, the parameter list is the list of information that will be passed to the method. It is in the following form and can consist of as many parameters as you want: DataType VariableName, DataType VariableName,... Note If you have no parameters, Java requires that you simply leave the parentheses empty. (This is unlike other languages that permit you to omit a parameter list, or C, which requires the keyword void.) Therefore, a method that took no parameters would have a declaration resembling the following: public static final void cleanBoard()

Passing Parameters in Java In C and C++, variables are always passed by value. In Pascal, they are always passed by reference. In Java, however, it depends on what data type you are using. This is probably the single most ambiguous part of the entire Java language. Here is the rule: If the type being passed is a primitive type (such as int, char, or float), the result is passed by value. If, however, the type being passed is an object (such as a class you created), the object is passed by reference. What does this mean? As shown in Listing 8.2, if you pass an int to a method and that method changes the int, in the old class the int still has the value it did before. However, when a class is passed and a variable is changed, the variable is changed in the old method, too. Take a look at Listing 8.3.

- 108 -

Listing 8.3 PassingDemo.javaThe Difference Between Passing an Object and a Primitive Type public class passingDemo { public void first(){ xObject o = new xObject (); o.x = 5; int x = 5; changeThem (x, o); System.out.println(); System.out.println("Back in the original System.out.println("The value of o.x is "+o.x); System.out.println("But, The value of x is now

method");

"+x);

public void changeThem (int x, xObject o){ x =9; o.x = 9; System.out.println("In the changThem method"); System.out.println("The value of o.x is "+o.x); System.out.println("The value of x is now "+x); } public static void main(String args[]){ passingDemo myDemo = new passingDemo(); myDemo.first(); } }

class xObject { public int x =5; } The resulting output from this code is In the changeThem method The value of o.x is 9 The value of x is 9

Back in the original method The value of o.x is 9 The value of x is 5 Pass by Reference or Pass by Value? One important thing to understand about any programming language is whether the values are passed into a method by value or by reference. If a language uses pass by reference, when you pass a value into a method

- 109 -

as a parameter, and then change the value it is changed back in the calling program as well. On the other hand, if a language uses pass by value, only the value is passed into the method and any changes aren't present in the calling method. Java is actually a mixed system. Native types (byte,short,char,int,long,float,double and boolean) are passed by value. All objects however are passed by reference. This is why in the example in the previous section the value of x (a native) is not changed in the original method. On the other hand since o (an object) is passed by reference, o.x has been changed when it's printed out in the original method.

Blocks and Statements


Methods and static initializers in Java are defined by blocks of statements. A block of statements is a series of statements enclosed within curly-braces {}. When a statement's form calls for a statement or substatement as a part, a block can be inserted in the substatement's place. The simplest block {} is shown in the following example: public void HiThere() { } The next example is only slightly more complex: public void HiThere(){ int Test; Test = 5; } Code blocks are not only integral for defining the start and end of a method, but they can also be used in a variety of locations throughout your code. One very important aspect of a block is that it is treated lexically as one instruction. This means that you can put together large blocks of code that will be treated as one instruction line. There is nothing in the definition of Java that prevents the programmer from breaking code into blocks even though they are not specifically called for, but this is seldom done. The following code fragment demonstrates this legal but seldom-performed technique: String Batter; Short Inning, Out, Strikes; Batsman Casey; // Object of class Batsman. ... if ((Inning == 9) && (Out==2) && (Batter.equals("Casey"))) { Casey.manner("ease"); Casey.bearing("pride"); { // Begins new block for no reason. int OnlyExistsInThisBlock = 1; Casey.face("smile"); Casey.hat("lightly doff"); } // Ends superfluous blocking. } Notice that this fragment contains two complete blocks. One is the substatement of the if statement, and the other is the unneeded block, which contains the unused integer

- 110 -

OnlyExistsInThisBlock.

Labeled Statements
Any statement in Java can have a label. The actual label has the same properties as any other identifier; it cannot have the same name as a keyword or already declared local identifier. If it has the same name as a variable, method, or type name that is available to this block, then within that block, the new label takes precedence and that outside variable, method, or type is hidden. The label has the scope of the current block. The label is followed by a colon. Labels are only used by the break and continue statements. An example of labeled statements appears in the following code fragment: writhing: Pitcher.GrindsBall("Hip"); Casey.eye("Defiance Gleams"); Casey.lip("Curling Sneer"); pitch: while (strike++ < 2) { if (strike < 2) continue pitch; break writhing; } The writhing statement is simple labeling of an expression statement, in this case, a method call from a rather complicated object called Pitcher. The pitch statement is labeling an iteration statement (while). This label is used as a parameter for the continue statement.

Scope
Another use of blocks is to control what is known as the scope of an object. When you declare a variable, it is only available for your use within a given code block. For instance, say you had the following block: { int x= 5; } System.out.println ("X is ="+x); // This line is not valid. The last line of this code would not be valid, because the computer creates the x variable, but when the computer reaches the closing brace, it gets rid of x.

Separators
Separators are single-character tokens, which (as their name implies) are found between other tokens. There are nine separators, which are loosely described as follows: ( Used both to open a parameter list for a method and to establish a precedence for operations in an expression ) Used both to close a parameter list for a method and to establish a precedence for operations in an expression { Used both to open a parameter list or used to begin a block of statements or an

- 111 -

initialization list } Used to close a block of statements or an initialization list [ Used both to open a parameter list for a Precedes an expression used as an array index ] Follows an expression used as an array index ; Used both to end an expression statement and to separate the parts of a for statement , Used as a list delimiter in many contexts . Used both as a decimal point and to separate such things as package name from class name from method or variable name

Chapter 9: Using Expressions


What Is an Expression?
Expressionscombinations of operators and operandsare one of the key building blocks of the Java language, as they are of many programming languages. Expressions allow you to perform arithmetic calculations, concatenate strings, compare values, perform logical operations, and manipulate objects. Without expressions, a programming language is deaduseless and lifeless. You've already seen some expressions, mostly fairly simple ones, in other chapters in this book. Chapter 7, "Data Types and Other Tokens," in particular showed you that operatorsone of the two key elements in an expressionform one of the main classifications of Java tokens, along with such things as keywords, comments, and so on. In this chapter, you take a closer look at how you can use operators to build expressionsin other words, how to put operators to work for you. There are all kinds of technical definitions of what an expression is, but at its simplest, an expression is what results when operands and operators are joined together. Expressions are usually used to perform operationsmanipulationson variables or values. In Table 9.1, you see several legal Java expressions. Table 9.1 Legal Java Expressions

Name of Expression

Example

Additive expression Assignment expression Array indexing Method invocation

x+5 x=5

sizes[11] Triangle.RotateLeft(50)

- 112 -

How Expressions Are Evaluated


When an expression is simple, like those shown in Table 9.1, figuring out the result of the expression is easy. When the expression becomes more detailed and more than one operator is used, things get more complicated. In Chapter 7, you learned that expressions are just combinations of operators and operands. And while that definition may be true, it's not always very helpful. Sometimes you need to create and use pretty complex expressionsmaybe to perform some kind of complicated calculation or other involved manipulation. To do this, you need a deeper understanding of how Java expressions are created and evaluated. In this section, you look at three major tools that will help you in your work with Java expressions: operator associativity, operator precedence, and order of evaluation.

Operator Associativity
The easiest of the expression rules is associativity. All the arithmetic operators are said to associate left-to-right. This means that if the same operator appears more than once in an expressionas the plus in a+b+c doesthen the leftmost occurrence is evaluated first, followed by the one to its right, and so on. Consider the following assignment statement: x = a+b+c; In this example, the value of the expression on the right of the = is calculated and assigned to the variable x on the left. In calculating the value on the right, the fact that the + operator associates left-to-right means that the value of a+b is calculated first, and the result is then added to c. The result of that second calculation is what is assigned to x. So if you were to write it using explicit parentheses, the line would read: x=((a+b)+c); Note Notice that in the previous example, a+b+c, the same operator appears twice. It's when the same operator appears more than onceas it does in this casethat you apply the associativity rule. You would use the associativity rule in evaluating the right sides of each of the following assignment statements: volume = length * width * height ; OrderTotal = SubTotal + Freight + Taxes ; PerOrderPerUnit = Purchase / Orders / Units ; Of these expressions, only the last one would result in a different way if you associated the expression incorrectly. The correct answer for this expression is (Purchase / Orders)/ Units However, evaluated incorrectly the result would be Purchase / (Orders/Units) which can also be written as

- 113 -

(Purchase * Units)/ Orders which is obviously not the same as the correct expression.

Precedence of Java Operators


When you have an expression that involves different operators, the associativity rule doesn't apply, because the associativity rule only helps figure out how combinations of the same operator would be evaluated. Now you need to know how expressions using combinations of different operators are evaluated. Precedence helps to determine which operator to act on first. If you write A+B*C, by standard mathematics you would first multiply B and C and then add the result to A. Precedence helps the computer to do the same thing. The multiplicative operators (*, /, and %) have higher precedence than the additive operators (+ and -). So, in a compound expression that incorporates both multiplicative and additive operators, the multiplicative operators are evaluated first. Consider the following assignment statement, which is intended to convert a Fahrenheit temperature to Celsius: Celsius = Fahrenheit - 32 * 5 / 9; The correct conversion between Celsius and Fahrenheit is that the degrees Celsius are equal degrees Fahrenheit minus 32 times 5 divided by 9. However, in the equation, because the * and / operators have higher precedence, the sub-expression 32*5/9 is evaluated first (yielding the result 17) and that value is subtracted from the Fahrenheit variable. To correctly write this equation, and whenever you need to change the order of evaluation of operators in an expression, you can use parentheses. Any expression within parentheses is evaluated first. To perform the correct conversion for the preceding example, you would write: Celsius = ( Fahrenheit - 32 ) * 5 / 9; Note Interestingly, there are some computer languages that do not use rules of precedence. Some languages, like APL for example, use a straight left-toright or right-to-left order of evaluation, regardless of the operators involved. Use of parentheses would also help with the following examples: NewAmount = (Savings + Cash) * ExchangeRate ; TotalConsumption = (Distance2 - Distance1) * ConsumptionRate ; The precedence of the unary arithmetic operatorsin fact all unary operatorsis very high; it's above all the other arithmetic operators. In the following example, you multiply the value -5 times the value of Xantham, and not Xantham times five negated (although the results are the same): Ryman = -5 * Xantham;

SummaryThe Operator Table


Table 9.2 is what is known as the precedence table. The operators with the highest

- 114 -

precedence are at the top. Operators on the same line are of equal precedence. All these operators associate left-to-right, except the unary operators, assignments, and the conditional. For any single operator, operand evaluation is strictly left-to-right, and all operands are evaluated before operations are performed. Table 9.2 The Complete Java Operator Precedence Table

Description

Operators

High Precedence

. [] ()

Instance Of Unary + - ~ ! ++ - Multiplicative Additive Shift Relational Equality Bitwise AND Bitwise XOR Bitwise OR Conditional-AND Conditional-OR Conditional Assignment * / % + << >> >>> < <= >= > > == != & ^ | && || ?: = op=

Order of Evaluation
Many people, when they first learn a language, confuse the issue of operator precedence with order of evaluation. The two are actually quite different. The precedence rules help you determine which operators come first in an expression and what the operands are for an operator. For example, in the following line of code, the operands of the * operator are a and (b+c): d = a * (b+c) ;

- 115 -

The order of evaluation rules, on the other hand, help you to determine not when operators are evaluated, but when operands are evaluated. Here are three rules that should help you remember how an expression is evaluated: For any binary operator, the left operand is evaluated before the right operand. Operands are always evaluated fully before the operator is evaluated; for example, before the operation is actually performed. If a number of arguments are supplied in a method call, separated by commas, the arguments are evaluated strictly left-to-right.

Of Special Interest to C Programmers


Because Java is an evolutionary outgrowth of C and C++, it's understandable that the expression syntax for the three languages is so similar. If you already know C, it's important that you keep in mind that the three languages are only similarnot identical. One very important difference is that order of evaluation is guaranteed in Java, and is generally undefined or implementation-specific in C. In Java, the remainder (%), increment (++), and decrement (- -) operators are defined for all primitive data types (except Boolean); in C, they are defined only for integers. Relational and equality operators in Java produce a Boolean result; in C, they produce results of type int. Furthermore, the logical operators in Java are restricted to Boolean operands. Java supports native operations on stringsincluding string concatenation and string assignment. C does not have this support for strings. In C, using the right-shift operator (>>) on a signed quantity results in implementationspecific behavior. Java avoids this confusion by using two different right-shift operators one that pads with zeroes and the other that does sign-extension.

Bitwise Operators
If you have a number, such as 0x0F2 (which is a hexadecimal number equal to 242), do you know how to get rid of just the 2? Do you know how to find out which of the bits of 0x0F2 are set the same as they are for the number 0x0A1? Bitwise operators allow you to solve these problems easily. (To answer the question: 0x0F2&0x0F0 and 0x0F2&0x0A1.) The bitwise operators are a set of operators that are either very important or completely unimportant to you depending on what you are doing. When you need a bitwise operator, it is rarely the case that you can substitute any other operation to easily reproduce the same results. But, at the same time, it's highly likely that most of the work you do will not require you to perform such esoteric calculations. So what are bitwise operators? Bitwise operators work on the fundamental level of how values are stored in a computer. Numbers are stored in sequences of on and off, known as bits, which are most often translated to the binary numbers 1 and 0. A typical variable such as an int has 32 of these 1s and 0s in order to make up a complete number. It is often helpful to be able to manipulate these values directly, and bitwise operators are the means to do that. Consider a simple example using bytes. A byte comprises eight bits of memory. Each of the eight bits can have the value of 0 or 1, and the value of the whole quantity is

- 116 -

determined by using base 2 arithmetic, meaning that the rightmost bit represents a value of 0 or 1; the next bit represents the value of 0 or 2; the next represents the value 0 or 4, and so on, where each bit has a value of 0 and 2^n and n is the bit number. Table 9.3 shows the binary representation of several numbers. Table 9.3 Some Base 10 Values and Their Base 2 Equivalents

Base 10

Value

128

64

32

16

17 63 75 131

0 0 0 0

0 0 0 1

0 0 1 0

0 1 0 0

1 1 0 0

0 1 1 0

0 1 0 0

0 1 1 1

1 1 1 1

To find the Base 10 value of the numbers in Table 9.3, you need to add together the number at the top of the column for each of the columns containing a 1. For instance, the first row would be 16+1 = 17 The numeric quantities in Table 9.3 are all positive integers, and that is on purpose. Negative numbers are a little more difficult to represent. For any integer quantity in Java, except char, the leftmost bit is reserved for the sign-bit. If the sign-bit is 1, then the value is negative. The rest of the bits in a negative number are also determined a little differently, in what is known as two's-complement, but don't worry about that now. Floating-point numbers also have their own special binary representation, but that's beyond the scope of this book. The three binary bitwise operators perform the logical operations of AND, OR, and Exclusive OR (sometimes called XOR) on each bit in turn. The three operators are: Bitwise AND: & Bitwise OR: | Bitwise Exclusive OR: ^ Each of the operators produces a result based on what is known as a truth table. Each of the operators has a different truth table, and the next three tables show them. To determine the results of a bitwise operator, it is necessary to take a look at each of the operands as a set of bits and compare the bits to the appropriate truth table. First Value (A) (A&B) 0 Second Value (B) Resulting Value

- 117 -

0 1 1 First Value (a)

1 0 1 Second Value (b)

0 0 1 Resulting Value (A|B) 0 1 1 1 Resulting Value (A ^ B) 0 1 1 0

0 0 1 1 First Value (a)

0 1 0 1 Second Value (b)

0 0 1 1

0 1 0 1

The operands of the bitwise operators can also be Boolean, in addition to being any other integer type. Table 9.4 shows the results of each of these operations performed on two sample values. First, you see the Boolean values of the two numbers 11309 and 798, and then the resulting bit sequences after the various bit operators are applied. Table 9.4 Bitwise Operation Examples

Expression

Binary Representation

11309 798 11309 & 798 11309 | 798 11309 ^ 798

0010 1100 0010 1101 0000 0011 0001 1110 0000 0000 0000 1100 0010 1111 0011 1111 0010 1111 0011 0011

- 118 -

The Shift Operators


There are three shift operators in Java, as follows: Left shift: << Signed right shift: >> Unsigned right shift: >>> The shift operators move (shift) all of the bits in a number to the left or the right. The left operand is the value to be shifted, while the right operand is the number of bits to shift by, so in the equation 17<<2 the number 17 will be shifted two bits to the left. The left shift and the unsigned right shift populate the vacated spaces with zeroes. The signed right shift populates the vacated spaces with the sign bit. The following table shows two 8-bit quantities, 31 and -17, and what happens when they are shifted: Quantity 31 -17 x 00011111 11101111 x<<2 01111100 10111100 x>>2 00000111 11111011 x>>>2 00000111 00111011

The precedence of the shift operators is above that of the relational operators, but below the additive arithmetic operators.

Type Conversions
One very critical aspect of types in general in any language is how they interrelate. In other words, if you have a float such as 1.2, how does that relate to, say, an integer? How does the language handle a situation where a byte (8 bits) is added to an int (32 bits)? To deal with these problems, Java performs type conversions. Java is called a strongly typed language, because at compile time the type of every variable is known. Java performs extensive type-checking (to help detect programmer errors) and imposes strict restrictions on when values can be converted from one type to another. There are really two different kinds of conversions: Explicit conversions occur when you deliberately change the data type of a value. Implicit conversions occur any time two unequal types are represented in an equation, and they can be adjusted to be the same time. This can happen without your intervention, even without your knowledge. Briefly then, casting and converting are the way Java allows the use of a variable of one type to be used in an expression of another type. Note In C, almost any data type can be converted to almost any other across an assignment statement. This is not the case in Java, and implicit conversions between numeric data types are only performed if they do not result in loss of precision or magnitude. Any attempted conversion that would result in such a loss produces a compiler error, unless there is an explicit cast.

- 119 -

Implicit Type Conversions


Java performs a number of implicit type conversions when evaluating expressions, but the rules are simpler and more controlled than in the case of C or even C++. For unary operators (such as ++ or - -), the situation is very simple: Operands of type byte or short are converted to int, and all other types are left as is. For binary operators, the situation is only slightly more complex. For operations involving only integer operands, if either of the operands is long, then the other is also converted to long; otherwise, both operands are converted to int. The result of the expression is an int, unless the value produced is so large that a long is required. For operations involving at least one floating-point operand, if either of the operands is double, then the other is also converted to double and the result of the expression is also a double; otherwise, both operands are converted to float, and the result of the expression is also a float. Consider the expressions in Listing 9.1. Fortunately, implicit conversions take place almost always without your wanting or needing to know. The compiler handles all the details of adding bytes and ints together so you don't have to. Listing 9.1 Some Mixed Expressions Showing Type Conversions short Width; long Length, Area; double TotalCost, CostPerFoot; // In the multiplication below, Width will be converted to a // long, and the result of the calculation will be a long. Area = Length * Width; // In the division below, Area will be converted to a double, // and the result of the calculation will be a double. CostPerFoot = TotalCost / Area ;

Cast Operator
Normally with implicit conversion, the conversion is so natural that you don't even notice. Sometimes, though, it is important to make sure a conversion occurs between two types. Doing this type of conversion requires an explicit cast, by using the cast operator. The cast operator consists of a type name within round brackets. It is a unary operator with high precedence and comes before its operand, the result of which is a variable of the type specified by the cast, but which has the value of the original object. The following example shows an example of an explicit cast: float x = 2.0; float y = 1.7; x = ( (int)(x/y) * y) When x is divided by y in this example, the type of the result is a floating-point number. However, the value of x/y is explicitly converted to type int by the cast operator, resulting in a 1, not 1.2. So the end result of this equation is that x equals 1.7.

- 120 -

Not all conversions are legal. For instance, Boolean values cannot be cast to any other type, and objects can only be converted to a parent class. See Declaring a Class. Note Because casting involves an unconditional type conversion (if the conversion is legal), it is also sometimes known as type coercion.

Casting and Converting Integers


The four integer types can be cast to any other type except Boolean. However, casting into a smaller type can result in a loss of data, and a cast to a floating-point number (float or double) will probably result in the loss of some precision, unless the integer is a whole power of two (for example, 1, 2, 4, 8,...).

Casting and Converting Characters


Characters can be cast in the same way 16-bit (short) integers are cast; that is, you can cast them to be anything. But, if you cast into a smaller type (byte), you lose some data. In fact, even if you convert between a character and a short, you can lose some data. Note If you are using the Han character set (Chinese, Japanese, or Korean), you can lose data by casting a char into a short (16-bit integer), because the top bit will be lost.

Casting and Converting Booleans


There are not any direct ways to cast or convert a Boolean to any other type. However, if you are intent on getting an integer to have a 0 or 1 value based on the current value of a Boolean, use an if-else statement, or imitate the following code. int j; boolean tf; ... j = tf?1:0; otherwise.

// Integer j gets 1 if tf is true, and 0

Conversion the other way can be done with zero to be equal to false, and anything else equal to true as follows: int j; boolean tf; ... tf = (j!=0); otherwise.

// Boolean tf is true if j is not 0, false

Addition of Strings
Before you can finally leave the subject of operators, it is important to also cover a special use of the addition operator as it relates to strings. In general, Java does not support operator overloading; however, in Java, the concatenation of strings is supported by using the + operator. The behavior of the + operator with strings is just what you'd expect if you're familiar with C++. The first and second string are concatenated to produce a string that contains the values of both. In the following expression, the resulting string would be "Hello World":

- 121 -

"Hello" + " World" If a non-string value is added to a string, it is first converted to a string using implicit typecasting before the concatenation takes place. This means, for example, that a numeric value can be added to a string. The numeric value is converted to an appropriate sequence of digit characters, which are concatenated to the original string. All the following are legal string concatenations: "George " + "Burns" "Burns" + " and " + "Allen" "Fahrenheit" + 451 "Answer is: " + true

Chapter 10: Control Flow


Controlling the Execution
Controlling the flow of execution is perhaps the most important aspect of any programming language. Control flow allows you to direct the computer in different directions depending on conditions. So, if you're lost, you might turn in a random direction. Otherwise, you would follow the map. You can also think about control flow like a stoplight. If the light is red, you want to stop your car, but if the light is green, you want all cars to go through the intersection. Without this type of decision making, programs would be flat and lifeless. This chapter teaches you how to make the computer follow the map and traffic laws.

true and false Operators on Booleans


Almost all control flow expressions in Java control the flow based on a true or false value. For instance, as you learn later in this chapter, an if (value) statement causes the next statement to be executed only if the value is true. You can actually write something like if (true), but there is little value in it. Instead, usually the value is a Boolean expression. Operators in Java have particular meanings for use with Boolean expressions. Many of the same operator symbols are used with other types of expressions. In most cases, the meanings are a natural extension from the operations performed on integer types. The operations shown in Table 10.1 can be performed on Booleans. Table 10.1 Operations on Boolean Expressions

Operation Name

Description

= ==

Assignment Equality

As in tf = true;. This produces a true if the two Boolean operands have the same value (true or false). It produces false

- 122 -

otherwise. This is equivalent to NOT EXCLUSIVE OR (NXOR). != Inequality This produces a true if the two Boolean operands have different values (one true, the other false). It produces false otherwise. This is equivalent to EXCLUSIVE OR (XOR). If the operand is false, the output is true, and vice versa. Produces a true if and only if both operands are true. Note: This is only valid for Boolean operands. For other values, it's a bitwise operator. Produces a false if and only if both operands are false. Note: This is only valid for Boolean operands. For other values, it's a bitwise operator. Produces true only if exactly one (exclusive OR) operand is true. Note: This is only valid for Boolean operands. For other values, it's a bitwise operator. Same result for Booleans as described for &. Same result for Booleans as described for |. Requires a Boolean expression before the question mark.

Logical NOT

&

AND

OR

XOR

&& || ?:

Logical AND Logical OR if-thenelse

The Relational Operators


The most intuitive comparative operators are those that fall into a category known as relational operators. Relational operators include those standard greater-than and lessthan symbols you learned about back in third grade. Conveniently enough, they work the same as they did back in third grade, too. For instance, you know that if you write (3>4), you wrote something wrong (false). On the other hand, (3<4) is correct (true). In Java and most other languages, you are not limited to evaluating constants; you are free to use variables, so the statement (Democrats>Republicans) is also valid. The complete list of relational operators is shown here: Operator < <= > >= Boolean Result Less than Less than or equal to Greater than Greater than or equal to

The precedence of the relational operators is below that of the arithmetic operators, but above that of the assignment operator. Thus, the following two assignment statements produce identical results:

- 123 -

result1 = a+b < c*d ; result2 = (a+b) < (c*d) ; The associativity is left-to-right, but this feature isn't really very useful. It may not be immediately obvious why, but consider the following expression: a < b < c The first expression, a<b, is evaluated first, and produces a value of true or false. This value then would have to be compared to c. Because a Boolean cannot be used in a relational expression, the compiler generates a syntax error. Note In C and C++, the relational operators produce an integer value of 0 or 1, which can be used in any expression expecting an integer. Expressions like the following are legal in C or C++, but generate compiler errors in Java: RateArray [ day1 < day2 ] NewValue = OldValue + ( NewRate > OldRate ) * Interest; Try a very basic program to test some of what you have just learned. Listing 10.1 shows a list of printouts that tell if the things you learned in grade school were true. Here, we're using another convenient fact of Javayou can add Boolean values to a string and the answer true or false will be displayed for you. Listing 10.1 QuickTest.javaA Simple Lesson from the Third Grade public class QuickTest { public static void main(String args[]){ System.out.println("5 is greater than 6:"+(5>6)); System.out.println("6 is greater than or equal to 3:"+(6>=3)); System.out.println("8 is less than 10:"+(8<10)); } } To run this program, first copy Listing 10.1 to a file called QuickTest.java. As discussed in previous chapters, it's important the file be called QuickTest.java with all capitalization the same. Next, compile the program using javac: javac QuickTest.java After the file is compiled, you're ready to run it: java QuickTest As you may have already guessed, the output you get should look like this: 5 is greater than 6:false 6 is greater than or equal to 3:true 8 is less than 10:true

The Equality Operators


The equality operators are the next set of evaluation operators in Java. Equality

- 124 -

operators enable you to compare one value to another and find out if they are equal. In third grade, you might have written this as (3=3). Unfortunately, in Java, this statement would cause the compiler to use the assignment operator (also known as gets) rather than evaluate the equation. gets is used in traditional computing as a substitute for the = operator when reading text, as shown here. So, if you were to read out loud the line 3=3, you would say "three gets three." The problem is that this is not the result you are looking for. To solve this problem, a separate two-character operator (==) is used. In Java then, you would write the equation as (3==3). This would be read out loud as "three equals three." On the other hand, obviously the equation (3==4) would result in an incorrect equation (false). The following equality operators are very similar to the relational operators, with slightly lower precedence: Operator == != Boolean Result Is equal to Is not equal to

The equality operators can take operands of virtually any type. In the case of the primitive data types, the values of the operands are compared. However, if the operands are some other type of object (such as a class you created), the evaluation determines if both operands refer to exactly the same object. Consider the following example: String1 == String2 In this example, String1 and String2 must refer to the same stringnot to two different strings that happen to contain the same sequence of characters. Consider the lines shown in Listing 10.2. Listing 10.2 ObjectEquals.javaComparing Objects in Java public class ObjectEquals { public static void main(String args[]){ String String1 = new String("Hi Mom"); String String2 = new String("Hi Mom"); //At this point String1 is not equal to String2 System.out.println("String1 == String2 :"+(String1==String2)); String String3=String1; //Now String1 is equal to String2 System.out.println("String1 == String3 :"+(String1==String3)); } } Given this sequence, String1==String2 would return false after the first two lines because despite the fact that they contain the same letters, they are not the same object. On the other hand, String1=String3 would return true because they refer to exactly the same object. So as you may have already guessed, the output of this program is as follows:

- 125 -

String1 == String2 :false String1 == String3 :true Note If you want to compare String1 to String2 in the first two lines of this example, you can use the equals method of String. This would be written String1.equals(String2). The equals() method compares the strings character by character. The associativity of these operators is again left-to-right. You've seen that the associativity of the relational operators is really not useful to you as a programmer. The associativity of the equality operators is only slightly more useful. Take a look at the following example: StartTemp == EndTemp == LastRace Here, the variables StartTemp and EndTemp are compared first, and the Boolean result of that comparison is compared to LastRace, which must be Boolean. If LastRace is of some non-Boolean type, the compiler generates an error. Caution Writing code that depends on this kind of subtlety is considered extremely poor form. Even if you understand it completely when you write it, chances are you'll be as mystified as everyone else when you try to read it a few weeks or months later. Try to use constructs in your code that are easily read. If there is some reason that you must use an expression like the one just given, be sure to use comments to explain how the expression operates and, if possible, why you've chosen to implement your algorithm that way.

Logical Expressions
The third set of evaluation operators falls into a category known as logical expressions. Logical expressions work a bit differently than the previous operators and are probably not something you covered in your third-grade math class. Logical expressions operate either on a pair of Booleans or on the individual bits of an object. There are two types of logical operators which are divided roughly along these lines: Boolean operators Only operate on Boolean values Bitwise operators Operate on each bit in a pair of integral operands You have already seen in Chapter 9, "Using Expressions," how bitwise operators work. This chapter covers only the conditional half of the logical expression operators. However, it is interesting to note that, with some minor exceptions, bitwise operators and conditional operators will produce the same result if the operands are Boolean.

Conditional-AND and Conditional-OR Operators


There are two primary Boolean operators: Conditional-AND: && Conditional-OR: || Oddly, in most computer languages (including Java) there is no conditional-XOR operator.

- 126 -

These operators obey the same truth table that was constructed in Chapter 9 for the bitwise operators. They also tend to be fairly easy to read. For instance, true && true when read "both true and true" is obviously true. For your convenience, the truth tables for AND and OR are reproduced: When A is false false true true And when B is false true false true (A && B) false false false true (A || B) false true true true

The operands of a conditional-OR or a conditional-AND expression are evaluated left-to-right; if the value of the expression is determined after evaluating the left operand, the right operand will not be evaluated. So, in the following example, if x is indeed less than y, then m and n are not compared: (x<y) || (m>n) If the left side of this expression produces the Boolean value true, then the result of the whole expression is true, regardless of the result of the comparison m>n. Note that in the following expression, if you instead used a bitwise operator, m and n are compared regardless of the values of x and y: (x<y) | (m>n) The precedence of the two conditional operators is below that of the bitwise operators.

The Unary Logical Operators


There are two unary logical operators: Logical negation of Boolean operand: ! Bitwise negation of integral or Boolean operand: ~ Note For integer operands, this operator is the bit flippereach bit in its operand is toggled. (What was 0 becomes 1; what was 1 becomes 0.) By placing a negation operator in front of any value, the expression continues with the opposite value of that which the value had originally. For instance, !true would be false. Both these operators have high precedence, equivalent to that of the other unary operators. Take a look at the following example, which shows a combination of the logical negation and the conditional-AND: if (!dbase.EOF && dbase.RecordIsValid() ) Because the logical negation has high precedence, it is evaluated first. If EOF refers to End of File, you first check to see if you have reached the end of the file on this database. If you

- 127 -

haven't, the second operand is evaluated, which in this case is a method invocation that might determine the validity of the record. The key to understanding this is to realize that if the first operand is falsein other words, you have reached the end of the filethen you won't check to see if the record is valid.

The Conditional Operator


The conditional operator is unique because it is the one ternary or triadic operator meaning that there are three operands to the expression (instead of the typical two). It operates in Java, as it does in C and C++, and takes the following form: expression1 ? expression2 : expression3 In this syntax, expression1 must produce a Boolean value. If this value is true, then expression2 is evaluated, and its result is the value of the conditional. If expression1 is false, then expression3 is evaluated, and its result is the value of the conditional. You can look at the ternary operator just as if it was a typical if statement: If (expression1) expression2; else expression3; Consider the following examples. The first is using the conditional operator to determine the maximum of two values; the second is determining the minimum of two values; the third is determining the absolute value of a quantity. BestReturn = Stocks > Bonds ? Stocks : Bonds ; LowSales = JuneSales < JulySales ? JuneSales : JulySales ; Distance = Site1-Site2 > 0 ? Site1-Site2 : Site2 - Site1 ; In reviewing these examples, think about the precedence rules and convince yourself that none of the three examples requires any brackets to be evaluated correctly.

Booleans in Control Flow Statements


Booleans (and Boolean expressions) are the only type that may be used in the true clause of the control flow statements as seen in the following code fragment: Boolean TestVal = false; int IntVal = 1; ... if (TestVal) {} else {} if (IntVal != 1) {} else {} ... while (TestVal) {} while (IntVal == 0) {} ... do {} while (TestVal) do {} while (IntVal == 0) for (int j=0; TestVal; j++) {} for (int j=0; IntVal < 5; j++) {} In this code fragment, the comparisons of the integer IntVal to an integer constant value

- 128 -

are very simple Boolean expressions. Naturally, much more complicated expressions could be used in the same place.

Control Flow Functions


Control flow is the heart of any program. Control flow is the ability to adjust (control) the way that a program progresses (flows). By adjusting the direction that a computer takes, the programs that you build become dynamic. Without control flow, programs would not be able to do anything more than several sequential operations.

if Statements
The simplest form of control flow is the if statement. An if takes a look at a conditional expression (probably derived through any of the means described the first half of this chapter) and if the value is true, the next block of code is executed. The general syntax for the if is as follows: if (expression) statement; If the value is false, the computer skips the statement and continues on. An example of an if statement is shown in the following code fragment: if (myNameIsFred) System.out.println("Hi Fred"); System.out.println("Welcome to the system"); If the value of myNameIsFred is true, when this fragment runs the computer prints out the following: Hi Fred Welcome to the system However, if the value is false, the program skips over the line after the if and the result is as follows: Welcome to the system In most situations, you will want to execute more than one line of code based on an evaluation. To do this, you can place a code block after the if, which begins and ends with a pair of curly braces. The following code fragment shows just such an example: if (umpire.says.equals("Strike two")){ //equals method returns Boolean Crowd.cry("Fraud"); // method call Strike++; // last statement in if block. } Casey.face("Christian charity"); // 1st statement after if block.

if-else Statements
Only slightly more advanced than a simple if, the if-else expression passes execution to the else statement if the if evaluates to false. The code in the else block is not run if the if is true. Only one or the other set of code is run. The general syntax for an if-else is as follows:

- 129 -

if (expression) if_statement; else else_statement; An example of an if-else statement is as follows: if (strike != 2) Casey.lip("Curling Sneer"); // single substatement (could have// been a block) else { Casey.teeth("Clenched in hate"); // block of substatements// (could have been single) Casey.bat.pound("Plate"); } One important aspect of if-else blocks is how else blocks are evaluated when there are nested ifs. In other words, consider the following code: if (firstVal==0) if (secondVal==1) firstVal++; else firstVal; When is the else executed? In this example, the tabbing shows you that the else is associated with the inner (second) if. An if-else expression counts as one statement, so the else belongs to the most recent if and is part of the if statement for the first if. Another way to put this is that ifs are evaluated to elses in a First In First Out (FIFO) fashion. You can change this by placing the second if in a block: if (firstVal==0){ if (secondVal==1) firstVal++; } else firstVal; Because a block counts as a single statement, the else is associated with the first if. Another equally valid if-else statement is known as the compound if: if (firstVal==0) if (secondVal==1) firstVal++; else if (thirdVal==2) firstVal-; In this example, the firstVal statement is only executed when firstVal is 0, secondVal is not 1, and the thirdVal is 2. Follow this last example through to verify to yourself that this is the case.

Iteration Statements
- 130 -

Programmers use iteration statements to control sequences of statements that are repeated according to runtime conditions. Java supports five types of iteration statements: while for break do continue These are very similar to the statements of the same type found in C and C++, with the exception that continue and break statements in Java have optional parameters that can change their behavior (compared with C and C++, where these statements have no parameters) within the substatement blocks.

while Statements
The while statement tests an expression and, if it is true, executes the next statement or block repeatedly until the expression becomes false. When the variable or expression is false, control is passed to the next statement after the while statement. The syntax for a while loop looks very similar to that of an if statement: while (expression) statement; while loops can become endless, either intentionally or by accident, if the expression is made so that it will never become false. The following example shows a while loop in action: while (Casey.RoundingTheBasepads==true) { Crowd.cry("Hooray for Casey"); } In this example, it is clear that the expression might not be true initially, and if not, the block in the substatement will never be executed. If it is true, this block of code is executed repeatedly until it is not true.

do Statements
The do statement is similar to the while statement. In fact, it has a while clause at the end. Like the while expression in the previous section, the expression in the while statement must be a Boolean. The execution of a do loop processes the statement and then evaluates the while. If the while is true, execution returns to the do statement until the expression becomes false. The complete syntax for a do-while loop is as follows: do statement; while (expression)

- 131 -

The primary reason a programmer chooses to use a do statement instead of a while statement is that the statement will always be executed at least once, regardless of the value of the expression. This is also known as post-evaluation. For example: do { Crowd.cry("Kill the Umpire!"); } while (umpire.says.equals("Strike two")); In this example, the method Crowd.cry is invoked at least once no matter what. As long as the umpire.says method returns the string "Strike two", the Crowd.cry method is called over and over again.

for Statements
The most complicated of the four iteration statements is the for loop. The for statement gives the programmer the capability of all three of the other iteration statements. The complete syntax of a for loop is as follows: for (initialization, expression , step ) statement; The for loop first runs the initialization code (like a do) and then evaluates the expression (like an if or while). If the expression is true, the statement is executed and then the step is performed. A for loop can also be written with a while loop as follows: initialization; while (expression){ statement; step; } An example of a for loop appears in the following code fragment: for (int ball=0, int strike=0; (ball<4) && (strike<3);Ump.EvaluateSwing()) { Pitcher.pitch(); Player.swing(); } This example demonstrates the fact that the initialization clause can have more than one statement, and that the statements are separated by commas. Both the initialization and step clauses can have multiple statements this way. On the flip side, the statements can also be empty, with no statements.

switch Statements
The next type of control flow is the switch statement. The switch statement is the first control flow statement that does not require a Boolean evaluation. A switch passes control to one of many statements within its block of substatements, depending on the value of the expression in the statement. Control is passed to the first statement following a case label with the same value as the expression. If there are none, control passes to the default label. If there is no default label, control passes to the first statement after the switch block.

- 132 -

The syntax for a switch is as follows: switch (expression){ case V1: statement1; break; case V2: statement2; break; default: statementD; } Unique to switches, the expression must be of an integer type. You may use bytes, shorts, chars, or ints, but not floats or Booleans. The break statements are not really required. However, because of the way a switch works, breaks frequently end up being used. As soon as a value matches the expression, execution continues from that point. The execution falls through all the other statements. Take a look at the following example: switch (1){ case 1: System.out.println ("one"); case 2: System.out.println ("two"); case default: System.out.println("Default"); } In this example, the resulting output would be as follows: one two Default This happens because as soon as a case match is made, the execution falls through, or continues through, to the end of the switch. It is likely, however, that you don't want to print all three results. The break can be used to only produce the one printout. To do this, the code should be changed to the following: switch (1){ case 1: System.out.println ("one"); break; case 2: System.out.println ("two"); break; case default: System.out.println("Default"); break; } Note Notice that unlike if, while, do, and for statements, the case statement is not limited to a single statement, and no blocks are required. Execution simply begins after the case and continues until a break. The switch expression and case label constants must all evaluate to either byte, short, char, or int. In addition, no two case labels in the same switch block can have the same value. Another example of the switch statement is included in the following code fragment:

- 133 -

switch (strike) { case 0: case 1: Casey.lip("Curling Sneer"); break; case 2: Casey.teeth("Clenched in hate"); Casey.bat.pound("Plate"); break; default: System.out.println("Strike out of range"); } In this example, assume that strike is a compatible integer type (for example, int). Control passes to the correct line, depending on the value of strike. If strike doesn't have one of the values it should have, a programmer-defined error message is printed.

Jump Statements
In addition to the more common control flow functions, Java also has three kinds of jump statements: break, continue, and return.

break Statements
The substatement blocks of loops and switch statements can be broken out of by using the break statement. An unlabeled break statement passes control to the next line after the current (innermost) iteration (while, do, for, or switch statement). With a label, control may be passed to a statement with that label within the current method. If there is a finally clause to a currently open try statement, that clause is executed before control is passed on.

continue Statements
A continue statement may only appear within the substatement block of an iteration statement (while, do, or for). The effect of the unlabeled continue statement is to skip the remainder of the statements in the innermost iteration statement's block and go on to the next pass through the loop. The label parameter permits the programmer to choose which level of nested iteration statements to continue with. If there is a finally clause for a currently open try statement within the indicated level of nesting, that clause is executed before control is passed on.

return Statements
A return statement passes control to the caller of the method, constructor, or static initializer containing the return statement. If the return statement is in a method that is not declared void, it may have a parameter of the same type as the method. If there is a finally clause for a currently open try statement, that clause is executed before control is passed. See "Returning Information."

- 134 -

Chapter 11: Classes


What Are Classes?
Classes are the major building block of an object-oriented structure. In fact, classes are what make objects possible, and without objects, object-oriented programming would just be oriented programming which, well, would not make sense. There are several major advantages to using objects. They enable you to encapsulate data, keeping all information and actions about a particular item separate from the rest of your code. They allow you to build class hierarchies, which enables you to build up more and more complex structures from simpler ones. Lastly, through a technique called polymorphism, dissimilar objects that share a common attribute can be utilized by their similarities. From a common-sense view, classes are a way to assemble a set of data and then determine all of the methods needed to access, use, and change that data. Fundamentally, every class has two major portions. The first portion is that of state. The state of an object is nothing more than the values of each of its variables. If, for instance, you had a class StopLight with one variable, RedGreenYellow, the state of the StopLight would be determined by the value of RedGreenYellow. For example: public class StopLight{ int RedGreenBlue; } The second portion of a class is its tools, or methods. The methods of a class determine the utility the class has. In the case of the StopLight, it is likely that you would have a method called changeLight(), which would cause the light to change from red to green (probably by changing the RedGreenYellow variable). public class StopLight{ int RedGreenBlue; changeLight(){ RedGreenBlue = ++RedGreenBlue%3; } } Note To distinguish class variables with variables that are parts of methods, class variables are often referred to as fields, or class scope variables. In the previous example, the RedGreenYellow variable would be a field of the StopLight class.

Why Use Classes?


When dealing with classes, it is important to remember that classes do not enable programmers to do anything more than what they would be able to do without them. While it might be significantly more work, you could write all OOP programs structurally. So why use classes? The answer to this question is similar to the reason why large companies are divided into departments and sub-departments. By organizing hundreds of people with thousands of tasks, the department architecture provides for a simple distribution of tasks and responsibilities. Furthermore, because the billing department knows how to bill customers, the sales department does not need to worry about those details. By doing this work, the billing department has effectively encapsulated the work of billing within itself.

- 135 -

However, the power of object-oriented programming extends beyond the simple capability to encapsulate functionality in objects. A great deal of the appeal of OOP is its capability to provide inheritancethe capability to create new classes based on old classes. As an example of inheritance, consider a game board. Assume that you wrote a Checkers game a couple of months ago, and would now like to write a chess game. By using traditional programming techniques, you would start from scratch, or maybe cut and paste some of your old code. Using inheritance can eliminate most of this work. Instead, you build upon the code you wrote for your Checkers game. Override only those methods that behave differently in Checkers instead of Chess, and add only those methods that Checkers simply doesn't need. Note When new classes inherit the properties of another class, they are referred to as child classes or subclasses. The class from which they are derived is then called a parent or superclass. Another benefit of enclosing data and methods in classes is the OOP characteristic of encapsulationthe capability to isolate and insulate information effectively from the rest of your program. By creating isolated modules, after you have developed a complete class that performs a certain task, you may effectively forget the intricacies of that task and simply use the methods provided by the class. Because the class mechanisms are isolated, even if you have to significantly change the inner workings of a given class later, you do not need to modify the rest of your program as long the methods used to gain access to the class do not change. A side benefit of this is that by placing the data within the class and creating the appropriate methods to manipulate it, you may seal off the data from the rest of the program, thereby preventing accidental corruption of the data. Finally, the allure of the OOP approach to creating self-sustaining modules is further enhanced by the fact that children of a given class are still considered to be of the same "type" as the parent. This feature, called polymorphism, enables you to perform the same operation on different types of classes as long as they share a common trait. Although the behavior of each class might be different, you know that the class will be able to perform the same operation as its parent because it is of the same family tree. For example, if you were to create a Vehicle class, you may later choose to create Truck and Bike classes, each extending the Vehicle class. Although bikes and trucks are very different, they are both still vehicles! Therefore, everything that you are permitted to do with an instance of the Vehicle class you may also do with an instance of the Truck or Bike classes. A car dealership, then, need not worry if it is selling a Volvo or Saturn. The lot is simply full of vehicles.

What's So New About Object-Oriented Programming? OOP emphasizes a modular view of programming by forcing you to break down your task into manageable components, each with a specific function. However, unlike procedural functions, which are simply pieced together to form a program, objects are living "creatures" that have the capability to manage themselves, running concurrently with other operations and even existing after the rest of the program has terminated. It is this capability to exist and work with objects as a separate entity that makes OOP a nice match for Java, a network-based language.

Caution In the previous example, while every bike and truck is also a vehicle, a vehicle is not necessarily a bike or a truck. Thus, while the Bike and Truck classes can be treated just like the Vehicle class in Java, you may not perform an operation reserved for the Bike class on an instance of the Vehicle class.

Classes in Java
- 136 -

As stated at the beginning of this chapter, classes are the essential building block in any Java applet or application. Classes are used to create objects. When you create an instance of a class, you create an object. You can include all the code for that object within the class. In accordance with the object-oriented paradigm, you can later choose to build upon that class to build new programs or enhance your current program.

Bigger and Better Java Java itself is built from classes that are made available to the general public in the JDK. While there are some limitations, a large number of the classes that make up the Java architecture may them- selves be extended. By doing this, you may tailor the classes in the Java API libraryespecially those in the AWTto meet your particular needs.

Before you start creating large programs, you must first learn how to create simple classes. In terms of syntax, there are two parts to a class in Java: the declaration and the body. Listing 11.1 is a simple class that fulfills some of the requirements of the simple game board discussed earlier. Examine this listing to get an idea of what constitutes a class. You can refer to this listing again later as your understanding of classes grows. Listing 11.1 GameBoard.javaA General Class for Creating a 1010 Board Game public class GameBoard { /* This is the beginning of a simple game board class that provides the basic */ /* structures necessary for a game board. It may easily be */ /* extended to create a richer game board. */ private static final int WIDTH = 10; /* These are constants */ private static final int HEIGHT = 10; /* that you want to */ private static final int EMPTY = 0; /* keep as standards */ private int board[][]; // This array will keep track of the board public String myname; played // what game is being

public GameBoard (String gamename) { board = new int[WIDTH][HEIGHT]; myname = new String(gamename); } public final void cleanBoard() { for (int i = 0; i < WIDTH; i++) for (int j = 0; j < HEIGHT; j++) board[i][j] = EMPTY; }

- 137 -

public synchronized void setSquare(int x, int y, int value) board[x][y] = value; } public synchronized boolean isEmpty(int x, int y) { if (board[x][y] == EMPTY) return(true); return(false); }

} Take a quick look through this class. The first part of any class is the class declaration. Most classes you write will look very similar to GameBoard: public class GameBoard Declaring a class states several things, but probably the most important one is the name of the class (GameBoard). In the case of any public class, the name of the class must also match up with the name of the file it is in. In other words, this class must appear in the file GameBoard.java. The next part of the class is the opening brace. You should notice that there is a brace ({) at the beginning of the class, and if you look all the way down at the bottom there is also a closing brace (}). The braces define the area in the file where the class definitions will exist. A bit farther down you will see several comments. As you learned in "Comments" (Chapter 7), comments can exist anywhere in the file and are ignored by the compiler, but they help you leave messages for yourself or other programmers. Next, you will see several fields declared. Each of these variables is accessible from any of the methods in the class. When you change them in one method, all the other methods will see the new value. private */ private private private // This static final int WIDTH = 10; /* These are constants

static final int HEIGHT = 10; /* that you want to */ static final int EMPTY = 0; /* keep as standards */ int board[][]; array will keep track of the board // what game is being played

public String myname; Finally, you should see four methods:

public GameBoard (String gamename) { board = new int[WIDTH][HEIGHT]; myname = new String(gamename); } public final void cleanBoard() { for (int i = 0; i < WIDTH; i++) for (int j = 0; j < HEIGHT; j++) board[i][j] = EMPTY; }

- 138 -

public synchronized void setSquare(int x, int y, int value) { board[x][y] = value; } public synchronized boolean isEmpty(int x, int y) { if (board[x][y] == EMPTY) return(true); return(false); } }

Declaring a Class
In general, Java class declarations have the form AccessSpecifier class NewClass NameofInterface extends NameofSuperClass implements

where everything in italics is optional. As you can see, there are four properties of the class that may be defined in the declaration: Modifiers Class name SuperClasses Interfaces

Access Specifiers
The access specifiers in a class declaration determine how the class can be handled in later development and are very similar to those four access specifiers discussed in Chapter 8, "Methods." Although they are usually not extremely important in developing the class itself, they become very important when you decide to create other classes, interfaces, and exceptions that involve that class. When creating a class, you may choose to accept the default status or you may employ one of the three specifiers: public, final, or abstract. Public Classes By placing the modifier public in front of the class declaration, the class is defined to be public. Public classes are, as their name implies, accessible by all objects. This means that they can be used or extended by any object, regardless of its package. Here's an example: public class PictureFrame Also note that public classes must be defined in a file called ClassName.java (for example, PictureFrame.java). Protected Classes If you choose not to place a modifier in front of the class declaration, the class is created with the default properties. Therefore, you should be aware of what these properties are.

- 139 -

By default, all classes are assigned the protected level of access. This means that while the class may be extended and employed by other classes, only those objects within the same package may make use of this class. Here's an example of a friendly class: class PictureFrame Final Classes Final classes may not have any subclasses and are created by placing the modifier final in front of the class declaration. The reason for creating final classes may not be not be evident at first. Why would you want to prevent other classes from extending your class? Isn't that one of the appeals of the object-oriented approach? It is important to remember that the object-oriented approach effectively enables you to create many versions of a class (by creating children that inherit its properties but nevertheless change it somewhat). Consequently, if you are creating a class to serve as a standard (for example, a class that will handle network communications), you would not want to allow other classes to handle this function in a different manner. Thus, by making the class final, you eliminate this possibility and ensure consistency. In addition, telling the compiler that this is the final version of a class allows the compiler to perform a number of performance optimizations that otherwise would not be possible. Here's an example: final class PictureFrame Abstract Classes An abstract class, denoted by the modifier abstract, is a class in which at least one method is not complete. This state of not being finished is referred to as abstract. For example: abstract class PictureFrame How can a finished class not be complete? In the case of a grammar-checking class that is to be implemented in many languages, there are several methods that would have to be changed for each language-dependent version class. To create a cleaner program, instead of creating an EnglishChecker, a FrenchChecker, and a SpanishChecker class from scratch, you could simply create a GrammarChecker class in which the language-specific methods are declared as abstract and left empty. When ready, you could then create the language-specific classes that would extend the abstract GrammarChecker class and fill in the blanks by redefining these methods with actual code. Although you would still end up with separate classes for each language, the heart of your code would be in the GrammarChecker class, leaving only the languagedependent portions for the specific classes. Note Because they are not complete, you may not create instances of abstract classes. The class declaration need not be very complex and most often is very simple. In this example, only one modifier, public, was used; no other classes or interfaces were required.

Class Name
Like all other Java identifiers, the only requirements on a class name are that it: Begin with a letter or the characters or $

- 140 -

Contain only Unicode characters above hex 00C0 (basic letters and digits, as well as some other special characters) Not be the same as any Java keyword (such as void or int) Also, it is general practice to capitalize the first letter in the name of any class. Tip Although only required for public classes, it is generally a good practice to name the file in which class NewClass is defined NewClass.java. Doing so helps the compiler find NewClass, even if NewClass has not been compiled yet.

Super ClassesExtending Another Class


One of the most important aspects of OOP is the ability to use the methods and fields of a class you have already built. By building upon these simpler classes to build bigger ones, you can save yourself a lot of coding. Possibly even more important, you can greatly reduce the work of finding and fixing bugs in your code. To build upon a previous class, you must extend the class in the class declaration. By extending a super class, you are making your class a new copy of that class but are allowing for growth. If you were simply to leave the rest of the class blank (and not do anything different with the modifiers), the new class would behave identically to the original class. Your new class will have all of the fields and methods declared or inherited in the original class. Note Does this example look familiar? public class MyClass extends Applet { If you look at the source of any applet, you see that its declaration resembles the example. In fact, you probably have been extending the java.applet.Applet class without even knowing what you were doing. Remember the methods you have been able to use in your applets, such as showStatus(), init(), and keyDown()? Did they appear out of thin air? No, they are drawn from the java.applet.Applet class or one of the classes that it extends, such as java.awt.Component. By extending the java.applet.Applet class, your applet class is able to access and implement these methods, thereby providing your applet with a great deal of power. Every class in Java is considered to be an object. By default, every class is derived from the java.lang.Object class. So if your class does not extend any other class, it still extends java.lang.Object. Note Multiple-inheritance does not exist in Java. Thus, unlike C++, Java classes may only extend one class.

Constructors
Constructors are very special methods with unique properties and a unique purpose. Constructors are used to set certain properties and perform certain tasks when instances of the class are created. For instance, the constructor for the GameBoard class is: public GameBoard (String gamename) { board = new int[WIDTH][HEIGHT];

- 141 -

myname = new String(gamename); } Constructors are identified by having the same name as the class itself. Thus, in the GameBoard class, the name of the constructor is GameBoard(). Secondly, constructors do not specify a return argument because they are not actually called as a method. For instance, if you wanted to create an instance of the GameClass, you would have a line that looked like this: GameClass myGame = new GameClass(); When the new GameClass() is actually instantiated, the constructor method is called. In general, constructors are used to initialize the class's fields and perform various tasks related to creation, such as connecting to a server or performing some initial calculations. Also note that overloading the constructor enables you to create an object in several different ways. For example, by creating several constructors, each with a different set of parameters, you enable yourself to create an instance of the GameBoard class by specifying the name of the game, the values of the board, both, or neither. This practice is prevalent in the Java libraries themselves. As a result, you can create most data types (such as java.lang.String and java.net.Socket) while specifying varying degrees and types of information. Tip Most programmers choose to make their constructors public. This is because if the level of access for the constructor is less than the level of access for the class itself, another class may be able to declare an instance of your class but will not actually be able to create an instance of that class. However, this loophole may actually be used to your advantage. By making your constructor private, you may enable other classes to use static methods of your class without enabling them to create an instance of it. Finally, constructors cannot be declared to be native, abstract, static, synchronized, or final.

Overriding Methods
It is not legal to create two methods within the same class that have both the same name and the same parameter list. After all, doing so would just confuse the whole system (which method would you really want to be calling?). However, one of the purposes of extending a class is to create a new class with added functionality. To allow you to do this, when you inherit another class, you can override any of its methods by defining a method with the same name and parameter list as a method in the superclass. For instance, consider an Elevator class, shown in Listing 11.2. Listing 11.2 Elevator.javaA Simple Elevator Class class Elevator { ... private boolean running = true; ... public void shutDown() { running = false; } }

- 142 -

At some point you realize that this elevator just isn't very safe, so you decide to create a safer one. You want to extend the old Elevator class and maintain most of its properties, but change some as well. Specifically, you want to check to make sure the elevator car is empty before stopping, so you override the shutDown() method as shown in Listing 11.3. Listing 11.3 SaferElevator.javaA Safer Elevator That Extends Elevator class SaferElevator extends Elevator { ... public void shutDown() { if ( isEmpty() ) running = false; else printErrorMessage(); } } Note that overriding is accomplished only if the new method has the same name and parameter signature as the method in the parent class. If the parameter signature is not the same, the new method will overload the parent method, not override it. For example, look at Listing 11.4. Listing 11.4 SaferElevator.javaSafer Elevator with an Overloaded shutDown() Not an Overridden One class SaferElevator extends Elevator { ... public void shutDown(int delay) { if ( isEmpty() ) running = false; else printErrorMessage(); } } The shutDown method from the Elevator class would not have changed. Adding the parameter (int delay) to the method changes what is known as the method signature. The new shutDown method is still valid, though, and can be called because it has overloaded the original shutDown, as you learned in Chapter 8, "Methods." Note When you override a method, you may not make it more protected than the original method. Because the shutDown method is public in Elevator, you cannot make it private in SaferElevator.

Creating an Instance of a Class


To actually use a class you have created, you need to be able to create an instance of that class. An instance is an object of the type of the class. Any class you create can be instantiated, just like any other data type in Java. For example, to create an instance of the GameBoard, you would generally declare a variable of that type. Listing 11.5 shows a class called Checkers creating an instance of the GameBoard class. Listing 11.5 Checkers.javaCreates an Instance of GameBoard

- 143 -

public class Checkers{ GameBoard myBoard = new GameBoard(); .... } Note Technically, it's not necessary to create an instance of a class in order to use it. If the method or variable you are calling is static, no instance is necessary. However, remember that a static method can only refer to static class variables. This exception is what allows you to access the out variable of System without actually instantiating a System variable. In other words, you can type: System.out.println("Note, System was not instantiated!!"); As you may have noticed, the one primary difference between declaring an Object type, like GameBoard, and a primitive type, like int, is the use of the new keyword. In Listing 11.5, we used the phrase new GameBoard() to create a new instance of GameBoard. new performs several key tasks: Tells the computer to allocate the space necessary to store a GameBoard Causes the constructor method of GameBoard to be called Returns a reference to the object (which is then assigned to myBoard) You may be wondering in all of this, how does the very first instance of my class get created? After all, when you create an applet or an application, you don't have any way to actually instantiate that class, so how does it come to be? The answer lies with the virtual machine. When a browser encounters an <APPLET> tag (see Chapter 14, "Writing an Applet," to learn more about applets) or the Java program is run on an application (see Chapter 17, "Applets Versus Applications"), the virtual machine does a few things. In the case of an application, when you type java MyClass, the virtual machine calls the static method main() in MyClass. That doesn't actually create an instance of MyClass, but, because it's static (see the preceding note), an instance isn't necessary. That's why you typically need to create an instance of your class in the main() method. In the case of an applet, the browser does create an instance of MyClass when it encounters <APPLET CODE="MyClass"> and automatically calls the init() method. Note One additional difference in Java between objects and primitive types is how they are referenced. Primitive types are always referred to by their value. Object types are always referred to by their reference. This means that in the following code, x and y are not equal at the end, but in w and z, myName is the same: int x = 5; int y = x; y++; // x = 5, y =6;

GameBoard w = new GameBoard(); GameBoard z = w;

- 144 -

w.myName = "newString"; //Since z and w point to the same object, they now both have the same myName

Referring to Parts of Classes


Now that you have begun to develop classes, examine how they can be used in other classes. As discussed earlier in the section "Why Use Classes?", Java classes may contain instances of other classes that are treated as variables. However, you may also deal with the fields and methods of these class type reference variables. To do so, Java uses the standard dot notation used in most OOP languages. Listing 11.6 is an example. Listing 11.6 Checkers.javaThe GameBoard is Accessed by its Instance Board import java.awt.*; public class Checkers { private GameBoard board; public Checkers() { board = new GameBoard("Checkers"); board.cleanBoard(); } ... public void movePiece(int player, int direction) { java.awt.Point destination; ... if (board.isEmpty(destination.x, destination.y) ) // code to move piece } private void showBoard(Graphics g) { g.drawString(board.myname,100,100); drawBoard(g); } private void drawBoard(Graphics g){ .... } } Notice that board is an instance in the GameBoard class, and the variable myname in the GameBoard class is referenced by board.myname. The general notation for this type of access is instanceName.methodOrVariableName. Caution Notice that the variable myname is referred to as board.myname, not as GameBoard.myname. If you try to do so, you get an error resembling: Checkers.java:5: Can't make a static reference to nonstatic variable

- 145 -

myname in class GameBoard. This is because GameBoard is a type of class, while board is an instance of the class. As discussed in the previous section, when you deal with board, you deal with a specific copy of the GameBoard class. Because myname is not a static variable, it is not a property of the GameBoard class, but rather a property of the instances of that class. Therefore, it cannot be changed or referenced by using GameBoard as the variable name. This Special Variable You have seen how to refer to other classes. However, what if you want the class to refer to itself? Although the reasons to do so may not seem so obvious at first, being able to refer to itself is a capability that is very important for a class. To solve this problem, a unique variable called this is used whenever it is necessary to explicitly refer to the class itself. In general, there are two situations that warrant use of the this variable: When there are two variables in your class with the same nameone belonging to the class and one belonging to a specific method. When a class needs to pass itself as an argument to a method. Often when you create applets that employ other classes, it is desirable to provide those classes with access to such methods as showStatus(). For example, if you are creating a Presentation applet class and want to use a simple TextScroll class to display some text across the status bar at the bottom of the screen, you need to provide the TextScroll class with some means of using the showStatus() method belonging to the applet. The best way to enable the TextScroll to do this is to create the TextScroll class with a constructor method that accepts an instance of the Presentation applet class as one of its arguments. As seen in Listing 11.7, the TextScroll class would then be able to display the information across the bottom of the Presentation class's screen. Listing 11.7 Presentation.javaAn Instance of the Presentation Is Passed to a TextScroll Constructor public class Presentation extends Applet { TextScroll scroller; public void init() { ... scroller = new TextScroll(this, length_of_text); scroller.start(); } ... } class TextScroll extends Thread { Presentation screen; String newMessage; boolean running; int size; TextScroll(Presentation appl, int size) { screen = appl; }

- 146 -

public void run() { while (running) { displayText(); } } void displayText() { // perform some operations to update what should // be displayed (newMessage) screen.showStatus(newMessage); } } See "What Are Threads?" Note the use of the special this variable in the init() method of the Presentation class as well as the result. This technique is extremely useful and powerful. super Special Variable Along the same lines as this, the special variable super provides access to a class's super class. This is useful when overriding a method, because when doing so you may want to use code from the old method as well. For example, if you were creating a new class NewGameBoard that extended the GameBoard class and were overriding the setSquare() method, you might employ the super variable to use the former code without recopying all of it (see Listing 11.8). Listing 11.8 NewGameBoard.javaExtending the setSquare Method, but Still Using the Results of the Existing Method class NewGameBoard extends game board { private static int FIXEDWALL = 99; // permanent wall, cannot be moved public static synchronized void setSquare(int x, int y, int value){ if (board[x][y] != FIXEDWALL) { super.setSquare(x,y,val); } } In the preceding example, you use the super variable to refer to the original version of the setSquare() method, found in the GameBoard class. By doing so, you save yourself the headache of recopying the entire method, while at the same time adding to the functionality of the setSquare method. This allows you to keep the functionality of setSquare encapsulated in the original GameBoard class. If, down the road you discover an error in some of the logic, you won't be forced to change it in both the GameBoard and the NewGameBoard classes. You should also examine how to call the super method if the method you are dealing with is a constructor. It is necessary to call the constructor for a parent class, just as you need to call the constructor for any class. Although calling a super constructor is not much different from any other super method, its syntax may seem confusing at first: public NewGameBoard(String gamename) {

- 147 -

// new code would go here super(gamename); } Note that on a simplistic level, super can be considered equivalent to GameBoard. Consequently, because GameBoard() is the name of the original constructor method, it may be referred to as super().

Variables
Obviously, variables are an integral part of programs and, thus, classes as well. In Chapter 7, "Data Types and Other Tokens," you examined the various types of variables, but now you must also consider how they are employed in your programs and the different roles they may assume. When creating variables, whether they are as simple as integers or as complex as derived classes, you must consider how they will be used, what processes will require access to the variables, and what degree of protection you want to provide to these variables. The ability to access a given variable is dependent on two things: the access modifiers used when creating the variable and the location of the variable declaration within the class. See "LiteralsAssigning Values."

Class Fields Versus Method Variables In a class, there are two types of variables: those belonging to the class itself and those belonging to specific methods. Those variables declared outside of any methods, but within a given class (usually immediately after the class declaration and before any methods), are referred to as fields of the class and are accessible to all methods of it. In addition, one may declare variables within a method. These variables are local to the method and may only be accessed within that method. Because method variables exist only for the lifetime of the method, they cannot be accessed by other classes. Consequently, you cannot apply any access modifiers to method variables.

Although it is possible to make every field accessible to every class, this is not a prudent practice. First of all, you would be defeating a great deal of the purpose of creating your program from classes. Why do you choose appropriate class names instead of class1, class2, class3, and so on? You do so simply to create a clean program that is easy to code, follow, and debug. For the same reason, by creating various levels of protection, you encapsulate your code into self-sufficient and more logical chunks. Furthermore, inasmuch as OOP is heavily dependent on the modification of code that you have written beforehand, access restrictions prevent you from later doing something that you shouldn't. (Keep in mind that preventing access to a field does not prevent the use of it.) For example, if you were creating a Circle class, there would most likely be several fields that would keep track of the properties of the class, such as radius, area,

- 148 -

border_color, and so onmany of which may be dependent on each other. Although it may seem logical to make the radius field public (accessible by all other classes), consider what would happen if a few weeks later you decided to write the code shown in Listing 11.9. Listing 11.9 Circle.javaCode Fragment Showing What Direct Access to a Class Field Looks Like import java.awt.*; class Circle { public int radius, area; public Color border_color; ... } class GraphicalInterface { Circle ball; ... void animateBall() { for (int update_radius = 0; update_radius <= 10; update_radius++){ ball.radius = update_radius; paintBall(ball.area, ball.border_color); ... } } void paintBall(int area,Color color){ ... } } This code would not produce the desired result. Although the ball.radius = update_radius; statement would change the radius, it would not affect the area field. As a result, you would be supplying the paintBall() method with incorrect information. Now, instead, if the radius and area variables are protected, and any update to the radius forced the area to be recomputed, the problem would disappear as shown in Listing 11.10. Listing 11.10 Circle.javaProviding Access to the Circle Fields Through Methods class Circle { protected int radius, area; public void newRadius (int rad){ radius = rad; area = rad *2 * Math.PI; } public int radius(){ return radius; }

- 149 -

public int area (){ return area; } } class GraphicalInterface { Circle ball; ... void animateBall() { for (int update_radius = 0; update_radius <= 10; update_radius++){ ball.newRadius (update_radius); paintBall(ball.area(), ball.border_color); ... } } } In the next few sections, you examine the various ways of regulating access and solving this problem. Although it is important to consider the level of access that other objects will have to your fields, it is also important to consider how visible the fields and method variables will be within your class. Where the variable is accessible, a property called scope is very important. In general, every variable is accessible only within the block (delimited by the curly braces { and }) in which it is declared. However, there are some slight exceptions to this rule. Examine Listing 11.11. Listing 11.11 CashRegister.javaVariables Have Scope Based on Where They Are Declared class CashRegister { public int total; int sales_value[]; Outputlog log; void printReceipt(int total_sale) { Tape.println("Total Sale = $"+ total_sale); Tape.println("Thank you for shopping with us."); } void sellItem(int value) { log.sale(value); total += value; } int totalSales() { int num_of_sales, total = 0; num_of_sales = log.countSales(); for (int i = 1; i <= num_of_sales; i++) total += sales_value[i]; re

- 150 -

turn(total); } } Now examine some of the variables and their scope: Variable Name total Declared As Scope

Field global to CashRegister class

Entire class

total

Local to totalSales() method

Within totalSales()

log

Field global to CashRegister class

Entire class

value

Parameter to sellItem()

Within sellItem()

Local to totalSales() within for loop

Within the for loop

There are several things to note from the table. Start with the simplest variable, log. log is a field of the CashRegister class and is, therefore, visible throughout the entire class. Every method in the class (as well as other classes in the same package) may access log. Similarly, value, although declared as a parameter, is nevertheless local to the method sellItem() in which it was declared. Although all statements in sellItem() may access value, it may not be accessed by any other methods. Slightly more confusing is the variable i, which is declared not at the beginning of a method but within a for statement. Like log and value that exist only within the block in which they were defined, i exists only within the for statement in which it was defined. In fact, if you consider a complex for loop like that shown in the following example, i is recreated (in this case, 10 times). for (int x = 0; x<10 ;x++){ for (int i =0;i < num_of_sales; i++ ) ... } To understand why this is the case, it may be helpful to look at how this code might look if you "unwound it" into a while loop. { int x = 0; //declare x and set it's initial value while (x <10) {

- 151 -

value

{ //start the next for loop int i = 0; //declare i and set it's initial while (i < num_of_sales) { ... //do whatever is in the inner for i++; //perform the increment of i } } x++; //increment x }

loop

} As you can see, even though the for loop looks fairly simple, the scope of the variables is actually quite complicated if you add all the implied braces. Finally, you arrive at the problem of having two total variables with overlapping scope. While the total field is accessible to all methods, a problem seems to arise in the totalSales() method. In such cases, using the multiply-defined identifier refers to the most local definition of the variable. Therefore, although having no impact on the rest of the class, within the totalSales() the identifier total actually refers to the local variable total, not the global one. This means that after exiting the totalSales() method, the total class variable is unchanged. In such a situation, you can access the class by using the this keyword. So, to set the class variable total to the value of the local variable total, you would type: this.total = total; Although using the same identifier as a field and method variable name does not cause many problems and is considered an acceptable practice, it is preferable to choose a different (and more descriptive) identifier, such as total_sales. Another equally valid way to make your code easier to read is to come up with a unique naming scheme for all your class variables. The following are two common ways to do this: Add the letter m (for my) as the first letter to all class field variables Add an underscore (_) to the beginning of the all field variables Personally, I prefer the second option because it doesn't cause the confusion that can come from the former solution. If we were to have used this naming scheme in the previous example, it would have looked like this: class CashRegister { public int _total; int _sales__value[]; Outputlog _log; Note Although you can use the same identifier as a class field and as a local variable within a method, this does not apply to all code blocks within your code. For example, declaring num_of_sales as your counter within the for block would produce an error.

Modifiers
Like the modifiers for classes and methods, access modifiers determine how accessible certain variables are to other classes. However, it is important to realize that access

- 152 -

modifiers apply only to the global fields of the class. It makes little sense to speak of access modifiers for variables within methods because they exist only while the method is executing. Afterwards, they are collected to free up memory for other variables.

Why Not Make All Variables Fields? Because all class variables (fields) are accessible to all methods in a given class, why not make all variables fields global to all methods in the class? The first reason is that you would be wasting a great deal of memory. Although local variables (those variables declared within the methods themselves) exist only while the method is executing, fields must exist for the lifetime of the Object. Consequently, instead of allocating memory for dozens of fields by making many of your variables local, you are able to use the same piece of memory over and over again. The second reason is that making all your variables global would create sloppy programs that would be hard to follow. If you are going to be using a counter only in one method, why not declare it in that method? Furthermore, if all of your variables are global, someone reviewing your code (or you, a few weeks later) would have no idea from where the variables were obtaining their values, because there would be no logical path of values being passed from method to method.

Default By default, fields are assigned a level of access that, although accessible to other classes within the same package, are not accessible to subclasses of the current class or classes outside of the current package. For example: int size; public Identical to the public access modifier for methods, the public modifier makes fields visible to all classes, regardless of their package, as well as all subclasses. Again, you should make an effort to limit public fields. For example: public int size; protected protected fields may be accessed by all subclasses of the current class, but are not visible to classes outside of the current package. For example: protected int size; private The highest degree of protection, private fields are accessible to all methods within the current class. They are, however, not accessible to any other classes, nor are they accessible to the subclasses of the current class. For example: private int size; static As with methods, placing the modifier static in front of the field declaration makes the field static. static fields are fields of the class whose values are the same in all instances of the class. Consequently, changing a static field in one class will affect that field in all instances of the given class. static fields may be modified in both static and non-static methods. For example: static int size;

- 153 -

See Chapter 8, "Methods." final Although Java does not have preprocess, #define-type statements, or constants, there is a very simple way of creating constantsfields whose values cannot change while the program is running. By placing the modifier final in front of a field declaration, you tell the compiler that the value of the field cannot change during execution. Furthermore, because it cannot change elsewhere, you must set the actual value of all final fields as soon as they are declared, as seen in the next example: final int SIZE = 5; If the value cannot change, why not use the value itself within the program? The answer to this question is twofold: While you cannot change the value of constants within your code, as a programmer, you may later change the value of a constant without having to change the value of each use of the constant. For instance, if SIZE is used in 10 locations, you only need to change the number 5 in one location, not in 10. By using constants, your code becomes a lot cleaner and easier to follow. For example, in the GameBoard class, using 0 as a check for an empty space would not always make sense to a reader of your code. However, using the final field EMPTY and assigning it the value 0 makes the code a lot easier to follow. Note By convention, all letters of constants are capitalized. Furthermore, to save memory, constants are usually made static as well. Note There are two additional modifiers for fields. When dealing with many threads, there are several problems that can result when multiple threads attempt to access the same data at the same time. Although a majority of these problems can be solved by making certain methods synchronized, in future releases of Java, you will be able to declare certain fields as threadsafe. Such fields will be handled extra carefully by the Java runtime environment. In particular, the validity of each volatile field will be checked before and after each use. The other heralded keyword, transient, is related closely to the capability to enable the creation of persistent Java applets and Beans. In such an environment, transient fields would not be part of the persistent object.

Using Methods to Provide Guarded Access


Although it may be advantageous to restrict access to certain fields in your class, it is nevertheless often necessary to provide some form of access to those fields. A very intelligent and useful way of doing this is to allow access to restricted fields through less restricted methods (often referred to as set and get methods), such as in Listing 11.12. Listing 11.12 Circle.javaA Circle with Protected Fields class Circle { private int radius, area; private Color border_color; public void setRadius(int update_radius) { radius = update_radius;

- 154 -

area = Math.PI * radius * 2; } public Color getColor() { return(border_color); } public int getRadius() { return(radius); } public int getArea() { return(area); } } class GraphicalInterface { Circle ball; ... void animateBall() { for (int update_radius = 0; update_radius <= 10; update_radius++){ ball.setRadius(update_radius); paintBall(ball.getArea(), ball.getColor() ); } ... } } By limiting access to the radius field to the setRadius() method, you ensure that any change of the radius will be followed by an appropriate change of the area variable. Because you have made the two fields private, you must also provide yourself with the means of accessing them through the various get-type methods. These methods are commonly referred to as accessor methods because they provide access to otherwise inaccessible fields. Although at first this may seem a bit cumbersome, its benefits by far outweigh its disadvantages. As a result, it is a very widely used approach that is extremely prevalent in the Java API libraries on which Java is heavily dependent.

Using the finalize() Method


Belonging to the java.lang.Object class, and thus present in all classes, is the finalize() method. Empty by default, this method is called by the Java runtime system during the process of garbage collection and, may be used to clean up any ongoing processes before the object is destroyed. For example, in a class that deals with sockets, it is good practice to close all sockets before destroying the object defined by the class. Therefore, you could place the code to close the sockets in the finalize() method. After the instance of the class is no longer being used in the program and is destroyed, this method would be invoked to close the sockets as required. Note The finalize() method is very similar to the ~classname() method in C++. For example, take a look at the finalize() method in Listing 11.13. Listing 11.13 NetworkSender.javaUsing finalize() import java.io.*;

- 155 -

Import java.net.*; public class NetworkSender { private Socket me; private OutputStream out; public NetworkSender(String host, int port) { try { me = new Socket(host,port); out = me.getOutputStream(); } catch (Exception e) { System.out.println(e.getMessage(); } } public void sendInfo(char signal) { try { out.write(signal); out.flush(); } catch (Exception e) { System.out.println(e.getMessage()); } } public void disconnect() { System.out.println("Disconnecting..."); try { me.close(); } catch (Exception e) System.out.println("Error on Disconnect" + e.getMessage()); System.out.println("done."); } /* In this case finalize() is the identical to disconnect() /* /* and only attempts to ensure closure of the socket in the /* /* case that disconnect() is not called. */ protected void finalize() { System.out.println("Disconnecting..."); try { me.close(); } catch (Exception e) System.out.println("Error on Disconnect" + e.getMessage()); System.out.println("done.");

- 156 -

} } Note finalize() is declared to be protected in java.lang.Object and must remain protected or become less restricted. Caution While the finalize() method is a legitimate tool, it should not be relied upon too heavily because garbage collection is not a completely predictable process. This is because garbage collection runs in the background as a low-priority thread and is generally performed when you have no memory left. Consequently, it is a good practice to attempt to perform such clean-up tasks elsewhere in your code, resorting to finalize() only as a last resort and when failure to execute such statements will not cause significant problems.

Inner Classes
With the Java 1.1 compiler, Sun added several new features to the language. One of these was nested classes. Nested classes can only be compiled using a Java 1.1 or 1.2 compiler.

What Are Inner Classes?


Inner classes are classes that are actually included within the body of another class. In fact, you can even include a class within the body of a method. Nested classes are primarily useful to programmers because they can help you structure your code in a more organized fashion. In addition, in some cases they can add to the readability of the code. You may wonder why you would ever want to do this. The reality is that you are never required to develop anything using inner classes. However, inner classes provide you with the ability to organize your code in a more understandable fashion, and occasionally provide the compiler with a means to further optimize the final code. It is also true that you can produce identical results by placing the inner classes in their own scope. At this point, if you're one of those programmers who rode out the evolution of C++, you might be wondering whether or not inner classes are just one of those concepts that seemed like a good idea to the designers at the time, but that ends up only causing confusion. Wasn't Java supposed to avoid these pitfalls? Wasn't that the rationalization for avoiding operator overloading, multiple inheritance and other useful but confusing aspects of languages such as C++? Well, the unfortunate answer is maybe. Time will tell how well inner classes are accepted by the developer community as a whole. Regardless of what your own view is, it's very important to understand how to utilize inner classes in case you find yourself editing code from individuals who do utilize the power of inner classes. With that spirit, forge ahead and look at how inner classes work.

Creating a Program with Inner Classes


The major advantage of inner classes is the ability to create what are known as adapter classes. Adapter classes are classes that implement an interface. By isolating individual adapters into nested classes, you can, in essence, build a package-like structure right within a single top-level class. Take a look at an example that uses an adapter class. Listing 11.14 demonstrates how two individual and separate Runnable interfaces can be created in the same class. Both of these interfaces need access to the variable currentCount of the top-level class.

- 157 -

Listing 11.14 BigBlueAn Application that Utilizes an Inner Class (Apple) /* * * BigBlue * */ public class BigBlue implements Runnable{ int currentCount; class Apple implements Runnable { public void run(){ while(true){ System.out.println("count="+currentCount); try{ Thread.sleep(100); }catch (Exception e){} } } } public Runnable getApple(){ return new Apple(); } public void run(){ while(true){ currentCount+=5; try{ Thread.sleep(75); }catch (Exception e){} } } public static void main(String argv[]){ BigBlue b = new BigBlue(); Thread appleThread = new Thread (b.get Apple()); appleThread.start(); Thread thisThread = new Thread (b); thisThread.start(); } }) As you look at the preceding example, notice that the run() method of BigBlue has access directly to the currentCount variable, because currentCount is a field of the BigBlue class. This works just like any other method. Now take a look at the Apple class. This class also has access to the currentCount variable, and it accesses it just like it was its own, only it's not; it's received from the top-level class BigBlue. To compile this program, it's not necessary to compile both Apple and BigBlue, just the BigBlue class:

- 158 -

javac BigBlue.java To run the program, type: java BigBlue What you end up seeing are a sequence of numbers. Notice that because the sleep time in the BigBlue thread is a bit shorter than the Apple one, every once in a while the numbers increment faster. This was done to demonstrate that they were in fact two different threads, running in two completely different loops. Caution If, when you compile a class containing an inner class, you get an error similar to: bigBlue.java:30 : no enclosing instance of class bigBlue is in scope; an explicit one must be provided when creating class bigBlue. apple, as in outer. new inner() or outer.super(). Thread appleThread = new Thread (new apple()); You may be very confused. To explain this error, look at what a main method would look like that might generate this error: public static void main(String argv[]){ bigBlue b = new bigBlue(); apple()); Thread appleThread = new Thread (new appleThread.start(); Thread thisThread = new Thread (b); thisThread.start();

What causes this error is an attempt to create a new apple() inside of the static main method. To be able to access the apple class, you must do so in a non-static instance of BigBlue.

Synchronization with Inner Classes


From time to time, it is necessary to be able to synchronize a method on the parent class of an inner class. Ordinarily, you might just declare a method to be synchronized or create a block that is synchronized (this). However, because this is a new class, how are you to specify a synchronization on the parent class? Consider the situation where we create an enumeration, as in Listing 11.15. Listing 11.15 Enumeration of Elements public class FixedStack { int array[] = new int[10]; int top=0; synchronized public void push(int item) { array[top++] = item;

- 159 -

} class Enumerator implements java.util.Enumeration { public int nextElement() { synchronized (FixedStack.this) { if (count > top) count = top; if (count == 0) throw new NoSuchElementException("FixedStack"); return array[count]; } } } } Note In Listing 11.15, make sure you don't try to access an element in the array with the nextElement() method of the Enumeration at the same time an element is added with the push() method. To do this, the example uses the qualified FixedStack.this variable. The qualified name refers to the super class of this. The inner class implicitly knows that the qualified this refers to the instance that instantiated the inner class.

So How Do Inner Classes Work?


At this point, you're probably wondering how inner classes work. Under Java 1.0, inner classes were not available. So, how did Java designers make the programs that you write using inner classes work with virtual machines that were designed from the 1.0 specification? The answer is that inner classes aren't really new. The solution lies in the fact that when you write a class with an inner class in it, the compiler takes the inner class outside of the main class and just adjusts the compiled result. Again, if you're one of those programmers who rode the change in the early days of C++, inner classes will spark a note. The reason is that in the beginning of C++, C++ was really C wrapped in an object-oriented shroud. When you wrote a C++ program, the C++ compiler actually just converted your C++ code into C code, and then a C compiler did the real compilation. Well, with Java, you don't actually need two compilers, but the end result is very similar.

Why Use Inner Classes?


You might be saying to yourself, "Why should I ever use an inner class?" The answer, as indicated at the beginning of this section, is to organize your code in a more suitable fashion. Sun's documentation refers to these inner classes as Adapter classes. To understand why, look at what inner classes are usually used for. An inner class can extend or implement any interface you would likeso can an ordinary class. The only problem is that when a standard class implements an interface, it's often difficult to locate where the methods associated with the interface are located within the code. However, because the declaration and the code are together with an inner class, this is generally much clearer.

Packages
When you start creating a large number of classes for a program, it is helpful to keep them together. A clutter of class files is not unlike how your hard drive would look without subdirectories or folders. Imagine if all the files on your hard drive were placed in a single

- 160 -

folder. You would have thousands of files, and you would have to make sure that none of them had the same name. Class files by themselves must comply with this same arrangement. That's a fairly rigid requirement. To overcome this, Java has a system called packages. You can think of each package as a subdirectory. You have already seen how a number of packages are used in the Java API. For example, java.awt is a package, java.lang is another package, and so on. Packages in Java are groups of classes. These are similar to libraries in many computer languages. A package of Java classes typically contains related classes. You can imagine a package called Transportation, which would have numerous classes defined in it such as Car, Boat, Airplane, Train, Rocket, AmphibiousCar, SeaPlane, and so on. Applications that deal with items of this sort might benefit from importing the imaginary Transportation package. To make a class a member of a package, you must declare it using the package statement: package Transportation; Some unique requirements go along with the package statement, however: For a class to be included in a package, its source code must be in the same directory as the rest of the package files. You can get around this requirement, but it's not really a good idea. The package statement itself must be the very first statement in the file. In other words, you can have comments and whitespace before the package line, but nothing else. The following table shows an example of a valid and an invalid package statement: Legal package Transportation import java.applet.Applet; Illegal import java.applet.Applet; package Transportation;

Importing Classes in Packages


After a file has been declared to be part of a package, the actual name for the class is the package name dot (.) and the name of the class. In other words, in our Transportation example, the Car class would be Transportation.Car, where before it would have been simply Car. This leads to a small problem with an easy solution. If you write a program and then later decide to make all of the classes a member of a package, how does the compiler find the other files? Before, they were called Car and Van. Now, you must import them as Transportation.Car in order to use them. In other words, as shown here, where before you imported Car, you must now import Transportation.Car: Old import Car; New import Transportation.Car

Importing Entire Packages


- 161 -

It is also possible to import the entire contents of a package or all of the classes in that package. You have probably already seen this done with some of the JDK classes such as java.awt. To import all the classes, replace the individual class name with the wild card (*): import java.awt.*; By importing entire packages, you give yourself access to every class in the package. This can be very convenient, because you don't need to make up a big list like: import import import import ... java.awt.Graphics; java.awt.Image; java.awt.Button; java.awt.Canvas;

Now, if you're thinking, "That seems simple; why don't I just import the entire package all the time?" The answer lies in the fact that there are a couple of drawbacks to importing the entire package: When you import an entire package, the virtual machine has to keep track of the names of all of the elements in the package. Using extra RAM to store class and method names is not terribly important right now because your computer probably has 16M or more of RAM. However, as more and more small, Java-based computers come into play, this could become an issue. In addition, this slows the system down slightly. If you import several packages and they happen to share a class file name, things start to fall apart. Which class do you really want? For instance, if you import YourCorp.*, which has a Button class, and import java.awt.*, which also contains a Button class, the two Button classes will collide. The most important drawback deals with the bandwidth over the Internet. When you import an entire package that is not on the computer already (this excludes the java.* packages) the Appletviewer or other browser has to drag all of the class files for the entire package across the Net before it can continue. If you have 30 classes in a package and are only using two, your applets aren't going to load nearly as fast, and you would be wasting a lot of resources.

Using a Class Without Importing It


You may have not realized this before, but it is not necessary to actually import a class before you use it. Ordinarily, classes in the null package (default) and that reside in the same physical directory can be used without doing anything. For instance, if there are two classes Car and Van in the same directory, you can create an instance of Car in the Van class without actually importing the Car class. Listings 11.16 and 11.17 show two such classes. Listing 11.16 A Simple Class File for the Car Class //Car is just a generic class with a few variables public class Car { int wheels; int tires; int speed; //simple constructor

- 162 -

public Car (int inWheels, int inTires, int inSpeed){ wheels=inWheels; tires = inTires; speed = inSpeed; } } Listing 11.17 A Simple Class File for Van that Uses the Car Class //The Van class is another simple class, but uses the Car class public class Van { //The Car class is used here without being imported Car theCar; int doors; //simple constructor public Van (Car inCar, int inDoor){ theCar= inCar; doors= inDoor; } } When you place a class in a package, you can still use the class without importing it. The only difference is that you must use the full class name when declaring the instance. Listings 11.18 and 11.19 are identical to 11.15 and 11.16 except that Car is a member of the Transportation package. Listing 11.18 A Simple Class File for the Car Class in a Package package Transportation; //Car is just a generic class with a few variables public class Car { int wheels; int tires; int speed; //simple constructor public Car (int inWheels, int inTires, int inSpeed){ wheels=inWheels; tires = inTires; speed = inSpeed; } } Listing 11.19 A Simple Class File for Van that Uses the Car Class in a Package //The Van class is another simple class, but uses the Car class public class Van { //The Car class is used here without being imported Transportation.Car theCar; int doors; //simple constructor public Van (Car inCar, int inDoor){ theCar= inCar; doors= inDoor;

- 163 -

} } Note Although you do not need to import a package to use the classes, doing so affords a shorthand way to refer to classes defined in the package. Specifically, in the previous example, if the package was imported: import Transportation.Car; to create an object of Class Car, you would not need Transportation in front of every Car reference, and the code would look otherwise identical to Listing 11.18.

Using Packages to Organize Your Code


Packages are more than just a shortcut. They are a way of keeping things organized. Java itself comes with a built-in set of packages, as shown in Table 11.1. Table 11.1 Standard Java Packages

Package

Description

java.applet

Contains classes needed to create Java applets that run under Netscape 2.0 (or greater), HotJava, or other Java-compatible browsers. Contains classes helpful in writing platform-independent graphic user interface (GUI) applications. This comes with several subpackages including java.awt.peer and java.awt.image. Contains classes for doing I/O (input and output). This is where the data stream classes are kept. Contains the essential Java classes. java.lang is implicitly imported, so you don't need to import its classes. Contains the classes used for making network connections. These are used in tandem with java.io for reading and writing data from the network. Contains other tools and data structures, such as encoding, decoding, vectors, stacks, and more.

java.awt

java.io

java.lang

java.net

java.util

Additional packages are also available commercially. The one feature to notice about these classes is how Sun Microsystems has used the packages to group similar classes together. When you set out to construct a program, you might be tempted to place the entire program in a package. For instance, say you were writing a Pac Man game. You might be tempted to place all of the classes in a

- 164 -

package called Pac. Would this be a good idea? Probably not, but it all depends on your implementation. The odds are that your Pac Man game will include a lot of code that is likely to be used by other arcade-style games you have written. For instance, you might create what is known as a game sprite engine. It's probably a more far-sighted approach to place all of the elements for the game-sprite in their own package and then place only those classes that are specific to the Pac Man game in the Pac package. Later you can go back and add to the game-sprite package without disrupting the readability of your Pac Man game.

Implicit Import of All java.lang Classes


You might have noticed from reading the code throughout this book that there is another set of classes that you don't need to import to use. The classes in the java.lang package are always imported for you. This means that you can use the java.lang.System class as if it was part of the systemwithout importing it in statements like this: System.out.println("Hi there, System hasn't been imported"); This can be a very convenient thing as in the case of System, but it can also be a source of confusion. For instance, look back at Listing 11.10; the Math class is also used without instantiating it to access the value of PI. However, if you're not familiar with how Math got imported (automatically), this may have caused you some confusion. The only way to overcome this is to become familiar with the java.lang package and learn what classes are available to you.

Chapter 12: Interfaces


What Are Interfaces?
Interfaces are Java's substitute for C++'s feature of multiple inheritance, the practice of allowing a class to have several superclasses. Although it is often desirable to have a class inherit several sets of properties, for several reasons the creators of Java decided not to allow multiple inheritance. Java classes, however, can implement several interfaces, thereby enabling you to create classes that build upon other objects without the problems created by multiple inheritance. Somewhat resembling classes in syntax, interfaces are used when you want to define a certain functionality to be used in several classes, but are not sure exactly how this functionality will be defined by each of these classes. By placing such methods in an interface, you are able to outline common behavior and leave the specific implementation to the classes themselves. This makes using interfaces instead of classes a better choice when dealing with advanced data handling. Interfaces are the underprivileged first cousins of classes. In fact, they are extremely similar to pure abstract classes. Although classes have the capability to define an object, interfaces define a set of methods and constants to be implemented by another object. From a practical viewpoint, interfaces help to define the behavior of an object by declaring a set of characteristics for the object. For example, knowing that a person is an athlete does not define her entire personality, but does ensure that she has certain traits and capabilities. As an example, say an athlete will always have a 100-meter time, be able to perform the task of running a mile, and be able to lift weights. By later implementing the athlete interface, you ensure that a person will possess these abilities.

- 165 -

Thinking of interfaces in another way, consider your radio, TV, and computer speakers. Each of them has one common control: volume. For this reason, you might want all these devices to implement an interface called VolumeControl. Interfaces have one major limitation: They can define abstract methods and final fields, but cannot specify any implementation for these methods. For methods, this means that the body is empty. The classes that implement the interface are responsible for specifying the implementation of these methods. This means that, unlike extending a class, when you implement an interface, you must override every method in the interface. In general, interfaces enable you as a programmer to define a certain set of functionality without having any idea as to how this functionality will be later defined. For example, if a class implemented the java.lang.Runnable interface (an interface with one method run()), the class is known to have a run() method. Because the VM can be assured that any Runnable class has a run() method, the VM can blindly call the run() method. At the same time, when the designers were writing the VM, they did not have to know anything about what would happen in the run() method. So, you could be doing an animation, or calculating the first 1,000 prime numbers. It doesn't matter; all that does matter is that you will be running, and you have established that by implementing the Runnable interface. Another excellent example is the java.applet.AppletContext interface. This interface defines a set of methods that returns information regarding the environment in which an applet is running. For instance, the AppletContext defines a method called getImage. Any viewer capable of running an applet has a means to load an image through the implementation of this method. The problem is that different viewers such as the Appletviewer or Netscape Navigator get images differently. Worse yet, even the same browser varies based on the platform it is running on. Fortunately, every Java-enabled browser implements the AppletContext interface, so although the java.applet.Applet class depends on the methods declared in the AppletContext interface, it does not need to worry about how these methods work. That means, you can use the same applet class and the same methods (such as java.applet.Applet.getImage()) in a variety of environments and browsers without worrying about whether the getImage() method will be there.

Creating an Interface
The syntax for creating an interface is extremely similar to that for creating a class. However, there are a few exceptions. The most significant difference is that none of the methods in your interface may have a body, nor can you declare any variables that will not serve as constants. An example interface is shown in Listing 12.1. It shows three items: an interface, a class that implements the interface, and a class that uses the derived class. Look it over to get an idea as to how interfaces are used and where we are going in this chapter. Listing 12.1 Product.java: Product Interface public interface Product { static final String MAKER = "My Corp"; static final String PHONE = "555-123-4567"; public int getPrice(int id); } ***begin Listing 12.1a: Shoe.java: Class Shoe which implements

- 166 -

the Product Interface public class Shoe implements Product { public int getPrice(int id) { if (id == 1) return(5); else return(10); } public String getMaker() { return(MAKER); } } ***Begin Listing 12.1b: Store.java: Class Store extends Shoe(which implements Product) public class Store { static Shoe hightop; public static void init() { hightop = new Shoe(); } public static void main(String argv[]) { init(); getInfo(hightop); orderInfo(hightop); } public static void getInfo(Shoe item) { System.out.println("This Product is made by "+ item.MAKER); System.out.println("It costs $" + item.getPrice(1) + '\n'); } public static void orderInfo(Product item) { System.out.println("To order from " + item.MAKER + " call "

item.PHONE + "."); System.out.println("Each item costs $" + item.getPrice(1)); } }

The Declaration
Interface declarations have the syntax public interface NameofInterface extends InterfaceList where everything in italics is optional. Public Interfaces By default, interfaces may be implemented by all classes in the same package. But if you make your interface public, you allow classes and objects outside of the given package to implement it as well. Tip Just like public classes, public interfaces must be defined in a file named

- 167 -

NameOf Interface.java. Interface Name The rules for an interface name are identical to those for classes. The only requirements on the name are that it begin with a letter, an underscore character, or a dollar sign; contain only Unicode characters (basic letters and digits, as well as some other special characters); and not be the same as any Java keyword (such as extends or int). Again, like classes, it is common practice to capitalize the first letter of any interface name. See "Keywords." Tip Although only required for public interfaces, it is a good practice to place all interfaces in a file named NameOf Interface.java. This enables both you and the Java compiler to find the source code for your class. Thus, while the Product interface is not public, you should still declare it in a file named Product.java. Extending Other Interfaces In keeping with the OOP practice of inheritance, Java interfaces may also extend other interfaces as a means of building larger interfaces upon previously developed code. The new sub-interface inherits all the methods and static constants of the super-interfaces just as subclasses inherit the properties of superclasses. See "Object-Oriented Programming: A New Way of Thinking." The one major rule that interfaces must obey when extending other interfaces is that they may not define the body of the parent methods, any more than they can define the body of their own methods. Any class that implements the new interface must define the body of all of the methods for both the parent and child interface. As an example, the following lines show a new interface that extends a previously defined interface (Runnable): interface MonitoredRunnable extends java.lang.Runnable { boolean isRunning() { } } The declaration shows a more detailed Runnable interface, including some of the features that can be found in java.lang.Thread. Note Interfaces cannot extend classes. There are a number of reasons for this, but probably the easiest to understand is that any class that the interface would be extending would have its method bodies defined. This violates the "prime directive" of interfaces. Remember that if you implement an extended interface, you must override both the methods in the new interface and the methods in the old interface, as seen in Listing 12.2. Listing 12.2 Fireworks Class Implementing the MonitoredRunnable Derived Interface class Fireworks implements MonitoredRunnable { private boolean running; // Keeps track of state. void run() {

- 168 -

shootFireWorks(); } boolean isRunning() { objects without return(running); running. } } Because Fireworks implements MonitoredRunnable, it must override isRunning(), declared in MonitoredRunnable. Because MonitoredRunnable extends Runnable, it must also override run(), declared in Runnable. Note Although classes implement interfaces to inherit their properties, interfaces extend other interfaces. When extending more than one interface, separate each by a comma. This means that although classes cannot extend multiple classes, interfaces are allowed to extend multiple interfaces: interface MonitoredRunnable extends java.lang.Runnable,java.lang.Cloneable { boolean isRunning() { } } // Provides access to other //allowing them to change the value of

The Interface Body


The body of an interface cannot specify the specific implementation of any methods, but it does specify their properties. In addition, interfaces may also contain final variables. For example, declaring the MAKER variable in the Product interface allows you to declare a constant that will be employed by all classes implementing the Product interface. Another good example of final fields in interfaces can be found in the java.awt.image.ImageConsumer interface. The interface defines a set of final integers that serve as standards for interpreting information. Because the RANDOMPIXELORDER variable equals 1, classes that implement the ImageConsumer interface can make reference to the variable and know that the value of 1 means that the pixels will be sent in a random order. This is shown in the setHints method of Listing 12.3. Listing 12.3 Pseudocode for a Class Implementing ImageConsumer public class MagnaImage implements ImageConsumer{ imageComplete(int status) { ... } setColorModel(ColorModel cm) { ... } setDimensions(int x, int y) { ...

- 169 -

} setHints(int hints) { if ((hints & RANDOMPIXELORDER)!=0){ ... } } setPixels(int x, int y, int w , int h, ColorModel cm , byte pixels[], int off, int scansize) { ... } setPixels(int x, int y, int w, int h, ColorModel cm, int pixels[], int off, int scansize) { ... } setProperties(Hashtable props) { ... } } Methods The main purpose of interfaces is to declare abstract methods that will be defined in other classes. As a result, if you are dealing with a class that implements an interface, you can be assured that these methods will be defined in the class. Although this process is not overly complicated, there is one important difference that should be noticed. The syntax for declaring a method in an interface is extremely similar to declaring a method in a class, but in contrast to methods declared in classes, methods declared in interfaces cannot possess bodies. An interface method consists of only a declaration. For example, the following two methods are complete if they are defined in an interface: public int getPrice(int id); public void showState(); However, in a class, they would require method bodies: public int getPrice(int id) { if (id == 1) return(5); else return(10); } public void showState() { System.out.println("Massachusetts"); } The method declaration does not determine how a method will behave; it does define how it will be used by defining what information it needs and what (if any) information will be returned. The method that is actually defined later in a class must have the same properties as you define in the interface. To make the best use of this fact, it is important

- 170 -

to carefully consider factors like return type and parameter lists when defining the method in the interface. Method declarations in interfaces have the following syntax: public return_value ExceptionList; nameofmethod (parameters) throws

where everything in italics is optional. Also note that unlike normal method declarations in classes, declarations in interfaces are immediately followed by a semicolon. Note All methods in interfaces are public by default, regardless of the presence or absence of the public modifier. This is in contrast to class methods which default to friendly. It's actually illegal to use any of the other standard method modifiers (including native, static, synchronized, final, private, protected, or private protected) when declaring a method in an interface. Variables in Interfaces Although interfaces are generally employed to provide abstract implementation of methods, you may also define variables within them. Because you cannot place any code within the bodies of the methods, all variables declared in an interface must be global to the class. Furthermore, regardless of the modifiers used when declaring the field, all fields declared in an interface are always public, final, and static. Tip Although all fields will be created as public, final, and static, you do not need to explicitly state this in the field declaration. All fields default to public, static, and final regardless of the presence of these modifiers. It is, however, a good practice to explicitly define all fields in interfaces as public, final, and static to remind yourself (and other programmers) of this fact. As seen in the Product interface, interface fieldslike final static fields in classesare used to define constants that can be accessed by all classes that implement the interface: public interface Product { //This variable is static and final. static final String MAKER = "My Corp"; //This variable is also static and final by default, even though not //stated explicitly. String PHONE = "555-123-4567"; public int getPrice(int id); }

Implementing Interfaces
Now that you know how to create interfaces, let's examine how they are used in developing classes. Listing 12.4 shows an example of a class that implements our Product interface. Listing 12.4 Shoe Class Implementing the Product Interface class Shoe implements Product { public int getPrice(int id) {

- 171 -

if (id == 1) return(5); else return(10); } public String getMaker() { return(MAKER); } } Of course, the code in the class can deal with functions other than those relating to the interface (such as the getMaker() method). But, to fulfill the requirements of implementing the Product interface, the class must override the getPrice(int) method.

Overriding Methods
Declaring a method in an interface is a good practice. However, the method cannot be used until a class implements the interface and overrides the given method. Tip Remember that if you implement an interface, you are required to override all methods declared in the interface. Failure to do so will make your class abstract.

Modifiers
As discussed earlier, methods declared in interfaces are by default assigned the public level of access. Consequently, because you cannot override a method to be more private than it already is, all methods declared in interfaces and overridden in classes must be assigned the public access modifier, unless they are explicitly made less public in the interface. Of the remaining modifiers that may be applied to methods, only native and abstract may be applied to methods originally declared in interfaces.

Parameter List
Interface methods define a set of parameters that must be passed to the method. Consequently, declaring a new method with the same name but a different set of parameters than the method declared in your interface overloads the method, not overrides it. Although there is nothing wrong with overloading methods declared in interfaces, it is also important to implement the method declared in the interface. Therefore, unless you declare your class to be abstract, you must override each method, employing the same parameter signature as in your interface (see Listing 12.5). By the way, only one method satisfies the run() method required for Runnable. Listing 12.5 Runner.javaA Class (Runner) that Implements Runnable and Has Two run Methods public void Runner implements Runnable { //This method overloads the run() method; it does not //fulfill the requirements for Runnable. public void run(int max){

- 172 -

int count =0; while (count++<max){ try{ Thread.sleep(500); } catch (Exception e){} } } //This method fulfills the requirement for Runnable. //You must have this method. public void run(){ while (true){ try{ Thread.sleep(500); } catch (Exception e){} } } } If the method String createName(int length, boolean capitalized) is declared in an interface, here are some valid and invalid examples of how to override it. The invalid methods can exist (as overloaded versions of the method) in addition to the valid ones, but will not be related to the interface: Valid String createName(int a, boolean b) String createName(int width, boolean formatted) Invalid String createName (boolean capitalized, int length) String createName(int length)

Body
When creating a class that implements an interface, one of your chief concerns will be creating bodies for the methods originally declared in the interface. Unless you decide to make the method native, it is necessary to create the body for every method originally declared in your interface if you do not want to make your new class abstract. The actual implementation and code of the body of your new method is entirely up to you. This is one of the good things about using interfaces. Although the interface ensures that, in a non-abstract class, its methods will be defined and will return an appropriate data type, the interface places no further restrictions or limitations on the method bodies.

Using Interfaces from Other Classes


You've learned how to create interfaces and build classes based on interfaces. However, interfaces are not useful unless you can develop classes that will either employ the derived classes or the interface itself.

Using an Interface's Fields


Although the fields of an interface must be both static and final, they can be extremely useful in your code.

- 173 -

The following example demonstrates that any variable from an interface can be referenced by using the same dot notation you use with classes. That means you can use java.awt.image.ImageConsumer.COMPLETESCANLINES just as with the class java.awt.Event you use with java.awt.Event.MOUSE_DOWN. This provides you with access to constants. Listing 12.6 shows an example of another ImageConsumer variable being used. Listing 12.6 Using the Constant Fields of an Interface import java.awt.image.*; class MyImageHandler { /* The java.awt.image.ImageConsumer interface defines certain constants to serve as indicators. STATICIMAGEDONE, which is set to equal 3, informs the consumer that the image is complete.*/ ImageConsumer picture; void checkStatus(boolean done) { if (done) picture.imageComplete(ImageConsumer.STATICIMAGEDONE); } }

Using Interfaces as Types


One of the most important features of an interface is that it can be used as a data type. An interface variable can be used just as you would any class. As a Parameter Type In Listing 12.7, you create a simple application that employs the Shoe class developed earlier. Because the Shoe class implements the Product interface, you may deal with the instances of the Shoe class either as standard Shoe objects or as objects based on the Product interface. Although both approaches produce the same results, treating the instance as an object based on the Product interface provides you with a more flexible and useful way of using the resources provided by the Product interface. Listing 12.7 Using the Product Interface as a Parameter Type class Store { static Shoe hightop; public static void init() { hightop = new Shoe(); } public static void main(String argv[]) { init(); getInfo(hightop); orderInfo(hightop); } public static void getInfo(Shoe item) { System.out.println("This Product is made by "+ item.MAKER); System.out.println("It costs $" + item.getPrice(1) +

- 174 -

'\n'); } public static void orderInfo(Product item) { System.out.println("To order from " +item.MAKER + " call " + item.PHONE + "."); System.out.println("Each item costs $" + item.getPrice(1)); } } Output In the following example, the getInfo() method treats hightop as a simple class with certain methods and fields. However, the interesting example is orderInfo(), which extracts almost the same information without knowing anything about a Shoe. Because a Shoe meets the requirements of a Product, you are able to implicitly cast a Shoe to become a Product. As a result, because you know that the Product interface declares certain features, you can be sure that these features, such as the getPrice() method, are present in the parameter item: C:\dev>\jdk\java\bin\java Store This Product is made by My Corp It costs $5 To order from My Corp call 555-123-4567. Each item costs $5 Note Notice that in treating hightop as a Product, you are implicitly casting it as a new data type without specifically stating so in your code. Although the compiler has no trouble doing this, you could substitute that line of code in the Store class for the following: orderInfo( (Product)hightop); This statement would accomplish the same goal and is often easier for other programmers to read, because it shows that orderInfo() accepts a Product, not a Shoe as its argument. Although it is not necessary to use the Product type as your argument in this simplistic example, its use becomes apparent when you have multiple classes, each of which implements the same interface. For example, consider a more elaborate Store class with several items, all of which implemented the Product interface, such as in Listing 12.8. Listing 12.8 Using an Interface as a Type to Deal with Several Classes interface Product { static final String MAKER = "My Corp"; static final String PHONE = "555-123-4567"; public int getPrice(int id); public void showName(); } class Book implements Product { public int getPrice(int id) { if (id == 1) return(20);

- 175 -

else return(30); } public void showName() { System.out.println("I'm a book!"); } } class Shoe implements Product { public int getPrice(int id) { if (id == 1) return(5); else return(10); } public void showName() { System.out.println("I'm a shoe!"); } } class store { static Shoe hightop; static Book using_java; public static void init() { hightop = new Shoe(); using_java = new Book(); } public static void main(String argv[]) { init(); orderInfo(hightop); orderInfo(using_java); } public static void orderInfo(Product item) { item.showName(); System.out.println("To order from " + item.MAKER + " call " + item.PHONE + "."); System.out.println("Each item costs $" + item.getPrice(1)); } }

Output: C:\dev>\JDK1.2\java\bin\java Store I'm a shoe! To order from My Corp call 555-123-4567. Each item costs $5 I'm a book! To order from My Corp call 555-123-4567. Each item costs $20

- 176 -

Exceptions
For an interface method to throw an exception, the exception type (or one of its superclasses) must be listed in the exception list for the method as defined in the interface. Here are the rules for overriding methods that throw exceptions: The new exception list may only contain exceptions listed in the original exception list, or subclasses of the originally listed exceptions. The new exception list does not need to contain any exceptions, regardless of the number listed in the original exception list. (This is because the original list is inherently assigned to the new method.) The new method may throw any exception listed in the original exception list or derived from an exception in the original list, regardless of its own exception list. In general, the exception list of the methodwhich is declared in the interface, not the redeclared methoddetermines which expectations can and cannot be thrown. In other words, when a redeclared method changes the exception list, it cannot add any exceptions that are not included in the original interface declaration. As an example, examine the interface and method declarations in Listing 12.9. Listing 12.9 Alternate Exception Lists interface Example { public int getPrice(int id) throws java.lang.RuntimeException; } class User implements Example { public int getPrice(int id) throws java.awt.AWTException { // Illegal - Reason 1 // java.awt.AWTException is not a subclass of java.lang.RuntimeException /// method body } public int getPrice(int id) { if (id == 6) throw new java.lang.IndexOutOfBoundsException(); // Legal - Reason 2 // IndexOutOfBoundsException is derived from // RuntimeException else ... } public int getPrice(int id) throws java.lang.IndexOutOfBoundsException { // Legal - Reason 1 // IndexOutOfBoundsException is derived from //RuntimeException if (id == 6) throw new java.lang.ArrayIndexOutOfBoundsException(); // Legal - Reason 3

- 177 -

derived from ... } }

//

ArrayIndexOutOfBoundsException is

//IndexOutOfBoundsException

Chapter 13: Threads


What Are Threads?
A unique property of Java is its built-in support for threads. Threads allow you to do many things at the same time. If you could only move one arm or leg at a time, you would probably feel fairly limited. Threads are the computer's answer to this problem. This chapter covers how threads can be used in Java programs. Think about a typical corporation. In almost every company there are at least three interdependent departments: management, accounting, and manufacturing/sales. For an efficient company to run, all three of these operations need to work at the same time. If accounting fails to do its job, the company will go bankrupt. If management fails, the company will simply fall apart, and if manufacturing doesn't do its job, the company will have nothing with which to make money. Many software programs operate under the same conditions as your company. In a company, you complete all the tasks at the same time by assigning them to different people. Each person goes off and does his or her appointed task. With software, you (usually) only have a single processor, and that single processor has to take on the tasks of all these groups. To manage this, a concept called multitasking was invented. In reality, the processor is still only doing one thing at any one time, but it switches between them so fast that it seems like it is doing them all simultaneously. Fortunately, modern computers work much faster than human beings, so you hardly even notice that this is happening. Now, let's go one step further. Have you ever noticed that the accounting person is really doing more than one thing? For instance, that person spends time photocopying spreadsheets, calculating how many widgets the company needs to sell to corner the widget market, adding up all the books, and making sure the bills get paid. In operating system terms, this is known as multithreading. Think about it in this way: Each program is assigned a particular person to carry out a group of tasks, called a process. That person then breaks up his or her time even further into threads.

Why Use Threads?


So, you're saying to yourself, "Why should I care how the computer works, so long as it runs my programs?" Multithreading is important to understand because one of the great advances Java makes over other programming languages is its built-in, native support for threading. By using threading, you can avoid long pauses between what your users do and when they see things happen. Better yet, you can send tasks such as printing off into the background where users don't have to worry about themthey can continue typing their dissertation or perform some other task. In Java, currently the most common use of a thread is to allow your applet to go off and do something while the browser continues to do its job. Any application you're working on that requires two things to be done at the same time is probably a great candidate for threading.

How to Make Your Classes Threadable


- 178 -

You can make your applications and classes run in separate threads in two ways: Extending the Thread class Implementing the Runnable interface It should be noted that making your class able to run as a thread does not automatically make it run as such. A section later in this chapter explains this.

Extend Thread
You can make your class runnable as a thread by extending the class java.lang.Thread. This gives you direct access to all the thread methods directly: public class GreatRace extends Thread

Implement Runnable
Usually, when you want to make a class able to run in its own thread, you also want to extend the features of some other class. Because Java doesn't support multiple inheritance, the solution to this is to implement the Runnable interface. In fact, Thread actually implements Runnable itself. The Runnable interface has only one method: run(). Any time you make a class implement Runnable, you need to have a run() method in your class. In the run() method you actually do all the work you want to have done by that particular thread: public class GreatRace extends java.applet.Applet implements Runnable

The Great Thread Race


Now that you have seen how to make your class runnable, let's take a look at a thread example. The source code for two classes follows (see Listings 13.1 and 13.2): GreatRace. A class that adds several items of the class Threader. Threader. Operates in its own thread and races along a track to the finish line. Listing 13.1 GreatRace.java import import import import java.awt.Graphics; java.awt.GridLayout; java.awt.Frame; Threader;

public class GreatRace extends java.applet.Applet implements Runnable{ Threader theRacers[]; static int racerCount = 3; Thread theThreads[]; Thread thisThread; static boolean inApplet=true;

- 179 -

int

numberofThreadsAtStart;

public void init(){ //we will use this later to see if all our Threads have died. numberofThreadsAtStart = Thread.activeCount(); //Specify the layout. We will be adding all of the racers one on top //of the other. setLayout(new GridLayout(racerCount,1)); //Specify the number of racers in this race, and make the arrays for the //Threaders and the actual threads the proper size. theRacers = new Threader [racerCount]; theThreads = new Thread[racerCount]; //Create a new Thread for each racer, and add it to the panel. for (int x=0;x<racerCount;x++){ theRacers[x]=new Threader ("Racer #"+x); theRacers[x].setSize(getSize().width,getSize().height/racerCount); add (theRacers[x]); theThreads[x]=new Thread(theRacers[x]); } } public void start(){ //Start all of the racing threads for (int x=0;x<racerCount;x++) theThreads[x].start(); //Create a thread of our own. We will use this to monitor the state of //the racers and determine when we should quit altogether. thisThread= new Thread (this); thisThread.start(); }

public void stop(){ for (int x= 0;x<theRacers.length;x++){ theRacers[x].stop(); } } public void run(){ //Loop around until all of the racers have finished the race. while(Thread.activeCount()>numberofThreadsAtStart+2){ try{ thisThread.sleep(100);

- 180 -

} } }

catch (InterruptedException e){ System.out.println("thisThread was interrupted");

//Once the race is done, end the program. if (inApplet){ stop(); destroy(); } else System.exit(0); }

public static void main (String argv[]){ inApplet=false; //Check to see if the number of racers has been specified on the command //line. if (argv.length>0) racerCount = Integer.parseInt(argv[0]); //Create a new frame and place the race in it. Frame theFrame = new Frame("The Great Thread Race"); GreatRace theRace = new GreatRace(); theFrame.setSize(400,200); theFrame.add ("Center",theRace); theFrame.show(); theRace.init(); theFrame.pack(); theRace.start(); } }//end class GreatRace. Listing 13.2 Threader.java import java.awt.Graphics; import java.awt.Color; public class Threader extends java.awt.Canvas implements Runnable { int myPosition =0; String myName; int numberofSteps=600; boolean keepRunning = true; //Constructor for a Threader. We need to know our name when we //create the Threader. public Threader (String inName){ myName=new String (inName);

- 181 -

} public synchronized void paint(Graphics g){ //Draw a line for the 'racing line'. g.setColor (Color.black); g.drawLine (0,getSize().height/2,getSize().width,getSize().height/2);

//Draw the round racer. g.setColor (Color.yellow); g.fillOval((myPosition*getSize().width/ numberofSteps),0,15,getSize().height); } public void stop(){ keepRunning = false; } public void run(){ //Loop until we have finished the race. while ((myPosition <numberofSteps)&& keepRunning){ //Move ahead one position. myPosition++; repaint(); //Put ourselves to sleep so the paint thread can get around to painting. try{ Thread.currentThread().sleep(10); }catch (Exception e){System.out.println("Exception on sleep");} } System.out.println("Threader:"+myName+" has finished the race"); }

}//end class Threader.

Understanding the GreatRace


Most of the code in Threader.java and GreatRace.java should be fairly easy for you to understand by now. Let's take a look at the key sections of the code that deal with the actual threads. The first one to look at is the for loop in the init() method of GreatRace (see Listing 13.3). Listing 13.3 for Loop from init() in GreatRace for (int x=0;x<racerCount;x++){ theRacers[x]=new Threader ("Racer #"+x); theRacers[x].resize(size().width,size().height/racerCount); add (theRacers[x]); theThreads[x]=new Thread(theRacers[x]);

- 182 -

} In the for loop, the first thing to do is create an instance of the class Threader. As you can see from Listing 13.2, Threader is an ordinary class that happens to also implement the Runnable interface. After an instance of Threader is created, it is added to the panel, and the new thread is created with your Threader argument. Don't confuse the Threader class with the Thread class. Caution The new Thread can only be called using an object extending Thread or one that implements Runnable. In either case, the object must have a run() method. However, when you first create the thread, the run() method is not called. That only happens when the thread is started. The next important set of code is in the start() method, again of GreatRace.java (see Listing 13.4). Listing 13.4 start() Method of GreatRace public void start(){ //Start all of the racing threads. for (int x=0;x<racerCount;x++) // start() will call the run() method. theThreads[x].start(); //Create a thread of our own. We will use this to monitor the state of //the racers and determine when we should quit altogether. thisThread= new Thread (this); thisThread.start(); } The first task is to start up all the threads created in the init() method. When the thread is started, it calls the run() method on its Runnable right away. In this case, that's the run() method of the Threader object that was passed to the constructor back in the init() method. Notice that after the racers have started, a thread is created for the actual applet. This thread will be used to monitor what is going on with all the threads. If the race finishes (that is, all the other threads have died and are no longer active), you might as well end the program. Finally, take a look at the last set of important codethe run() method of Threader (see Listing 13.5). Listing 13.5 run() Method of Threader (racer) public void run(){ //Loop until we have finished the race. while ((myPosition <numberofSteps)&& keepRunning){ //Move ahead one position. myPosition++; repaint(); //Put ourselves to sleep so the paint thread can get around to painting. try{

- 183 -

Thread.currentThread().sleep(10); }catch (Exception e){System.out.println("Exception on sleep");} } System.out.println("Threader:"+myName+" has finished the race"); } Notice that the while loop is fairly long. run() is only called once when the thread is started. If you plan to do a lot of repetitive workwhich is usually the case in a thread you need to stay within the confines of run(). In fact, it isn't a bad idea to think of the run() method as being a lot like typical main() methods in other structured languages. Look down a few lines and notice that you put the thread to sleep a bit, in the middle of each loop (Thread.currentThread().sleep(10)). This is an important task. You should almost always put your threads to sleep once in a while to prevent other threads from going into starvation. It is true that under Windows you can get away without doing this in some cases. This works because Windows doesn't really behave like it should with respect to the priority of a thread, as discussed later in the section "A Word About Thread Priority, Netscape, and Windows." However, this is a bad idea, and it probably will not be portable. UNIX machines in particular will look like the applet has hung, and the Macintosh will do the same thing. This has to do with the priority assigned to the paint thread, but there are many other reasons to give the system a breather from your thread.

Thread Processing
To better understand the importance of putting a thread to sleep, it is important to first understand how it is that a computer actually performs threading. How does a computer handle threads so that it seems to us that it is doing more than one thing at a time? The answer lies at the heart of what is known as task swapping. Inside a computer is a periodic clock. For this example, say that the clock ticks every millisecond (in reality, the period is probably much shorter). Now, every millisecond the computer looks at its process table. In the table are pointers to each of the processes (and threads) currently running. It then checks to see whether there are any threads that want to run, and if not goes back to the one it was previously running. This is shown in the timeline of Figure 13.1.

Figure 13.1: With only one process running, the Task Manager always goes back to that process.

If the Task Manager looks at the process table and there are more threads that are not sleeping, it then goes round-robin between them if they are the same priority. This activity is shown in Figure 13.2.

Figure 13.2: With two processes of the same priority running, the Task Manager swaps between them.

- 184 -

The third option that the Task Manager might find is that there are two threads running, but process 2 is of a lower priority than process 1. In this case, the Task Manager runs only the thread that is the higher priority. The timeline for this session is shown in Figure 13.3.

Figure 13.3: The Task Manager always returns to the higher priority thread (1) until it decides to go to sleep.

Try Out the Great Thread Race


Go ahead and compile the GreatRace and run it as shown in Figure 13.4 by typing java GreatRace

Figure 13.4: GreatRace runs as an application.

You can also access it using your browser, by opening the index.html file. You just saw three rather boring ovals run across the screen. Did you notice that they all ran at almost the same speed, yet they were really all processing separately? You can run the GreatRace with as many racers as you want by typing java GreatRace 5 The racers should all make it across the screen in about the same time (see Figure 13.5).

- 185 -

Figure 13.5: GreatRace as an applet.

If you run the race a number of times, you see that the race is actually quite fair, and each of the racers wins just about an equal number of times. If you show the Java Console under Netscape or look at the window you ran Java GreatRace from, you can actually see the order in which the racers finish, as shown in Figure 13.6.

Figure 13.6: A window shows GreatRace and the DOS window it was run from.

Changing the Priority


There are two methods in java.lang.Thread that deal with the priority of a thread: setPriority(int)used to set a new priority for a thread. getPriority()used to obtain the current priority of a thread. Let's see what happens when you tell the computer you want it to treat each of the racers a bit differently by changing the priority. Change the init() method in GreatRace.java by adding the following line into the for loop: theThreads[x].setPriority(Thread.MIN_PRIORITY+x); The for loop now looks like Listing 13.6. Listing 13.6 New for Loop for init() Method //Create a new Thread for each racer, and add it to the panel.

- 186 -

for (int x=0;x<racerCount;x++){ theRacers[x]=new Threader ("Racer #"+x); theRacers[x].setSize(getSize().width,getSize().height/racerCount); add (theRacers[x]); theThreads[x]=new Thread(theRacers[x]); theThreads[x].setPriority(Thread.MIN_PRIORITY+x); } Recompile GreatRace now, and run it again, as shown in Figure 13.7.

Figure 13.7: The New GreatRace shown as it is runmid-race.

By changing the priority of the racers, all of a sudden the bottom racer always wins. Why? The highest priority thread always gets to use the processor when it is not sleeping. This means that every 10ms, the bottom racer gets to advance towards the finish line, stopping the work of the other racers. The other racers get a chance to try to catch up only when that racer decides to go to sleep. Unlike the hare in the fable about the tortoise and the hare, though, the highest priority thread always wakes up in 10ms, and rather quickly outpaces the other racers all the way to the finish line. As soon as that racer finishes, the next racer becomes the highest priority and gets to move every 10ms, leaving the next racer farther behind. Note The priority of the thread was changed with the method setPriority(int) from Thread. Note that you did not just give it a number. The priority was set relative to the MIN_PRIORITY variable in Thread. This is an important step. The MIN_PRIORITY and MAX_PRIORITY are variables that could be set differently for a particular machine. Currently, the MIN_PRIORITY on all machines is 1, and the MAX_PRIORITY is 10. It is important not to exceed these values. Doing so will cause an IllegalArgumentException to be thrown.

A Word About Thread Priority, Netscape, and Windows


If you ran the updated version of GreatRace under Windows, you saw something like Figure 13.8. No doubt you're wondering why your race did not turn out the same as was shown in Figure 13.7. The trailing two racers stayed very close together until the first one won.

- 187 -

Figure 13.8: The New GreatRace as it appears running under Windows 95.

With Netscape under Windows, as shown in Figure 13.9, you may be wondering why your last racer didn't even win!

Figure 13.9: New GreatRace run as an applet running under Windows 95.

The reason for this discrepancy is that threads under Windows don't have nearly the amount of control in terms of priority as do threads under UNIX or Macintosh machines. In fact, threads that have nearly the same priority are treated almost as if they had the same priority with the Windows version of Netscape. That is the reason why under Netscape the last two racers seem to have a nearly equal chance at winning the race. To make the last racer always win, you must increase the priority difference. Try changing the line in the GreatRace init() method to read like this: theThreads[x].setPriority(Thread.MIN_PRIORITY+x*2); Now if you try the race under Windows 95, the last racer should always win by a good margin, as seen in Figure 13.10.

Figure 13.10: GreatRace with increased priorities under Windows 95.

If you run it again under Netscape, the last racer also wins, but just barely (see Figure 13.11).

- 188 -

Figure 13.11: GreatRace with increased priorities as an applet under Windows 95.

This difference is important to realize. If you're going to depend on the priority of your threads, make sure that you test the application on both a Windows and Macintosh or UNIX machine. If you don't have the luxury of a UNIX machine or Macintosh, it seems that running the program as a Java application rather than a Java applet is a closer approximation to how the thread priorities should be handled, as you saw in the last two figures. Caution These thread priority differences make it dangerous to not put your threads to sleep occasionally if you're only using a Windows 95 machine. The paint thread, which is a low-priority thread, will get a chance at the processor under Windows, but only because it will be able to keep up just as the racers did. However, this does not work under a Macintosh or UNIX machine.

Synchronization
When dealing with multiple threads, consider this: What happens when two or more threads want to access the same variable at the same time, and at least one of the threads wants to change the variable? If they were allowed to do this at will, chaos would reign. For example, while one thread reads Joe Smith's record, another thread tries to change his salary (Joe has earned a 50-cent raise). The problem is that this little change causes the thread reading the file in the middle of the other update to see something somewhat random, and it thinks Joe has gotten a $500 raise. That's a great thing for Joe, but not such a great thing for the company, and probably a worse thing for the programmer who will lose his job because of it. How do you resolve this? The first thing to do is declare the method that will change the data and the method that will read to be synchronized. Java's keyword, synchronized, tells the system to put a lock around a particular method. At most, one thread may be in any synchronized method at a time. Listing 13.7 shows an example of two synchronized methods. Listing 13.7 Two synchronized Methods public synchronized void setVar(int){ myVar=x; } public synchronized int getVar (){ return myVar;

- 189 -

} Now, while in setVar(), the JVM sets a condition lock, and no other thread will be allowed to enter a synchronized method, including getVar(), until setVar() has finished. Because the other threads are prevented from entering getVar(), no thread will obtain incorrect information because setVar() is in mid-write. Don't make all your methods synchronized or you won't be able to do any multithreading at all because the other threads will wait for the lock to be released and only one thread will be active at a time. But even with only a couple of methods declared as synchronized, what happens when one thread starts a synchronized method, stops execution until some condition happens that needs to be set by another thread, and that other thread would itself have to go into a (blocked) synchronized method? The solution lies in the dining philosopher's problem.

Speaking with a Forked Tongue


What is the dining philosopher's problem? Well, I won't go into all the details, but let me lay out the scenario for you. Five philosophers are sitting around a table with a plate of food in front of them. One chopstick lies on the table between each philosopher, for a total of five chopsticks. What happens when they all want to eat? They need two chopsticks to eat the food, but there are not enough chopsticks to go around. At most, two of them can eat at any one time the other three will have to wait. How do you make sure that each philosopher doesn't pick up one chopstick, and none of them can get two? This will lead to starvation because no one will be able to eat. (The philosophers are too busy thinking to realize that one of them can go into the kitchen for more chopsticks; that isn't the solution.) There are a number of ways to solve this ancient problem (at least in terms of the life of a computer). I won't even try to solve this problem for you. But it's important to realize the consequences. If you make a method synchronized, and it is going to stop because of some condition that can only be set by another thread, make sure that you exit the method and return the chopstick to the table. If you don't, it is famine waiting to happen. The philosopher won't return his chopstick(s) to the table, and he will be waiting for something to happen that can't happen because his fellow thinkers don't have utensils to be able to start eating.

Changing the Running State of the Threads


Threads have a number of possible states. Let's take a look at how to change the state and what the effects are. The methods covered here are: start() yield() destroy() sleep(long), sleep(long,int) *stop() *resume() *suspend()

- 190 -

*These methods have been deprecated, so generally speaking don't use them. start() and stop() are relatively simple operations for a thread. start() tells a thread to start the run() method of its associated Runnable object. stop() tells the thread to stop. There is more that goes into stop()it actually throws a ThreadDeath object at the thread. In almost every situation, you should not try to catch this object. The only time you need to consider doing so is if you have a number of extraordinary things you need to clean up before you can stop. Caution stop(),suspend(), and resume() have all been deprecated in JDK 1.2. This is because they can inherently lead to thread deadlocks, like we talked about with the philosophers. Instead of using these methods, you should use conditions in the run() method to produce the same result. Caution If you catch the ThreadDeath object, be sure to throw it again. If you don't do this, the thread will not actually stop, and, because the error handler won't notice this, nothing will ever complain. You have already briefly looked at the sleep() method, when putting the Threadable to sleep in the GreatRace. Putting a thread to sleep essentially tells the VM, "I'm done with what I am doing right now; wake me up in a little while." By putting a thread to sleep, you are allowing lower-priority threads a chance to get a shot at the processor. This is especially important when very low-priority threads are doing tasks that, although not as important, still need to be done periodically. Without stepping out of the way occasionally, your thread can put these threads into starvation. The sleep() method comes in two varieties. The first is sleep(long), which tells the interpreter that you want to go to sleep for a certain number of milliseconds: thisThread.sleep(100); The only problem with this version is that a millisecond, although only an instant for humans, is an awfully long time for a computer. Even on a 486/33 computer, this is enough time for the processor to do 25,000 instructions. On high-end workstations, hundreds of thousands of instructions can be done in one millisecond. As a result, there is a second incantation: sleep(long,int). With this version of the sleep command, you can put a thread to sleep for a number of milliseconds, plus a few nanoseconds: thisThread.sleep(99,250); suspend() and resume() are two methods that you can use to put threads to sleep until some other event has occurred. One such example is if you were about to start a huge mathematical computation, such as finding the millionth prime number, and you don't want the other threads to be taking up any of the processor until the answer had been computed. (Incidentally, if you're really trying to find the millionth prime number, I would suggest you write the program in a language other than Java. Fortran still is king for this type of calculationand get yourself a very large computer.) Again, as of JDK 1.2, suspend() and resume() have been deprecated. You should have your thread monitor its status and use a wait(), notify() scheme. yield() works a bit differently from suspend(). yield() is much closer to sleep(). With yield() you're telling the interpreter that you want to get out of the way of the other threads, but when they are done, you want to pick back up. yield() does not require a resume() to start back up when the other threads have stopped, gone to

- 191 -

sleep, or died. The last method to change a thread's running state is destroy(). In general, don't use destroy(). destroy() does not do any cleanup on the thread; it just destroys it. Because it is essentially the same as shutting down a program in progress, you should use destroy() only as a last resort.

Obtaining the Number of Threads That Are Running


Java.lang.Thread has one method that deals with determining the number of threads that are running: activeCount(). Thread.activeCount() returns the integer number of the number of threads that are running in the current ThreadGroup. This is used in the GreatRace to find out when all the threads have finished executing. Notice that in the init() method, you check the number of threads that are running when you start your program. In the run() method, you then compare this number plus two to the number of threads currently running to see whether your racers have finished the race: while(Thread.activeCount()>numberofThreadsAtStart+2){ Note Why add +2? You need to account for two additional threads that do not exist before the race starts. The first one is made out of GreatRace(thisThread), which actually runs through the main loop of GreatRace. The other thread that has not started up at the point the init() method is hit is the Screen_Updater thread. This thread does not start until it is required to do something. Tip As with most programming solutions, you have many ways to determine whether all the racers have finished. You can use thread messaging with PipedInputStream and PipedOutputStream, or check to see whether the threads are alive.

Finding All the Threads That Are Running


Sometimes it's necessary to be able to see all the threads that are running. For instance, what if you did not know that there were two threads you needed to account for in the main() loop of the GreatRace? There are three methods in java.lang.Thread that help you show just this information: enumerate(Thread[]) getName() setName(String) enumerate(Thread[]) is used to get a list of all the threads that are running in the current ThreadGroup. getName() is used to get the name assigned to the thread, whereas its counterpart setName(String) is used to actually set this name. By default, if you do not pass in a name for the thread to the constructor of a thread, it is assigned the default name Thread-x where x is a unique number for that thread. Let's modify the GreatRace a bit to show all the threads that are running. Change the run() method to look like what's shown in Listing 13.8. Listing 13.8 New run() Method for GreatRace

- 192 -

public void run(){ Thread allThreads[]; //Loop around until all of the racers have finished the race. while(Thread.activeCount()>1){ try{ //Create a Thread array for allThreads. allThreads = new Thread[Thread.activeCount()]; //Obtain a link to all of the current Threads. Thread.enumerate (allThreads); //Display the name of all the Threads. System.out.println("****** New List ***** "); for (int x=0;x<allThreads.length;x++) System.out.println("Thread:"+allThreads[x].getName() +":"+allThreads[x].getPriority()+":"+allThreads[x].isDaemon()); thisThread.sleep(1000); } catch (InterruptedException e){ System.out.println("thisThread was interrupted"); } //Once the race is done, end the program. if (inApplet){ destroy(); } else System.exit(0); } The new set of lines is at the beginning of the while() loop. These lines create an array of threads, use the enumerate method, which was just talked about, and write out the name of each of the threads to System.out. Now recompile the program and run it. Under Netscape, make sure that you show the Java Console by choosing Options, Show Java Console (see Figure 13.12).

Figure 13.12: The GreatRace running under Netscape with the Java Console showing.

As the race progresses and each of the racers completes the race, you can see that the number of active threads really does decrease. In fact, run the application and give it a

- 193 -

number higher than three (see Figure 13.13). In other words, try: java GreatRace 5

Figure 13.13: GreatRace can be run with five racers.

The Daemon Property


Threads can be one of two types: either a user thread or a daemon thread. So what is a daemon? Well, Webster's Dictionary says it is "a supernatural being or force, not specifically evil." In a sense, Webster's is right, even with respect to daemon threads. Although the thread is not actually supernatural and it is definitely not evil, a daemon thread is not a natural thread, either. You can set off daemon threads on a path without ever worrying whether they come back. After you start a daemon thread, you don't need to worry about stopping it. When the thread reaches the end of the tasks it was assigned, it stops and changes its state to inactive, much like user threads. An important difference between daemon threads and user threads is that daemon threads can run all the time. If the Java interpreter determines that only daemon threads are running, it will exit, without worrying whether the daemon threads have finished. This is useful because it enables you to start threads that do things such as monitoring; they die on their own when there is nothing else running. The usefulness of this technique is limited for graphical Java applications because, by default, several base threads are not set to be daemon. These include: AWT-Input Main AWT-Motif Screen_Updater

- 194 -

Unfortunately, this means that any application using the AWT class will have non-daemon threads that prevent the application from exiting. Two methods in java.lang.Thread deal with the daemonic state assigned to a thread: isDaemon() setDaemon(boolean) The first method, isDaemon(), is used to test the state of a particular thread. Occasionally, this is useful to an object running as a thread so that it can determine whether it is running as a daemon or a regular thread. isDaemon() returns true if the thread is a daemon, and false otherwise. The second method, setDaemon(boolean), is used to change the daemonic state of the thread. To make a thread a daemon, you indicate this by setting the input value to true. To change it back to a user thread, you set the Boolean value to false. If you had wanted to make each of the racers in the GreatRace daemon threads, you could have done so. In the init() for loop, this would have looked like Listing 13.9. Listing 13.9 New for Loop for init() Method in GreatRace.java for (int x=0;x<racerCount;x++){ theRacers[x]=new Threader ("Racer #"+x); theRacers[x].resize(size().width,size().height/racerCount); add (theRacers[x]); theThreads[x]=new Thread(theRacers[x]); theThreads[x].setDaemon(true); }

Chapter 14: Writing an Applet


Java's Children
In the beginning there was FTP, and then came Telnet; years later Telnet begot the Web. The Web was static and without life until there came CGI, but CGI required a submit button and whole new pages to be downloaded, and the world saw that this was not good. Then a few visionaries saw a product called Oak lying in the ashes, and like a phoenix, they resurrected it to make the Web dynamic and client/server. They renamed this product Java, with children they called applets. The world paused and saw that it was good. If you're new to Java, one thing you're probably dying to learn how to do is write applets. Applets are those Java programs you have seen running all over the World Wide Web. They provide a fascinating layer on top of the already dynamic Java language, which extends far beyond traditional programming architecture and methodology. When you write an applet, you create a program that can not only be run on just about any computer but also can be included in a standard HTML page. Now that you've learned the Java language, you are no doubt excited to start creating applets, those dynamic creatures you see all over the Internet. In this chapter, you will learn to apply your new knowledge toward writing Java applets.

Applets and HTML

- 195 -

Because you're interested in writing Java applets, you're probably already familiar with using HTML (Hypertext Markup Language) to create Web pages. If not, it's probably not a bad idea to pick up a book on HTML such as Que's Special Edition Using HTML 4, Fourth Edition, to get some idea of how that markup language actually works. As you now know, Java can be used to create two types of programs: applets and standalone applications. An applet must be included as part of a Web page, such as an image or a line of text. When your Java-capable Web browser loads an HTML document containing a reference to an applet, the applet is also loaded and executed. (See Chapter 1, "What Java Can Do for You," for more information.) Let's quickly review how an applet's code comes to run on your computer. When the browser detects an <APPLET> tag in an HTML file, it will retrieve the class files for the applet from the server. The bytecode verifier then determines whether the class is a legitimate one. Assuming that the class is legit, the verifier will start to process the class file. As the VM detects import statements, it will continue to go back to the server for more class files until it has downloaded all the code for the applet. For a visual depiction of this cycle see Figure 14.1.

Figure 14.1: The bytecode verifier will continue to return to the server until all the applet code has been downloaded.

Including a Java Applet in an HTML Page


If your primary goal with this chapter is to be able to display the "Java Compliant" logo on your pages, this section is for you. The simplest means to obtain a Java applet is to get one that has already been built, or that you contract to have built for you. If you have not had time to read the rest of this book and learn to program in Java yourself, this is probably the direction you will take. Look at how to include in a Web page a simple applet from MagnaStar, Inc., called Muncher. Listing 14.1 shows the simplest version of an HTML file that could be used to display Muncher. Listing 14.1 An HTML File that Includes the Muncher Applet <HTML> <BODY> <APPLET </BODY> </HTML>

CODE="GobLoader.class" HEIGHT=0 WIDTH=0></APPLET>

Notice the <APPLET> tag on the third line. The <APPLET> tag is used to indicate to the browser that you want it to include an applet on your page. In many ways the <APPLET> tag is similar to the <IMG> tag. There are three key attributes to notice about the

- 196 -

<APPLET> tag: CODE, HEIGHT, and WIDTH. Note Like most HTML tags, the <APPLET> tag is mostly case-insensitive. In other words, all three of the following tags perform the same thing: <APPLET CODE="GobLoader.class" height=0 width=0></APPLET> <Applet code="GobLoader.class" HEIGHT=0 WIDTH=0></Applet> <apPlEt cOdE="GobLoader.class" height=0 width=0></ApPlET> However, an important distinction needs to be made. Although the <APPLET> tag itself is case-insensitive, its attribute values are not. This means that you cannot enter GobLoader as gobloader or GOBLOADER. The first attribute of the <APPLET> tag is the CODE statement. The CODE value of <APPLET> is similar to the SRC value of <IMG>. In the case of <APPLET>, the CODE value must be set to the name of the main class file of the applet. In the case of Muncher, there are a number of classes, but the only one you should include in the HTML file is GobLoader.class (Muncher used to be called Gobbler, so the name is a hold over). This is important to realize; including the wrong class name can cause some strange and disastrous problems. It's also important to remember that having a CODE value is a required portion of an <APPLET> tag, unless an alternative OBJECT attribute is not present. Note Most applets come with either a description of which class file to include, or a sample HTML file you can look at to find this answer. Alternatively, the class name is the one thing you can see when viewing the HTML document source on another site. The second and third attributes to notice are the HEIGHT and WIDTH attributes. These are identical to those in the <IMG> tag. There is one unique thing about an applet, though, that is not exactly the same as an image. Some applets, such as Muncher, don't actually take up any space on the Web page. Instead they create their own windows. This means that the size should be set to 0. In addition, unlike images, for almost all applets, the HEIGHT and WIDTH attributes should be set. With images, if you do not specify the height and width, the browser can figure them out on its own eventually. With applets, this is usually not the case. The final thing to notice about the <APPLET> tag is the closing </APPLET> tag. The ending tag is required for an applet. In addition, as you will see in Listing 14.2, because the <APPLET> tag does not have an ALT attribute like <IMG>, the space before the </APPLET> tag can be used to include alternative information.

Including Alternative Information


Listing 14.2 shows a more complete version of the HTML for Muncher (see Figure 14.2).

- 197 -

Figure 14.2: Muncher is a shareware applet available on the Internet.

Listing 14.2 An HTML File That Includes an Applet Plus Alternative Information for Non-Java Browsers <HTML> <BODY> <APPLET CODE="GobLoader.class" HEIGHT=0 WIDTH=0> Warning: You are not using a Java browser. There is an applet on this page you cannot see. If you had a Java-enabled browser you would see something similar to the picture below<BR> <IMG SRC="gobbler.gif" ALT="Game Picture"> </APPLET> </BODY> </HTML> As you can see, you can include any standard HTML between the <APPLET> and </APPLET> tag. A non-Java browser will ignore the <APPLET> tag and only read this information. The <PARAM> Tag Java applets have a tag in addition to <APPLET>. This HTML tag is <PARAM>. Many applets use the parameter tag to specify additional information about the applet's behavior. Take a look at another applet that does this. GrayButton, also from MagnaStar, Inc., provides a simple means of adding some interaction to your Web pages (see Figure 14.3).

- 198 -

Figure 14.3: The GrayButton applet is used on this page to provide some limited interaction.

The complete listing for including GrayButton on your Web page is shown in Listing 14.3. Listing 14.3 An HTML File for an Applet That Uses <PARAM> Tags <HTML> <BODY> <APPLET CODE="gray.class" WIDTH=300 HEIGHT=300> <PARAM NAME="graphic" VALUE ="http://www.magnastar.com/NOW.GIF"> <PARAM NAME ="link" VALUE="http://www.magnastar.com/GrayButton/license.html"> <A HREF="license.html"><IMG SRC="NOW.GIF"></a> </APPLET> </BODY> </HTML> This example demonstrates two important things. First note the <PARAM> tags on lines 4 and 5. To get this applet to run, you must specify a graphic for it to load and a place for it to link to if the user clicks that button. Take a look at the syntax for the <PARAM> tag. The <PARAM> tag must be included between the <APPLET> and the </APPLET> tags. A <PARAM> tag anywhere else has no point of reference, so the browser ignores it. In general, the <PARAM> tag has two attributes of its own: NAME and VALUE. The NAME attribute is used to specify which parameter you are setting. In the case of the GrayButton, there are two NAMEs that must be set, "graphic" and "link". The second attribute of the <PARAM> tag is VALUE. The VALUE attribute is used to dictate the VALUE that should be associated with the NAME. The VALUE does not have to be a string, although both of them with GrayButton are. The VALUE could easily be a number if the applet called for that type of data. Note In addition to the <PARAM> tags, the example in Listing 14.3 also shows the use of an image link before the </APPLET>. This is another example of an alternative display. If the viewer does not have a Java-enabled browser, the graphic will be displayed instead. In the case of GrayButton, this works out especially nice, because the only thing that is lost without a Java browser is the level of interaction.

- 199 -

Additional <APPLET> Attributes


In addition to the attributes already mentioned, you can use several attribute values to further customize how an applet will behave, as shown in Table 14.1. Table 14.1 Attributes for the <APPLET> Tag

Attribute

Value

Description

CODE*

Class name

Defines the name of the class file that extends java.applet.Applet. Height in pixels that the applet occupies vertically on the Web page. Width in pixels that the applet occupies horizontally on the Web page. Vertical space in pixels between the applet and the rest of the HTML. Behaves identically to the Vspace value of an <IMG> tag. Horizontal space in pixels between the applet and the rest of the HTML. Behaves identically to the HSpace value of an <IMG> tag. Indicates the alignment of the applet in relationship to the rest of the page. These values work the same as their <IMG>counterparts.

HEIGHT^ WIDTH^ VSPACE

Number

Number

Number

HSPACE

Number

ALIGN

Any of: LEFT, RIGHT, TOP, TEXTTOP, MIDDLE, ABSMIDDLE, BASELINE, BOTTOM, ABSBOTTOM String

ALT

Specifies alternate text to be displayed by the browser if it is unable to display the actual applet. This attribute is only utilized if the browser understands the <APPLET> tag but is unable to display the applet. Otherwise, the open HTML between the <APPLET> and </APPLET> tags is displayed. Contains a list of archives and other resources that should be "preloaded" by the browser before it begins execution. Contains the name of the file that has a serialized representation of the applet. The init() method of the applet is not called because it is presumed to have been called on the serialized applet; however, the start() method is.

ARCHIVE

Archive list

OBJECT

Serialized applet

- 200 -

Note: If an OBJECT attribute is present, a CODE attribute need not be; however, one or the other is required. CODEBASE URL URL of base directory where the class files for the applet are located (under the security manager). This host, and the host where the HTML with the <APPLET> tag is located, are the only hosts that can be accessed by the applet.

* Required ^ Highly Recommended To sum up, look at Listing 14.4. The text in normal characters is typed literally; the text shown in italics is replaced by whatever is appropriate for the applet you're including in the document. The first and last lines are required. Other lines in the tag are optional. Figure 14.4 shows how attributes can affect an applet's placement.

Figure 14.4: As you look at this figure, you can see how the various attributes affect the applet's placement.

Listing 14.4 LST14_04.TXTThe <APPLET> Tag <APPLET attributes> parameters alternate-content </APPLET>

Using Java Plug-in


One of the best innovations that Sun Microsystems, Inc. has added in a while is known as the Java Plug-in. Java Plug-in was designed to directly address the fragmentation of the Java Virtual Machine in the variety of browsers. Over time, each browser started to include its own version of the VM. This led to minor differences between each of the browsers. In addition, Microsoft chose not to implement some of the key features of the JDK. To use the Java Plug-in, users must download the Java Plug-in first and plug it into their

- 201 -

browsers. Adding the Java Plug-in gives the browser full support for the latest JDK. As an added benefit, the way the Java Plug-in is used it will actually upgrade itself. The great thing about this is it means in the future you will no longer have to concern yourself with using JDK 1.2 and future JDKs because browsers will already be upgraded.

Using Java Plug-in in Internet Explorer


Using Java Plug-in in Internet Explorer requires that you use a different pattern other than the one that you just learned with the <APPLET> tag. Java Plug-in is actually a different program for Internet Explorer altogether, so you need to include it just like any other ActiveX component. Listing 14.5 shows how Java Plug-in can be used in an HTML page designed for Internet Explorer, with the same applet used previously in Listing 14.3. Listing 14.5 Using Java Plug-in in Internet Explorer <OBJECT CLASSID="clsid:8AD9C840-044E-11D1-B3E9-00805F499D93" WIDTH="300" HEIGHT="300" ALIGN="baseline" codebase="http://java.sun.com/products/plugin/1.1/jinstall-11win32.cab#Version=1,1,0,0"> <PARAM NAME="code" VALUE="gray.class"> <PARAM NAME="codebase" VALUE="html/"> <PARAM NAME="graphic" VALUE ="http://www.magnastar.com/NOW.GIF"> <PARAM NAME ="link" VALUE="http://www.magnastar.com/GrayButton/license.html"> No JDK 1.2 support for APPLET!! </OBJECT> The <OBJECT> tag in Listing 14.5 has many of the same attributes as the <APPLET> tag in Listing 14.3. There are some differences, however. First, and perhaps most obvious, is the CLASSID parameter. This ID identifies not the Java class, but rather the Java Plug-in. It should always be this number, so you don't have to worry about where this came from. The number will actually be different for each different version of the Java Plug-in, so you may need to find out what the latest version is and get its CLASSID. Now, the CODEBASE in the <OBJECT> tag that you see is not the CODEBASE for the java class, but it's the CODEBASE for the Java Plug-in. Because both the code and CODEBASE parameters can't be specified in the <OBJECT> tag itself, they end up in the <PARAM> tags between <OBJECT> and </OBJECT>.

Using Java Plug-in in Netscape


Netscape. does not use ActiveX components like Internet Explorer. Instead, you need to use a Netscape plug-in. Listing 14.6 shows how to use Java Plug-in in Netscape. Listing 14.6 Using Java Plug-in in Netscape. <EMBED TYPE="application/x-java-applet;version=1.2" WIDTH="300" HEIGHT="300" ALIGN="baseline" CODE="gray.class" CODEBASE="html/" GRAPHIC="http://www.magnastar.com/NOW.GIF" LINK="http://www.magnastar.com/GrayButton/license.html" pluginspage="http://java.sun.com/products/plugin/1.1/plugininstall.html"> <NOEMBED> No JDK 1.2 support for APPLET!! </NOEMBED>

- 202 -

</EMBED> With the <EMBED> tag, the new parameter isn't CLASSID; instead it's the TYPE value. You might notice that there is a VERSION value in the type. The VERSION allows you to specify the Java version you wish to use. Note the PLUGINSPAGE parameter, which specifies where Netscape can find the plug-in if it hasn't already downloaded it. One of the interesting things about using an <EMBED> tag is that there are no equivalents to the <PARAM> tag. Instead, you see all of the values listed inside of the <EMBED> tag itself. Look at the LINK parameter for an example of how this is used.

Setting Up the HTML for All Browsers


You can combine the <EMBED> and <OBJECT> tags as shown in Listing 14.7 so that both Netscape and Internet Explorer will use Java Plug-in. Listing 14.7 Using Java Plug-in in Both Internet Explorer and Netscape <OBJECT CLASSID="clsid:8AD9C840-044E-11D1-B3E9-00805F499D93" WIDTH="300" HEIGHT="300" ALIGN="baseline" codebase="http://java.sun.com/products/plugin/1.1/jinstall-11win32.cab #Version=1,1,0,0"><PARAM NAME="code" VALUE="gray.class"> <PARAM NAME="codebase" VALUE="html/"> <PARAM NAME="graphic" VALUE ="http://www.magnastar.com/NOW.GIF"> <PARAM NAME ="link" VALUE="http://www.magnastar.com/GrayButton/license.html"> <PARAM NAME="type" VALUE="application/x-java-applet;version=1.1"> <COMMENT> <EMBED TYPE="application/x-java-applet;version=1.1" WIDTH="300" HEIGHT="300" ALIGN="baseline" CODE="gray.class" CODEBASE="html/" GRAPHIC=http://www.magnastar.com/NOW.GIF LINK="http://www.magnastar.com/GrayButton/license.html" pluginspage="http://java.sun.com/products/plugin/1.1/plugininstall.html"> <NOEMBED> </COMMENT> No JDK 1.2 support for APPLET!! </NOEMBED></EMBED> </OBJECT> But Listing 14.7 tries to use Java Plug-in, even if it's on a browser that doesn't support the ActiveX or plug-in. So to be truly accurate, the best thing to do is use Listing 14.8. This listing includes the necessary JavaScript code to have the browser properly look for the right system. Under Internet Explorer and Netscape on a Windows machine the browser will use the Java Plug-in, and on all other platforms it will use the built-in VM. Normally you can just copy Listing 14.8 into your HTML and replace all of the correct parameters, so even though this looks complicated, you really just need to copy and paste. Listing 14.8 Using the Best Java VM Regardless of Platform <SCRIPT LANGUAGE="JavaScript"><! if (_ie == true) document.writeln('<OBJECT CLASSID="clsid:8AD9C840-044E-11D1-B3E9-00805F499D93" WIDTH="300" HEIGHT="300" ALIGN="baseline"

- 203 -

codebase="http://java.sun.com/products/plugin/1.1/jinstall-11win32.cab#Version=1,1,0,0"> <NOEMBED><XMP>'); else if (_ns == true) document.writeln('<EMBED TYPE="application/x-java-applet;version=1.1" WIDTH="200" HEIGHT="200" ALIGN="baseline" CODE="gray.class" CODEBASE="html/" GRAPHIC=http://www.magnastar.com/NOW.GIF LINK ="http://www.magnastar.com/GrayButton/license.html" pluginspage="http://java.sun.com/products/plugin/1.1/plugininstall.html"> <NOEMBED><XMP>'); //></SCRIPT> <APPLET CODE="gray.class" CODEBASE="html/" ALIGN="baseline" WIDTH="300" HEIGHT="300"></XMP> <PARAM NAME="code" VALUE="gray.class"> <PARAM NAME="codebase" VALUE="html/"> <PARAM NAME="graphic" VALUE ="http://www.magnastar.com/NOW.GIF"> <PARAM NAME ="link" VALUE="http://www.magnastar.com/GrayButton/license.html"> No JDK 1.2 support for APPLET!! </APPLET></NOEMBED></EMBED></OBJECT>

Begin Developing Java Applets


Now that you have explored how to include an applet in an HTML page, take a look at how to write some of your own. Many years ago, two programming visionaries named Kernie and Richie invented a language called C. The first program they wrote was called Hello World. Since that time, the first program that any programmer writes in any language simply displays "Hello World" to the screen. So, take a look at how to write the HelloWorld applet in Java. In the preceding several chapters, you have learned about each of the parts of the Hello World application, but let's review it one more time, as shown in Listing 14.9. Listing 14.9 Hello World as an Applet import java.applet.Applet; import java.awt.Graphics; /* * * HelloWorld * */ public class HelloWorld extends Applet { public void paint (Graphics g){ g.drawString ("HelloWorld",5,20); } } To create the HelloWorld applet, copy the contents of Listing 14.9 into a file called HelloWorld.java. It is important that you call the file HelloWorld.java, or you will be unable to compile the program. Now, assuming that you have installed the JDK from Sun in your path, compile the program by typing the following at a command prompt:

- 204 -

javac HelloWorld.java Note Windows users, for this to work, you will need to open a DOS prompt window. If everything has worked correctly, you should now have an additional file in your directory called HelloWorld.class. This file is the Java equivalent of an .exe file. Before you can run the applet, though, you will need to create an HTML file as discussed in the previous section. In the case of the HelloWorld applet, the HTML file should look like Listing 14.10. Note Technically, the class file is not an executable file by itself. However, several products such as Asymetric's SuperCede and Microsoft's Visual J++ now include native compilers for Java that actually produce .exe files. These compilers are also known as static compilers and will generate .exe files, but are no longer platform independent. Listing 14.10 An HTML File for the HelloWorld Applet <HTML> <BODY> <APPLET CODE="HelloWorld.class" HEIGHT=100 WIDTH=100></APPLET> </BODY> </HTML> After you have created the HTML file, you can open it in a browser like Netscape Navigator, or use one of the tools that come with the JDK called appletviewer. Figure 14.5 shows what happens when you load this file in Netscape.

Figure 14.5: HelloWorld displays some text on the browser.

Notice that when a Java applet is loaded, the Navigator has to go back to the server (or in this case, your hard drive) to download the HelloWorld.class file before it can be run. This is done exactly the same way that a GIF file is grabbed for an image, but it does take an extra second or two.

Understanding Hello WorldBuilding Applets


Now, go back and break down the code in the HelloWorld applet, so you can understand it.

- 205 -

The first thing that you should have noticed is that HelloWorld extends java.applet.Applet. Every applet in the world must extend Applet. As you can see, you take advantage of object-oriented programming (OOP) inheritance to declare your applet class by subclassing Java's Applet class. For more information on inheritance, check out Chapter 11, "Classes." Note The reason it is necessary to extend Applet is because every browser expects to receive an Applet class from the CODE attribute. By using the polymorphic characteristics of inheritance, your custom applet, such as HelloWorld, is both a HelloWorld class and an Applet class.

Exploring the Life Cycle of an Applet


It might surprise you to learn that an applet actually has a life cycle. This means that throughout the time that an applet exists, certain methods will be called on that applet. To be precise, four methods are called on an applet: init()Called the first time that an applet is loaded start()Called after the init() method, and thereafter each time a browser returns to a page on which the applet is contained stop()Called any time a browser leaves a Web page containing the applet destroy()Called before a browser completely shuts down Figure 14.6 shows the life cycle of an applet. To better understand how the life cycle of an applet works, take a look at a program designed to show when these methods are called. Listing 14.11 contains a program that prints out a message each time one of the methods is called and puts up a graph of this activity.

Figure 14.6: A visual representation of the life cycle of an applet.

Listing 14.11 InitStartStop Applet, Which Demonstrates the Use of the Life Cycle Methods import java.applet.Applet; import java.awt.*; /* * * InitStartStop *

- 206 -

*/ public class InitStartStop extends Applet{ int initCount = 0; int startCount = 0; int stopCount = 0; int destroyCount = 0; public void paint (Graphics g){ //clear the area g.setColor(Color.white); g.fillRect(0,0,size().width,size().height); //paint all the standard parts of the graph g.setColor (Color.red); g.drawLine (120,20,120,220); g.drawLine (120,220,300,220); //draw the labels g.setColor (Color.gray); g.drawString ( "Init Count", 5,50); g.drawString ( "Start Count", 5,100); g.drawString ( "Stop Count", 5,150); g.drawString ( "Destroy Count", 5,200); //paint the grid lines g.setColor(Color.lightGray); for (int x=(120+25);x<300;x+=25){ g.drawLine(x,20,x,199); } //draw the g.setColor g.fillRect g.fillRect g.fillRect g.fillRect } public void update(Graphics g){ paint(g); } bars for each of the stats (Color.black); (120,30,initCount * 25,40); (120,80,startCount * 25,40); (120,130,stopCount * 25, 40); (120,180,destroyCount * 25, 40);

public void init(){ initCount++; System.out.println("init"); repaint(); } public void start(){ startCount++; System.out.println("start"); repaint(); }

- 207 -

public void stop(){ stopCount++; System.out.println("stop"); repaint(); } public void destroy(){ destroyCount++; System.out.println("destroy"); repaint(); } }

Compiling the InitStartStop Applet


To be able to run the InitStartStop applet, just like the HelloWorld applet, you must compile it and generate an HTML file that references the applet. To do this, first copy the contents of Listing 14.11 to a file called InitStartStop.java. Then compile this file using javac: javac InitStartStop.java Now, before you can actually use the InitStartStop applet, you must first create the HTML for it. The InitStartStop.html file is as follows: <HTML> <BODY> <APPLET code="InitStartStop.class" HEIGHT=300 WIDTH=400></APPLET> </BODY> </HTML> Finally, you're set to run the InitStartStop applet. To do this, load the InitStartStop.html file into a browser such as Netscape Navigator. The first time you load the program you will see something that looks like Figure 14.7. The init() method has been called once, as has the start() method. This should be exactly what you expected to see.

Figure 14.7: When InitStartStop first starts, it has run the init() method and the start() method once.

- 208 -

Now click the reload button a couple of times. Each time you do, the number of times that stop() is called and the number of times that start() is called will both increment once, as demonstrated in Figure 14.8. However, the init() count will stay the same because the init() method is only called the first time the browser loads the applet.

Figure 14.8: After leaving the page and coming back several times, start() and stop() will have incremented. Notice that the applet has always started one more time than it has stopped.

As you run the applet, you can also look at those printout statements you were generating. To do this in Netscape 3.1 and earlier, select Options, Show Java Console. Users of Netscape 4.0 can get to the Java Console by accessing Communicator, Java Console. This should produce yet another window, as shown in Figure 14.9. Inside this window, you can see all the System.out messages as they appear. Try clicking reload a few more times. Now, try going to a different Web page. What happened? Well of course, stop() was called, and start() wasn't. Now click the back button. start() is called.

Figure 14.9: The Java Console in Netscape shows you the System.out messages as they appear.

Understanding the InitStartStop Applet


To understand the InitStartStop applet, take it step by step. import java.applet.Applet;

- 209 -

import java.awt.*; The first thing in the file are several import statements. As you learned in Chapter 11, for a class to be used (without fully qualifying its name each time), the class must first be imported. Just like the HelloWorld applet, InitStartStop needs access to the java.awt.Graphics class. In addition, InitStartStop will need access to a couple of other java.awt classes. So rather than import each individual class separately, the entire package of java.awt is imported here. The first method in InitStartStop is the paint method. This method paints a number of things to the screen using methods available in the java.Graphics class. You will learn more about the Graphics class in Chapter 27, "Files, Streams, and Java," so for now, just concentrate on the last part of the paint() method. //draw the g.setColor g.fillRect g.fillRect g.fillRect g.fillRect bars for each of the stats (Color.black); (120,30,initCount * 25,40); (120,80,startCount * 25,40); (120,130,stopCount * 25, 40); (120,180,destroyCount * 25, 40);

The purpose of this section is to draw the actual bars that you saw indicating how many times each of the methods had been called. This is accomplished by increasing the width of the bar by 25 times the count number (such as initCount*25). public void update(Graphics g){ paint(g); } The next method in the class is update(). update() just calls paint(), so you might be wondering what it is doing there. To understand why, it's necessary to understand the relationship between update() and paint(). Ordinarily when an applet needs to be painted, either because it's just been displayed to the screen, or perhaps a different screen that had been covering the applet was just removed, the paint() method is called. However, when an applet only needs to be partially painted, such as when another window has only partially obscured the applet or when the repaint() method was called, the update() method is called. By default, update() clears the panel and then calls paint(). However, this can cause an annoying flicker (try running InitStartStop with this method removed). To get around this, it's become routine for programmers to insert an update() method, which does not clear the screen but calls paint() right away. The next several methods are really the ones you want to see something from. Each method increments a counter, does a printout, and calls repaint()(which causes the update/paint() method to be called). public void init(){ initCount++; System.out.println("init"); repaint(); } public void start(){ startCount++; System.out.println("start"); repaint();

- 210 -

} public void stop(){ stopCount++; System.out.println("stop"); repaint(); } public void destroy(){ destroyCount++; System.out.println("destroy"); repaint(); } }

Java Animator Applet


One of the fun things to do with Java is create simple animations. It should be pointed out that Java is not the best medium to do this. If all you want to do is create an animation, there are much better ways to do so, such as GIF89a Cel Frame animations. Or you can use the Java Media Framework discussed in Chapter 44, "Java Media Framework." However, because derivations of animations are so frequently done in Java, an animator is shown here. Listing 14.12 shows a complete version of an animator written in Java. Listing 14.12 Animator Class Cycles Through Images import java.awt.*; import java.util.Vector; public class Animator extends java.applet.Applet implements Runnable { Vector images; int imgNumber; int currentImage=1; Thread thisThread; public void init(){ //Read in the number of images in the animation imgNumber = new Integer(getParameter("imgNumber")).intValue(); //Load the images for (int x=0;x<imgNumber;x++){ Image img = getImage(getDocumentBase(),"images/img"+(x+1)); images.addElement(img); } } public void paint(Graphics g){ g.drawImage((Image)images.elementAt(currentImage++),0,0,null); currentImage%=imgNumber; }

- 211 -

public void update(Graphics g){ paint(g); } public void start(){ thisThread = new Thread(this); thisThread.start(); }

public void stop(){ thisThread.stop(); } public void run(){ while(true){ try{ thisThread.sleep(100); } catch (Exception e){} } } } You can probably tell that there is much more to this applet than to the HelloWorld one. To compile this program, first copy all of Listing 14.12 into a file called Animator.java. To run it, you will need to create an HTML file that should look something like Listing 14.13. Listing 14.13 HTML File for Including Animator <HTML> <BODY> <APPLET code="Animator.class" HEIGHT=200 WIDTH=200> <PARAM NAME="imgNumber" VALUE="5"> </APPLET> </BODY> </HTML> In addition to these files, you will also need to have several images that you want to animate, and you will need to place them in a subdirectory called images. The images must be called img1.gif, img2.gif, and so on, where img1.gif is the first image of the animation. You will also want to change the imgNumber parameter to have the correct number of images. With all that done, you should see something similar to Figure 14.10.

- 212 -

Figure 14.10: Java can be used to generate some interesting animations.

Now, to understand how Animator works, break Listing 14.12 into some more manageable chunks. First, take the first three lines of the code: import java.awt.*; import java.util.Vector; public class Animator extends java.applet.Applet implements Runnable { The first two lines serve to import other Java classes. Java is an extensible language, and the object-oriented nature of the language allows you to take advantage of prebuilt classes. The first two lines of the Animator code import such classes. The third line of code is the class declaration. At the end of the line you will notice that the Animator, like HelloWorld, extends java.applet.Applet. java.applet.Applet is the name of the class from which all applets extend. Immediately after the class declaration is the statement implements Runnable, which indicates that the application can be run as a thread. It is important that Animator be able to run as a thread because it will continue to process even after the rest of the page is finished loading. Immediately after these lines of code, Animator declares several variables of its own. Vector images; int imgNumber; int currentImage=1; Thread thisThread; Remember from Chapter 10, "Control Flow," that Java is a strongly typed language. This means that each variable must be declared to be a specific type. In some other languages, such as JavaScript, you would have created the variables with only the var keyword. var var var var images; imgNumber; currentImage=1; thisThread;

- 213 -

For a variety of reasons, this is not really the best way to work, and Java requires that you declare the type that each variable will be. As you can see, you are creating four variables. The Vector is a class type that is convenient to contain a number of elements, especially if you do not know ahead of time how many you will be adding. The thread variable will be used to control the activity of the applet later on. The Animator applet has several methods. The first of these is the init() method. public void init(){ //Read in the number of images in the animation imgNumber = new Integer(getParameter("imgNumber")).intValue(); //Load the images for (int x=0;x<imgNumber;x++){ Image img = getImage(getDocumentBase(),"images/img"+(x+1)); images.addElement(img); } } The init() method is called when the page is initially loaded into the browser. It is convenient to use the init() method to set up variables that only have to be initialized once. In the case of the Animator class, all the images only need to be loaded once. Notice that after the getImage method is called, the image is added to the Vector of images. The next method is the paint() method. The paint() method is called each time the applet needs to be displayed on the Web page. This can happen if the user scrolls the applet off the screen and then scrolls back, or if you specifically cause the applet to be repainted. public void paint(Graphics g){ g.drawImage((Image)images.elementAt(currentImage++),0,0,null); currentImage%=imgNumber; } Without breaking the paint() method apart completely, break the drawImage line apart a bit. drawImage()is a method that obviously draws an image to the graphics screen. Four parameters must be given the drawImage() method. First, the name of the image, next the x and y locations, and finally the imageObserver, which should pay attention to the image. So why is the image name ((Image)images.elementAt(currentImage++) so complicated? Well, take it from the right side back. First, you want to display the current image (currentImage). It is convenient to increment the currentImage number so that the next time through you will display the next image and you automatically increment the currentImage variable (currentImage++). Now you have stored the images in a vector, and the way to get the current image from the vector is to use the method elementAt on the image object (elementAt(CurrentImage++)). The only problem at this point is that the vector does not really know it is holding an image. The vector only knows that it has something, and so it returns the image to you in a way that isn't quite right, so you need to perform what is known as a cast. The (Image) in front of the images.elementAt performs the cast for you, and now you have retrieved an image. The next method is start(). start() is called each time the user goes to a specific page. But wait, isn't that when the init() method is called? No, not exactly. You see,

- 214 -

the init() method is only called the first time the page is loaded. From that point on, each time the page is loaded, the only method called is start(). start() is called the first time too, after the init() method, but on successive loads only start() is called. public void start(){ thisThread = new Thread(this); thisThread.start(); } The start() method is a great place to put the applet into a known state. In the case of Animator, a thread is created. Without a complete explanation of threads, this means that the applet will continue to run as the rest of the browser does other things. public void stop(){ thisThread.stop(); } See Chapter 13, "Threads." A close cousin to the start() method is the stop() method, which is called each time the user leaves the page. It is important to clean up what you have started when the page is exited. The stop() method of Animator takes the thread it was running and stops it. The last method for Animator is run(). run() is the method that actually runs in the thread. public void run(){ while(true){ repaint(); try{ thisThread.sleep(100); } catch (Exception e){} } } Essentially what occurs in Animator's run method is a constant loop that consists of first telling the Animator to repaint and then to place the Animator thread in a state known as sleep for 100ms. The result of this is that 10 times a second (1/100ms) the next frame of the animation is displayed.

An Applet That Uses Controls


As you saw in the previous applet example, applets are interactive applications that can handle messages generated by both the system and the user. Another way, besides the mouse, that you can enable user interaction is by including controlssuch as buttons, menus, list boxes, and text boxesin your applet's display. Although controls are covered thoroughly in Chapter 19, "java.awt: Components," you'll get an introduction to them now, as you create an applet that can connect you to various Web sites on the Internet. Listing 14.14 is the Java source code for the applet in question, and Listing 14.15 is the applet's HTML document. Before running this applet (by loading its HTML document into a Java-compatible browser), make your Internet connection. Then, when you run the applet, you see a window something like Figure 14.16, which shows InternetApplet running in Netscape Navigator 3.1. Just click one of the connection buttons, and you

- 215 -

automatically log on to the Web site associated with the button. Figure 14.12 shows where you end up when you click the CNet button.

Figure 14.11: The InternetApplet applet uses buttons to provide an instant connection to eight different Web sites.

Figure 14.12: The CNet button, for example, connects to CNet's terrific site.

Listing 14.14 InternetApplet.javaThe InternetApplet Applet import java.awt.*; import java.awt.event.*; import java.applet.*; import java.net.*; public class InternetApplet extends Applet implements ActionListener { boolean badURL; public void init() { GridLayout layout = new GridLayout(2, 4, 10, 10); setLayout(layout); Font font = new Font("TimesRoman", Font.PLAIN, 24); setFont(font); Button button = new Button("Sun");

- 216 -

button.setActionCommand("http://www.sun.com"); button.addActionListener(this); add(button); button = new Button("Netscape"); button.setActionCommand("http://www.netscape.com"); button.addActionListener(this); add(button); button = new Button("Javasoft"); button.setActionCommand("http://www.javasoft.com"); button.addActionListener(this); add(button); button = new Button("Macmillan"); button.setActionCommand("http://www.mcp.com"); button.addActionListener(this); add(button); button = new Button("Time"); button.setActionCommand("http://www.pathfinder.com"); button.addActionListener(this); add(button); button = new Button("CNet"); button.setActionCommand("http://www.cnet.com"); button.addActionListener(this); add(button); button = new Button("Borland"); button.setActionCommand("http://www.borland.com"); button.addActionListener(this); add(button); button = new Button("Yahoo"); button.setActionCommand("http://www.yahoo.com"); button.addActionListener(this); add(button); badURL = false; } public void paint(Graphics g) { if (badURL) g.drawString("Bad URL!", 60, 130); } public void actionPerformed(ActionEvent event) { String pageName = event.getActionCommand();

try { URL url = new URL(pageName); AppletContext context = getAppletContext(); context.showDocument(url); } catch (MalformedURLException e) { badURL = true; repaint(); } }

- 217 -

Note The preceding applet works only in browsers that support Java 1.1 or better. So, if you need to use an older browser that has not been upgraded, you will want to look through the following code in Listing 14.15, which supports the 1.0 model. Listing 14.15 InternetApplet.javaThe InternetApplet Applet import java.awt.*; import java.applet.*; import java.net.*; public class InternetApplet extends Applet { boolean badURL; public void init() { GridLayout layout = new GridLayout(2, 4, 10, 10); setLayout(layout); Font font = new Font("TimesRoman", Font.PLAIN, 24); setFont(font); Button button = new Button("Sun"); add(button); button = new Button("Netscape"); add(button); button = new Button("Microsoft"); add(button); button = new Button("Macmillan"); add(button); button = new Button("Time"); add(button); button = new Button("CNet"); add(button); button = new Button("Borland"); add(button); button = new Button("Yahoo"); add(button); badURL = false; } public void paint(Graphics g) { if (badURL) g.drawString("Bad URL!", 60, 130); } public boolean action(Event evt, Object arg) { String str; if (arg == "Sun") str = "http://www.sun.com"; else if (arg == "Netscape") str = "http://www.netscape.com"; else if (arg == "Microsoft")

- 218 -

str = "http://www.microsoft.com"; else if (arg == "Macmillan") str = "http://www.mcp.com"; else if (arg == "Time") str = "https://appwritefunc.yet-another-testing-domain.