CARVIEW |
Select Language
HTTP/2 302
server: nginx
date: Tue, 05 Aug 2025 22:34:18 GMT
content-type: text/plain; charset=utf-8
content-length: 0
x-archive-redirect-reason: found capture at 20071227082519
location: https://web.archive.org/web/20071227082519/https://www.oreilly.com/catalog/learnjava3/toc.html
server-timing: captures_list;dur=0.745228, exclusion.robots;dur=0.037648, exclusion.robots.policy;dur=0.021447, esindex;dur=0.016962, cdx.remote;dur=17.702809, LoadShardBlock;dur=167.852391, PetaboxLoader3.datanode;dur=75.852787
x-app-server: wwwb-app200
x-ts: 302
x-tr: 217
server-timing: TR;dur=0,Tw;dur=0,Tc;dur=1
set-cookie: wb-p-SERVER=wwwb-app200; path=/
x-location: All
x-rl: 0
x-na: 0
x-page-cache: MISS
server-timing: MISS
x-nid: DigitalOcean
referrer-policy: no-referrer-when-downgrade
permissions-policy: interest-cohort=()
HTTP/2 200
server: nginx
date: Tue, 05 Aug 2025 22:34:19 GMT
content-type: text/html
x-archive-orig-date: Thu, 27 Dec 2007 08:25:19 GMT
x-archive-orig-server: Apache
x-archive-orig-p3p: policyref="https://www.oreillynet.com/w3c/p3p.xml",CP="CAO DSP COR CURa ADMa DEVa TAIa PSAa PSDa IVAa IVDa CONo OUR DELa PUBi OTRa IND PHY ONL UNI PUR COM NAV INT DEM CNT STA PRE"
x-archive-orig-last-modified: Fri, 21 Dec 2007 15:19:35 GMT
x-archive-orig-accept-ranges: bytes
x-archive-orig-content-length: 1021263
x-archive-orig-x-cache: MISS from olive.bp
x-archive-orig-x-cache-lookup: MISS from olive.bp:3128
x-archive-orig-via: 1.0 olive.bp:3128 (squid/2.6.STABLE13)
x-archive-orig-connection: close
x-archive-guessed-content-type: text/html
x-archive-guessed-charset: iso-8859-1
memento-datetime: Thu, 27 Dec 2007 08:25:19 GMT
link: ; rel="original", ; rel="timemap"; type="application/link-format", ; rel="timegate", ; rel="first memento"; datetime="Thu, 30 Jun 2005 01:23:00 GMT", ; rel="prev memento"; datetime="Tue, 27 Nov 2007 01:10:58 GMT", ; rel="memento"; datetime="Thu, 27 Dec 2007 08:25:19 GMT", ; rel="next memento"; datetime="Sat, 26 Jan 2008 21:34:54 GMT", ; rel="last memento"; datetime="Wed, 24 Sep 2008 14:49:18 GMT"
content-security-policy: default-src 'self' 'unsafe-eval' 'unsafe-inline' data: blob: archive.org web.archive.org web-static.archive.org wayback-api.archive.org athena.archive.org analytics.archive.org pragma.archivelab.org wwwb-events.archive.org
x-archive-src: 51_1_20071227055708_crawl100-c/51_1_20071227082204_crawl100.arc.gz
server-timing: captures_list;dur=0.544549, exclusion.robots;dur=0.025718, exclusion.robots.policy;dur=0.016254, esindex;dur=0.010975, cdx.remote;dur=44.565219, LoadShardBlock;dur=448.133050, PetaboxLoader3.datanode;dur=399.416683, PetaboxLoader3.resolve;dur=154.898756, load_resource;dur=185.224049
x-app-server: wwwb-app200
x-ts: 200
x-tr: 1283
server-timing: TR;dur=0,Tw;dur=0,Tc;dur=2
x-location: All
x-rl: 0
x-na: 0
x-page-cache: MISS
server-timing: MISS
x-nid: DigitalOcean
referrer-policy: no-referrer-when-downgrade
permissions-policy: interest-cohort=()
content-encoding: gzip
O'Reilly Media | Learning Java
Buy this Book
Learning Java, Third Edition
By?Patrick Niemeyer, Jonathan Knudsen
Price: $44.95 USD
£31.95 GBP
Cover | Table of Contents
Table of Contents
- Chapter 1: A Modern Language
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterThe greatest challenges and most exciting opportunities for software developers today lie in harnessing the power of networks. Applications created today, whatever their intended scope or audience, will almost certainly be run on machines linked by a global network of computing resources. The increasing importance of networks is placing new demands on existing tools and fueling the demand for a rapidly growing list of completely new kinds of applications.We want software that works—consistently, anywhere, on any platform—and that plays well with other applications. We want dynamic applications that take advantage of a connected world, capable of accessing disparate and distributed information sources. We want truly distributed software that can be extended and upgraded seamlessly. We want intelligent applications—such as autonomous agents that can roam the Net for us, ferreting out information and serving as electronic emissaries. We know, to some extent, what we want. So why don't we have it?The problem, historically, has been that the tools for building these applications have fallen short. The requirements of speed and portability have been, for the most part, mutually exclusive, and security has been largely ignored or misunderstood. In the past, truly portable languages were bulky, interpreted, and slow. These languages were popular as much for their high-level functionality as for their portability. Fast languages usually provided speed by binding themselves to particular platforms, so they met the portability issue only halfway. There were even a few safe languages, but they were primarily offshoots of the portable languages and suffered from the same problems. Java is a modern language that addresses all three of these fronts: portability, speed, and security. This is why it has become dominant in the world of programming today.The Java programming language, developed at Sun Microsystems under the guidance of Net luminaries James Gosling and Bill Joy, is designed to be a machine-independent programming language that is both safe enough to traverse networks and powerful enough to replace native executable code. Java addresses the issues raised here and helps us start building the kinds of applications we want.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Enter Java
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterThe Java programming language, developed at Sun Microsystems under the guidance of Net luminaries James Gosling and Bill Joy, is designed to be a machine-independent programming language that is both safe enough to traverse networks and powerful enough to replace native executable code. Java addresses the issues raised here and helps us start building the kinds of applications we want.Initially, most of the enthusiasm for Java centered on its capabilities for building embedded applications for the Web called applets . But in the early days, applets and other client-side GUI applications written in Java were limited. Today, Java has Swing, one of the most sophisticated toolkits for building graphical user interfaces (GUIs) in any language. This development has allowed Java to become a popular platform for developing traditional client-side application software.Of even more importance in the past few years, Java has become the premier platform for web-based applications and web services. These applications use technologies including the Java Servlet API, Enterprise JavaBeans?, and many popular open source and commercial Java application servers and frameworks. Java's portability and speed make it the platform of choice for modern business applications.This book will show you how to use Java to accomplish all of these real-world programming tasks. In the coming chapters we'll cover everything from text processing to networking, building rich client-side GUI applications with Swing and lightweight web-based applications with XML.The seeds of Java were planted in 1990 by Sun Microsystems patriarch and chief researcher, Bill Joy. At the time, Sun was competing in a relatively small workstation market while Microsoft was beginning its domination of the more mainstream, Intel-based PC world. When Sun missed the boat on the PC revolution, Joy retreated to Aspen, Colorado to work on advanced research. He was committed to the idea of accomplishing complex tasks with simple software and founded the aptly named Sun Aspen Smallworks.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - A Virtual Machine
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterJava is both a compiled and an interpreted language. Java source code is turned into simple binary instructions, much like ordinary microprocessor machine code. However, whereas C or C++ source is reduced to native instructions for a particular model of processor, Java source is compiled into a universal format—instructions for a virtual machine.Compiled Java bytecode is executed by a Java runtime interpreter. The runtime system performs all the normal activities of a real processor, but it does so in a safe, virtual environment. It executes a stack-based instruction set and manages memory like an operating system. It creates and manipulates primitive data types and loads and invokes newly referenced blocks of code. Most importantly, it does all this in accordance with a strictly defined open specification that can be implemented by anyone who wants to produce a Java-compliant virtual machine. Together, the virtual machine and language definition provide a complete specification. There are no features of the base Java language left undefined or implementation-dependent. For example, Java specifies the sizes and mathematical properties of all its primitive data types rather than leaving it up to the platform implementation.The Java interpreter is relatively lightweight and small; it can be implemented in whatever form is desirable for a particular platform. The interpreter may be run as a separate application, or it can be embedded in another piece of software, such as a web browser. Put together, this means that Java code is implicitly portable. The same Java application bytecode can run on any platform that provides a Java runtime environment, as shown in Figure 1-1. You don't have to produce alternative versions of your application for different platforms, and you don't have to distribute source code to end users.Figure 1-1: The Java runtime environmentAdditional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Java Compared with Other Languages
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterJava is a relatively new language, but it draws on many years of programming experience with other languages in its choice of features. It is worth taking a moment to compare Java at a high level with some other popular languages today, both for the benefit of those of you with other programming experience and for the newcomers who need to put things in context. We do not expect you to have a knowledge of any particular programming language in this book and when we refer to other languages by way of comparison we hope that the comments are self-explanatory.At least three pillars are necessary to support a universal programming language today: portability, speed, and security. Figure 1-2 shows how Java compares to a couple of other languages.Figure 1-2: Programming languages comparedYou may have heard that Java is a lot like C or C++, but that's really not true, except at a superficial level. When you first look at Java code, you'll see that the basic syntax looks like C or C++. But that's where the similarities end. Java is by no means a direct descendant of C or a next-generation C++. If you compare language features, you'll see that Java actually has more in common with highly dynamic languages such as Smalltalk and Lisp. In fact, Java's implementation is about as far from native C as you can imagine.The surface-level similarities to these languages are worth noting, however. Java borrows heavily from C and C++ syntax, so you'll see terse language constructs, including an abundance of curly braces and semicolons. Java subscribes to the C philosophy that a good language should be compact; in other words, it should be sufficiently small and regular so a programmer can hold all the language's capabilities in his or her head at once. Just as C is extensible with libraries, packages of Java classes can be added to the core language components to extend its vocabulary.C has been successful because it provides a reasonably feature-packed programming environment, with high performance and an acceptable degree of portability. Java also tries to balance functionality, speed, and portability, but it does so in a very different way. C trades functionality for portability; Java initially traded speed for portability. Java also addresses security issues while C doesn't.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Safety of Design
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterYou have no doubt heard a lot about the fact that Java is designed to be a safe language. But what do we mean by safe? Safe from what or whom? The security features that attract the most attention for Java are those features that make possible new types of dynamically portable software. Java provides several layers of protection from dangerously flawed code as well as more mischievous things such as viruses and Trojan horses. In the next section, we'll take a look at how the Java virtual machine architecture assesses the safety of code before it's run and how the Java class loader (the bytecode loading mechanism of the Java interpreter) builds a wall around untrusted classes. These features provide the foundation for high-level security policies that can allow or disallow various kinds of activities on an application-by-application basis.In this section, though, we'll look at some general features of the Java programming language. Perhaps more important than the specific security features, although often overlooked in the security din, is the safety that Java provides by addressing common design and programming problems. Java is intended to be as safe as possible from the simple mistakes we make ourselves as well as those we inherit from legacy software. The goal with Java has been to keep the language simple, provide tools that have demonstrated their usefulness, and let users build more complicated facilities on top of the language when needed.With Java, simplicity rules. Since Java started with a clean slate, it was able to avoid features that proved to be messy or controversial in other languages. For example, Java doesn't allow programmer-defined operator overloading (which in some languages allows programmers to redefine the meaning of basic symbols like + and -). Java doesn't have a source code preprocessor, so it doesn't have things like macros,
#define
statements, or conditional source compilation. These constructs exist in other languages primarily to support platform dependencies, so in that sense, they should not be needed in Java. Conditional compilation is also commonly used for debugging, but Java's sophisticated runtime optimizations and features such asAdditional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Safety of Implementation
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterIt's one thing to create a language that prevents you from shooting yourself in the foot; it's quite another to create one that prevents others from shooting you in the foot.Encapsulation is the concept of hiding data and behavior within a class; it's an important part of object-oriented design. It helps you write clean, modular software. In most languages, however, the visibility of data items is simply part of the relationship between the programmer and the compiler. It's a matter of semantics, not an assertion about the actual security of the data in the context of the running program's environment.When Bjarne Stroustrup chose the keyword
private
to designate hidden members of classes in C++, he was probably thinking about shielding you from the messy details of a class developer's code, not the issues of shielding that developer's classes and objects from attack by someone else's viruses and Trojan horses. Arbitrary casting and pointer arithmetic in C or C++ make it trivial to violate access permissions on classes without breaking the rules of the language. Consider the following code:// C++ code class Finances { private: char creditCardNumber[16]; ... }; main() { Finances finances; // Forge a pointer to peek inside the class char *cardno = (char *)&finances; printf("Card Number = %s\n", cardno); }
In this little C++ drama, we have written some code that violates the encapsulation of theFinances
class and pulls out some secret information. This sort of shenanigan—abusing an untyped pointer—is not possible in Java. If this example seems unrealistic, consider how important it is to protect the foundation (system) classes of the runtime environment from similar kinds of attacks. If untrusted code can corrupt the components that provide access to real resources, such as the filesystem, the network, or the windowing system, it certainly has a chance at stealing your credit card numbers.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Application and User-Level Security
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterThere's a fine line between having enough power to do something useful and having all the power to do anything you want. Java provides the foundation for a secure environment in which untrusted code can be quarantined, managed, and safely executed. However, unless you are content with keeping that code in a little black box and running it just for its own benefit, you will have to grant it access to at least some system resources so that it can be useful. Every kind of access carries with it certain risks and benefits. For example, in the web browser environment, the advantages of granting an untrusted (unknown) applet access to your windowing system are that it can display information and let you interact in a useful way. The associated risks are that the applet may instead display something worthless, annoying, or offensive. Since most people can accept that level of risk, graphical applets and the Web in general are possible.At one extreme, the simple act of running an application gives it a resource—computation time—that it may put to good use or burn frivolously. It's difficult to prevent an untrusted application from wasting your time or even attempting a "denial of service" attack. At the other extreme, a powerful, trusted application may justifiably deserve access to all sorts of system resources (e.g., the filesystem, process creation, network interfaces); a malicious application could wreak havoc with these resources. The message here is that important and sometimes complex security issues have to be addressed.In some situations, it may be acceptable to simply ask the user to "okay" requests. With Sun's Java plug-in, web browsers can pop up a dialog box and ask the user's permission for an applet to access an otherwise restricted file. However, we can put only so much burden on our users. An experienced person will quickly grow tired of answering questions; an inexperienced user may not be able to answer the questions correctly. Is it okay for me to grant an applet access to something if I don't understand what that is?Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Java and the Web
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterThe application-level safety features of Java make it possible to develop new kinds of applications that were not feasible before. A web browser that uses the Java runtime system can incorporate Java applets as executable content inside documents. This means that web pages can contain not only static textual information but also full-fledged interactive applications. The added potential for use of the Web is enormous. A user can retrieve and use software simply by navigating with a web browser. Formerly static information can be paired with portable software for interpreting and using the information. Instead of just providing some data for a spreadsheet, for example, a web document might contain a fully functional spreadsheet application embedded within it that allows users to view and manipulate the information. In recent years, some of this has started to happen, but the full potential has not yet been realized.In addition to applets, a more recent model for Internet downloadable application content is Java Web Start. The Web Start API allows your web browser to install applications locally, with security still enforced by the Java runtime system. This system can also automatically update the software when it is used. We'll discuss this more in Chapter 23.The term "applet" is used to mean a small, subordinate, or embeddable application. By "embeddable," we mean it's designed to be run and used within the context of a larger system. In that sense, most programs are embedded within a computer's operating system. An operating system manages its native applications in a variety of ways: it starts, stops, suspends, and synchronizes applications; it provides them with certain standard resources; and it protects them from one another by partitioning their environments.As far as the web browser model is concerned, an applet is just another type of object to display; it's embedded into an HTML page with a special tag. Java-enabled web browsers can execute applets directly, in the context of a particular document, as shown in Figure 1-4. Browsers can also implement this feature using Sun's Java Plug-in, which runs Java just like other browser plug-ins display other kinds of content.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Java as a General Application Language
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterJava was introduced to the world through the web browser and the Java applet API. However, Java is more than just a tool for building multimedia applications. Java is a powerful, general-purpose programming language that just happens to be safe and architecture-independent. Standalone Java applications are not subject to the restrictions placed on applets; they can perform the same jobs as do programs written in languages such as C and C++.Any software that implements the Java runtime system can run Java applications. Applications written in Java can be large or small, standalone or component-like, as in other languages. Java applets are different from other Java applications only in that they expect to be managed by a larger application. They are also normally considered untrusted code. In this book, we will build examples of both applets and standalone Java applications. With the exception of the few things untrusted applets can't do, such as access files, all the tools we examine in this book apply to both applets and standalone Java applications.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - A Java Road Map
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterWith everything that's going on, it's hard to keep track of what's available now, what's promised, and what has been around for some time. The following sections comprise a road map that imposes some order on Java's past, present, and future.Java 1.0 provided the basic framework for Java development: the language itself plus packages that let you write applets and simple applications. Although 1.0 is officially obsolete, there are still a lot of applets in existence that conform to its API.Java 1.1 superseded 1.0, incorporating major improvements in the Abstract Window Toolkit (AWT) package (Java's original GUI facility), a new event pattern, new language facilities such as reflection and inner classes, and many other critical features. Java 1.1 is the version that was supported natively by most versions of Netscape and Microsoft Internet Explorer for many years. For various political reasons, the browser world was frozen in this condition for a long time. This version of Java is still considered a sort of baseline for applets, although even this will fall away as Microsoft drops support for Java in their platforms.Java 1.2, dubbed "Java 2" by Sun, was a major release in December 1998. It provided many improvements and additions, mainly in terms of the set of APIs that were bundled into the standard distributions. The most notable additions were the inclusion of the Swing GUI package as a core API and a new, full-fledged 2D drawing API. Swing is Java's advanced user interface toolkit with capabilities far exceeding the old AWT's. (Swing, AWT, and some other packages have been variously called the JFC, or Java Foundation Classes.) Java 1.2 also added a proper Collections API to Java.Java 1.3, released in early 2000, added minor features but was primarily focused on performance. With Version 1.3, Java got significantly faster on many platforms and Swing received many bug fixes. In this timeframe, Java enterprise APIs such as Servlets and Enterprise JavaBeans also matured.Java 1.4, released in 2002, integrated a major new set of APIs and many long-awaited features. This included language assertions, regular expressions, preferences and logging APIs, a new I/O system for high-volume applications, standard support for XML, fundamental improvements in AWT and Swing, and a greatly matured Java Servlets API for web applications.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Chapter 2: A First Application
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterBefore diving into our full discussion of the Java language, let's get our feet wet by jumping into some working code and splashing around a bit. In this chapter, we'll build a friendly little application that illustrates many of the concepts used throughout the book. We'll take this opportunity to introduce general features of the Java language and applications.This chapter also serves as a brief introduction to the object-oriented and multithreaded aspects of Java. If these concepts are new to you, we hope that encountering them here in Java for the first time will be a straightforward and pleasant experience. If you have worked with another object-oriented or multithreaded programming environment, you should especially appreciate Java's simplicity and elegance. This chapter is intended only to give you a bird's eye view of the Java language and a feel for how it is used. If you have trouble with any of the concepts introduced here, rest assured they will be covered in greater detail later in the book.We can't stress enough the importance of experimentation as you learn new concepts here and throughout the book. Don't just read the examples—run them. The source code for these examples and all of the examples in this book can be found on the accompanying CD-ROM and on our web site at
https://www.oreilly.com/catalog/learnjava3
. Compile the programs and try them. Then, turn our examples into your examples: play with them, change their behavior, break them, fix them, and hopefully have some fun along the way.In this chapter, we concentrate on Java concepts and do not spend much time on tools. So we will refer only to the command-linejava
runtime and thejavac
compiler for Java 5.0. But we have also packaged all of the example code in this book to be run with the open-source Eclipse integrated development environment (IDE). If you would like to follow along with the examples using Eclipse, see Appendix A for an introduction to Eclipse and full instructions on loading the example project. You can then return here to follow along as we build the examples.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Java Tools and Environment
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterIn this chapter, we concentrate on Java concepts and do not spend much time on tools. So we will refer only to the command-line
java
runtime and thejavac
compiler for Java 5.0. But we have also packaged all of the example code in this book to be run with the open-source Eclipse integrated development environment (IDE). If you would like to follow along with the examples using Eclipse, see Appendix A for an introduction to Eclipse and full instructions on loading the example project. You can then return here to follow along as we build the examples.If you want to use the command line to follow our examples, you'll need to install the Sun Java Development Environment (JDK) before proceeding. As described at the end of Chapter 1, you can get the latest version online or find Java 5.0 on the CD accompanying this book. The Java 5.0 JDK is called, somewhat confusingly, JDK 1.5. The JDK comes with a standard installer. If you have problems running the command-line tools, turn to "Troubleshooting" at the end of this chapter for some guidance.We'll show a Windows command prompt in this chapter. To follow along using the command line, simply open a command window. (Under Windows, select Start → Run. Type command and press Enter.) Type the given command, and press Enter.C:\> javac HelloJava .java
The command you enter is identical on Unix, except where explicitly noted. Most other command-line examples throughout the book show a Unix shell prompt instead:% javac HelloJava.java
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - HelloJava
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterIn the tradition of introductory programming texts, we will begin with Java's equivalent of the archetypal "Hello World" application,
HelloJava
.We'll end up taking four passes at this example before we're done (HelloJava
,HelloJava2
, etc.), adding features, and introducing new concepts along the way. But let's start with the minimalist version:public class HelloJava { public static void main( String[] args ) { System.out.println("Hello, Java!"); } }
This five-line program declares a class calledHelloJava
and a method calledmain()
. It uses a predefined method calledprintln()
to write some text as output. This is a command-line program, which means that it runs in a shell or DOS window and prints its output there. That's a bit old school for our taste, so before we go any further, we're going to giveHelloJava
a graphical user interface (GUI). Don't worry about the code yet; just follow along with the progression here, and we'll come back for explanations in a moment.In place of the line containing theprintln()
method, we're going to use something called aJFrame
object to put a window on the screen. We can start by replacing theprintln
line with the following three lines:JFrame frame = new JFrame( "Hello, Java!" ); frame.setSize( 300, 300 ); frame.setVisible( true );
This snippet creates aJFrame
object with the title "Hello, Java!" TheJFrame
is a graphical window. To display it, we simply configure its size on the screen using thesetSize()
method and make it visible by calling thesetVisible()
method.If we stopped here, we would see an empty window on the screen with our "Hello, Java!" banner as its title. We'd like our message inside the window, not just scrawled on the top of it. To put something in the window, we need a couple more lines. The following, complete example adds aJLabel
object to display the text centered in our window. The additionalAdditional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - HelloJava2: The Sequel
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterNow that we've got some basics down, let's make our application a little more interactive. The following minor upgrade,
HelloJava2
, allows us to drag the message text around with the mouse.We'll call this exampleHelloJava2
rather than cause confusion by continuing to expand the old one, but the primary changes here and further on lie in adding capabilities to theHelloComponent
class and simply making the corresponding changes to the names to keep them straight, e.g.,HelloComponent2
,HelloComponent3
, etc. Having just seen inheritance at work, you might wonder why we aren't creating a subclass ofHelloComponent
and exploiting inheritance to build upon our previous example and extend its functionality. Well, in this case, that would not provide much advantage, and for clarity we simply start over.Here isHelloJava2
://file: HelloJava2.java import java.awt.*; import java.awt.event.*; import javax.swing.*; public class HelloJava2 { public static void main( String[] args ) { JFrame frame = new JFrame( "HelloJava2" ); frame.getContentPane().add( new HelloComponent2("Hello, Java!") ); frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); frame.setSize( 300, 300 ); frame.setVisible( true ); } } class HelloComponent2 extends JComponent implements MouseMotionListener { String theMessage; int messageX = 125, messageY = 95; // Coordinates of the message public HelloComponent2( String message ) { theMessage = message; addMouseMotionListener(this); } public void paintComponent( Graphics g ) { g.drawString( theMessage, messageX, messageY ); } public void mouseDragged(MouseEvent e) { // Save the mouse coordinates and paint the message. messageX = e.getX(); messageY = e.getY(); repaint(); } public void mouseMoved(MouseEvent e) { } }
Two slashes in a row indicates that the rest of the line is a comment. We've added a few comments toHelloJava2
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - HelloJava3: The Button Strikes!
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterNow we can move on to some fun stuff.
HelloJava3
brings us a new graphical interface component:JButton
. In this example, we add aJButton
component to our application that changes the color of our text each time the button is pressed. The draggable-message capability is still there, too. Our new code looks like this://file: HelloJava3.java import java.awt.*; import java.awt.event.*; import javax.swing.*; public class HelloJava3 { public static void main( String[] args ) { JFrame frame = new JFrame( "HelloJava3" ); frame.add( new HelloComponent3("Hello, Java!") ); frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); frame.setSize( 300, 300 ); frame.setVisible( true ); } } class HelloComponent3 extends JComponent implements MouseMotionListener, ActionListener { String theMessage; int messageX = 125, messageY = 95; // Coordinates of the message JButton theButton; int colorIndex; // Current index into someColors static Color[] someColors = { Color.black, Color.red, Color.green, Color.blue, Color.magenta }; public HelloComponent3( String message ) { theMessage = message; theButton = new JButton("Change Color"); setLayout( new FlowLayout() ); add( theButton ); theButton.addActionListener( this ); addMouseMotionListener( this ); } public void paintComponent( Graphics g ) { g.drawString( theMessage, messageX, messageY ); } public void mouseDragged( MouseEvent e ) { messageX = e.getX(); messageY = e.getY(); repaint(); } public void mouseMoved( MouseEvent e ) {} public void actionPerformed( ActionEvent e ) { // Did somebody push our button? if (e.getSource() == theButton) changeColor(); } synchronized private void changeColor() { // Change the index to the next color, awkwardly. if (++colorIndex == someColors.length) colorIndex = 0; setForeground( currentColor() ); // Use the new color. repaint(); } synchronized private Color currentColor() { return someColors[colorIndex]; } }
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - HelloJava4: Netscape's Revenge
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterWe have explored quite a few features of Java with the first three versions of the
HelloJava
application. But until now, our application has been rather passive; it has been completely event-driven, waiting patiently for events to come its way and responding to the whims of the user. Now our application is going to take some initiative—HelloJava4
will blink! Here is the code for our latest version://file: HelloJava4.java import java.awt.*; import java.awt.event.*; import javax.swing.*; public class HelloJava4 { public static void main( String[] args ) { JFrame frame = new JFrame( "HelloJava4" ); frame.add( new HelloComponent4("Hello, Java!") ); frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); frame.setSize( 300, 300 ); frame.setVisible( true ); } } class HelloComponent4 extends JComponent implements MouseMotionListener, ActionListener, Runnable { String theMessage; int messageX = 125, messageY = 95; // Coordinates of the message JButton theButton; int colorIndex; // Current index into someColors. static Color[] someColors = { Color.black, Color.red, Color.green, Color.blue, Color.magenta }; boolean blinkState; public HelloComponent4( String message ) { theMessage = message; theButton = new JButton("Change Color"); setLayout( new FlowLayout() ); add( theButton ); theButton.addActionListener( this ); addMouseMotionListener( this ); Thread t = new Thread( this ); t.start(); } public void paintComponent( Graphics g ) { g.setColor(blinkState ? getBackground() : currentColor()); g.drawString(theMessage, messageX, messageY); } public void mouseDragged(MouseEvent e) { messageX = e.getX(); messageY = e.getY(); repaint(); } public void mouseMoved(MouseEvent e) { } public void actionPerformed( ActionEvent e ) { if ( e.getSource() == theButton ) changeColor(); } synchronized private void changeColor() { if (++colorIndex == someColors.length) colorIndex = 0; setForeground( currentColor() ); repaint(); } synchronized private Color currentColor() { return someColors[colorIndex]; } public void run() { try { while(true) { blinkState = !blinkState; // Toggle blinkState. repaint(); // Show the change. Thread.sleep(300); } } catch (InterruptedException ie) { } } }
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Troubleshooting
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterIf you are having trouble with the java or javac commands, this section provides some guidance about what might be wrong. If you do not feel comfortable with the command line, you might prefer to run the examples in the Eclipse IDE. See Appendix A for an introduction to Eclipse and full instructions on running the example code.If the javac command is not found, you may have installed the JRE (Java runtime environment) instead of the JDK. Install Java 5.0 (also known as JDK 1.5), as described in "Java Tools and Environment" at the beginning of this chapter.If you are getting syntax error messages on the
HelloJava
examples, it is likely that your source code has a mistake or that the source file has become corrupted. The best way to eliminate this possibility is to copy the source directly from the ZIP file on the CD or download them from the examples link at the web site for this book,https://www.oreilly.com/catalog/learnjava3/
.Most runtime errors are related to the Java CLASSPATH environment variable.If you are gettingNoClassDefFound
orClassNotFound
errors when attempting to run the examples using the java command, you may have a classpath issue. By default there should be no value set in the environment variable CLASSPATH, but some untidy applications may set this value for you when you install them.To display the value of CLASSPATH under Windows, use this command:C:\> set classpath
Use this command for Unix:% echo $CLASSPATH
To clear any CLASSPATH value, use this command under Windows:C:\> set classpath=
Use this command for Unix:% unset CLASSPATH; export CLASSPATH
To check the version of Java, use the -version switch with the java command. Type the following at the command prompt and press Enter:C:\> java -version
This should report "java version 5.0." If it doesn't, install Java 5.0 as described in "Java Tools and Environment" at the beginning of this chapter.What if you get an error that saysAdditional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Chapter 3: Tools of the Trade
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterThere are many options for Java development environments, ranging from the traditional text editor and command-line tools to a whole slew of advanced IDEs, including IBM's Eclipse, Sun's NetBeans, and Borland's JBuilder. (Both Eclipse and NetBeans are open source projects and can be downloaded for free as well as found on the CD-ROM accompanying this book.) The examples in this book were developed using Sun's no-frills Java Development Kit (JDK) on, at various times, Solaris, Windows, and Mac OS X platforms. The JDK includes the basic tools needed to compile, run, and package Java applications, and we will describe these tools in this chapter. But there is no reason you can't use your preferred IDE to follow along with the examples in this book. The source code for all of the examples can be found on the CD-ROM.For an introduction to the Eclipse IDE and instructions for loading all of the examples in this book as an Eclipse project, see Appendix A. In Chapter 22, we introduce the NetBeans IDE with our discussion of the JavaBeans component architecture, so you will get little GUI development environment flavor there.A Java virtual machine (VM) is software that implements the Java runtime system and executes Java applications. It can be a standalone application like the java program that comes with the JDK or part of a larger application like a browser. Usually the interpreter itself is a native application, supplied for each platform, which then bootstraps other tools written in the Java language. Tools such as Java compilers and IDEs are often implemented directly in Java to maximize their portability and extensibility. NetBeans, for example, is a pure-Java application.The Java VM performs all the runtime activities of Java. It loads Java class files, verifies classes from untrusted sources, and executes the compiled bytecode. It manages memory and system resources. In implementations that support dynamic compilation, the interpreter also serves as a specialized compiler that turns Java bytecode into native machine instructions.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - The Java VM
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterA Java virtual machine (VM) is software that implements the Java runtime system and executes Java applications. It can be a standalone application like the java program that comes with the JDK or part of a larger application like a browser. Usually the interpreter itself is a native application, supplied for each platform, which then bootstraps other tools written in the Java language. Tools such as Java compilers and IDEs are often implemented directly in Java to maximize their portability and extensibility. NetBeans, for example, is a pure-Java application.The Java VM performs all the runtime activities of Java. It loads Java class files, verifies classes from untrusted sources, and executes the compiled bytecode. It manages memory and system resources. In implementations that support dynamic compilation, the interpreter also serves as a specialized compiler that turns Java bytecode into native machine instructions.Throughout most of this book, we'll be building standalone Java programs, but we'll make frequent references to Java applets as well. Both are kinds of Java applications run by a Java VM. A standalone Java application is a complete program intended to be run independently. An applet is, conceptually, an embeddable component to be used in a larger application. Both technically and in usage there is not much difference between the two, other than the Java VM can't run an applet directly. To run an applet, you must use a web browser or the appletviewer tool that comes with the JDK.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Running Java Applications
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterA standalone Java application must have at least one class that contains a method called
main()
, which contains the first code to be executed upon start up. To run the application, start the VM, specifying that class as an argument. You can also specify options to the interpreter as well as arguments to be passed to the application. Sun's Java VM is called java:% java [interpreter options] class_name [program arguments]
The class should be specified as a fully qualified class name, including the package name, if any. Note, however, that you don't include the .class file extension. Here are a couple of examples:% java animals.birds.BigBird % java MyTest
The interpreter searches for the class in the classpath, a list of directories and archive files where classes are stored. We'll discuss the classpath in detail in the next section. The classpath can be specified either by an environment variable or with the command-line option -classpath. If both are present, the command-line option is used.Alternately, the java command can be used to launch an "executable" Java archive (JAR) file:% java -jar spaceblaster.jar
In this case, the JAR file is annotated with the name of the class containing themain()
method and the classpath becomes the JAR file itself.However it is launched, after loading the first class, the interpreter executes the class'smain()
method. From there, the application can reference other classes, start additional threads, and create its user interface or other structures, as shown in Figure 3-1.Figure 3-1: Starting a Java applicationThemain()
method must have the right method signature . A method signature is the set of information that defines the method. It includes the method's name, arguments, and return type, as well as type and visibility modifiers. Themain()
method must be apublic
,static
method that takes an array ofString
objects as its argument and does not return any value (Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - The Classpath
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterThe concept of a path should be familiar to anyone who has worked on a DOS or Unix platform. It's an environment variable that provides an application with a list of places to look for some resource. The most common example is a path for executable programs. In a Unix shell, the
PATH
environment variable is a colon-separated list of directories that are searched, in order, when the user types the name of a command. The JavaCLASSPATH
environment variable, similarly, is a list of locations that are searched for Java class files. Both the Java interpreter and the Java compiler use theCLASSPATH
when searching for packages and Java classes.An element of the classpath can be a directory or JAR file. Java also supports archives in the conventional ZIP format, but JAR and ZIP are really the same format. JARs are simple archives that include extra files (metadata) that describe each archive's contents. JAR files are created with the JDK's jar utility; many tools for creating ZIP archives are publicly available and can be used to inspect or create JAR files. The archive format enables large groups of classes and their resources to be distributed in a single file; the Java runtime automatically extracts individual class files from an archive as needed.The precise means and format for setting the classpath vary from system to system. On a Unix system (including Mac OS X), you set theCLASSPATH
environment variable with a colon-separated list of directories and class archive files:% CLASSPATH=/home/vicky/Java/classes:/home/josh/lib/foo.jar:. % export CLASSPATH
This example specifies a classpath with three locations: a directory in the user's home, a JAR file in another user's directory, and the current directory, which is always specified with a dot (.
). The last component of the classpath, the current directory, is useful when tinkering with classes.On a Windows system, theCLASSPATH
environment variable is set with a semicolon-separated list of directories and class archive files:Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - The Java Compiler
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterIn this section, we'll say a few words about javac, the Java compiler in the JDK. The javac compiler is written entirely in Java, so it's available for any platform that supports the Java runtime system. javac turns Java source code into a compiled class that contains Java bytecode. By convention, source files are named with a .java extension; the resulting class files have a .class extension. Each source code file is considered a single compilation unit. As you'll see in Chapter 6, classes in a given compilation unit share certain features, such as
package
andimport
statements.javac allows one public class per file and insists the file have the same name as the class. If the filename and class name don't match, javac issues a compilation error. A single file can contain multiple classes, as long as only one of the classes is public. Avoid packing too many classes into a single source file. Packing classes together in a .java file only superficially associates them. In Chapter 6 we'll talk about inner classes, classes that contain other classes and interfaces.As an example, place the following source code in file BigBird.java:package animals.birds; public class BigBird extends Bird { }
Next, compile it with:% javac BigBird.java
Unlike the Java interpreter, which takes just a class name as its argument, javac needs a filename (with the .java extension) to process. The previous command produces the class file BigBird.class in the same directory as the source file. While it's nice to see the class file in the same directory as the source for this example, for most real applications, you need to store the class file in an appropriate place in the classpath.You can use the -d option with javac to specify an alternative directory for storing the class files javac generates. The specified directory is used as the root of the class hierarchy, so .class files are placed in this directory or in a subdirectory below it, depending on whether the class is contained in a package. (The compiler creates intermediate subdirectories automatically, if necessary.) For example, we can use the following command to create theAdditional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - JAR Files
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterJava Archive (JAR) files are Java's suitcases. They are the standard and portable way to pack up all the parts of your Java application into a compact bundle for distribution or installation. You can put whatever you want into a JAR file: Java class files, serialized objects, data files, images, sounds, etc. As we'll see in Chapter 23, a JAR file can carry one or more digital signatures that attest to its integrity and authenticity. A signature can be attached to the file as a whole or to individual items in the file.The Java runtime system understands JAR files and can load class files directly from an archive. So you can pack your application's classes in a JAR file and place it in your
CLASSPATH
, as described earlier. You can do the equivalent for applets by listing the JAR file in theARCHIVE
attribute of the HTML<applet>
tag. Nonclass files (data, images, etc.) contained in your JAR file can also be retrieved from the classpath using thegetResource()
method (described in Chapter 12). Using this facility, your code doesn't have to know whether any resource is in a plain file or a member of a JAR archive. Whether a given class or datafile is an item in a JAR file, an individual file on the classpath, or an applet on a remote server, you can always refer to it in a standard way and let Java's class loader resolve the location.Items stored in JAR files are compressed with the standard ZIP file compression. Compression makes downloading classes over a network much faster. A quick survey of the standard Java distribution shows that a typical class file shrinks by about 40 percent when it is compressed. Text files such as arbitrary HTML or ASCII containing English words often compress to one-quarter their original size. (On the other hand, image files don't get much smaller when compressed; most of the common image formats have compression built in.)Compression is not the only advantage that a JAR file has for transporting files over a network. Placing all the classes in a single JAR file enables them to be downloaded in a single transaction. Eliminating the overhead of making HTTP requests is likely to be a big savings, since individual class files tend to be small, and a complex applet could easily require many of them. On the downside, startup time could be increased if a large JAR file must be downloaded over a slow connection before the applet can start up.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Policy Files
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterOne of the truly novel things about Java is that security is built into the language. As described in Chapter 1, the Java VM can verify class files and Java's security manager can impose limits on what classes do. In early versions of Java, it was necessary to implement security policies programmatically by writing a Java security manager class and using it in your application. A major shift occurred in Java 1.2, when a new declarative security system was added. This system allows you to write policy files —text-based descriptions of permissions—which are much simpler and don't require code changes. These policy files tell the security manager what to allow and disallow and for whom.With security policies you can answer questions such as: "If I download a program from somewhere on the Internet, how can I prevent it from stealing information on my computer and sending it back to someone else?" "How can I prevent a malicious program from disabling my computer or erasing data on my disk?" Most computing platforms have no answer for these questions.In early versions of Java, much of the buzz had to do with the security of applets. Applets generally run with security restrictions that prevent them from doing questionable things such as reading from or writing to the disk or contacting arbitrary computers on the network. With security policy files, it's just as easy to apply applet-style security to any application without modifying it. Furthermore, it's easy to fine-tune the access you grant. For example, you can allow an application to access only a specific directory on the disk, or you can allow network access to certain addresses.Understanding security and security policies is important, so we'll cover it here. However, in practice, you probably won't use this facility yourself, unless you are writing a framework for running applications from many unknown sources. Java Web Start is an example of such a framework. It installs and updates Java applications over the Web with user-definable security restrictions.By default, no security manager is installed when you launch a Java application locally. You can turn on security using an option of theAdditional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Chapter 4: The Java Language
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterThis chapter begins our introduction to the Java language syntax. Since readers come to this book with different levels of programming experience, it is difficult to set the right level for all audiences. We have tried to strike a balance between a thorough tour of the language syntax for beginners and providing enough background information so that a more experienced reader can quickly gauge the differences between Java and other languages. Since Java's syntax is derived from C, we make some comparisons to features of that language, but no special knowledge of C is necessary. We spend more time on aspects of Java that are different from other languages and less on elemental programming concepts. For example, we'll take a close look at arrays in Java because they are significantly different from those in other languages. We won't, on the other hand, spend as much time explaining basic language constructs such as loops and control structures. Chapters 5 through 7 will build on this chapter by talking about Java's object-oriented side and complete the discussion of the core language. Chapter 8 discusses generics, a Java 5.0 feature that enhances the way types work in the Java language, allowing you to write certain kinds of classes more flexibly and safely. After that, we dive into the Java APIs and see what we can do with the language. The rest of this book is filled with concise examples that do useful things and if you are left with any questions after these introductory chapters, we hope they'll be answered by real world usage.Java is a language for the Internet. Since the people of the Net speak and write in many different human languages, Java must be able to handle a large number of languages as well. One of the ways in which Java supports internationalization is through the Unicode character set. Unicode is a worldwide standard that supports the scripts of most languages. Java bases its character and string data on the Unicode 4.0 standard, which uses 16 bits to represent each symbol.Java source code can be written using Unicode and stored in any number of character encodings, ranging from its full 16-bit form to ASCII-encoded Unicode character values. This makes Java a friendly language for non-English-speaking programmers who can use their native language for class, method, and variable names just as they can for the text displayed by the application.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Text Encoding
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterJava is a language for the Internet. Since the people of the Net speak and write in many different human languages, Java must be able to handle a large number of languages as well. One of the ways in which Java supports internationalization is through the Unicode character set. Unicode is a worldwide standard that supports the scripts of most languages. Java bases its character and string data on the Unicode 4.0 standard, which uses 16 bits to represent each symbol.Java source code can be written using Unicode and stored in any number of character encodings, ranging from its full 16-bit form to ASCII-encoded Unicode character values. This makes Java a friendly language for non-English-speaking programmers who can use their native language for class, method, and variable names just as they can for the text displayed by the application.The Java
char
type andString
objects natively support Unicode values. But if you're concerned about having to labor with two-byte characters, you can relax. The String API makes the character encoding transparent to you. Unicode is also very ASCII-friendly (ASCII is the most common character encoding for English). The first 256 characters are defined to be identical to the first 256 characters in the ISO 8859-1 (Latin-1) character set, so Unicode is effectively backward-compatible with the most common English character sets. Furthermore, the most common encoding for Unicode, called UTF-8, preserves ASCII values in their single byte form. This encoding is used in compiled Java class files, so for English text, storage remains compact.Most platforms can't display all currently defined Unicode characters. As a result, Java programs can be written with special Unicode escape sequences. A Unicode character can be represented with this escape sequence:\uxxxx
xxxx is a sequence of one to four hexadecimal digits. The escape sequence indicates an ASCII-encoded Unicode character. This is also the form Java uses to output (print) Unicode characters in an environment that doesn't otherwise support them. Java also comes with classes to read and write Unicode character streams in specific encodings, including UTF-8.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Comments
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterJava supports both C-style block comments delimited by
/*
and*/
and C++-style line comments indicated by//
:/* This is a multiline comment. */ // This is a single-line comment // and so // is this
Block comments have both a beginning and end sequence and can cover large ranges of text. However, they cannot be "nested"; meaning that you can't have a block comment inside of a block comment without the compiler getting confused. Single-line comments have only a start sequence and are delimited by the end of a line; extra//
indicators inside a single line have no effect. Line comments are useful for short comments within methods; they don't conflict with block comments, so you can still comment-out larger chunks of code including them.A block comment beginning with/**
indicates a special doc comment. A doc comment is designed to be extracted by automated documentation generators, such as the JDK's javadoc program. A doc comment is terminated by the next*/
, just as with a regular block comment. Within the doc comment, lines beginning with@
are interpreted as special instructions for the documentation generator, giving it information about the source code. By convention, each line of a doc comment begins with a*
, as shown in the following example, but this is optional. Any leading spacing and the*
on each line are ignored:/** * I think this class is possibly the most amazing thing you will * ever see. Let me tell you about my own personal vision and * motivation in creating it. * <p> * It all began when I was a small child, growing up on the * streets of Idaho. Potatoes were the rage, and life was good... * * @see PotatoPeeler * @see PotatoMasher * @author John 'Spuds' Smith * @version 1.00, 19 Dec 2006 */ class Potato {
javadoc creates HTML documentation for classes by reading the source code and pulling out the embedded comments andAdditional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Types
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterThe type system of a programming language describes how its data elements (variables and constants) are associated with storage in memory and how they are related to one another. In a statically typed language, such as C or C++, the type of a data element is a simple, unchanging attribute that often corresponds directly to some underlying hardware phenomenon, such as a register or a pointer value. In a more dynamic language such as Smalltalk or Lisp, variables can be assigned arbitrary elements and can effectively change their type throughout their lifetime. A considerable amount of overhead goes into validating what happens in these languages at runtime. Scripting languages such as Perl achieve ease of use by providing drastically simplified type systems in which only certain data elements can be stored in variables, and values are unified into a common representation, such as strings.Java combines the best features of both statically and dynamically typed languages. As in a statically typed language, every variable and programming element in Java has a type that is known at compile time, so the runtime system doesn't normally have to check the validity of assignments between types while the code is executing. Unlike traditional C or C++, Java also maintains runtime information about objects and uses this to allow truly dynamic behavior. Java code may load new types at runtime and use them in fully object-oriented ways, allowing casting and full polymorphism (extending of types).Java data types fall into two categories. Primitive types represent simple values that have built-in functionality in the language; they are fixed elements, such as literal constants and numbers. Reference types (or class types) include objects and arrays; they are called reference types because they "refer to" a large data type which is passed "by reference," as we'll explain shortly. In Java 5.0, generic types were introduced to the language, but they are really an extension of classes and are, therefore, actually reference types.Numbers, characters, and Boolean values are fundamental elements in Java. Unlike some other (perhaps more pure) object-oriented languages, they are not objects. For those situations where it's desirable to treat a primitive value as an object, Java provides "wrapper" classes. The major advantage of treating primitive values as special is that the Java compiler and runtime can more readily optimize their implementation. Primitive values and computations can still be mapped down to hardware as they always have been in lower-level languages. As of Java 5.0, the compiler can automatically convert between primitive values and their object wrappers as needed to partially mask the difference between the two. We'll explain what that means in more detail in the next chapter when we discussAdditional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Statements and Expressions
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterJava statements appear inside methods and classes; they describe all activities of a Java program. Variable declarations and assignments, such as those in the previous section, are statements, as are basic language structures such as if/then conditionals and loops.
int size = 5; if ( size > 10 ) doSomething(); for( int x = 0; x < size; x++ ) { ... }
Expressions produce values; an expression is evaluated to produce a result, to be used as part of another expression or in a statement. Method calls, object allocations, and, of course, mathematical expressions are examples of expressions. Technically, since variable assignments can be used as values for further assignments or operations (in somewhat questionable programming style), they can be considered to be both statements and expressions.new Object(); Math.sin( 3.1415 ); 42 * 64;
One of the tenets of Java is to keep things simple and consistent. To that end, when there are no other constraints, evaluations and initializations in Java always occur in the order in which they appear in the code—from left to right, top to bottom. We'll see this rule used in the evaluation of assignment expressions, method calls, and array indexes, to name a few cases. In some other languages, the order of evaluation is more complicated or even implementation-dependent. Java removes this element of danger by precisely and simply defining how the code is evaluated. This doesn't mean you should start writing obscure and convoluted statements, however. Relying on the order of evaluation of expressions in complex ways is a bad programming habit, even when it works. It produces code that is hard to read and harder to modify.Statements and expressions in Java appear within a code block. A code block is syntactically a series of statements surrounded by an open curly brace ({
) and a close curly brace (}
). The statements in a code block can include variable declarations and most of the other sorts of statements and expressions we mentioned earlier:{ int size = 5; setName("Max"); ... }
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Exceptions
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterJava has its roots in embedded systems—software that runs inside specialized devices, such as hand-held computers, cellular phones, and fancy toasters. In those kinds of applications, it's especially important that software errors be handled robustly. Most users would agree that it's unacceptable for their phone to simply crash or for their toast (and perhaps their house) to burn because their software failed. Given that we can't eliminate the possibility of software errors, it's a step in the right direction to recognize and deal with anticipated application-level errors methodically.Dealing with errors in a language such as C is entirely the responsibility of the programmer. The language itself provides no help in identifying error types and no tools for dealing with them easily. In C, a routine generally indicates a failure by returning an "unreasonable" value (e.g., the idiomatic
-1
ornull
). As the programmer, you must know what constitutes a bad result and what it means. It's often awkward to work around the limitations of passing error values in the normal path of data flow. An even worse problem is that certain types of errors can legitimately occur almost anywhere, and it's prohibitive and unreasonable to explicitly test for them at every point in the software.Java offers an elegant solution to these problems through exceptions . (Java exception handling is similar to, but not quite the same as, exception handling in C++.) An exception indicates an unusual condition or an error condition. Program control becomes unconditionally transferred or "thrown" to a specially designated section of code where it's caught and handled. In this way, error handling is orthogonal to (or independent of) the normal flow of the program. We don't have to have special return values for all our methods; errors are handled by a separate mechanism. Control can be passed a long distance from a deeply nested routine and handled in a single location when that is desirable, or an error can be handled immediately at its source. A few standard methods returnAdditional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Assertions
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterAn assertion is a simple pass/fail test of some condition, performed while your application is running. Assertions can be used to "sanity" check your code anywhere you believe certain conditions are guaranteed by correct program behavior. Assertions are distinct from other kinds of tests because they check conditions that should never be violated at a logical level: if the assertion fails, the application is to be considered broken and generally halts with an appropriate error message. Assertions are supported directly by the Java language and they can be turned on or off at runtime to remove any performance penalty of including them in your code.Using assertions to test for the correct behavior of your application is a simple but powerful technique for ensuring software quality. It fills a gap between those aspects of software that can be checked automatically by the compiler and those more generally checked by "unit tests" and human testing. Assertions test assumptions about program behavior and make them guarantees (at least while they are activated).Explicit support for assertions was added in Java 1.4. However, if you've written much code in any language, you have probably used assertions in some form. For example, you may have written something like the following:
if ( !condition ) throw new AssertionError("fatal error: 42");
An assertion in Java is equivalent to this example but performed with theassert
language keyword. It takes a Boolean condition and an optional expression value. If the assertion fails, anAssertionError
is thrown, which usually causes Java to bail out of the application.The optional expression may evaluate to either a primitive or object type. Either way, its sole purpose is to be turned into a string and shown to the user if the assertion fails; most often you'll use a string message explicitly. Here are some examples:assert false; assert ( array.length > min ); assert a > 0 : a // shows value of a to the user assert foo != null : "foo is null!" // shows message to user
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Arrays
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterAn array is a special type of object that can hold an ordered collection of elements. The type of the elements of the array is called the base type of the array; the number of elements it holds is a fixed attribute called its length. Java supports arrays of all primitive and reference types.The basic syntax of arrays looks much like that of C or C++. We create an array of a specified length and access the elements with the index operator,
[]
. Unlike other languages, however, arrays in Java are true, first-class objects. An array is an instance of a special Javaarray
class and has a corresponding type in the type system. This means that to use an array, as with any other object, we first declare a variable of the appropriate type and then use thenew
operator to create an instance of it.Array objects differ from other objects in Java in three respects:- Java implicitly creates a special array class type for us whenever we declare a new type of array. It's not strictly necessary to know about this process in order to use arrays, but it helps in understanding their structure and their relationship to other objects in Java later.
- Java lets us use the
[]
operator to access array elements so that arrays look as we expect. We could implement our own classes that act like arrays, but we would have to settle for having methods such asget()
andset()
instead of using the special[]
notation. - Java provides a corresponding special form of the
new
operator that lets us construct an instance of an array with a specified length with the[]
notation or initialize it directly from a structured list of values.
An array type variable is denoted by a base type followed by the empty brackets,[]
. Alternatively, Java accepts a C-style declaration, with the brackets placed after the array name.The following are equivalent:int [] arrayOfInts; // preferred int arrayOfInts []; // C-style
In each case,arrayOfInts
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Chapter 5: Objects in Java
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterIn this chapter, we get to the heart of Java and explore the object-oriented aspects of the language. The term object-oriented design refers to the art of decomposing an application into some number of objects, which are self-contained application components that work together. The goal is to break your problem down into a number of smaller problems that are simpler and easier to handle and maintain. Object-based designs have proven themselves over the years, and object-oriented languages such as Java provide a strong foundation for writing very small to very large applications. Java was designed from the ground up to be an object-oriented language, and all the Java APIs and libraries are built around solid object-based design patterns.An object design "methodology" is a system or a set of rules created to help you break down your application into objects. Often this means mapping real-world entities and concepts (sometimes called the "problem domain") into application components. Various methodologies attempt to help you factor your application into a good set of reusable objects. This is good in principle, but the problem is that good object-oriented design is still more art than science. While you can learn from the various off-the-shelf design methodologies, none of them will help you in all situations. The truth is that there is no substitute for experience.We won't try to push you into a particular methodology here; there are shelves full of books to do that. Instead, we'll provide some common sense hints to get you started. The following general design guidelines will hopefully make more sense after you've read this chapter and the next:
- Hide as much of your implementation as possible. Never expose more of the internals of an object than you have to. This is key to building maintainable, reusable code. Avoid public variables in your objects, with the possible exception of constants. Instead define accessor methods to set and return values (even if they are simple types). Later, when you need to, you'll be able to modify and extend the behavior of your objects without breaking other classes that rely on them.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Classes
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterClasses are the building blocks of a Java application. A class can contain methods (functions), variables, initialization code, and, as we'll discuss later, other classes. It serves as a blueprint for making class instances, which are runtime objects that implement the class structure. You declare a class with the
class
keyword. Methods and variables of the class appear inside the braces of the class declaration:class Pendulum { float mass; float length = 1.0; int cycles; float getPosition ( float time ) { ... } ... }
ThePendulum
class contains three variables:mass
,length
, andcycles
. It also defines a method calledgetPosition()
, which takes afloat
value as an argument and returns afloat
value as a result. Variables and method declarations can appear in any order, but variable initializers can't make "forward references" to other variables that appear later. Once we've defined thePendulum
class, we can create aPendulum
object (an instance of that class) as follows:Pendulum p; p = new Pendulum();
Recall that our declaration of the variablep
doesn't create aPendulum
object; it simply creates a variable that refers to an object of typePendulum
. We still had to create the object, using thenew
keyword, as shown in the second line of the preceding code snippet. Now that we've created aPendulum
object, we can access its variables and methods , as we've already seen many times:p.mass = 5.0; float pos = p.getPosition( 1.0 );
Two kinds of variables can be defined in a class: instance variables and static variables. Every object instance has its own set of instance variables; the values of these variables in one instance of an object can differ from the values in another object. We'll talk about static variables later, which, in contrast, are shared among all instances of an object. In either case, if you don't initialize a variable when you declare it, it's given a default value appropriate for its type (Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Methods
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterMethods appear inside class bodies. They contain local variable declarations and other Java statements that are executed when the method is invoked. Methods may return a value to the caller. They always specify a return type, which can be a primitive type, a reference type, or the type
void
, which indicates no returned value. Methods may take arguments, which are values supplied by the caller of the method.Here's a simple example:class Bird { int xPos, yPos; double fly ( int x, int y ) { double distance = Math.sqrt( x*x + y*y ); flap( distance ); xPos = x; yPos = y; return distance; } ... }
In this example, the classBird
defines a method,fly()
, that takes as arguments two integers:x
andy
. It returns adouble
type value as a result, using thereturn
keyword.Prior to Java 5.0, the number and type of method arguments was fixed. Now Java has variable-length argument lists for methods , which allow a method to specify that it can take any number of arguments and sort them itself at runtime. We provide more details later in this chapter.Thefly()
method declares a local variable calleddistance
, which it uses to compute the distance flown. A local variable is temporary; it exists only within the scope of its method. Local variables are allocated when a method is invoked; they are normally destroyed when the method returns. They can't be referenced from outside the method itself. If the method is executing concurrently in different threads, each thread has its own version of the method's local variables . A method's arguments also serve as local variables within the scope of the method.An object created within a method and assigned to a local variable may or may not persist after the method has returned. As with all objects in Java, it depends on whether any references to the object remain. If an object is created, assigned to a local variable, and never used anywhere else, that object is no longer referenced when the local variable disappears from scope, so garbage collection removes the object. If, however, we assign the object to an instance variable, pass it as an argument to another method, or pass it back as a return value, it may be saved by another variable holding its reference. We'll discuss object creation and garbage collection in more detail shortly.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Object Creation
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterObjects in Java are allocated on a system "heap" memory space. Unlike other languages, however, we needn't manage that memory ourselves. Java takes care of memory allocation and deallocation for you. Java explicitly allocates storage for an object when you create it with the
new
operator. More importantly, objects are removed by garbage collection when they're no longer referenced.Objects are allocated with thenew
operator using an object constructor. A constructor is a special method with the same name as its class and no return type. It's called when a new class instance is created, which gives the class an opportunity to set up the object for use. Constructors, like other methods, can accept arguments and can be overloaded (they are not, however, inherited like other methods; we'll discuss inheritance in Chapter 6).class Date { long time; Date() { time = currentTime(); } Date( String date ) { time = parseDate( date ); } ... }
In this example, the classDate
has two constructors . The first takes no arguments; it's known as the default constructor. Default constructors play a special role: if we don't define any constructors for a class, an empty default constructor is supplied for us. The default constructor is what gets called whenever you create an object by calling its constructor with no arguments. Here we have implemented the default constructor so that it sets the instance variabletime
by calling a hypothetical method,currentTime()
, which resembles the functionality of the realjava.util.Date
class. The second constructor takes aString
argument. Presumably, thisString
contains a string representation of the time that can be parsed to set thetime
variable. Given the constructors in the previous example, we create aDate
object in the following ways:Date now = new Date(); Date christmas = new Date("Dec 25, 2006");
In each case, Java chooses the appropriate constructor at compile time based on the rules for overloaded method selection.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Object Destruction
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterNow that we've seen how to create objects, it's time to talk about their destruction. If you're accustomed to programming in C or C++, you've probably spent time hunting down memory leaks in your code. Java takes care of object destruction for you; you don't have to worry about traditional memory leaks, and you can concentrate on more important programming tasks.Java uses a technique known as garbage collection to remove objects that are no longer needed. The garbage collector is Java's grim reaper. It lingers in the background, stalking objects and awaiting their demise. It finds and watches them, periodically counting references to them to see when their time has come. When all references to an object are gone and it's no longer accessible, the garbage-collection mechanism declares the object unreachable and reclaims its space back to the available pool of resources. An unreachable object is one that can no longer be found through any combination of "live" references in the running application.Garbage collection uses a variety of different algorithms; the Java virtual machine architecture doesn't require a particular scheme. It's worth noting, however, how some implementations of Java have accomplished this task. In the beginning, Java used a technique called "mark and sweep." In this scheme, Java first walks through the tree of all accessible object references and marks them as alive. Java then scans the heap, looking for identifiable objects that aren't marked. In this technique, Java is able to find objects on the heap because they are stored in a characteristic way and have a particular signature of bits in their handles unlikely to be reproduced naturally. This kind of algorithm doesn't become confused by the problem of cyclic references, in which objects can mutually reference each other and appear alive even when they are dead (Java handles this problem automatically). This scheme wasn't the fastest method, however, and caused pauses in the program. Since Java 1.3, implementations have become much more sophisticated.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Enumerations
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterNow that we've covered the basics of classes, we can talk in more depth about one of the cool new features in Java 5.0, enumerations. An enumeration is an object type in the Java language that is limited to an explicit set of values. The values have an order, defined by their order of declaration in the code, and have a correspondence with a string name that is the same as their declared name in the source code.We've already seen a couple of examples of enumerations used in place of static identifiers. For example:
enum Weekday { Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday } // usage setDay( Weekday.Sunday );
Let's take a look at what the Java compiler is actually generating for the enum. It is a regular Java class, in this case namedWeekday
, so we can display it with thejavap
command like so:% javap Weekday public final class Weekday extends java.lang.Enum { public static final Weekday Sunday; public static final Weekday Monday; public static final Weekday Tuesday; public static final Weekday Wednesday; public static final Weekday Thursday; public static final Weekday Friday; public static final Weekday Saturday; public static final Weekday[] values(); public static Weekday valueOf(java.lang.String); }
Weekday
is a subclass of theEnum
type with seven static, final, "constant" object references corresponding to our seven enumerated values. Each of the enumerated values is of typeWeekday
. The Java compiler does not let us extend this class or create any other instances of this type. The only instances ofWeekday
that will ever exist are the seven enumerated values. This is what gives enumerations their type safety. A method expecting aWeekday
can be given one of only seven values. Unlike a numeric constant identifier, no value other than aWeekday
will work. As we saw in Chapter 4, enumerations (unlike most objects) can also be used inswitch
statements with all the same benefits.Because enumerations are static values, they can be imported with the new Java static import, saving us some typing:Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Chapter 6: Relationships Among Classes
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterSo far in our exploration of Java, we have seen how to create Java classes and objects, which are instances of those classes. By themselves objects would be little more than a convention for organizing code. It is in the relationships between objects—their connections and privileges with respect to one another—that the power of an object-oriented language is really expressed.That's what we'll cover in this chapter. In particular, we'll look at several kinds of relationships:
- Inheritance relationships
- How a class inherits methods and variables from its parent class
- Interfaces
- How to declare that a class implements certain behavior and define a type to refer to that behavior
- Packaging
- How to organize objects into logical groups
- Inner classes
- A generalization of classes that lets you nest a class definition inside another class definition
Classes in Java exist in a hierarchy. A class in Java can be declared as a subclass of another class using theextends
keyword. A subclass inherits variables and methods from its superclass and can use them as if they were declared within the subclass itself:class Animal { float weight; ... void eat() { ... } ... } class Mammal extends Animal { // inherits weight int heartRate; ... // inherits eat() void breathe() { ... } }
In this example, an object of typeMammal
has both the instance variableweight
and the methodeat()
. They are inherited fromAnimal
.A class can extend only one other class. To use the proper terminology, Java allows single inheritance of class implementation. Later in this chapter, we'll talk about interfaces, which take the place of multiple inheritance as it's primarily used in other languages.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Subclassing and Inheritance
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterClasses in Java exist in a hierarchy. A class in Java can be declared as a subclass of another class using the
extends
keyword. A subclass inherits variables and methods from its superclass and can use them as if they were declared within the subclass itself:class Animal { float weight; ... void eat() { ... } ... } class Mammal extends Animal { // inherits weight int heartRate; ... // inherits eat() void breathe() { ... } }
In this example, an object of typeMammal
has both the instance variableweight
and the methodeat()
. They are inherited fromAnimal
.A class can extend only one other class. To use the proper terminology, Java allows single inheritance of class implementation. Later in this chapter, we'll talk about interfaces, which take the place of multiple inheritance as it's primarily used in other languages.A subclass can be further subclassed. Normally, subclassing specializes or refines a class by adding variables and methods (you cannot remove or hide variables or methods by subclassing). For example:class Cat extends Mammal { // inherits weight and heartRate boolean longHair; ... // inherits eat() and breathe() void purr() { ... } }
TheCat
class is a type ofMammal
that is ultimately a type ofAnimal
.Cat
objects inherit all the characteristics ofMammal
objects and, in turn,Animal
objects.Cat
also provides additional behavior in the form of thepurr()
method and thelongHair
variable. We can denote the class relationship in a diagram, as shown in Figure 6-1.A subclass inherits all members of its superclass not designated asprivate
. As we'll discuss shortly, other levels of visibility affect what inherited members of the class can be seen from outside of the class and its subclasses, but at a minimum, a subclass always has the same set of visible members as its parent. For this reason, the type of a subclass can be considered aAdditional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Interfaces
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterJava expands on the concept of abstract methods with interfaces . It's often desirable to specify a group of abstract methods defining some behavior for an object without tying it to any implementation at all. In Java, this is called an interface . An interface defines a set of methods that a class must implement. A class in Java can declare that it implements an interface if it implements the required methods. Unlike extending an abstract class, a class implementing an interface doesn't have to inherit from any particular part of the inheritance hierarchy or use a particular implementation.Interfaces are kind of like Boy Scout or Girl Scout merit badges. A scout who has learned to build a birdhouse can walk around wearing a little sleeve patch with a picture of one. This says to the world, "I know how to build a birdhouse." Similarly, an interface is a list of methods that define some set of behavior for an object. Any class that implements each method listed in the interface can declare at compile time that it implements the interface and wear, as its merit badge, an extra type—the interface's type.Interface types act like class types. You can declare variables to be of an interface type, you can declare arguments of methods to accept interface types, and you can specify that the return type of a method is an interface type. In each case, what is meant is that any object that implements the interface (i.e., wears the right merit badge) can fill that role. In this sense, interfaces are orthogonal to the class hierarchy. They cut across the boundaries of what kind of object an item is and deal with it only in terms of what it can do. A class can implement as many interfaces as it desires. In this way, interfaces in Java replace much of the need for multiple inheritance in other languages (and all its messy complications).An interface looks, essentially, like a purely
abstract
class (i.e., a class with onlyabstract
methods). You define an interface with theAdditional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Packages and Compilation Units
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterA package is a name for a group of related classes and interfaces. In Chapter 3, we discussed how Java uses package names to locate classes during compilation and at runtime. In this sense, packages are somewhat like libraries; they organize and manage sets of classes. Packages provide more than just source code-level organization. They create an additional level of scope for their classes and the variables and methods within them. We'll talk about the visibility of classes later in this section. In the next section, we discuss the effect that packages have on access to variables and methods among classes.The source code for a Java class is organized into compilation units . A simple compilation unit contains a single class definition and is named for that class. The definition of a class named
MyClass
, for instance, could appear in a file named MyClass.java. For most of us, a compilation unit is just a file with a .java extension, but theoretically in an integrated development environment, it could be an arbitrary entity. For brevity, we'll refer to a compilation unit simply as a file.The division of classes into their own files is important because the Java compiler assumes much of the responsibility of a make utility. The compiler relies on the names of source files to find and compile dependent classes. It's possible to put more than one class definition into a single file, but there are some restrictions we'll discuss shortly.A class is declared to belong to a particular package with thepackage
statement. Thepackage
statement must appear as the first statement in a compilation unit. There can be only onepackage
statement, and it applies to the entire file:package mytools.text; class TextComponent { ... }
In this example, the classTextComponent
is placed in the packagemytools.text
.Package names are constructed hierarchically, using a dot-separated naming convention. Package-name components construct a unique path for the compiler and runtime systems to locate files; however, they don't create relationships between packages in any other way. There is really no such thing as a "subpackage"; the package namespace is, in actuality, flat—not hierarchical. Packages under a particular part of a package hierarchy are related only by convention. For example, if we create another package calledAdditional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Visibility of Variables and Methods
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterOne of the most important aspects of object-oriented design is data hiding, or encapsulation. By treating an object in some respects as a "black box" and ignoring the details of its implementation, we can write stronger, simpler code with components that can be easily reused.By default, the variables and methods of a class are accessible to members of the class itself and to other classes in the same package. To borrow from C++ terminology, classes in the same package are friendly. We'll call this the default level of visibility . As you'll see as we go on, the default visibility lies in the middle of the range of restrictiveness that can be specified.The modifiers
public
andprivate
, on the other hand, define the extremes. As we mentioned earlier, methods and variables declared asprivate
are accessible only within their class. At the other end of the spectrum, members declared aspublic
are accessible from any class in any package, provided the class itself can be seen. (The class that contains the methods must also bepublic
to be seen outside of its package, as we discussed previously.) Thepublic
members of a class should define its most general functionality—what the black box is supposed to do.Figure 6-7 illustrates the four simplest levels of visibility, continuing the example from the previous section. Public members inTextArea
are accessible from anywhere. Private members are not visible from outside the class. The default visibility allows access by other classes in the package.Figure 6.7: Private, default, protected, and public visibilityTheprotected
modifier allows special access permissions for subclasses. Contrary to how it might sound,protected
is slightly less restrictive than the default level of accessibility. In addition to the default access afforded classes in the same package,protected
members are visible to subclasses of the class, even if they are defined in a different package. If you are a C++ programmer used to more restrictive meanings, this may rub you the wrong way.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Arrays and the Class Hierarchy
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterNow we're going to shift gears a bit and return to the topic of arrays , considering them from the object point of view. At the end of Chapter 4, we mentioned that arrays have a place in the Java class hierarchy, but we didn't give you any details. Now that we've discussed the object-oriented aspects of Java, we can give you the whole story.Array classes live in a parallel Java class hierarchy under the
Object
class. If a class is a direct subclass ofObject
, an array class for that base type also exists as a direct subclass ofObject
. Arrays of more derived classes are subclasses of the corresponding array classes. For example, consider the following class types:class Animal { ... } class Bird extends Animal { ... } class Penguin extends Bird { ... }
Figure 6-8 illustrates the class hierarchy for arrays of these classes. Arrays of the same dimension are related to one another in the same manner as their base type classes. In our example,Bird
is a subclass ofAnimal
, which means that theBird[]
type is a subtype ofAnimal[]
. In the same way aBird
object can be used in place of anAnimal
object, aBird[]
array can be assigned to a variable of typeAnimal[]
:Animal [][] animals; Bird [][] birds = new Bird [10][10]; birds[0][0] = new Bird(); // make animals and birds reference the same array object animals = birds; observe( animals[0][0] ); // processes Bird object
Because arrays are part of the class hierarchy, we can useinstanceof
to check the type of an array:if ( birds instanceof Animal[][] ) // true
An array is a type ofObject
and so can be assigned toObject
type variables:Object obj = animals;
Since Java knows the actual type of all objects, you can also cast back if appropriate:animals = (Animal [][])something;
Section 6.5.1.1: ArrayStoreException
Because arrays have the property that an array of one type is assignable to an array of its supertype, it is possible to play games with the compiler and try to trick it into storing the wrong kind of object in an array. Java may not be able to check the typesAdditional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Inner Classes
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterAll of the classes we've seen so far in this book have been top-level , "free standing" classes declared at the file and package level. But classes in Java can actually be declared at any level of scope, within any set of curly braces (i.e., almost anywhere that you could put any other Java statement). These inner classes belong to another class or method as a variable would and may have their visibility limited to its scope in the same way. Inner classes are a useful and aesthetically pleasing facility for structuring code. Their cousins, anonymous inner classes , are an even more powerful shorthand that make it seem as if you can create new kinds of objects dynamically within Java's statically typed environment. In Java, anonymous inner classes take the place of closures in other languages, giving the effect of handling state and behavior independently of classes.However, as we delve into their inner workings, we'll see that inner classes are not quite as aesthetically pleasing or dynamic as they seem. Inner classes are pure syntactic sugar; they are not supported by the VM but are instead mapped to regular Java classes by the compiler. As a programmer, you may never need be aware of this; you can simply rely on inner classes like any other language construct. However, you should know a little about how inner classes work to better understand the compiled code and a few potential side effects.Inner classes are essentially nested classes, for example:
Class Animal { Class Brain { ... } }
Here, the classBrain
is an inner class: it is a class declared inside the scope of classAnimal
. Although the details of what that means require a bit of explanation, we'll start by saying that Java tries to make the meaning, as much as possible, the same as for the other members (methods and variables) living at that level of scope. For example, let's add a method to theAnimal
class:Class Animal { Class Brain { ... } void performBehavior() { ... } }
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Chapter 7: Working with Objects and Classes
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterIn the previous two chapters, we came to know Java objects and their interrelationships. We will now climb the scaffolding of the Java class hierarchy to the very top and finish our study of the core language at the summit. In this chapter, we'll talk about the
Object
class itself, which is the "grandmother" of all classes in Java. We'll also describe the even more fundamentalClass
class (the class named "Class") that represents Java classes in the Java virtual machine. We'll discuss what you can do with these components in their own right. This will lead us to a more general topic: the Java Reflection API, which lets a Java program inspect and interact with (possibly unknown) objects dynamically, at runtime. Finally, we'll also talk about the Java Annotations API, new in Java 5.0, which allows developers to add metadata to their source code, for use by the compiler and runtime systems that look for it.java.lang.Object
is the ancestor of all objects; it's the primordial class from which all other classes are ultimately derived. Methods defined inObject
are, therefore, very important because they appear in every instance of every class, throughout all of Java. At last count, there were nine public methods and two protected methods inObject
. Five of these are versions ofwait()
andnotify()
that are used to synchronize threads on object instances, as we'll discuss in Chapter 9. The remaining four methods are used for basic comparison, conversion, and administration.Every object has atoString()
method that can be called when it's to be represented as a text value.PrintStream
objects usetoString()
to print data, as discussed in Chapter 12.toString()
is also used implicitly when an object is referenced in a string concatenation. Here are some examples:MyObj myObject = new MyObj(); Answer theAnswer = new Answer(); System.out.println( myObject ); String s = "The answer is: " + theAnswer ;
To be friendly, a new kind of object can overridetoString()
and implement its own version that provides appropriate information about itself. This is particularly helpful in debugging, where it is common to print the value of an object to see what is going on. Two other methods,Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - The Object Class
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapter
java.lang.Object
is the ancestor of all objects; it's the primordial class from which all other classes are ultimately derived. Methods defined inObject
are, therefore, very important because they appear in every instance of every class, throughout all of Java. At last count, there were nine public methods and two protected methods inObject
. Five of these are versions ofwait()
andnotify()
that are used to synchronize threads on object instances, as we'll discuss in Chapter 9. The remaining four methods are used for basic comparison, conversion, and administration.Every object has atoString()
method that can be called when it's to be represented as a text value.PrintStream
objects usetoString()
to print data, as discussed in Chapter 12.toString()
is also used implicitly when an object is referenced in a string concatenation. Here are some examples:MyObj myObject = new MyObj(); Answer theAnswer = new Answer(); System.out.println( myObject ); String s = "The answer is: " + theAnswer ;
To be friendly, a new kind of object can overridetoString()
and implement its own version that provides appropriate information about itself. This is particularly helpful in debugging, where it is common to print the value of an object to see what is going on. Two other methods,equals()
andhashCode()
, may also require specialization when you create a new class.equals()
determines whether two objects are equivalent. Precisely what that means for a particular class is something that you'll have to decide for yourself. TwoString
objects, for example, are considered equivalent if they hold precisely the same characters in the same sequence:String userName = "Joe"; ... if ( userName.equals( suspectName ) ) arrest( userName );
Usingequals()
is not the same as:if ( userName == suspectName ) // Wrong!
This statement tests whether the two reference variables,userName
andsuspectName
, refer to the same object. It is a test forAdditional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - The Class Class
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterA good measure of the complexity of an object-oriented language is the degree of abstraction of its class structures. We know that every object in Java is an instance of a class, but what exactly is a class? In languages like C++, objects are formulated by and instantiated from classes, but classes are really just artifacts of the compiler. In those languages, you see classes mentioned only in source code, not at runtime. By comparison, classes in Smalltalk are real, runtime entities in the language that are themselves described by "metaclasses" and "metaclass classes." Java strikes a happy medium between these two languages with what is effectively a two-tiered system that uses
Class
objects.Classes in Java source code are represented at runtime by instances of thejava.lang.Class
class. There's aClass
object for every object type you use; thisClass
object is responsible for producing instances of that type. But you don't generally have to worry about that unless you are interested in loading new kinds of classes dynamically at runtime or using a highly abstracted API that wants a "type" instead of an actual argument. TheClass
object is also the basis for "reflecting" on a class to find its methods and other properties, allowing you to find out about an object's structure or invoke its methods programmatically at runtime. We'll discuss reflection in the next section.We get theClass
associated with a particular object with thegetClass()
method:String myString = "Foo!" Class stringClass = myString.getClass();
We can also get theClass
reference for a particular class statically, using the.class
notation:Class stringClass = String.class;
The.class
reference looks like a static field that exists in every class. However, it is really resolved by the compiler.One thing we can do with theClass
object is ask for its full name:String s = "Boofa!"; Class stringClass = s.getClass(); System.out.println( stringClass.getName() ); // "java.lang.String"
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Reflection
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterIn this section, we'll take a look at the Java Reflection API, supported by the classes in the
java.lang.reflect
package. As its name suggests, reflection is the ability for a class or object to examine itself. Reflection lets Java code look at an object (more precisely, the class of the object) and determine its structure. Within the limits imposed by the security manager, you can find out what constructors, methods, and fields a class has, as well as their attributes. You can even change the value of fields, dynamically invoke methods, and construct new objects, much as if Java had primitive pointers to variables and methods. And you can do all this on objects that your code has never even seen before. In Java 5.0, the Annotations API also has the ability to preserve metadata about source code in the compiled classes and we can retrieve this information with the Reflection API.We don't have room here to cover the Reflection API fully. As you might expect, thereflect
package is complex and rich in details. But reflection has been designed so that you can do a lot with relatively little effort; 20% of the effort gives you 80% of the fun.The Reflection API is used by JavaBeans to determine the capabilities of objects at runtime. It's also used at a lower level by object serialization to tear apart and build objects for transport over streams or into persistent storage. Obviously, the power to pick apart objects and see their internals must be zealously guarded by the security manager. The general rule is that your code is not allowed to do anything with the Reflection API that it couldn't do with static (ordinary, compiled) Java code. In short, reflection is a powerful tool, but it isn't an automatic loophole. By default, an object can't use it to work with fields or methods that it wouldn't normally be able to access (for example, another object's private fields), although those privileges can be granted, as we'll discuss later.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Annotations
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterAs we mentioned in Chapter 4, Java for a long time has supported a limited kind of metadata in Java source code through the use of Javadoc comment tags. With Javadoc tags like
@deprecated
or@author
, we can add some information to a class, method, or field. In this case, the information is mainly useful to the Javadoc documentation generator, because comments exist only in Java source code. However, developers have long wanted a way to generalize metadata for other purposes. And in fact, some tools have been developed over the years that read extended Javadoc-style tags in comments and do all sorts of things with them, including code generation and documentation. In Java 5.0, a new formal, extensible metadata system called annotations has been added to the language that provides the Javadoc-style, source-level functionality as well as new possibilities for using metadata at runtime.Annotations allow you to add metadata to Java classes, methods, and fields. This metadata can be utilized by tools at compile time and optionally retained in the compiled Java classes for use at runtime as well. The availability of annotation data to the running program opens up new uses for metadata. For example, annotations cannot only be used at compile time to generate auxiliary classes or resources but also could be used by a server to provide special services to classes such as importing or exporting of values, security, or monitoring. Annotations will be used heavily in the Enterprise JavaBeans (EJB) Version 3 specification to simplify configuration and deployment information.Technically, according to the spec, annotations are not supposed to "directly affect the semantics of a program." However, that admonition is a little vague and there is some fear in the Java community that this facility will open a Pandora's box of possible abuses. Hopefully, developers will use them with restraint.Only a handful of "built-in" annotations are supplied with Java 5.0 and we'll summarize them in this section. Creating new annotations is syntactically easy, but implementing the behavior for them (via the compiler or a runtime system) is a bit beyond the scope of this book, so we won't cover that here. The Sun JDK provides a framework tool calledAdditional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Chapter 8: Generics
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterIt's been almost 10 years since the introduction of the Java programming language (and the first edition of this book). In that time, the Java language has matured and come into its own. But only with Java 5.0, the sixth major release of Java, did the core language itself change in a significant way. Yes, there were subtle changes and drop-ins over the years. Inner classes, added very early on, were important. But no language improvements prior to this point have affected all Java code or all Java developers in the way that Java 5.0 will.Generics are about abstraction. Generics let you create classes and methods that work in the same way on different types of objects. The term "generic" comes from the idea that we'd like to be able to write general algorithms that can be broadly reused for many types of objects rather than having to adapt our code to fit each circumstance. This concept is not new; it is the impetus behind object-oriented programming itself. Java generics do not so much add new capabilities to the language as they make reusable Java code easier to write and easier to read.Generics take reuse to the next level by making the type of the objects we work with an explicit parameter of the generic code. For this reason, generics are also referred to as parameterized types. In the case of a generic class, the developer specifies a type as a parameter (an argument) whenever she uses the generic type. The class is parameterized by the supplied type, to which the code adapts itself.In other languages, generics are sometimes referred to as templates, which is more of an implementation term. Templates are like intermediate classes, waiting for their type parameters so that they can be used. Java takes a different path, which has both benefits and drawbacks that we'll describe in detail in this chapter.There is much to say about Java generics and some of the fine points may be a bit obscure at first. But don't get discouraged. The vast majority of what you'll do with generics is easy and intuitive. The rest will come with a little patience and tinkering.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Containers: Building a Better Mousetrap
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterIn an object-oriented programming language like Java, polymorphism means that objects are always to some degree interchangeable. Any child of a type of object can serve in place of its parent type and, ultimately, every object is a child of
java.lang.Object
, the object-oriented "Eve," so to speak. It is natural, therefore, for the most general types of containers in Java to work with the typeObject
so that they can hold most anything. By containers, we mean classes that hold instances of other classes in some way. The Java Collections Framework is the best example of containers. AList
, for example, holds an ordered collection of elements of typeObject
. AMap
holds an association of key-value pairs, with the keys and values also being of the most general type,Object
. With a little help from wrappers for primitive types, this arrangement has served us well. But (not to get too Zen on you), in a sense, a "collection of any type" is also a "collection of no type," and working withObject
s pushes a great deal of responsibility onto the user of the container.It's kind of like a costume party for objects where everybody is wearing the same mask and disappears into the crowd of the collection. Once objects are dressed as theObject
type the compiler can no longer see the real types and loses track of them. It's up to the user to pierce the anonymity of the objects later using a type cast. And like attempting to yank off a party-goer's fake beard, you'd better have the cast correct or you'll get an unwelcome surprise.Date date = new Date(); List list = new ArrayList(); list.add( date ); ... Date firstElement = (Date)list.get(0); // Is the cast correct? Maybe.
TheList
interface has anadd()
method that accepts any type ofObject
. Here, we assigned an instance ofArrayList
, which is simply an implementation of theList
interface, and added aDate
object. Is the cast in this example correct? It depends on what happens in the elided "..." period of time.It's natural to ask if there is a way to make this situation better. What if we know that we are only going to putAdditional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Enter Generics
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterGenerics in Java are an enhancement to the syntax of classes that allow us to specialize the class for a given type or set of types. A generic class requires one or more type parameters wherever we refer to the class type and uses them to customize itself.If you look at the source or Javadoc for the
List
class, for example, you'll see it defined something like this:public class List< E > { ... public void add( E element ) { ... } public E get( int i ) { ... } }
The identifierE
between the angle brackets (<>
) is a type variable. It indicates that the classList
is generic and requires a Java type as an argument to make it complete. The nameE
is arbitrary, but there are conventions that we'll see as we go on. In this case, the type variableE
represents the type of elements we want to store in the list. TheList
class refers to the type variable within its body and methods as if it were a real type, to be substituted later. The type variable may be used to declare instance variables, arguments to methods, and the return type of methods. In this case,E
is used as the type for the elements we'll be adding via theadd()
method and the return type of theget()
method. Let's see how to use it.The same angle bracket syntax supplies the type parameter when we want to use theList
type:List<String> listOfStrings;
In this snippet, we declared a variable calledlistOfStrings
using the generic typeList
with a type parameter ofString
.String
refers to theString
class, but we could have specializedList
with any Java class type. For example:List<Date> dates; List<java.math.BigDecimal> decimals; List<Foo> foos;
Completing the type by supplying its type parameter is called instantiating the type. It is also sometimes called invoking the type, by analogy with invoking a method and supplying its arguments. Whereas with a regular Java type, we simply refer to the type by name, a generic type must be instantiated with parameters wherever it is used. Specifically this means we must instantiate the type everywhere types can appear: as the declared type of a variable (as shown in this code snippet), as the type of a method argument, as the return type of a method, or in an object allocation expression using theAdditional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - "There Is No Spoon"
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterIn the movie The Matrix, the hero Neo is offered a choice. Take the blue pill and remain in the world of fantasy or take the red pill and see things as they really are. In dealing with generics in Java, we are faced with a similar ontological dilemma. We can go only so far in any discussion of generics before we are forced to confront the reality of how they are implemented. Our fantasy world is one created by the compiler to make our lives writing code easier to accept. Our reality (though not quite the dystopian nightmare in the movie) is a harsher place, filled with unseen dangers and questions. Why don't casts and tests work properly with generics? Why can't I implement what appear to be two different generic interfaces in one class? Why is it that I can declare an array of generic types, even though there is no way in Java to create such an array?!? We'll answer these questions and more in this chapter, and you won't even have to wait for the sequel. Let's get started.The design goals for Java generics were formidable: add a radical new syntax to the language that introduces parameterized types, safely, with no impact on performance and, oh, by the way, make it backward-compatible with all existing Java code and don't change the compiled classes in any serious way. It's actually fairly amazing that these conditions could be satisfied at all and no surprise that it took a while. But as always, the compromises lead to some headaches.To accomplish this feat, Java employs a technique called erasure , which relates to the idea that since most everything we do with generics applies statically, at compile time, generic information does not really have to be carried over into the compiled classes. The generic nature of the classes, enforced by the compiler, can be "erased" in the compiled classes, allowing us to maintain compatibility with nongeneric code. While Java does retain information about the generic features of classes in the compiled form, this information is used mainly by the compiler. The Java runtime does not actually know anything about generics at all.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Parameterized Type Relationships
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterWe know now that parameterized types share a common, raw type. This is why our parameterized
List<Date>
is just aList
at runtime. In fact, we can assign any instantiation ofList
to the raw type if we want:List list = new ArrayList<Date>();
We can even go the other way and assign a raw type to a specific instantiation of the generic type:List<Date> dates = new ArrayList(); // unchecked warning
This statement generates an unchecked warning on the assignment, but thereafter the compiler trusts you that the list contained onlyDate
s prior to the assignment. It is also permissible, but pointless, to perform a cast in this statement. We'll talk about casting to generic types a bit later.Whatever the runtime types, the compiler is running the show and does not let us assign things that are clearly incompatible:List<Date> dates = new ArrayList<String>(); // Compile-time Error!
Of course, theArrayList<String>
does not implement the methods ofList<Date>
conjured by the compiler, so these types are incompatible.But what about more interesting type relationships? TheList
interface, for example, is a subtype of the more generalCollection
interface. Is a particular instantiation of the genericList
also assignable to some instantiation of the genericCollection
? Does it depend on the type parameters and their relationships? Clearly, aList<Date>
is not aCollection<String>
. But is aList<Date>
aCollection<Date>
? What about aList<Date>
being aCollection<Object>
?We'll just blurt out the answer first, then walk through it and explain. The rule is that for the simple types of generic instantiations we've discussed so far in this chapter inheritance applies only to the "base" generic type and not to the parameter types. Furthermore, assignability applies only when the two generic types are instantiated on exactly the same parameter type. In other words, there is still one-dimensional inheritance, following the base generic class type, but with the catch that the parameter types must be identical.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Casts
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterWe've now talked about relationships between generic types and even between generic types and raw types. But we haven't brought up the concept of a cast yet. No cast was necessary when we interchanged generics with their raw types. Instead, we just crossed a line that triggers unchecked warnings from the compiler:
List list = new ArrayList<Date>(); List<Date> dl = list; // unchecked warning
Normally, we use a cast in Java to work with two types that could be assignable. For example, we could attempt to cast anObject
to aDate
because it is plausible that theObject
is aDate
value. The cast then performs the check at runtime to see if we are correct. Casting between unrelated types is a compile-time error. For example, we can't even try to cast anInteger
to aString
. Those types have no inheritance relationship. What about casts between compatible generic types?Collection<Date> cd = new ArrayList<Date>(); List<Date> ld = (List<Date>)cd; // Ok!
This code snippet shows a valid cast from a more generalCollection<Date>
to aList<Date>
. The cast is plausible here because aCollection<Date>
is assignable from and could actually be aList<Date>
. Similarly, the following cast catches our mistake where we have aliased aTreeSet<Date>
as aCollection<Date>
and tried to cast it to aList<Date>
:Collection<Date> cd = new TreeSet<Date>(); List<Date> ld = (List<Date>)cd; // Runtime ClassCastException! ld.add( new Date() );
There is one case where casts are not effective with generics, however, and that is when we are trying to differentiate the types based on their parameter types:Object o = new ArrayList<String>(); List<Date> ldfo = (List<Date>)o; // unchecked warning, ineffective Date d = ldfo.get(0); // unsafe at runtime, implicit cast may fail
Here, we aliased anArrayList<String>
as a plainObject
. Next, we cast it to aList<Date>
. Unfortunately, Java does not know the difference between aList<String>
and aList<Date>
at runtime, so the cast is fruitless. The compiler warns us of this by generating an unchecked warning at the location of the cast; we should be aware that we might find out later when we try to use the cast object that it is incorrect. Casts are ineffective at runtime because of erasure and the lack of type information.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Writing Generic Classes
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterNow that we have (at least some of) the "end user" view of generics, let's try writing a few classes ourselves. In this section, we'll talk about how type variables are used in the definition of generic classes, where they may appear, and some of their limitations. We'll also talk about subclassing generic types.We've already seen the basics of how type variables are used in the declaration of a generic class. One or more type variables are declared in the angle bracket (<>) type declaration and used throughout the body and instance methods of the class. For example:
class Mouse { } class Bear { } class Trap< T > { T trapped; public void snare( T trapped ) { this.trapped = trapped; } public T release() { return trapped; } } // usage Trap<Mouse> mouseTrap = new Trap<Mouse>(); mouseTrap.snare( new Mouse() ); Mouse mouse = mouseTrap.release();
Here, we created a genericTrap
class that can hold any type of object. We used the type variableT
to declare an instance variable of the parameter type as well as in the argument type and return type of the two methods.The scope of the type variable is the instance portion of the class, including methods and any instance initializer blocks. The static portion of the class is not affected by the generic parameterization, and type variables are not visible in static methods or static initializers. As you might guess, just as all instantiations of the generic type have only one actual class (the raw type), they have only one, shared, static context as well. You cannot even invoke a static method through a parameterized type. You must use the raw type or an instance of the object.The type variable can also be used in the type instantiation of other generic types used by the class. For example, if we wanted ourTrap
to hold more than one animal, we could create aList
for them like so:List<T> trappedList = new ArrayList<T>();
Just to cover all the bases, we should mention that instantiations of generic types on the type variable act just like any other type and can serve in all the places that other instantiations of a type can. For example, a method in our class can take aAdditional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Bounds
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterIn the process of discussing generics, we've already had to mention bounds a few times. A bound is a constraint on the type of a type parameter. Bounds use the
extends
keyword and some new syntax to limit the parameter types that may be applied to a generic type. In the case of a generic class, the bounds simply limit the type that may be supplied to instantiate it.A type variable may extend a class or interface type, meaning that its instantiation must be of that type or a subtype:class EmployeeList< T extends Employee > { ... }
Here, we made a genericEmployeeList
type that can be instantiated only withEmployee
types. We could further require that theEmployee
type implement one or more interfaces using the special&
syntax:class EmployeeList< T extends Employee & Ranked & Printable > { ... }
The order of the&
interface bounds is not significant, but only one class type can be specified and if there is one, it must come first. When a type has no specific bounds, the boundextends Object
is implicit.By applying bounds to our type, we not only limit the instantiations of the generic class but we make the type arguments more useful. Now that we know our type must extend some type or implement some set of interfaces, we can use variables and arguments declared withT
by those other type names. Here is a somewhat contrived extension of our previous example:class EmployeeList< T extends Employee & Ranked & Printable > { Ranked ranking; List<Printable> printList = new ArrayList<Printable>(); public void addEmployee( T employee ) { this.ranking = employee; // T as Ranked printList.add( employee ); // T as Printable } }
Type variables can also refer to other type variables within the type declaration:class Foo <A, B extends A> { ... }
We'll see a particularly vicious example of this later when we talk about the definition of theEnum
class. We'll also see a more convenient technique for declaring how individual elements of a generic class relate to the parameter type when we cover wildcards in the next section.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Wildcards
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterWe mentioned earlier that the kinds of generic type instantiations discussed so far in this chapter have all been concrete type instantiations. We described this as meaning that all of the parameter arguments are real Java types. For example,
List<String>
andList<Date>
are instantiations of the genericList
class with the concrete typesString
andDate
. Now we're going to look at another kind of generic type instantiation : wildcard instantiation.As we'll see in this section, wildcards are Java's way of introducing polymorphism into the type parameter portion of the generic equation. A wildcard instantiation uses a question mark (?
) in place of an actual type parameter at instantiation time and denotes that the type can be assigned any of a range of possible instantiations of the generic type. The?
wildcard by itself is called the unbounded wildcard and denotes that any type instantiation is acceptable (assignable to the type).List<?> anyInstantiationOfList = new ArrayList<Date>(); anyInstantiationOfList = new ArrayList<String>(); // another instantiation
In this snippet, we declared a variableanyInstantiationOfList
whose type is the unbounded wildcard instantiation of the genericList
type. (What a mouthful.) This means that the type we instantiated can be assigned any particular concrete instantiation of theList
type, whetherDate
s,String
s, orFoo
s. Here, we assigned it aList<Date>
first and, subsequently, aList<String>
.The unbounded wildcard instantiation is a kind ofsupertype
of all of these concrete instantiations. In contrast to the generic type relationships that we saw earlier, which followed only raw, "base" generic types, wildcards let us implement polymorphism on the parameter types. The unbounded wildcard is to generic type parameters what theObject
type is to regular Java types: a supertype of everything.// A List<Object> is not a List<Date>! List<Object> objectList = new ArrayList<Date>() // Error! // A List<?> can be a List<Date> List<?> anyList = new ArrayList<Date>(); // Yes!
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Generic Methods
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterThus far in this chapter, we've talked about generic types and the implementation of generic classes. Now, we're going to look at a different kind of generic animal: generic methods . Generic methods essentially do for individual methods what type parameters do for generic classes. But as we'll see, generic methods are smarter and can figure out their parameter types from their usage context, without having to be explicitly parameterized. (In reality, of course, it is the compiler that does this.) Generic methods can appear in any class (not just generic classes) and are very useful for a wide variety of applications.First, let's quickly review the way that we've seen regular methods interact with generic types. We've seen that generic classes can contain methods that use type variables in their arguments and return types in order to adapt themselves to the parameterization of the class. We've also mentioned that generic types themselves can be used in most of the places that any other type can be used. So methods of generic or nongeneric classes can use generic types as argument and return types as well. Here are examples of those usages:
// Not generic methods class GenericClass< T > { // method using generic class parameter type public void T cache( T entry ) { ... } } class RegularClass { // method using concrete generic type public List<Date> sortDates( List<Date> dates ) { ... } // method using wildcard generic type public List<?> reverse( List<?> dates ) { ... } }
Thecache()
method inGenericClass
accepts an argument of the parameter typeT
and also returns a value of typeT
. ThesortDates()
method, which appears in the nongeneric example class, works with a concrete generic type, and thereverse()
method works with a wildcard instantiation of a generic type. These are examples of methods that work with generics, but they are not true generic methods.Like generic classes, generic methods have a parameter type declaration using theAdditional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Arrays of Parameterized Types
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterThere is one place where we haven't yet considered how generic types affect the Java language: array types. After everything we've seen, it would seem natural to expect that arrays of generic types would come along for the ride. But as we'll see, Java has a schizophrenic relationship with arrays of parameterized types.The first thing we need to do is recall how arrays work for regular Java types. An array is a kind of built-in collection of some base type of element. Furthermore, array types (including all multidimensional variations of the array) are true types in the Java language and are represented at runtime by unique class types. This is where the trouble begins. Although arrays in Java act a lot like generic collections (they change their APIs to adopt a particular type for "reading" and "writing"), they do not behave like Java generics with respect to their type relationships. As we saw in Chapter 6, arrays exist in the Java class hierarchy stemming from
Object
and extending down parallel branches with the plain Java objects.Arrays are covariant subtypes of other types of arrays, which means that, unlike concrete generic types, although they change their method signatures, they are still related to their parents. This means thatStrings []
in Java is a subtype ofObject []
. This brings up the aliasing problem that we mentioned earlier. An array ofString
s can be aliased as an array ofObject
s and we can attempt to put things into it illegally that won't be noticed until runtime:String [] strings = new String[5]; Object [] objects = strings; objects[0] = new Date(); // Runtime ArrayStoreException!
To prevent disaster, Java must check every array assignment for the correct type at runtime. But recall that generic types do not have real representations at runtime; there is only the raw type. So Java would have no way to know the difference between aTrap<Mouse>
and aTrap<Bear>
element in an array once the array was aliased as, say, anObject []
. For this reason, Java does not allow you to create arrays of generic types—at least not concrete ones. (More on that later in this chapter.)Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Case Study: The Enum Class
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterIf you take a look at the definition of the
java.lang.Enum
class in Java 5.0, you'll see a rather bizarre-looking generic type declaration:Enum< E extends Enum<E> > { ... }
In trying to parse this, you may be hampered by two thoughts, which we'll try to dispel right away. First, upon quick inspection this may appear to be recursive. The type variableE
seems to be defined as something that's not yet finished being defined. But it's not really. We often have mathematical equations of the formx = function( x )
and they are not recursive. What they really call out for is a special value ofx
that satisfies the condition. Next, although it's pretty clear thatE
is a subtype of some formulation of the genericEnum
type, you may jump to the conclusion thatE
itself must be a generic type. Remember that concrete types can extend generics just as well as generics can.With these thoughts in mind, let's hunt for some arrangement that satisfies these bounds. Let's focus only on the bound for a moment:E extends Enum<E>
E
is a subclass of some parameterization ofEnum
and, in particular, the parameterization ofEnum
is on the subclass type itself. To say this again, what it does is to require that any invocations of theEnum
type are by subclasses of some parameterization of theEnum
type. And specifically, the parameterizations of theEnum
type supply their own type as the type parameter to their parent,Enum
. What kind of class satisfies this condition?class Foo extends Enum<Foo> { }
ThisFoo
class does. The declaration ofFoo
, in fact, reads just as the bound does.Foo
is a plain concrete type that extendsEnum
parameterized by its own type.What does this accomplish exactly? The first implication of this arrangement is thatEnum
can be instantiated only by subclasses of itself. Next, we have the condition that theEnum
must be instantiated with the child type as its parameter type. This means that any methods of the parentEnum
class that refer to the type variableAdditional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Case Study: The sort() Method
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterPoking around in the
java.util.Collections
class we find all kinds of static utility methods for working with collections. Among them is this goody—the static generic methodsort()
:<T extends Comparable<? super T>> void sort( List<T> list ) { ... }
Another nut for us to crack. Let's focus on the last part of the bound:Comparable<? super T>
This is a wildcard instantiation of theComparable
interface, so we can read theextends
asimplements
, if it helps.Comparable
holds acompareTo()
method for some parameter type. AComparable<String>
means that thecompareTo()
method takes typeString
. Therefore,Comparable<? super T>
is the set of instantiations ofComparable
onT
and all of its superclasses. AComparable<T>
suffices and, at the other end, so does aComparable<Object>
. What this means in English is that the elements must be comparable to their own type or some supertype of their own type. This is sufficient to ensure that the elements can all be compared to one another, but not as restrictive as saying that they must all implement thecompareTo()
method themselves. Some of the elements may inherit theComparable
interface from a parent class that knows how to compare only to a supertype ofT
and that is exactly what is allowed here.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Conclusion
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterJava generics are a very powerful and useful addition to the language. Although some of the details we delved into later in this chapter may seem daunting, the common usage is very simple and compelling: generics make collections better. As you begin to write more code using generics you will find that your code becomes more readable and more understandable. Generics make explicit what previously had to be inferred from usage. They complete the promise of type safety in the Java language and make Java a better language, despite their idiosyncrasies.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Chapter 9: Threads
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterAt the heart of designing computer systems and software lies the problem of managing time. We take for granted that modern computer systems such as desktop computers can manage many applications running concurrently and produce the effect that the software is running simultaneously. Of course we know that, for the most part, our single processor computers can do only one thing at a time. The magic is performed by slight of hand in the operating system (OS), which juggles applications and turns its attention from one to the next so quickly that they appear to run at once.In the old days, the unit of concurrency for such systems was the application or process. To the OS, a process was more or less a black box that decided what do to on its own. If an application required greater concurrency, it could get it only by running multiple processes and communicating between them, but this was a heavyweight approach and not very elegant. Later, the concept of threads was introduced. Threads provide fine-grained concurrency within a process, under the application's own control. Threads have existed for a long time but have historically been tricky to use. In Java, support for threading is built into the language, making it easier to work with threads. In Java 5.0, a whole new set of utilities was introduced that address common patterns and practices in multithreaded applications and raise them to the level of tangible Java APIs. Collectively, this means that Java is a language that supports threading both natively and at a high level. It also means that Java's APIs take full advantage of threading, so it's important that you become familiar with these concepts early in your exploration of Java.Threads are integral to the design of many Java APIs, especially those involved in client-side applications, graphics, and sound. For example, when we look at GUI programming later in this book, you'll see that a component's
paint()
method isn't called directly by the application but rather by a separate drawing thread within the Java runtime system. At any given time, many such background threads may be performing activities in parallel with your application. On the server side, writing code that does explicit thread handling is less common and actively discouraged in the context of application servers and web applications. In those scenarios, the server environment should control the allocation of time. However, Java threads are there, servicing every request and running your application components. It's important to understand how your code fits into that environment.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Introducing Threads
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterConceptually, a thread is a flow of control within a program. A thread is similar to the more familiar notion of a process, except that threads within the same application are much more closely related and share much of the same state. It's kind of like a golf course, which many golfers use at the same time. The threads may cooperate to share a working area. They have access to the same objects including static and instance variables within their application. However, threads have their own copies of local variables, just as players share the golf course, but not personal things like clubs and balls.Multiple threads in an application have the same problems as the golfers—in a word, synchronization. Just as you can't have two sets of players blindly playing the same green at the same time, you can't have several threads trying to access the same variables without some kind of coordination. Someone is bound to get hurt. A thread can reserve the right to use an object until it's finished with its task, just as a golf party gets exclusive rights to the green until it's done. And a thread that is more important can raise its priority, asserting its right to play through.The devil is in the details, of course, and those details have historically made threads difficult to use. Fortunately, Java makes creating, controlling, and coordinating threads simpler by integrating some of these concepts directly into the language.It is common to stumble over threads when you first work with them because creating a thread exercises many of your new Java skills all at once. You can avoid confusion by remembering that two players are always involved in running a thread: a Java language
Thread
object that represents the thread itself and an arbitrary target object that contains the method the thread is to execute. Later, you will see that it is possible to play some sleight of hand and combine these two roles, but that special case just changes the packaging, not the relationship.All execution in Java is associated with aAdditional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Threading an Applet
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterApplets are embeddable Java applications that are expected to start and stop themselves on command, possibly many times in their lifetime. A Java-enabled web browser normally starts an applet when the applet is displayed and stops it when the user moves to another page or (in theory) when the user scrolls the applet out of view. To conform to this API, we would like an applet to cease its nonessential activity when it is stopped and resume it when started again. We'll talk about applets in Chapter 23, but it's not really essential to know about them here. We'll just use this as a more realistic example and as a transition to talk about our next topic, synchronization.In this section, we will build
UpdateApplet
, a simple base class for an applet that maintains a thread to automatically update its display at regular intervals.UpdateApplet
handles the basic creation and termination of the thread in the Applet'sstart()
andstop()
methods:public class UpdateApplet extends java.applet.Applet implements Runnable { Thread thread; boolean running; int updateInterval = 1000; public void run() { while ( running ) { repaint(); try { Thread.sleep( updateInterval ); } catch ( InterruptedException e ) { System.out.println("interrupted..."); return; } } } public void start() { System.out.println("starting..."); if ( !running ) // naive approach { running = true; thread = new Thread(this); thread.start(); } } public void stop() { System.out.println("stopping..."); thread.interrupt(); running = false; } }
UpdateApplet
is aRunnable
object that alternately sleeps and calls itsAdditional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Synchronization
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterEvery thread has a life of its own. Normally, a thread goes about its business without any regard for what other threads in the application are doing. Threads may be time-sliced, which means they can run in arbitrary spurts and bursts as directed by the operating system. On a multiprocessor system, it is even possible for many different threads to be running simultaneously on different CPUs. This section is about coordinating the activities of two or more threads so that they can work together and not collide in their use of the same variables and methods (coordinating their play on the golf course).Java provides a few simple structures for synchronizing the activities of threads. They are all based on the concept of monitors, a widely used synchronization scheme (developed by C.A.R. Hoare). You don't have to know the details about how monitors work to be able to use them, but it may help you to have a picture in mind.A monitor is essentially a lock. The lock is attached to a resource that many threads may need to access, but that should be accessed by only one thread at a time. It's very much like a restroom with a lock on the door. If the resource is not being used, the thread can acquire the lock and access the resource. That is, if the restroom is unlocked, you can enter and lock the door. When the thread is done, it relinquishes the lock, just as you unlock the door and leave it open for the next person. However, if another thread already has the lock for the resource, all other threads have to wait until the current thread finishes and releases the lock. This is just like when the restroom is occupied when you arrive: you have to wait until the current user is done and unlocks the door.Fortunately, Java makes the process of synchronizing access to resources fairly easy. The language handles setting up and acquiring locks; all you have to do is specify which resources require synchronization.The most common need for synchronization among threads in Java is to serialize their access to some resource (an object)—in other words, to make sure that only one thread at a time can manipulate an object or variable. In Java, every object has an associated lock. To be more specific, every class and every instance of a class has its own lock. TheAdditional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Scheduling and Priority
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterJava makes few guarantees about how it schedules threads. Almost all of Java's thread scheduling is left up to the Java implementation and, to some degree, the application. Although it might have made sense (and would certainly have made many developers happier) if Java's developers had specified a scheduling algorithm, a single scheduling algorithm isn't necessarily suitable for all the roles that Java can play. Instead, Sun decided to put the burden on you to write robust code that works whatever the scheduling algorithm, and let the implementation tune the algorithm for whatever is best.Therefore, the priority rules that we describe next are carefully worded in the Java language specification to be a general guideline for thread scheduling. You should be able to rely on this behavior overall (statistically), but it is not a good idea to write code that relies on very specific features of the scheduler to work properly. You should instead use the control and synchronization tools that we have described in this chapter to coordinate your threads.Every thread has a priority value. In general, any time a thread of a higher priority than the current thread becomes runnable (is started, stops sleeping, or is notified), it preempts the lower priority thread and begins executing. By default, threads with the same priority are scheduled round-robin, which means once a thread starts to run, it continues until it does one of the following:
- Sleeps, by calling
Thread.sleep()
orwait()
- Waits for a lock, in order to run a
synchronized
method - Blocks on I/O, for example, in a
read()
oraccept()
call - Explicitly yields control, by calling
yield()
- Terminates, by completing its target method or with a
stop()
call (deprecated)
This situation looks something like Figure 9-4.Figure 9-4: Priority preemptive, round-robin schedulingAt any given time, a thread is in one of five general states that encompass its lifecycle and activities. In Java 5.0, these states are made explicit through theThread.State
enumeration and theAdditional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Thread Groups
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterThe
ThreadGroup
class allows us to deal with threads wholesale: we can use it to arrange threads in groups and deal with the groups as a whole. A thread group can contain other thread groups, in addition to individual threads, so our arrangements can be hierarchical. Thread groups are particularly useful when we want to start a task that might create many threads of its own. By assigning the task a thread group, we can later identify and control all the task's threads. Thread groups are also the subject of restrictions that can be imposed by the Java Security Manager, so we can restrict a thread's behavior according to its thread group. For example, we can forbid threads in a particular group from interacting with threads in other groups. This is one way web browsers can prevent threads started by Java applets from stopping important system threads.When we create a thread, it normally becomes part of the thread group to which the currently running thread belongs. To create a new thread group of our own, we can call the constructor:ThreadGroup myTaskGroup = new ThreadGroup("My Task Group");
TheThreadGroup
constructor takes a name, which a debugger can use to help you identify the group. (You can also assign names to the threads themselves.) Once we have a group, we can put threads in the group by supplying theThreadGroup
object as an argument to theThread
constructor:Thread myTask = new Thread( myTaskGroup, taskPerformer );
Here,myTaskGroup
is the thread group, andtaskPerformer
is the target object (theRunnable
object that performs the task). Any additional threads thatmyTask
creates also belong to themyTaskGroup
thread group.TheThreadGroup
class exists so that you can control threads in batches. It has methods that parallel the basicThread
control methods—even the deprecatedstop()
,suspend()
, andresume()
. These methods operate on all the threads in a thread group. You can also mark a thread group as a "daemon"; a daemon thread group is automatically removed when all its children are gone. If a thread group isn't a daemon, you have to callAdditional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Thread Performance
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterThe way that applications use threads and the associated costs and benefits have greatly impacted the design of many Java APIs. We will discuss some of the issues in detail in other chapters. But it is worth briefly mentioning some aspects of thread performance and how the use of threads has dictated the form and functionality of several recent Java packages.The act of acquiring locks to synchronize threads, even when there is no contention, takes time. In older implementations of Java, this time could be significant. With newer VMs, it is almost negligible. However, unnecessary low-level synchronization can still slow applications by blocking threads where legitimate concurrent access otherwise could be allowed. Because of this, two important APIs, the Java Collections API and the Swing GUI API, were specifically crafted to avoid unnecessary synchronization, by placing it under the developer's control.The
java.util
Collections API replaces earlier, simple Java aggregate types—namelyVector
andHashtable
—with more fully featured and, notably, unsynchronized types (List
andMap
). The Collections API instead defers to application code to synchronize access to collections when necessary and provides special "fail fast" functionality to help detect concurrent access and throw an exception. It also provides synchronization "wrappers" that can provide safe access in the old style. In Java 5.0, special implementations of theMap
and newQueue
collections were added as part of thejava.util.concurrent
package. These implementations go even further in that they are written to allow a high degree of concurrent access without any user synchronization. We'll talk about these in Chapter 11.The Java Swing GUI, which grew out of AWT, has taken a different approach to providing speed and safety. Swing dictates that modification of its components (with notable exceptions) must all be done by a single thread: the main event queue. Swing solves performance problems as well as nasty issues of determinism in event ordering by forcing a single super-thread to control the GUI. The application may access the event queue thread indirectly by pushing commands onto a queue through a simple interface.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Concurrency Utilities
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterSo far in this chapter we've demonstrated how to create and synchronize threads at a low level, using Java language primitives. The
java.util.concurrent
package and subpackages introduced with Java 5.0 build on this functionality, adding important threading utilities and codifying some common design patterns by supplying standard implementations. Roughly in order of generality, these areas include:- Thread-aware Collections implementations
- The
java.util.concurrent
package augments the Java Collections API with several implementations for specific threading models. These include timed wait, blocking implementations of theQueue
interface, as well as nonblocking, concurrent-access optimized implementations of theQueue
andMap
interfaces. The package also adds "copy on write"List
andSet
implementations for extremely efficient "almost always read" cases. These may sound complex, but actually cover some fairly simple cases very well. We'll cover the Collections API in Chapter 11. - Executors
Executor
s run tasks, includingRunnable
s, and abstract the concept of thread creation and pooling from the user. Executors are intended to be a high-level replacement for the idiom of creating new threads to service a series of jobs. Along withExecutor
s, theCallable
andFuture
interfaces are introduced, which expand uponRunnable
to allow management, value return, and exception handling.- Locks
- The
java.util.concurrent.locks
package holds a set of classes includingLock
andCondition
that parallels the Java language-level synchronization primitives and promotes them to the level of a concrete API. The locks package also adds the concept of nonexclusive reader/writer locks, allowing for greater concurrency in synchronized data access. - High-level synchronization constructs
- This includes the classes
CyclicBarrier
,CountDownLatch
,Semaphore
, andExchanger
. These classes implement common synchronization patterns drawn from other languages and systems and can serve as the basis for new high-level tools.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Conclusion
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterJava was one of the first mainstream languages to provide support for threading at the language level and is now one of the first languages to standardize high-level threading utilities and APIs as well. In this chapter, we've covered both of these aspects. At this point, we've come to the end of our discussion of threads in Java and also, in a way, to the end of the first part of this book. In Chapters 1 through 9, we have discussed the Java language: its syntax and "built-in" features. In the rest of the book, we will focus mainly on the APIs and libraries that make up the rest of the Java platform. We will see that the real appeal of Java is the combination of this simple language married with powerful tools and standards.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Chapter 10: Working with Text
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterIf you've been reading this book sequentially, you've read all about the core Java language constructs, including the object-oriented aspects of the language and the use of threads. Now it's time to shift gears and start talking about the Java Application Programming Interface (API), the collection of classes that comprise the standard Java packages and come with every Java implementation. Java's core packages are one of its most distinguishing features. Many other object-oriented languages have similar features, but none has as extensive a set of standardized APIs and tools as Java does. This is both a reflection of and a reason for Java's success. Table 10-1 lists the most important packages in the API and shows which chapters discuss each of the packages.
Table 10-1: Java API packages PackageContentsChapterjava.lang
Basic language classes4-9java.lang.reflect
Reflection7java.util.concurrent
Thread utilities9java.text
java.util.regex
International text classes and regular expressions10java.util
Utilities and collections classesAdditional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Text-Related APIs
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterIn this chapter, we cover most of the special-purpose, text-related APIs in Java, from simple classes for parsing words and numbers to advanced text formatting, internationalization, and regular expressions. But since so much of what we do with computers is oriented around text, classifying APIs as strictly text-related can be somewhat arbitrary. Some of the text-related packages we cover in the next chapter include the Java Calendar API, the Properties and User Preferences APIs, and the Logging API. But probably the most important new tools in the text arena are those for working with the Extensible Markup Language, XML. In Chapter 24, we cover this topic in detail, along with the XSL/XSLT stylesheet language. Together they provide a powerful framework for rendering documents.Before we dive in, we should mention that one of the biggest developments in Java in a long time has been the introduction of printf style text formatting, introduced in Java 5.0. We call it "printf style" after the C language printf function, from which it was largely borrowed. Although this new formatting capability does not technically add many new features to Java, it is an important and highly anticipated addition that changes the "feel" of the language in a fundamental way. We'll show both the older and newer style tools in this chapter so that you can be familiar with both.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Strings
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterWe'll start by taking a closer look at the Java
String
class (or, more specifically,java.lang.String
). Since working withString
s is so fundamental, understanding the wayString
s are implemented in Java and what you can do with them is very important. AString
object encapsulates a sequence of Unicode characters. Internally, these characters are stored in a regular Java array, but theString
object guards this array jealously and gives you access to it only through its own API. This is to support the idea thatString
s are immutable; once you create aString
object, you can't change its value. Lots of operations on aString
object appear to change the characters or length of a string, but what they really do is return a newString
object that copies or internally references the needed characters of the original. Java implementations make an effort to consolidate identical strings used in the same class into a shared-string pool and to share parts ofString
s where possible.The original motivation for all of this was performance. ImmutableString
s can save memory and be optimized for speed by the Java VM. The flip side is that a programmer should have a basic understanding of theString
class in order to avoid creating an excessive number ofString
objects in places where performance is an issue. That was especially true in the past, when VMs were slow and handled memory poorly. Nowadays string usage is not usually an issue in the overall performance of a real application.Literal strings, defined in your source code, are declared with double quotes and can be assigned to aString
variable:String quote = "To be or not to be";
Java automatically converts the literal string into aString
object and assigns it to the variable.String
s keep track of their own length, soString
objects in Java don't require special terminators. You can get the length of aString
with thelength()
method:int length = quote.length();
String
s can take advantage of the only overloaded operator in Java, the+
operator, for string concatenation. The following code produces equivalent strings:Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Internationalization
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterThe Java VM lets us write code that executes in the same way on any Java platform. But in a global marketplace, that is only half the battle. A big question remains: will the application content and data be understandable to end users worldwide? Must users know English to use your application? The answer is that Java provides thorough support for localizing the text of your application for most modern languages and dialects. In this section, we'll talk about the concepts of internationalization (often abbreviated "I18N") and the classes that support them.Internationalization programming revolves around the
Locale
class. The class itself is very simple; it encapsulates a country code, a language code, and a rarely used variant code. Commonly used languages and countries are defined as constants in theLocale
class. (Maybe it's ironic that these names are all in English.) You can retrieve the codes or readable names, as follows:Locale l = Locale.ITALIAN; System.out.println(l.getCountry()); // IT System.out.println(l.getDisplayCountry()); // Italy System.out.println(l.getLanguage()); // it System.out.println(l.getDisplayLanguage()); // Italian
The country codes comply with ISO 3166. You will find a complete list of country codes athttps://www.chemie.fu-berlin.de/diverse/doc/ISO_3166.html
. The language codes comply with ISO 639. A complete list of language codes is online athttps://www.ics.uci.edu/pub/ietf/http/related/iso639.txt
. There is no official set of variant codes; they are designated as vendor-specific or platform-specific. You can get an array of all supportedLocale
s with the staticgetAvailableLocales()
method (which you might use to let your users choose). Or you can retrieve the defaultLocale
for the location where your code is running with the staticLocale.getDefault()
method and let the system decide for you.Many classes throughout the Java API use aLocale
to decide how to represent text. We ran into one earlier when talking about sorting text with theAdditional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Parsing and Formatting Text
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterParsing and formatting text is a large, open-ended topic. So far in this chapter, we've looked at only primitive operations on strings—creation, basic editing, searching, and turning simple values into strings. Now we'd like to move on to more structured forms of text. Java has a rich set of APIs for parsing and printing formatted strings, including numbers, dates, times, and currency values. We'll cover most of these topics in this chapter, but we'll wait to discuss date and time formatting until Chapter 11.We'll start with parsing—reading primitive numbers and values as strings and chopping long strings into tokens. Then we'll go the other way and look at formatting strings and the
java.text
package. We'll revisit the topic of internationalization to see how Java can localize parsing and formatting of text, numbers, and dates for particular locales. Finally, we'll take a detailed look at regular expressions, the most powerful text-parsing tool Java offers. Regular expressions let you define your own patterns of arbitrary complexity, search for them, and parse them from text.We should mention that you're going to see a great deal of overlap between the new formatting and parsing APIs (printf
and Scanner) introduced in Java 5.0 and the older APIs of thejava.text
package. The new APIs effectively replace much of the old ones and in some ways are easier to use. Nonetheless, it's good to know about both because so much existing code uses the older APIs.In Java, numbers and Booleans are primitive types—not objects. But for each primitive type, Java also defines a primitive wrapper class. Specifically, thejava.lang
package includes the following classes:Byte
,Short
,Integer
,Long
,Float
,Double
, andBoolean
. We'll talk about these in Chapter 1, but we bring them up now because these classes hold static utility methods that know how to parse their respective types from strings. Each of these primitive wrapper classes has a static "parse" method that reads aAdditional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Printf-Style Formatting
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterOne of the most anticipated new features in Java 5.0 is
printf
-style string formatting.printf
-style formatting utilizes special format strings embedded into text to tell the formatting engine where to place arguments and to give detailed specification about conversions, layout, and alignment. Theprintf
formatting methods also make use of variable-length argument lists, which makes working with them much easier. Here is a quick example ofprintf
-formatted output:System.out.printf( "My name is %s and I am %d years old\n", name, age );
As we mentioned,printf
formatting draws it name from the C languageprintf()
function, so if you've done any C programming, this will look familiar. Java has extended the concept, adding some additional type safety and convenience features. Although Java has had some text formatting capabilities in the past (we'll discuss thejava.text
package andMessageFormat
later),printf
formatting was not really feasible until variable-length argument lists and autoboxing of primitive types were added in Java 5.0.The primary new tool in our text formatting arsenal is thejava.util.Formatter
class and itsformat()
method. Several convenience methods can hide theFormatter
object from you and you may not need to create aFormatter
directly. First, the staticString.format()
method can be used to format aString
with arguments (like the C languagesprintf()
method):String message = String.format("My name is %s and I am %d years old.", name, age );
Next, thejava.io.PrintStream
andjava.io.PrintWriter
classes, which are used for writing text to streams, have their ownformat()
method. We discuss streams in Chapter 12, but this simply means that you can use this sameprintf
-style formatting for writing strings to any kind of stream, whether it be toSystem.out
standard console output, to a file, or to a network connection.In addition to theformat()
method,PrintStream
andPrintWriter
also have a version of the format method that is actually calledprintf().
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Formatting with the java.text Package
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterThe
java.text
package includes, among other things, a set of classes designed for generating and parsing string representations of objects. In this section, we'll talk about three classes:NumberFormat
,ChoiceFormat
, andMessageFormat
. Chapter 11 describes theDateFormat
class. As we said earlier, the classes of thejava.text
package overlap to a large degree with the capabilities of theScanner
andprintf
-styleFormatter
in Java 5.0. Despite these new features, a number of areas in the parsing of currencies, dates, and times can only be handled with thejava.text
package.TheNumberFormat
class can be used to format and parse currency, percentages, or plain old numbers.NumberFormat
is an abstract class, but it has several useful factory methods that produce formatters for different types of numbers. For example, to format or parse currency strings, usegetCurrencyInstance()
:double salary = 1234.56; String here = // $1,234.56 NumberFormat.getCurrencyInstance().format(salary); String italy = // L 1.234,56 NumberFormat.getCurrencyInstance(Locale.ITALY).format(salary);
The first statement generates an American salary, with a dollar sign, a comma to separate thousands, and a period as a decimal point. The second statement presents the same string in Italian, with a lire sign, a period to separate thousands, and a comma as a decimal point. Remember thatNumberFormat
worries about format only; it doesn't attempt to do currency conversion. (That would require, among other things, access to a dynamically updated table of exchange rates—a good opportunity for a Java bean but too much to ask of a simple formatter.) We can go the other way and parse a formatted value using theparse()
method, as we'll see in the next example.Likewise,getPercentInstance()
returns a formatter you can use for generating and parsing percentages. If you do not specify aLocale
when calling agetInstance()
method, the defaultLocale
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Regular Expressions
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterNow, it's time to take a brief detour on our trip through Java and enter the land of regular expressions. A regular expression, or regex for short, describes a text pattern. Regular expressions are used with many tools—including the
java.util.regex
package, text editors, and many scripting languages—to provide sophisticated text-searching and powerful string-manipulation capabilities.If you are already familiar with the concept of regular expressions and how they are used with other languages, you may wish to simply skim this section. At the very least, you'll need to look at the section "The java.util.regex API," later in this chapter, which covers the Java classes necessary to use them. On the other hand, if you've come to this point on your Java journey with a clean slate on this topic, and you're wondering exactly what regular expressions are, then pop open your favorite beverage and get ready. You are about to learn about the most powerful tool in the arsenal of text manipulation and what is, in fact, a tiny language within a language, all in the span of a few pages.A regular expression describes a pattern in text. By pattern, we mean just about any feature you can imagine identifying in text from the literal characters alone, without actually understanding their meaning. This includes features, such as words, word groupings, lines and paragraphs, punctuation, case, and more generally, strings and numbers with a specific structure to them, such as phone numbers, email addresses, and quoted phrases. With regular expressions you can search the dictionary for all the words that have the letter "q" without its pal "u" next to it, or words that start and end with the same letter. Once you have constructed a pattern, you can use simple tools to hunt for it in text or to determine if a given string matches it. A regex can also be arranged to help you dismember specific parts of the text it matched, which you could then use as elements of replacement text if you wish.Section 10.7.1.1: Write once, run away
Before moving on, we should say a few words about regular expression syntax in general. At the beginning of this section, we casually mentioned that we would be discussing a new language. Regular expressions do, in fact, comprise a simple form of programming language. If you think for a moment about the examples we cited earlier, you can see that something like a language is going to be needed to describe even simple patterns—such as email addresses—that have some variation in form.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Chapter 11: Core Utilities
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterIn this chapter, we'll continue our look at the core Java APIs, covering more of the tools of the
java.util
package. Thejava.util
package includes a wide range of utilities including tools for mathematical operations, working with dates and times, holding structured collections of objects, storing user preference data, and logging.Java supports integer and floating-point arithmetic directly in the language. Higher-level math operations are supported through thejava.lang.Math
class. As you may have seen by now, wrapper classes for primitive data types allow you to treat them as objects. Wrapper classes also hold some methods for basic conversions. Java provides thejava.util.Random
class for generating random numbers.First, a few words about built-in arithmetic in Java. Java handles errors in integer arithmetic by throwing anArithmeticException
:int zero = 0; try { int i = 72 / zero; } catch ( ArithmeticException e ) { // division by zero }
To generate the error in this example, we created the intermediate variablezero
. The compiler is somewhat crafty and would have caught us if we had blatantly tried to perform division by a literal zero.Floating-point arithmetic expressions, on the other hand, don't throw exceptions. Instead, they take on the special out-of-range values shown in Table 11-1.Table 11-1: Special floating-point values ValueMathematical representationPOSITIVE_INFINITY
1.0/0.0NEGATIVE_INFINITY
-1.0/0.0NaN
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Math Utilities
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterJava supports integer and floating-point arithmetic directly in the language. Higher-level math operations are supported through the
java.lang.Math
class. As you may have seen by now, wrapper classes for primitive data types allow you to treat them as objects. Wrapper classes also hold some methods for basic conversions. Java provides thejava.util.Random
class for generating random numbers.First, a few words about built-in arithmetic in Java. Java handles errors in integer arithmetic by throwing anArithmeticException
:int zero = 0; try { int i = 72 / zero; } catch ( ArithmeticException e ) { // division by zero }
To generate the error in this example, we created the intermediate variablezero
. The compiler is somewhat crafty and would have caught us if we had blatantly tried to perform division by a literal zero.Floating-point arithmetic expressions, on the other hand, don't throw exceptions. Instead, they take on the special out-of-range values shown in Table 11-1.Table 11-1: Special floating-point values ValueMathematical representationPOSITIVE_INFINITY
1.0/0.0NEGATIVE_INFINITY
-1.0/0.0NaN
0.0/0.0The following example generates an infinite result:double zero = 0.0; double d = 1.0/zero; if ( d == Double.POSITIVE_INFINITY ) System.out.println( "Division by zero" );
The special valueNaN
(not a number) indicates the result of dividing zero by zero. This value has the special mathematical distinction of not being equal to itself (Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Dates and Times
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterWorking with dates and times without the proper tools can be a chore. Fortunately, Java has three classes that handle most of the work for you. The
java.util.Date
class encapsulates a point in time. Thejava.util.GregorianCalendar
class, which extends the abstractjava.util.Calendar
, translates between a point in time and calendar fields like month, day, and year. Finally, thejava.text.DateFormat
class knows how to generate and parse string representations of dates and times in many languages.The separation of theDate
andGregorianCalendar
classes is analogous to having a class representing temperature and a class that translates that temperature to Celsius units. ADate
represents an absolute point in time as defined by a number of milliseconds from the reference point: midnight, Jan 1, 1970, GMT. This is the same frame of reference used by theSystem.currentTimeMillis()
call. ACalendar
encapsulates a point in time and maps it to higher-level (and messier) notions like years, months, weeks, and days, and deals with discontinuities like leap years. Conceivably, we could define other subclasses ofCalendar
, sayJulianCalendar
orLunarCalendar
, that map time using other sociological or cultural conventions.The defaultGregorianCalendar
constructor creates a calendar initialized to the current time, in the current time zone:GregorianCalendar now = new GregorianCalendar();
However, more generally we can just ask theCalendar
class for an appropriate calendar instance without worrying about what type of calendar system the world is using this century:Calendar now = Calendar.getInstance();
In either case, all the real work is done through the mainset()
andget()
methods ofCalendar
. These methods use static identifiers to refer to calendar fields and values. For example:Calendar birthday = Calendar.getInstance(); birthday.set( Calendar.YEAR, 1972 ); birthday.set( Calendar.MONTH, Calendar.MAY ); birthday.set( Calendar.DATE, 20 );
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Timers
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterJava includes two handy classes for timed code execution. If you write a clock application, for example, you might want to update the display every second. You might want to play an alarm sound at some predetermined time. You could accomplish these tasks using multiple threads and calls to
Thread.sleep()
. But thejava.util.Timer
andjava.util.TimerTask
classes handle this for you.TheTimer
class is a scheduler. Each instance ofTimer
has a single thread that runs in the background, watching the clock and executing one or moreTimerTask
s at appropriate times. You could, for example, schedule a task to run once, at a specific time like this:import java.util.*; public class Y2K { public static void main(String[] args) { Timer timer = new Timer(); TimerTask task = new TimerTask() { public void run() { System.out.println("Y2K!"); } }; Calendar cal = new GregorianCalendar( 2000, Calendar.JANUARY, 1 ); timer.schedule( task, cal.getTime()); } }
TimerTask
implements theRunnable
interface. To create a task, you can simply subclassTimerTask
and supply arun()
method. Here, we've created a simple anonymous subclass ofTimerTask
that prints a message toSystem.out
. Using theschedule()
method ofTimer
, we've asked that the task be run on January 1, 2000. If the scheduled time has already passed (as in our example), the task is run immediately.There are some other varieties ofschedule()
; you can run tasks once or at recurring intervals. There are two kinds of recurring tasks—fixed delay and fixed rate. Fixed delay means that a fixed amount of time elapses between the end of the task's execution and the beginning of the next execution. Fixed rate means that the task should begin execution at fixed time intervals. The difference comes into play when the time to execute the task is long relative to the interval. Keep in mind that tasks are executed by theTimer
's single scheduler thread. If one task takes a very long time, other tasks may be delayed, in which case, they run as soon as the thread becomes available.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Collections
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterCollections are fundamental to all kinds of programming. Anywhere we need to keep a group of objects, we have some kind of collection. At the most basic level, Java supports collections in the form of arrays. But since arrays have a fixed length, they are awkward for groups of things that grow and shrink over the lifetime of an application. Arrays also do not represent abstract relationships between objects well. In the early days, the Java platform had only two basic classes to address these needs: the
java.util.Vector
class, which represents a dynamic list of objects, and thejava.util.Hashtable
, class which holds a map of key/value pairs. Today, Java has a more comprehensive approach to collections called the Collections Framework. The older classes still exist, but they have been retrofitted into the framework (with some eccentricities).Though conceptually simple, collections are one of the most powerful parts of any programming language. Collections implement data structures that lie at the heart of managing complex information and relationships. A great deal of basic computer science is devoted to describing the most efficient ways to implement certain types of algorithms over collections. Having these tools at your disposal and understanding how to use them can make your code both much smaller and faster. It can also save you from reinventing the wheel.Prior to Java 5.0, the Collections Framework had two major drawbacks. The first was that collections were, of necessity, untyped and worked only with anonymousObject
s instead of real types likeDate
s andString
s. This meant that you had to perform a type cast every time you took an object out of a collection. In theory, this broke Java's compile-time type safety. In practice, this was less the problem than that it was just plain cumbersome and tedious. The second problem was that, for practical reasons, collections could work only with objects and not with primitive types. This meant that any time you wanted to put a number or other primitive type into a collection you had to store it in a wrapper class first and, of course, unpack it later upon retrieving it. The combination of these factors made code working with collections less readable and more dangerous to boot.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Properties
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterThe
java.util.Properties
class is a specialized hash table for strings. Properties are generally used to hold textual configuration data. Examples of this are the Java System properties , which are passed to a Java application on the command line. We'll cover those later. More generally, you can use aProperties
table to hold arbitrary configuration information for an application in an easily accessible format. The neat thing about aProperties
table is that it can load and store its information in text format using streams (see Chapter 12 for information on streams). As of Java 5.0,Properties
can also save themselves in XML format.Any string values can be stored as key/value pairs in aProperties
table. However, the convention is to use a dot-separated naming hierarchy to group property names into logical structures. (Unfortunately, this is just a convention, and you can't work with groups of properties in a hierarchical way as this might imply.) For example, you can create an emptyProperties
table and addString
key/value pairs just as you could with aMap
:Properties props = new Properties(); props.setProperty("myApp.xsize", "52"); props.setProperty("myApp.ysize", "79");
Thereafter, you can retrieve values with thegetProperty()
method:String xsize = props.getProperty( "myApp.xsize" );
If the named property doesn't exist,getProperty()
returnsnull
. You can get anEnumeration
of the property names with thepropertyNames()
method:for ( Enumeration e = props.propertyNames(); e.hasMoreElements; ) { String name = e.nextElement(); ... }
When you create aProperties
table, you can specify a second table for default property values:Properties defaults = ... Properties props = new Properties( defaults );
Now, when you callgetProperty()
, the method searches the default table if it doesn't find the named property in the current table. An alternative version ofgetProperty()
also accepts a default value; this value is returned instead ofAdditional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - The Preferences API
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterThe Java Preferences API accommodates the need to store both system and per-user configuration data persistently across executions of the Java VM. The Preferences API is like a portable version of the Windows registry, a mini database in which you can keep small amounts of information, accessible to all applications. Entries are stored as name/value pairs, where the values may be of several standard types including strings, numbers, Booleans, and even short byte arrays. We should stress that the Preferences API is not intended to be used as a true database and you can't store large amounts of data in it. (That's not to say anything about how it's actually implemented.)Preferences are stored logically in a tree. A preferences object is a node in the tree located by a unique path. You can think of preferences as files in a directory structure; within the file are stored one or more name/value pairs. To store or retrieve items, you ask for a preferences object for the correct path. Here is an example; we'll explain the node lookup shortly:
Preferences prefs = Preferences.userRoot().node("oreilly/learningjava"); prefs.put("author", "Niemeyer"); prefs.putInt("edition", 4); String author = prefs.get("author", "unknown"); int edition = prefs.getInt("edition", -1);
In addition to theString
andint
type accessors, there are the following get methods for other types:getLong()
,getFloat()
,getDouble()
,getByteArray()
, andgetBoolean()
. Each of these get methods takes a key name and default value to be used if no value is defined. And, of course, for each get method, there is a corresponding "put" method that takes the name and a value of the corresponding type. Providing defaults in the get methods is mandatory. The intent is for applications to function even if there is no preference information or if the storage for it is not available, as we'll discuss later.Preferences are stored in two separate trees: system preferences and user preferences.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - The Logging API
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterThe
java.util.logging
package provides a highly flexible and easy to use logging framework for system information, error messages, and fine-grained tracing (debugging) output. With the logging package, you can apply filters to select log messages, direct their output to one or more destinations (including files and network services), and format the messages appropriately for their consumers.Most importantly, much of this basic logging configuration can be set up externally at runtime through the use of a logging setup properties file or an external program. For example, by setting the right properties at runtime, you can specify that log messages are to be sent both to a designated file in XML format and also logged to the system console in a digested, human-readable form. Furthermore, for each of those destinations you can specify the level or priority of messages to be logged, discarding those below a certain threshold of significance. By following the correct source conventions in your code, you can even make it possible to adjust the logging levels for specific parts of your application, allowing you to target individual packages and classes for detailed logging without being overwhelmed by too much output. As of Java 5.0, the Logging API can even be controlled remotely via Java Management Extensions MBean APIs.Any good logging API must have at least two guiding principles. First, performance should not inhibit the developer from using log messages freely. As with Java language assertions (discussed in Chapter 4), when log messages are turned off, they should not consume any significant amount of processing time. This means there's no performance penalty for including logging statements as long as they're turned off. Second, although some users may want advanced features and configuration, a logging API must have some simple mode of usage that is convenient enough for time-starved developers to use in lieu of the old standbySystem.out.println()
. Java's Logging API provides a simple model and many convenience methods that make it very tempting.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Observers and Observables
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterThe
java.util.Observer
interface andjava.util.Observable
class are relatively small utilities, but they provide a glimpse of a fundamental design pattern in Java. Observers and observables are part of the MVC (Model-View-Controller) framework. It is an abstraction that lets a number of client objects (the observers) be notified whenever a certain object or resource (the observable) changes in some way. We will see this pattern used extensively in Java's event mechanism, covered in Chapters 16 through 19. Although these classes are not often used directly, it's worth looking at them to understand the pattern.TheObservable
object has a method anObserver
calls to register its interest. When a change happens, theObservable
sends a notification by calling a method in each of theObserver
s. The observers implement theObserver
interface, which specifies that notification causes anObserver
object'supdate()
method to be called.In the following example, we create aMessageBoard
object that holds aString
message.MessageBoard
extendsObservable
, from which it inherits the mechanism for registering observers (addObserver()
) and notifying observers (notifyObservers()
). To observe theMessageBoard
, we haveStudent
objects that implement theObserver
interface so that they can be notified when the message changes://file: MessageBoard.java import java.util.*; public class MessageBoard extends Observable { private String message; public String getMessage() { return message; } public void changeMessage( String message ) { this.message = message; setChanged(); notifyObservers( message ); } public static void main( String [] args ) { MessageBoard board = new MessageBoard(); Student bob = new Student(); Student joe = new Student(); board.addObserver( bob ); board.addObserver( joe ); board.changeMessage("More Homework!"); } } // end of class MessageBoard class Student implements Observer { public void update(Observable o, Object arg) { System.out.println( "Message board changed: " + arg ); } }
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Chapter 12: Input/Output Facilities
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterIn this chapter, we continue our exploration of the Java API by looking at many of the classes in the
java.io
andjava.nio
packages. These packages offer a rich set of tools for basic I/O and also provide the framework on which all file and network communication in Java is built.Figure 12-1 shows the class hierarchy of these packages.We start by looking at the stream classes injava.io
, which are subclasses of the basicInputStream
,OutputStream
,Reader
, andWriter
classes. Then we'll examine theFile
class and discuss how you can read and write files using classes injava.io
. We also take a quick look at the data compression classes provided injava.util.zip
. Finally, we begin our investigation of thejava.nio
package. The NIO, or "new" I/O, package (introduced in Java 1.4) adds significant new functionality for building high-performance services.Most fundamental I/O in Java is based on streams . A stream represents a flow of data, or a channel of communication with (at least conceptually) a writer at one end and a reader at the other. When you are working with thejava.io
package to perform terminal input and output, reading or writing files, or communicating through sockets in Java, you are using various types of streams. Later in this chapter, we look at the NIO package, which introduces a similar concept called a channel. But for now, let's summarize the available types of streams:-
InputStream
-
OutputStream
- Abstract classes that define the basic functionality for reading or writing an unstructured sequence of bytes. All other byte streams in Java are built on top of the basic
InputStream
andOutputStream
.Figure 12-1: The java.io package -
Reader
-
Writer
- Abstract classes that define the basic functionality for reading or writing a sequence of character data, with support for Unicode. All other character streams in Java are built on top of
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! -
- Streams
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterMost fundamental I/O in Java is based on streams . A stream represents a flow of data, or a channel of communication with (at least conceptually) a writer at one end and a reader at the other. When you are working with the
java.io
package to perform terminal input and output, reading or writing files, or communicating through sockets in Java, you are using various types of streams. Later in this chapter, we look at the NIO package, which introduces a similar concept called a channel. But for now, let's summarize the available types of streams:-
InputStream
-
OutputStream
- Abstract classes that define the basic functionality for reading or writing an unstructured sequence of bytes. All other byte streams in Java are built on top of the basic
InputStream
andOutputStream
.Figure 12-1: The java.io package -
Reader
-
Writer
- Abstract classes that define the basic functionality for reading or writing a sequence of character data, with support for Unicode. All other character streams in Java are built on top of
Reader
andWriter
. -
InputStreamReader
-
OutputStreamWriter
- "Bridge" classes that convert bytes to characters and vice versa according to a specific character encoding scheme. Remember: in Unicode, a character is not a byte!
-
DataInputStream
-
DataOutputStream
- Specialized stream filters that add the ability to read and write simple data types, such as numeric primitives and
String
objects in a universal format. -
ObjectInputStream
-
ObjectOutputStream
- Specialized stream filters that are capable of writing whole serialized Java objects and reconstructing them.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! -
- Files
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterWorking with files in Java is easy but poses some conceptual problems. In the real world, the host filesystem lies outside of Java's virtual environment, and can, therefore, still suffer from architecture and implementation differences. Java tries to mask some of these differences by providing information to help an application tailor itself to the local environment; we'll mention these areas as they come up. Later, we'll show you how to avoid these issues for read-only application files and resources by using the Java classpath to insulate you from the filesystem entirely.The
java.io.File
class encapsulates access to information about a file or directory. It can be used to get attribute information about a file, list the entries in a directory, and perform basic filesystem operations, such as removing a file or making a directory. While theFile
object handles these "meta" operations, it doesn't provide the API for reading and writing file data; there are specialized streams for that purpose.Section 12.2.1.1: File constructors
You can create an instance ofFile
from aString
pathname:File fooFile = new File( "/tmp/foo.txt" ); File barDir = new File( "/tmp/bar" );
You can also create a file with a relative path:File f = new File( "foo" );
In this case, Java works relative to the current working directory of the Java interpreter. You can determine the current working directory by checking theuser.dir
property in theSystem Properties
list:System.getProperty("user.dir")); // e.g., /users/pat
An overloaded version of theFile
constructor lets you specify the directory path and filename as separateString
objects:File fooFile = new File( "/tmp", "foo.txt" );
With yet another variation, you can specify the directory with aFile
object and the filename with aString
:File tmpDir = new File( "/tmp" ); // File for directory /tmp File fooFile = new File ( tmpDir, "foo.txt" );
None of theseFile
constructors actually creates a file or directory, and it isn't an error to create aAdditional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Serialization
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterUsing a
DataOutputStream
, you could write an application that saves the data content of your objects as simple types. However, Java provides an even more powerful mechanism called object serialization that does almost all the work for you. In its simplest form, object serialization is an automatic way to save and load the state of an object. However, object serialization has depths that we cannot plumb within the scope of this book, including complete control over the serialization process and interesting conundrums such as class versioning.Basically, an instance of any class that implements theSerializable
interface can be saved to and restored from a stream. Special stream subclasses,ObjectInputStream
andObjectOutputStream
, are used to serialize primitive types and objects. Subclasses ofSerializable
classes are also serializable. The default serialization mechanism saves the value of all of the object's fields, except those that are static and those marked transient .One of the most important (and tricky) things about serialization is that when an object is serialized, any object references it contains are also serialized. Serialization can capture entire "graphs" of interconnected objects and put them back together on the receiving end (we'll demonstrate this in an upcoming example). The implication is that any object we serialize must contain only references to otherSerializable
objects. We can take control by marking nonserializable variables astransient
or overriding the default serialization mechanisms. Thetransient
modifier can be applied to any instance variable to indicate that its contents are not useful outside of the current context and should never be saved.In the following example, we create aHashtable
and write it to a disk file called hash.ser. TheHashtable
object is already serializable because it implements theSerializable
interface.//file: Save.java import java.io.*; import java.util.*; public class Save { public static void main(String[] args) { Hashtable hash = new Hashtable(); hash.put("string", "Gabriel Garcia Marquez"); hash.put("int", new Integer(26)); hash.put("double", new Double(Math.PI)); try { FileOutputStream fileOut = new FileOutputStream( "hash.ser" ); ObjectOutputStream out = new ObjectOutputStream( fileOut ); out.writeObject( hash ); out.close(); } catch (Exception e) { System.out.println(e); } } }
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Data Compression
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterThe
java.util.zip
package contains classes you can use for data compression . In this section, we'll talk about how to use these classes. We'll also present two useful example programs that build on what you have learned about streams and files. The classes in thejava.util.zip
package support two widespread compression formats: GZIP and ZIP.Thejava.util.zip
package provides two filter streams for writing compressed data. TheGZIPOutputStream
is for writing data in GZIP compressed format. TheZIPOutputStream
is for writing compressed ZIP archives, which can contain one or many files. To write compressed data in the GZIP format, simply wrap aGZIPOutputStream
around an underlying stream and write to it. The following is a complete example that shows how to compress a file using the GZIP format://file: GZip.java import java.io.*; import java.util.zip.*; public class GZip { public static int sChunk = 8192; public static void main(String[] args) { if (args.length != 1) { System.out.println("Usage: GZip source"); return; } // create output stream String zipname = args[0] + ".gz"; GZIPOutputStream zipout; try { FileOutputStream out = new FileOutputStream(zipname); zipout = new GZIPOutputStream(out); } catch (IOException e) { System.out.println("Couldn't create " + zipname + "."); return; } byte[] buffer = new byte[sChunk]; // compress the file try { FileInputStream in = new FileInputStream(args[0]); int length; while ((length = in.read(buffer, 0, sChunk)) != -1) zipout.write(buffer, 0, length); in.close(); } catch (IOException e) { System.out.println("Couldn't compress " + args[0] + "."); } try { zipout.close(); } catch (IOException e) {} } }
First, we check to make sure we have a command-line argument representing a filename. We then construct aAdditional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - The NIO Package
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterThe
java.nio
package was introduced in Java 1.4. The name NIO stands for "new I/O," which may seem to imply that it is to be a replacement for thejava.io
package. In fact, much of the NIO functionality overlaps with existing APIs. NIO was added primarily to address specific issues of scalability for large systems, especially in networked applications. That said, NIO also provides several new features Java lacked in basic I/O, so you'll want to look at some tools here even if you aren't planning to write any large or high-performance services. The following sections outline the primary features of NIO.Most of the need for the NIO package was driven by the desire to add nonblocking and selectable I/O to Java. Prior to NIO, most read and write operations in Java were bound to threads and were forced to block for unpredictable amounts of time. Although certain APIs such as Sockets (which we'll see in Chapter 13) provided specific means to limit how long an I/O call could take, this was a workaround to compensate for the lack of a more general mechanism. Prior to the introduction of threads, in many languages I/O could still be done efficiently by setting I/O streams to a nonblocking mode and testing them for their readiness to send or receive data. In a nonblocking mode, a read or write does only as much work as can be done immediately—filling or emptying a buffer and then returning. Combined with the ability to test for readiness, this allows a single thread to continuously service many channels efficiently. The main thread "selects" a stream that is ready and works with it until it blocks and then moves to another. On a single-processor system, this is fundamentally equivalent to using multiple threads. Even now, this style of processing has scalability advantages when using a pool of threads (rather than just one). We'll discuss this in detail in Chapter 13 when we discuss networking and building servers that can handle many clients simultaneously.In addition to nonblocking and selectable I/O, the NIO package enables closing and interrupting I/O operations asynchronously. As discussed in Chapter 9, prior to NIO there was no reliable way to stop or wake up a thread blocked in an I/O operation. With NIO, threads blocked in I/O operations always wake up when interrupted or when the channel is closed by anyone. Additionally, if you interrupt a thread while it is blocked in an NIO operation, its channel is automatically closed. (Closing the channel because the thread is interrupted might seem too strong, but usually it's the right thing to do.)Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Chapter 13: Network Programming
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterThe network is the soul of Java. Most of what is interesting about Java centers around the potential for dynamic, networked applications. As Java's networking APIs have matured, Java has also become the language of choice for implementing traditional client-server applications and services. In this chapter, we start our discussion of the
java.net
package, which contains the fundamental classes for communications and working with networked resources (we'll finish this discussion in Chapter 14). This chapter next discusses thejava.rmi
package, which provides Java's powerful, high-level, Remote Method Invocation (RMI) facilities. Finally, building on the material in Chapter 12, we complete our discussion of thejava.nio
package, which is highly efficient for implementing large servers.The classes ofjava.net
fall into two general categories: the Sockets API for working with low-level Internet protocols and higher-level, web-oriented APIs that work with uniform resource locators (URLs). Figure 13-1 shows thejava.net
package.Java's Sockets API provides access to the standard network protocols used for communications between hosts on the Internet. Sockets are the mechanism underlying all other kinds of portable networked communications. Sockets are the lowest-level tool—you can use sockets for any kind of communications between client and server or peer applications on the Net, but you have to implement your own application-level protocols for handling and interpreting the data. Higher-level networking tools, such as remote method invocation, HTTP, and web services are implemented on top of sockets.Java RMI is a powerful tool that leverages Java object serialization, allowing you to transparently work with objects on remote machines almost as if they were local. With RMI, it is easy to write distributed applications in which clients and servers work with each other's data as full-fledged Java objects rather than raw streams or packets of data. Technologies like Enterprise JavaBeans build on RMI and extend its semantics, so it is very important to understand the concepts involved.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Sockets
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterSockets are a low-level programming interface for networked communications. They send streams of data between applications that may or may not be on the same host. Sockets originated in BSD Unix and are, in other programming languages, hairy, complicated things with lots of small parts that can break off and choke little children. The reason for this is that most socket APIs can be used with almost any kind of underlying network protocol. Since the protocols that transport data across the network can have radically different features, the socket interface can be quite complex.The
java.net
package supports a simplified, object-oriented socket interface that makes network communications considerably easier. If you have done network programming using sockets in other languages, you should be pleasantly surprised at how simple things can be when objects encapsulate the gory details. If this is the first time you've come across sockets, you'll find that talking to another application over the network can be as simple as reading a file or getting user input. Most forms of I/O in Java, including most network I/O, use the stream classes described in Chapter 12. Streams provide a unified I/O interface so that reading or writing across the Internet is similar to reading or writing on the local system. In addition to the stream-oriented interfaces, the Java networking APIs can work with the Java NIO buffer-oriented API for highly scalable applications. We'll see both in this chapter.Java provides sockets to support three distinct classes of underlying protocols:Socket
s,DatagramSocket
s, andMulticastSocket
s. In this first section, we look at Java's basicSocket
class, which uses a connection-oriented and reliable protocol. A connection-oriented protocol provides the equivalent of a telephone conversation. After establishing a connection, two applications can send streams of data back and forth and the connection stays in place even when no one is talking. Because the protocol is reliable, it also ensures that no data is lost (resending data as necessary) and that whatever you send always arrives in the order that you sent it.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Datagram Sockets
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapter
TinyHttpd
used aSocket
to create a connection to the client using the TCP protocol. In that example, the TCP protocol took care of data integrity; we didn't have to worry about data arriving out of order or incorrect. Now, let's take a walk on the wild side, building an applet that uses ajava.net.DatagramSocket
, which uses the UDP protocol. A datagram is sort of like a letter sent via the postal service: it's a discrete chunk of data transmitted in one packet. Unlike the previous example, where we could get a convenientOutputStream
from ourSocket
and write the data as if writing to a file, with aDatagramSocket
, we have to work one datagram at a time. (Of course, the TCP protocol was taking ourOutputStream
and slicing the data into packets, too, but we didn't have to worry about those details.)UDP doesn't guarantee that the data is received. If the data packets are received, they may not arrive in the order in which they were sent; it's even possible for duplicate datagrams to arrive (under rare circumstances). Using UDP is something like cutting the pages out of the encyclopedia, putting them into separate envelopes, and mailing them to your friend. If your friend wants to read the encyclopedia, it's his or her job to put the pages in order. If some pages get lost in the mail, your friend has to send you a letter asking for replacements.Obviously, you wouldn't use UDP to send a huge amount of data without error correction. However, it's significantly more efficient than TCP, particularly if you don't care about the order in which messages arrive or whether 100 percent of their arrival is guaranteed. For example, in a simple periodic database lookup, the client can send a query; the server's response itself constitutes an acknowledgment. If the response doesn't arrive within a certain time, the client can just send another query. It shouldn't be hard for the client to match responses to its original queries. Some important applications that use UDP are the Domain Name System (DNS) and Sun's Network File System (NFS).Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Simple Serialized Object Protocols
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterEarlier in this chapter, we showed a hypothetical conversation in which a client and server exchanged some primitive data and a serialized Java object. Passing an object between two programs may not have seemed like a big deal at the time, but, in the context of Java as a portable bytecode language, it has profound implications. In this section, we show how a protocol can be built using serialized Java objects.Before we move on, it's worth considering network protocols . Most programmers would consider working with sockets to be tedious and complex. Even though Java makes sockets much easier to use than many other languages, sockets still provide only an unstructured flow of bytes between their endpoints. If you want to do serious communications using sockets, the first thing you have to do is come up with a protocol that defines the data you are sending and receiving. The most complex part of that protocol usually involves how to marshal (package) your data for transfer over the Net and unpack it on the other side.As we've seen, Java's
DataInputStream
andDataOuputStream
classes solve this problem for simple data types. We can read and write numbers,String
s, and Java primitives in a standard format that can be understood on any other Java platform. To do real work, we need to be able to put simple types together into larger structures. Java object serialization solves this problem elegantly by allowing us to send our data in the state that we will use it—as Java objects. Serialization can even pack up entire graphs of interconnected objects and put them back together at a later time in another Java VM.In the following example, a client sends a serialized object to the server, and the server responds in kind. The object sent by the client represents a request and the object returned by the server represents the response. The conversation ends when the client closes the connection. It's hard to imagine a simpler protocol. All the hairy details are taken care of by object serialization, which allows us to work with standard Java objects as we are used to.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Remote Method Invocation
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterThe most fundamental means of communication in Java is method invocation. Mechanisms such as the Java event model are built on simple method invocations between objects in the same virtual machine. Therefore, when we want to communicate between virtual machines on different hosts, it's natural to want a mechanism with similar capabilities and semantics. Java's RMI mechanism does just that. It lets us get a reference to an object on a remote host and use it almost as if it were in our own virtual machine. RMI lets us invoke methods on remote objects, passing real Java objects as arguments and getting real Java objects as returned values.Remote invocation is nothing new. For many years, C programmers have used remote procedure calls (RPC) to execute a C function on a remote host and return the results. The primary difference between RPC and RMI is that RPC, an offshoot of the C language, is primarily concerned with data structures. It's relatively easy to pack up data and ship it around, but for Java, that's not enough. In Java we don't just work with data structures; we work with objects that contain both data and methods for operating on the data. Not only do we have to be able to ship the state of an object (the data) over the wire, but the recipient has to be able to interact with the object (use its methods) after receiving it. With Java RMI, you can work with network services in an object-oriented fashion, using real, extensible types and pass "live" references between client and server.It should be no surprise that RMI uses object serialization, which allows us to send graphs of objects (objects and all the connected objects that they reference). When necessary, RMI can also use dynamic class loading and the security manager to transport Java classes safely. In addition to making remote method calls almost as easy to use as local calls, RMI makes it possible to ship both data and behavior (code) around the Net.Before an object can be used remotely through RMI, it must be serializable. But that's not sufficient. Remote objects in RMI are real distributed objects. As the name suggests, a remote object can be an object on a different machine or an object on the local host. The termAdditional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Scalable I/O with NIO
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterWe'll now conclude the discussion of the NIO package we began in Chapter 12 by talking about nonblocking and selectable network communications. All our server examples in this chapter have used a thread-bound pattern (one thread per I/O operation). In Java this is very natural because of the ease with which we can create threads. It's also very efficient, within limits. Problems arise when you try to build very large-scale servers using this style of client handling. While on a large machine it's certainly possible to have hundreds or even thousands of threads (especially if they're mostly idle, waiting for I/O), this is a resource-hungry solution. Every thread you start in Java consumes memory for its internal stack, and the performance of managing this number of threads is highly system-dependent.An alternative approach is to take a lesson from the old, dark days before threading was available and use nonblocking I/O operations to manage a lot of communications from a single thread. Better yet, our server uses a configurable pool of threads, taking advantage of machines with many processors.At the heart of this process is the concept of selectable I/O. It's not good enough to simply have nonblocking I/O operations if you have no way to efficiently poll for work to be done. The NIO package provides for efficient polling using selectable channels. A selectable channel allows for the registration of a special kind of listener called a selector that can check the readiness of the channel for operations, such as reading and writing or accepting or creating network connections.The selector and the selection process are not typical Java listeners of the kind we'll see elsewhere in this book but instead rather slavishly follow the conventions of C language systems. This is mainly for performance reasons; since this API is primarily intended for high-volume servers, it is bound very tightly to the traditional, underlying operating system facilities with less regard for ease of use. This, combined with the other details of using the NIO package, mean that this section is somewhat dense and the server we create here is one of the longer and more complex examples in the book. Don't be discouraged if you are a bit put off by this section. You can use the general techniques earlier in this chapter for most applications and reserve this knowledge for creating services that handle very high volumes of simultaneous client requests.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Chapter 14: Programming for the Web
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterWhen you think about the Web, you probably think of applications—web browsers, web servers—and the many kinds of content that those applications move around the network. But it's important to note that standards and protocols, not the applications themselves, have enabled the Web's growth. Since the earliest days of the Internet, there have been ways to move files from here to there, and document formats that were just as powerful as HTML, but there was not a unifying model for how to identify, retrieve, and display information nor was there a universal way for applications to interact with that data over the network. Since the web explosion began, HTML has reigned supreme as a common format for documents, and most developers have at least some familiarity with it. In this chapter, we're going to talk a bit about its cousin, HTTP, the protocol that handles communications between web clients and servers, and URLs, which provide a standard for naming and addressing objects on the Web. Java provides a very simple API for working with URLs to address objects on the Web. We'll discuss how to write web clients that can interact with the servers using the HTTP
GET
andPOST
methods and also say a bit about web services, which are the next step up the evolutionary chain. In Chapter 15, we'll jump over to the server side and take a look at servlets, Java programs that run on web servers and implement the other side of these conversations.A URL points to an object on the Internet. It's a text string that identifies an item, tells you where to find it, and specifies a method for communicating with it or retrieving it from its source. A URL can refer to any kind of information source. It might point to static data, such as a file on a local filesystem, a web server, or an FTP site; or it can point to a more dynamic object such as an RSS news feed or a record in a database. URLs can even refer to less tangible resources such as Telnet sessions and email addresses.Since there are many different ways to locate an item on the Net and different mediums and transports require different kinds of information, URLs can have many forms. The most common form has four components: a network host or server, the name of the item, its location on that host, and a protocol by which the host should communicate:Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Uniform Resource Locators (URLs)
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterA URL points to an object on the Internet. It's a text string that identifies an item, tells you where to find it, and specifies a method for communicating with it or retrieving it from its source. A URL can refer to any kind of information source. It might point to static data, such as a file on a local filesystem, a web server, or an FTP site; or it can point to a more dynamic object such as an RSS news feed or a record in a database. URLs can even refer to less tangible resources such as Telnet sessions and email addresses.Since there are many different ways to locate an item on the Net and different mediums and transports require different kinds of information, URLs can have many forms. The most common form has four components: a network host or server, the name of the item, its location on that host, and a protocol by which the host should communicate:
protocol://hostname/path/item-name
protocol (also called the "scheme") is an identifier such ashttp
orftp
, hostname is usually an internet hostname, and the path and item components form a unique path that identifies the object on that host. Variants of this form allow extra information to be packed into the URL, specifying, for example, port numbers for the communications protocol and fragment identifiers that reference sections inside documents. Other more specialized types of URLs such as "mailto" URLs for email addresses or URLs for addressing things like database components may not follow this format precisely but do conform to the general notion of a protocol followed by a unique identifier.Since most URLs have the notion of a hierarchy or path, we sometimes speak of a URL that is relative to another URL, called a base URL. In that case, we are using the base URL as a starting point and supplying additional information to target an object relative to that URL. For example, the base URL might point to a directory on a web server; a relative URL might name a particular file in that directory or in a subdirectory.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - The URL Class
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterBringing this down to a more concrete level is the Java URL class. The URL class represents a URL address and provides a simple API for accessing web resources, such as documents and applications on servers. It can use an extensible set of protocol and content handlers to perform the necessary communication and even data conversion. With the URL class, an application can open a connection to a server on the network and retrieve content with just a few lines of code. As new types of servers and new formats for content evolve, additional URL handlers can be supplied to retrieve and interpret the data without modifying your applications.A URL is represented by an instance of the
java.net.URL
class. AURL
object manages all the component information within a URL string and provides methods for retrieving the object it identifies. We can construct aURL
object from a URL string or from its component parts:try { URL aDoc = new URL( "https://foo.bar.com/documents/homepage.html" ); URL sameDoc = new URL("http","foo.bar.com","documents/homepage.html"); } catch ( MalformedURLException e ) { }
These twoURL
objects point to the same network resource, the homepage.html document on the server foo.bar.com. Whether the resource actually exists and is available isn't known until we try to access it. When initially constructed, theURL
object contains only data about the object's location and how to access it. No connection to the server has been made. We can examine the various parts of theURL
with thegetProtocol()
,getHost()
, andgetFile()
methods. We can also compare it to anotherURL
with thesameFile()
method (which has an unfortunate name for something which may not point to a file).sameFile()
determines whether two URLs point to the same resource. It can be fooled, butsameFile()
does more than compare the URL strings for equality; it takes into account the possibility that one server may have several names as well as other factors. (It doesn't go as far as to fetch the resources and compare them, however.)Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Talking to Web Applications
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterWeb browsers are the universal clients for web applications. They retrieve documents for display and serve as a user interface, primarily through the use of HTML forms and linked documents. Next, we show how to write client-side Java code that uses HTTP through the
URL
class to work with web applications directly usingGET
andPOST
operations to retrieve and send data. Later in this chapter, we'll begin a discussion of web services, which marry HTTP with XML to enable cross-platform application-to-application communications using web standards.There are many reasons an application (or applet) might want to communicate via HTTP. For example, compatibility with another browser-based application might be important, or you might need to gain access to a server through a firewall where direct socket connections (and, hence, RMI or IIOP) are not available. HTTP is the lingua franca of the Net and despite its limitations (or more likely because of its simplicity), it has rapidly become one of the most widely supported protocols in the world. As for using Java on the client side, all the other reasons you would write a client GUI application (as opposed to a pure Web/HTML-based application) also present themselves. A client-side GUI can do sophisticated presentation and validation while, with the techniques presented here, still use web-enabled services over the network.The primary task we discuss here is sending data to the server, specifically HTML form-encoded data. In a web browser, the name/value pairs of HTML form fields are encoded in a special format and sent to the server using one of two methods. The first method, using the HTTPGET
command, encodes the user's input into the URL and requests the corresponding document. The server recognizes that the first part of the URL refers to a program and invokes it, passing along the information encoded in the URL as a parameter. The second method uses the HTTPPOST
command to ask the server to accept the encoded data and pass it to a web application as a stream. In Java, we can create a URL that refers to a server-side program and request or send it data using theAdditional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Web Services
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterWeb services is a big, fast-moving topic and really the subject for another book entirely. However, since we have already covered so many of the basic networking concepts (and cover XML in detail in Chapter 24), we would be shirking our duties if we didn't provide an introduction to this important direction in application development. We conclude this chapter on client-side web communications with a small example of invoking a web service.In contrast to regular web applications intended to be visited by web browsers, web services are application-level APIs intended to be invoked by other application components. The primary distinction from other types of interapplication communications mechanisms is that they use web standards and XML to maximize cross-platform interoperability. We will leave the analysis of when exactly this is important and the cost versus benefits tradeoffs out of our discussion here. But the value in this idea should be evident from the explosion of web-based business applications in the past few years. Web services allow web-based applications to provide well-defined, "hardened" interfaces for other web-based applications.The term web services means different things to different people and has spawned many (probably too many) new standards in recent years. However, the original concept is simple. Web services take the ubiquitous, universally understood, and easily implemented HTTP transaction and marry it with XML to define a standard for invoking application services over the Web. The process is a type of remote procedure call in which HTTP plays its traditional role as the basic communication provider and XML adds a "business envelope" in which structured data is passed. This RPC-style web service interaction defines both the basic structure of an invocation request and also a set of XML encodings for marshaling the primitive data types, allowing data parameters and results to be exchanged in a truly cross-platform way. In contrast, another form of web services termed "document style" places more emphasis on the exchange of application-specific XML documents than on RPC-style data marshaling and unmarshaling. We will concentrate on RPC-style web services since they currently provide the tightest coupling to Java.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Chapter 15: Web Applications and Web Services
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterWe're going to take a leap from the client side to the server side to learn how to write web-based Java applications and services. What distinguishes a web-based application or service from a regular Java program is that most of the code and logic reside on the server and the user utilizes a lightweight client or a web browser to access it. This is a very appealing model of software deployment and that is why it is spreading from interactive, browser-based, page-oriented web applications to more formal, application-to-application web services.Most of this chapter is about the mechanics of the Java Servlet API, which is a framework for writing application components for servers, just as applets are client-side application components for web pages. The Servlet API is used in both Java web applications and in the implementation of web services. However, we'll deal with servlets directly only in the first part of this chapter, when writing web applications to be used from a web browser. Later, when we look at application-level web services, we'll be working with tools that shield us from this level of detail. Nonetheless, the two types of server-side applications still have things in common, including how they are deployed to the server using a Web Archive (WAR) file.The Servlet API lives in the
javax.servlet
package, a standard Java API extension, so technically it isn't part of the core Java APIs. Similarly, the APIs used for building and deploying web services are bundled separately in the Java Web Services Developer Pack (JWSDP). In this book, we haven't talked about many standard extension packages, but these are particularly important. This chapter covers Java Servlet API 2.4 and JWSDP Version 1.5. Most web servers support the Java Servlet API either directly or indirectly through add-on modules. Most application servers now also offer a way to deploy web services, but this is not yet as standardized as servlets and web application deployment.Servers that support the full set of Java Enterprise APIs (including servlets, JSPs, Enterprise JavaBeans, and usually web services) are calledAdditional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Web Application Technologies
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterMany different ways of writing server-side software for web applications have evolved over the years. Early on, the standard was CGI, usually in combination with a scripting language such as Perl. Various web servers also offered native-language APIs for pluggable software modules. Java, however—and in particular the Java Servlet API—is rapidly becoming the most popular architecture for building web-based applications. Java servlet containers are available for virtually every web server and servlets are becoming foundational for new levels of web infrastructure, such as web services.Why has Java become so popular on the server side? Java is generally faster than scripting languages, especially in a server-side environment where long-running applications can be highly optimized by the VM. Servlets have an additional speed advantage over traditional CGI programs, because servlets execute in a multithreaded way within one instance of a VM. Older CGI applications required the server to start a separate process, pipe data to it, and receive the response as a stream. The unique runtime safety of Java also beats most native APIs in a production web-server environment, where it would be very bad to have an errant transaction bring down the server. Java's portability also means that server-side applications can be scaled up rapidly across different types of hardware without significant porting issues. In many ways, Java has really proven itself in this "business environment" to a greater extent than in the Windows-dominated desktop world.Speed and safety are factors, but perhaps the most important reason for using Java is that it makes writing large and complex applications much more manageable. Java servlets may not be quite as easy to write as scripts, but they are easier to update with new features, and servlets are far better at scaling for complex, high-volume applications. From servlet code, you can access all the standard Java APIs within the VM while your servlets are handling requests. This means that your Java servlet code can work well in a multitiered architecture, accessing "live" database connections with JDBC or communicating with other network services that have already been established. This kind of behavior has been hacked into CGI environments, but for Java, it is both robust and natural.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Web Applications
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterSo far we've used the term "web application" generically, referring to any kind of browser-based application that is located on a web server. Now we are going to have to be more precise with that term. In the context of the Java Servlet API, a web application is a collection of servlets, supporting Java classes, content such as HTML or JSP pages and images, and configuration information. For deployment (installation on a web server), a web application is bundled into a WAR file. We'll discuss WAR files in detail later, but suffice it to say that they are essentially JAR archives containing all the application files along with some deployment information. The important thing is that the standardization of WAR files means not only that the Java code is portable, but also that the process of deploying all the application's parts—its Java classes, resources, and configuration—is standardized.At the heart of the WAR archive is the web.xml file. This XML configuration file describes which servlets and JSPs are to be deployed, their names and URL paths, their initialization parameters, and a host of other information, including security and authentication requirements.Web applications, or web apps, also have a very well-defined runtime environment. Each web app has its own "root" path on the web server, meaning that all the URLs addressing its servlets and files start with a common unique prefix (e.g.,
www.oreilly.com/someapplication/
). The web app's servlets are also isolated from those of other web applications. Web apps cannot directly access each other's files (although they may be allowed to do so through the web server, of course). Each web app also has its own servlet context. We'll discuss the servlet context in more detail, but in brief, it is a common area for servlets within an application to share information and get resources from the environment. The high degree of isolation between web applications is intended to support the dynamic deployment and updating of applications required by modern business systems and address security and reliability concerns. Web apps are intended to be coarse-grained, relatively complete applications—not to be tightly coupled with other web apps. Although there's no reason you can't make web apps cooperate at a high level, for sharing logic across applications, you might want to consider web services, which we'll discuss later in this chapter.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - WAR Files and Deployment
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterAs we described in the introduction to this chapter, a WAR file is an archive that contains all the parts of a web application: Java class files for servlets, JSPs, HTML pages, images, and other resources. The WAR file is simply a JAR file with specified directories for the Java code and one very important file: the web.xml file, which tells the application server what to run and how to run it. WAR files always have the extension .war, but they can be created and read with the standard jar tool.The contents of a typical WAR might look like this, as revealed by the jar tool:
$ jar tvf shoppingcart.war index.html purchase.html receipt.html images/happybunny.gif WEB-INF/web.xml WEB-INF/classes/com/mycompany/PurchaseServlet.class WEB-INF/classes/com/mycompany/ReturnServlet.class WEB-INF/lib/thirdparty.jar
When deployed, the name of the WAR becomes, by default, the root path of the web application, in this case, shoppingcart. Thus, the base URL for this web app, if deployed onhttps://www.oreilly.com
, ishttps://www.oreilly.com/shoppingcart/
, and all references to its documents, images, and servlets start with that path. The top level of the WAR file becomes the document root (base directory) for serving files. Our index.html file appears at the base URL we just mentioned, and our happybunny.gif image is referenced ashttps://www.oreilly.com/shoppingcart/images/happybunny.gif
.The WEB-INF directory (all caps, hyphenated) is a special directory that contains all deployment information and application code. This directory is protected by the web server, and its contents are not visible to outside users of the application, even if you add WEB-INF to the base URL. Your application classes can load additional files from this area usinggetResource()
on the servlet context, however, so it is a safe place to store application resources. The WEB-INF directory contains the all-important web.xml file, which we'll talk more about in the next section.The WEB-INF/classes and WEB-INF/libAdditional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Servlet Filters
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterThe servlet Filter API generalizes the Java Servlet API to allow modular component "filters " to operate on the servlet request and responses in a sort of pipeline. Filters are chained, meaning that when more than one filter is applied, the servlet request is passed through each filter in succession, with each having an opportunity to act upon or modify the request before passing it to the next filter. Similarly, upon completion, the servlet result is effectively passed back through the chain on its return trip to the browser. Servlet filters may operate on any requests to a web application, not just those handled by the servlets; they may filter static content, as well. As of Servlet API 2.4, you can also control whether filters are applied to error and welcome pages as well as pages forwarded or included using the request dispatcher.Filters are declared and mapped to servlets in the web.xml file. There are two ways to map a filter: using a URL pattern like those used for servlets or by specifying a servlet by its instance name (
<servlet-name>
). Filters obey the same basic rules as servlets when it comes to URL matching, but when multiple filters match a path, they are all invoked.The order of the chain is determined by the order in which matching filter mappings appear in the web.xml file, with<url-pattern>
matches taking precedence over<servlet-name>
matches. This is contrary to the way servlet URL matching is done, with specific matches taking the highest priority. Filter chains are constructed as follows. First, each filter with a matching URL pattern is called in the order in which it appears in the web.xml file; next, each filter with a matching servlet name is called, also in order of appearance. URL patterns take a higher priority than filters specifically associated with a servlet, so in this case, patterns such as/*
have first crack at an incoming request.The Filter API is very simple and mimics the Servlet API. A servlet filter implements thejavax.servlet.Filter
interface and implements three methods:init()
,doFilter()
, anddestroy()
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Building WAR Files with Ant
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterThus far in this book, we have not become too preoccupied with special tools to help you construct Java applications. Partly, this is because it's outside the scope of this text, and partly it reflects a small bias of the authors against getting too entangled with particular development environments. There is, however, one universal tool that should be in the arsenal of every Java developer: the Jakarta Project's Ant. Ant is a project builder for Java, a pure Java application that fills the role that make does for C applications. Ant has many advantages over make when building Java code, not the least of which is that it comes with a wealth of special "targets" (declarative commands) to perform common Java-related operations such as building WAR files. Ant is fast, portable, and easy to install and use. Make it your friend.We won't cover the usage of Ant in detail here. You can learn more and download it from its home page,
https://jakarta.apache.org/ant/
or grab it from the CD-ROM accompanying this book (view CD content online athttps://examples.oreilly.com/learnjava3/CD-ROM/
). To get you started we give you a sample build file here. The Ant build file supplied with the examples for this chapter will compile the source and build the completed WAR file for you. You can find it with the example source.At the beginning of this chapter, we described the layout of a WAR, including the standard files and directories that must appear inside the archive. While this file organization is necessary for deployment inside the archive, it may not be the best way to organize your project during development. Maintaining web.xml and libraries inside a directory named WEB-INF under all of your content may be convenient for running the jar command, but it doesn't line up well with how those areas are created or maintained from a development perspective. Fortunately, with a simple Ant build file, we can create our WAR from an arbitrary project layout.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Implementing Web Services
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterNow that we've covered servlets and web applications in detail, we'd like to return to the topic of web services. In the previous chapter, we introduced the concept of a web service as an extension (formalization) of the basic HTTP web transaction, using XML content for application-to-application communication instead of consumption by a web browser client. In that chapter, we showed how easy it is to invoke an RPC-style web service, using client-side classes generated from a WSDL description file. In this section, we'll show the other side of that equation and demonstrate how to implement and deploy a web service.The world of web services has been moving quickly and the APIs, buzzwords, and hype continue to proliferate. The appeal of this style of interapplication communication using simple web protocols has, to some extent, been tarnished by the design-by-committee approach of every standards body and competitor adding features and layers to the web services concept. The truth is that web services are (were) simple and elegant when compared to more elaborate protocols largely because they did not support all of the same semantics—state management, callbacks, transactions, authentication, and security. As these features are added, the complexity returns. We will not cover all aspects of web services in detail but instead focus on the original XML-RPC model that is appealing for a wide variety of simple applications. The future adoption or rejection of the bulk of web services standards will dictate how they affect us all in the coming years.In Chapter 14, we walked through generating and running the client side of a web service (the Temperature service hosted at xmethods.net). In this chapter, we'll build and deploy our own web service, a simple façade called
EchoService
. We'll be using the JWSDP again and Tomcat as a web services container.It's worth taking a moment to review what a web service really is. In this case, we are using the RPC-style web service, which means that both the client and server have well-defined API functions with known arguments and return types. That API is ultimately specified in a WSDL document that anyone can use to implement either side of the service. What's really at the heart of this kind of web service is the standardization of the way that the arguments and return values are marshaled (packed up) for their trip over the net, using XML. Most other kinds of RPC (such as Java RMI) use "native" protocols that may not be easy to implement in all languages. Web services use XML to send their data. Furthermore, the data is sent over the standard web protocol, HTTP, which means that it uses the same kind of request/response that your web browser does (and that we implemented in Chapter 13 with our own little web server).Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Chapter 16: Swing
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterSwing is Java's graphical user interface toolkit. The
javax.swing
package (and its numerous subpackages) contain classes representing interface items such as windows, buttons, combo boxes, trees, tables, and menus—everything you need to build a modern, rich client-side application.Swing is part of a larger collection of software called the Java Foundation Classes (JFC), which includes the following APIs:- The Abstract Window Toolkit (AWT), the original user interface toolkit and base graphics classes
- Swing, the pure Java user interface toolkit
- Accessibility, which provides tools for integrating nonstandard input and output devices into your user interfaces
- The 2D API, a comprehensive set of classes for high-quality drawing
- Drag and Drop, an API that supports the drag-and-drop metaphor
JFC is one of the largest and most complex parts of the standard Java platform, so it shouldn't be any surprise that we'll take several chapters to discuss it. In fact, we won't even get to talk about all of it, just the most important parts—Swing and the 2D API. Here's the lay of the land:- This chapter covers the basic concepts you need to understand how to build user interfaces with Swing.
- Chapter 17 discusses the basic components from which user interfaces are built: buttons, lists, text fields, checkboxes, and so on.
- Chapter 18 dives further into the Swing toolkit, describing text components, trees, tables, and other advanced components.
- Chapter 19 discusses layout managers, which are responsible for arranging components within a window.
- Chapter 20 discusses the fundamentals of drawing, including simple image display.
- Chapter 21 covers the image generation and processing tools of the
java.awt.image
package. We'll throw in audio and video for good measure.
We can't cover the full functionality of Swing in this book; if you want the whole story, see Java Swing by Marc Loy, Robert Eckstein, Dave Wood, Brian Cole, and James Elliott (O'Reilly). Instead, we'll cover the basic tools you are most likely to use and show some examples of what can be done with some of the more advanced features. Figure 16-1 shows the user interface component classes of theAdditional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Components
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterA component is the fundamental user interface object in Java. Everything you see on the display in a Java application is a component. This includes things like windows, panels, buttons, checkboxes, scrollbars, lists, menus, and text fields. To be used, a component usually must be placed in a container. Container objects group components, arrange them for display using a layout manager, and associate them with a particular display device. All Swing components are derived from the abstract
javax.swing.JComponent
class, as you saw in Figure 16-1. For example, theJButton
class is a subclass ofAbstractButton
, which is itself a subclass of theJComponent
class.JComponent
is the root of the Swing component hierarchy, but it descends from the AWTContainer
class. At this bottom level, Swing is based on AWT, so our conversation occasionally delves into the AWT package.Container
's superclass isComponent
, the root of all AWT components, andComponent
's superclass is, finally,Object
. BecauseJComponent
inherits fromContainer
, it has the capabilities of both a component and a container.AWT and Swing, then, have parallel hierarchies. The root of AWT's hierarchy isComponent
, while Swing's components are based onJComponent
. You'll find similar classes in both hierarchies, such asButton
andJButton
,List
, andJList
. But Swing is much more than a replacement for AWT—it contains sophisticated components as well as a real implementation of the Model-View-Controller (MVC) paradigm, which we'll discuss later.For the sake of simplicity, we can split the functionality of theJComponent
class into two categories: appearance and behavior. TheJComponent
class contains methods and variables that control an object's general appearance. This includes basic attributes, such as its visibility, its current size and location, and certain common graphical defaults, such as font and color, used by different subclasses in different ways. TheJComponent
class also contains graphics and event-handling methods which are overridden by subclasses to produce all of the different kinds of widgets that we will see.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Events
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterWe've spent a lot of time discussing the different kinds of objects in Swing—components, containers, and special containers such as frames and windows. Now it's time to discuss interobject communication in detail.Swing objects communicate by sending events. The way we talk about events—"firing" them and "handling" them—makes it sound as if they are part of some special Java language feature. But they aren't. An event is simply an ordinary Java object that is delivered to its receiver by invoking an ordinary Java method. Everything else, however interesting, is purely convention. The entire Java event mechanism is really just a set of conventions for the kinds of descriptive objects that should be delivered; these conventions prescribe when, how, and to whom events should be delivered.Events are sent from a single source object to one or more listeners. A listener implements prescribed event-handling methods that enable it to receive a type of event. It then registers itself with a source of that kind of event. Sometimes an adapter object may be interposed between the event source and the listener, but in any case, registration of a listener is always established before any events are delivered.An event object is an instance of a subclass of
java.util.EventObject
; it holds information about something that's happened to its source. TheEventObject
parent class itself serves mainly to identify event objects; the only information it contains is a reference to the event source (the object that sent the event). Components don't normally send or receiveEventObject
s as such; they work with subclasses that provide more specific information.AWTEvent
is a subclass ofjava.awt.EventObject
; further subclasses ofAWTEvent
provide information about specific event types. Swing has events of its own that descend directly fromEventObject
. For the most part, you'll just be working with specific event subclasses from the AWT or Swing packages.ActionEvent
s correspond to a decisive "action" a user has taken with the component—like clicking a button or pressing Enter. AnAdditional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Event Summary
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterTables 16-1 and 16-2 summarize commonly used Swing events, which Swing components fire them, and the methods of the listener interfaces that receive them. The events and listeners are divided between the
java.awt.event
andjavax.swing.event
packages.Table 16-1: Swing component and container events EventFired byListener interfaceHandler methodsjava.awt.event.ComponentEvent
All componentsComponentListenercomponentResized()
componentMoved()
componentShown()
componentHidden()
java.awt.event.FocusEvent
All componentsFocusListenerfocusGained()
focusLost()
java.awt.event.KeyEvent
All componentsKeyListenerkeyTyped()
keyPressed()
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - The AWT Robot!
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterThis topic may not be of immediate use to everyone, but sometimes an API is just interesting enough that it deserves mentioning. In Java 1.3 a class with the intriguing name
java.awt.Robot
was added. The AWT robot provides an API for generating input events such as keystrokes and mouse gestures programmatically. It could be used to build automated GUI testing tools and the like. The following example uses theRobot
class to move the mouse to the upper-left area of the screen and perform a series of events corresponding to a double click. On most Windows systems, this opens up the My Computer folder that lives in that region of the screen.public class RobotExample { public static void main( String [] args ) throws Exception { Robot r = new Robot(); r.mouseMove(35,35); r.mousePress( InputEvent.BUTTON1_MASK ); r.mouseRelease( InputEvent.BUTTON1_MASK ); Thread.sleep(50); r.mousePress( InputEvent.BUTTON1_MASK ); r.mouseRelease( InputEvent.BUTTON1_MASK ); } }
In addition to its magic fingers, the AWTRobot
also has eyes! You can use theRobot
class to capture an image of the screen or a rectangular portion of it, using thecreateScreenCapture()
method. (Note that you can get the exact dimensions of the screen from the AWT'sgetScreenSize()
method.)Java 5.0 added a correspondingly useful API,java.awt.MouseInfo
, which allows the gathering of mouse movement information from anywhere on the screen (not restricted to the area within the Java application's windows). The combination ofRobot
andMouseInfo
should make it easier to record and play back events occurring anywhere on the screen from within Java.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Multithreading in Swing
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterAn important compromise was made early in the design of Swing relating to speed, GUI consistency, and thread safety. To provide maximum performance and simplicity in the common case, Swing does not explicitly synchronize access to most Swing component methods. This means that most Swing components are, technically, not thread-safe for multithreaded applications. Now don't panic: it's not as bad as it sounds because there is a plan. All event processing in AWT/Swing is handled by a single system thread using a single system event queue. The queue serves two purposes. First, it eliminates thread-safety issues by making all GUI modifications happen in a single thread. Second, the queue imposes a strict ordering of all activity in Swing. Because painting is handled in Swing using events, all screen updating is also ordered with respect to all event handling.What this means for you is that multithreaded programs need to be careful about how they update Swing components after they are realized (added to a visible container). If you make arbitrary modifications to Swing components from your own threads, you run the risk of malformed rendering on the screen and inconsistent behavior.There are several conditions under which it is always safe to modify a Swing component. First, Swing components can be modified before they are realized. The term realized originates from the days when the component would have created its peer object. It is the point when it is added to a visible container or when it is made visible in the case of a window. Most of our examples in this book set up GUI components in their
main()
method, add them to aJFrame
, and then, as their final action, cause theJFrame
to be displayed usingsetVisible()
. This setup style is safe because components are not realized until the container is made visible. Actually, that last sentence is not entirely true. Technically, components can also be realized by theJFrame() pack()
method. However, since no GUI is shown until the container is made visible, it is unlikely that any GUI activity can be mishandled.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Chapter 17: Using Swing Components
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterIn the previous chapter, we discussed a number of concepts, including how Java's user interface facility is put together and how the fundamental pieces work. You should understand what components and containers are, how they work together to create a display, what events are, how components use them to communicate with the rest of your application, and what layout managers are.Now that we're through with the general concepts and background, we'll get to the fun stuff: how to do things with Swing . We will cover most of the components that the Swing package supplies, how to use these components in applets and applications, and how to build your own components. We will have lots of code and lots of pretty examples to look at.There's more material on this topic than fits in a single chapter. In this chapter, we'll cover all the basic user interface components. In the next chapter, we'll cover some of the more involved topics: text components, trees, tables, and creating your own components.We'll start with the simplest components: buttons and labels . Frankly, there isn't much to say about them. If you've seen one button, you've seen them all, and you've already seen buttons in the applications in Chapter 2 (
HelloJava3
andHelloJava4
). A button generates anActionEvent
when the user presses it. To receive these events, your program registers anActionListener
, which must implement theactionPerformed()
method. The argument passed toactionPerformed()
is the event itself.There's one more thing worth saying about buttons, which applies to any component that generates an action event. Java lets us specify an "action command" string for buttons (and other components, like menu items, that can generate action events). The action command is less interesting than it sounds. It is just aString
that serves to identify the component that sent the event. By default, the action command of aAdditional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Buttons and Labels
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterWe'll start with the simplest components: buttons and labels . Frankly, there isn't much to say about them. If you've seen one button, you've seen them all, and you've already seen buttons in the applications in Chapter 2 (
HelloJava3
andHelloJava4
). A button generates anActionEvent
when the user presses it. To receive these events, your program registers anActionListener
, which must implement theactionPerformed()
method. The argument passed toactionPerformed()
is the event itself.There's one more thing worth saying about buttons, which applies to any component that generates an action event. Java lets us specify an "action command" string for buttons (and other components, like menu items, that can generate action events). The action command is less interesting than it sounds. It is just aString
that serves to identify the component that sent the event. By default, the action command of aJButton
is the same as its label; it is included in action events so that you could use it to figure out which button an event came from. However, often you'll know this from the context of your event listener.To get the action command from an action event, call the event'sgetActionCommand()
method. The following code checks whether the user pressed the button labeled Yes:public void actionPerformed(ActionEvent e){ if (e.getActionCommand().equals("Yes") { //the user pressed "Yes"; do something ... } }
Yes is a string, not a command per se. You can change the action command by calling the button'ssetActionCommand()
method. The following code changes buttonmyButton
's action command to "confirm":myButton.setActionCommand("confirm");
It's a good idea to get used to setting action commands explicitly; this helps to prevent your code from breaking when you or some other developer internationalizes it or otherwise changes the button's label. If you rely on the button's label, your code stops working as soon as that label changes; a French user might see the labelAdditional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - HTML Text in Buttons and Labels
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterA neat feature of Swing is that it can interpret HTML-formatted text in
JLabel
andJButton
labels. The following example shows how to create a button with some HTML-formatted text:JButton button = new JButton( "<html>" + "S<font size=-1>MALL<font size=+0> " + "C<font size=-1>APITALS");
Older versions of Java may not render complex HTML very well. But as of JDK 1.4, most basic HTML features are supported, including crazy things such as images and tables.Figure 17-1 uses an HTML table to arrange its text.Figure 17-1: Button using HTML tableFigure 17-2 uses an HTML image tag to display an image.Figure 17-2: Button using HTML img tagThe code for the two figures looks like this:String html= "<html><table border=1>" +"<tr><td>One</td><td>Two</td></tr>" +"<tr><td>Three</td><td>Four</td></tr>" +"</table>"; JButton button = new JButton(html); String html2= "<html><h3>Learning Java</h3>" +"<img src=\"https://www.oreilly.com/catalog/covers/learnjava3.s.gif\">"; Jbutton button2 = new JButton(html2);
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Checkboxes and Radio Buttons
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterA checkbox is a labeled toggle switch. Each time the user clicks it, its state toggles between checked and unchecked. Swing implements the checkbox as a special kind of button. Radio buttons are similar to checkboxes, but they are normally used in groups. Clicking on one radio button in the group automatically turns the others off. They are named for the mechanical preset buttons on old car radios (like some of us had in high school).Checkboxes and radio buttons are represented by instances of
JCheckBox
andJRadioButton
, respectively. Radio buttons can be tethered together using an instance of another class calledButtonGroup
. By now you're probably well into the swing of things (no pun intended) and could easily master these classes on your own. We'll use an example to illustrate a different way of dealing with the state of components and to show off a few more things about containers.AJCheckBox
sendsItemEvent
s when it's pushed. Because a checkbox is a kind of button, it also firesActionEvent
s when checked. For something like a checkbox, we might want to be lazy and check on the state of the buttons only at some later time, such as when the user commits an action. For example, when filling out a form you may only care about the user's choices when the submit button is finally pressed.The next application,DriveThrough
, lets us check off selections on a fast food menu, as shown in Figure 17-3.DriveThrough
prints the results when you press the Place Order button. Therefore, we can ignore all the events generated by our checkboxes and radio buttons and listen only for the action events generated by the submit button:Figure 17-3: The DriveThrough application//file: DriveThrough.java import java.awt.*; import java.awt.event.*; import javax.swing.*; public class DriveThrough { public static void main(String[] args) { JFrame frame = new JFrame("Lister v1.0"); JPanel entreePanel = new JPanel(); final ButtonGroup entreeGroup = new ButtonGroup(); JRadioButton radioButton; entreePanel.add(radioButton = new JRadioButton("Beef")); radioButton.setActionCommand("Beef"); entreeGroup.add(radioButton); entreePanel.add(radioButton = new JRadioButton("Chicken")); radioButton.setActionCommand("Chicken"); entreeGroup.add(radioButton); entreePanel.add(radioButton = new JRadioButton("Veggie", true)); radioButton.setActionCommand("Veggie"); entreeGroup.add(radioButton); final JPanel condimentsPanel = new JPanel(); condimentsPanel.add(new JCheckBox("Ketchup")); condimentsPanel.add(new JCheckBox("Mustard")); condimentsPanel.add(new JCheckBox("Pickles")); JPanel orderPanel = new JPanel(); JButton orderButton = new JButton("Place Order"); orderPanel.add(orderButton); Container content = frame.getContentPane(); // unnecessary in 5.0+ content.setLayout(new GridLayout(3, 1)); content.add(entreePanel); content.add(condimentsPanel); content.add(orderPanel); orderButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent ae) { String entree = entreeGroup.getSelection().getActionCommand(); System.out.println(entree + " sandwich"); Component[] components = condimentsPanel.getComponents(); for ( Component c : components ) { JCheckBox cb = (JCheckBox)c; if (cb.isSelected()) System.out.println("With " + cb.getText()); } } }); frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); frame.setSize(300, 150); frame.setVisible(true); } }
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Lists and Combo Boxes
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapter
JList
s andJComboBox
es are a step up on the evolutionary chain fromJButton
s andJLabel
s. Lists let the user choose from a group of alternatives. They can be configured to force a single selection or allow multiple choices. Usually, only a small group of choices is displayed at a time; a scrollbar lets the user move to the choices that aren't visible. The user can select an item by clicking on it. She can expand the selection to a range of items by holding down Shift and clicking on another item. To make discontinuous selections, the user can hold down the Control key instead of the Shift key (on a Mac, this is the Command key).A combo box is a cross-breed between a text field and a list. It displays a single line of text (possibly with an image) and a downward pointing arrow on one side. If you click on the arrow, the combo box opens up and displays a list of choices. You can select a single choice by clicking on it. After a selection is made, the combo box closes up; the list disappears, and the new selection is shown in the text field.Like other components in Swing, lists and combo boxes have data models that are distinct from visual components. The list also has a selection model that controls how selections may be made on the list data.Lists and combo boxes are similar because they have similar data models. Each is simply an array of acceptable choices. This similarity is reflected in Swing, of course: the type of aJComboBox
's data model is a subclass of the type used for aJList
's data model. The next example demonstrates this relationship.The following example creates a window with a combo box, a list, and a button. The combo box and the list use the same data model. When you press the button, the program writes out the current set of selected items in the list (see Figure 17-4).Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - The Spinner
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapter
JList
andJComboBox
are two ways to let the user choose from a set of values. AJComboBox
has added flexibility when it is made editable, but, in general, both of these components are limited in that they can only prompt the user from a fixed set of choices. In Java 1.4, Swing added a component calledJSpinner
that is useful for large or open-ended sequences of values such as numbers or dates. TheJSpinner
is a cousin of theJComboBox
; it displays a value in a field, but instead of providing a drop-down list of choices, it gives the user a small pair of up and down arrows for moving over a range of values (see Figure 17-5). Like the combo box, aJSpinner
can also be made editable, allowing the user to type a valid value directly into the field.Figure 17-5: Image of DateSelector applicationSwing provides three basic types ofSpinner
s, represented by three different data models for theJSpinner
component:SpinnerListModel
,SpinnerNumberModel
, andSpinnerDateModel
.TheSpinnerListModel
acts like a combo box, specifying a fixed set of objects:String [] options = new String [] { "small", "medium", "large", "huge" }; SpinnerListModel model = new SpinnerListModel( options ); JSpinner spinner = new JSpinner( model );
You can retrieve the current value from the model at any time:String value = (String)model.getValue();
Alternatively, you can register aChangeListener
to receive updates as the user changes values. With aSpinnerListModel
, if the spinner is editable and the user enters a value directly, it is validated against the set of choices before being accepted. This behavior is a little different from the other types ofSpinnerModel
s, which when editable, accept any valid value of the correct type (e.g., a number or date).TheSpinnerNumberModel
displays numeric values. It can be configured with initial, minimum, and maximum values:Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Borders
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterAny Swing component can have a decorative border.
JComponent
includes a method calledsetBorder()
; all you have to do is call it, passing it an appropriate implementation of theBorder
interface.Swing provides many usefulBorder
implementations in thejavax.swing.border
package. You could create an instance of one of these classes and pass it to a component'ssetBorder()
method, but there's an even simpler technique.TheBorderFactory
class creates any kind of border for you using static "factory" methods. Creating and setting a component's border, then, is simple:JLabel labelTwo = new JLabel("I have an etched border."); labelTwo.setBorder(BorderFactory.createEtchedBorder());
Every component has asetBorder()
method, from simple labels and buttons right up to the fancy text and table components we cover in Chapter 18.BorderFactory
is convenient, but it does not offer every option of every border type. For example, if you want to create a raisedEtchedBorder
instead of the default lowered border, you'll need to useEtchedBorder
's constructor, like this:JLabel labelTwo = new JLabel("I have a raised etched border."); labelTwo.setBorder( new EtchedBorder(EtchedBorder.RAISED) );
TheBorder
implementation classes are listed and briefly described here:-
BevelBorder
- This border draws raised or lowered beveled edges, giving an illusion of depth.
-
SoftBevelBorder
- This border is similar to
BevelBorder
, but thinner. -
EmptyBorder
- Doesn't do any drawing, but does take up space. You can use it to give a component a little breathing room in a crowded user interface.
-
EtchedBorder
- A lowered etched border gives the appearance of a rectangle that has been chiseled into a piece of stone. A raised etched border looks like it is standing out from the surface of the screen.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! -
- Menus
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterA
JMenu
is a standard pull-down menu with a fixed name. Menus can hold other menus as submenu items, enabling you to implement complex menu structures. In Swing, menus are first-class components, just like everything else. You can place them wherever a component would go. Another class,JMenuBar
, holds menus in the conventional horizontal bar. Menu bars are real components, too, so you can place them wherever you want in a container: top, bottom, or middle. But in the middle of a container, it usually makes more sense to use aJComboBox
rather than some kind of menu.Menu items may have associated images and shortcut keys; there are even menu items that look like checkboxes and radio buttons. Menu items are really a kind of button. Like buttons, menu items fire action events when they are selected. You can respond to menu items by registering action listeners with them.There are two ways to use the keyboard with menus . The first is called mnemonics . A mnemonic is one character in the menu name. If you hold down the Alt key and type a menu's mnemonic, the menu drops down, just as if you had clicked on it with the mouse. Menu items may also have mnemonics. Once a menu is dropped down, you can select individual items in the same way.Menu items may also have accelerators. An accelerator is a key combination that selects the menu item, whether or not the menu that contains it is showing. A common example is the accelerator Ctrl-C, which is frequently used as a shortcut for the Copy item in the Edit menu.The next example demonstrates several different features of menus. It creates a menu bar with three different menus. The first, Utensils, contains several menu items, a submenu, a separator, and a Quit item that includes both a mnemonic and an accelerator. The second menu, Spices, contains menu items that look and act like checkboxes. Finally, the Cheese menu demonstrates radio button menu items.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Pop-up Menus
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterOne of Swing's nifty components is
JPopupMenu
, a context menu that appears at the mouse location when you press the appropriate mouse button or keystroke. (On a two-button mouse, clicking the right mouse button invokes a pop-up menu. On a single-button Mac, you Command-click.) Which button you press depends on the platform you're using; fortunately, from the code's point of view you don't have to care—Swing figures it out for you.The care and feeding ofJPopupMenu
is basically the same as any other menu. You use a different constructor (JPopupMenu()
) to create it, but otherwise, you build a menu and add elements to it the same way. The big difference is that you don't attach it to aJMenuBar
. Instead, just pop up the menu whenever and wherever you need it. Prior to Java 5.0, this process is a little cumbersome; you have to register to receive the appropriate mouse events, check them to see if they are the pop-up trigger and then pop the menu manually. With Java 5.0, the process is simplified by having components manage their own pop-up menus .First, we'll show an example of explicit pop-up handling. The following example,PopupColorMenu
, contains three buttons. You can use aJPopupMenu
to set the color of each button or the background frame itself, depending on where you clickthe mouse.//file: PopUpColorMenu.java import java.awt.*; import java.awt.event.*; import javax.swing.*; public class PopUpColorMenu implements ActionListener { Component selectedComponent; public PopUpColorMenu() { JFrame frame = new JFrame("PopUpColorMenu v1.0"); final JPopupMenu colorMenu = new JPopupMenu("Color"); colorMenu.add(makeMenuItem("Red")); colorMenu.add(makeMenuItem("Green")); colorMenu.add(makeMenuItem("Blue")); MouseListener mouseListener = new MouseAdapter() { public void mousePressed(MouseEvent e) { checkPopup(e); } public void mouseClicked(MouseEvent e) { checkPopup(e); } public void mouseReleased(MouseEvent e) { checkPopup(e); } private void checkPopup(MouseEvent e) { if (e.isPopupTrigger()) { selectedComponent = e.getComponent(); colorMenu.show(e.getComponent(), e.getX(), e.getY()); } } }; Container content = frame.getContentPane(); // unnecessary in 5.0+ content.setLayout(new FlowLayout()); JButton button = new JButton("Uno"); button.addMouseListener(mouseListener); content.add(button); button = new JButton("Due"); button.addMouseListener(mouseListener); content.add(button); button = new JButton("Tre"); button.addMouseListener(mouseListener); content.add(button); frame.getContentPane().addMouseListener(mouseListener); frame.setSize(200,50); frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); frame.setVisible(true); } public void actionPerformed(ActionEvent e) { String color = e.getActionCommand(); if (color.equals("Red")) selectedComponent.setBackground(Color.red); else if (color.equals("Green")) selectedComponent.setBackground(Color.green); else if (color.equals("Blue")) selectedComponent.setBackground(Color.blue); } private JMenuItem makeMenuItem(String label) { JMenuItem item = new JMenuItem(label); item.addActionListener( this ); return item; } public static void main(String[] args) { new PopUpColorMenu(); } }
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Component-Managed Pop-ups
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterThings get a bit easier in Java 5.0, using the new pop-up menu API for components. In Java 5.0, any
JComponent
can manage aJPopupMenu
directly with thesetComponentPopupMenu()
method.JComponent
s can also be told to simply inherit their parent container's pop-up menu via thesetInheritsPopupMenu()
method. This combination makes it very simple to implement a context menu that should appear in many components within a container.Unfortunately, this doesn't lend itself well to our previous example (PopupColorMenu
) for two reasons. First, we need to know which component the mouse was in when the pop-up was triggered and we don't get that information using this API. The pop-up handling is actually delegated to the container, not inherited. Second, not all types of components are registered to receive mouse events by default. As a result, we'll create a new example that is more appropriate for a "one context menu to rule them all" application. The following example,ContextMenu
, shows aTextArea
andTextField
that both inherit the sameJPopupMenu
from theirJPanel
container. When you select a menu item, the action is displayed in the text area.import java.awt.*; import java.awt.event.*; import javax.swing.*; public class ContextMenu implements ActionListener { JTextArea textArea = new JTextArea(); public ContextMenu() { final JPopupMenu contextMenu = new JPopupMenu("Edit"); contextMenu.add(makeMenuItem("Save")); contextMenu.add(makeMenuItem("Save As")); contextMenu.add(makeMenuItem("Close")); JFrame frame = new JFrame("ContextMenu v1.0"); JPanel panel = new JPanel(); panel.setLayout( new BorderLayout() ); frame.add( panel ); panel.setComponentPopupMenu( contextMenu ); textArea.setInheritsPopupMenu( true ); panel.add( BorderLayout.CENTER, textArea ); JTextField textField = new JTextField(); textField.setInheritsPopupMenu( true ); panel.add( BorderLayout.SOUTH, textField ); frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); frame.setSize(400,200); frame.setVisible(true); } public void actionPerformed( ActionEvent e ) { textArea.append( e.getActionCommand() +"\n" ); } private JMenuItem makeMenuItem(String label) { JMenuItem item = new JMenuItem(label); item.addActionListener( this ); return item; } public static void main(String[] args) { new ContextMenu(); } }
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - The JScrollPane Class
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterWe used
JScrollPane
earlier in this chapter without explaining much about it. In this section, we'll remedy the situation.AJScrollPane
is a container that can hold one component. Said another way, aJScrollPane
wraps another component. By default, if the wrapped component is larger than theJScrollPane
itself, theJScrollPane
supplies scrollbars.JScrollPane
handles the events from the scrollbars and displays the appropriate portion of the contained component.Technically,JScrollPane
is aContainer
, but it's a funny one. It has its own layout manager, which can't be changed, and it accommodates only one component at a time. This isn't really a limitation. If you want to put a lot of stuff in aJScrollPane
, just collect your components in aJPanel
, with whatever layout manager you like, and put that panel into theJScrollPane
.When you create aJScrollPane
, you specify the conditions under which its scrollbars are displayed. This is called the scrollbar display policy; a separate policy is used for the horizontal and vertical scrollbars. The following constants can be used to specify the policy for each of the scrollbars:-
HORIZONTAL_SCROLLBAR_AS_NEEDED
-
VERTICAL_SCROLLBAR_AS_NEEDED
- Displays a scrollbar only if the wrapped component doesn't fit.
-
HORIZONTAL_SCROLLBAR_ALWAYS
-
VERTICAL_SCROLLBAR_ALWAYS
- Always shows a scrollbar, regardless of the contained component's size.
-
HORIZONTAL_SCROLLBAR_NEVER
-
VERTICAL_SCROLLBAR_NEVER
- Never shows a scrollbar, even if the contained component won't fit. If you use this policy, you should provide some other way to manipulate the
JScrollPane
.
By default, the policies areHORIZONTAL_SCROLLBAR_AS_NEEDED
andVERTICAL_SCROLLBAR_AS_NEEDED
.Support for scrolling with mouse wheels is automatic as of Java 1.4. You do not have to do anything explicit in your application to get this to work.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! -
- The JSplitPane Class
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterA split pane is a special container that holds two components, each in its own sub-pane. A splitter bar adjusts the sizes of the two subpanes. In a document viewer, for example, you might use a split pane to show a table of contents next to a page of text.The following example uses two
JLabel
s containingImageIcon
s, like the previous example. It displays the two labels, wrapped inJScrollPanes
, on either side of aJSplitPane
(see Figure 17-10). You can drag the splitter bar back and forth to adjust the sizes of the two contained components.//file: SplitPaneFrame.java import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.border.*; public class SplitPaneFrame { public static void main(String[] args) { String fileOne = "Piazza di Spagna.jpg"; String fileTwo = "L1-Light.jpg"; if (args.length > 0) fileOne = args[0]; if (args.length > 1) fileTwo = args[1]; JFrame frame = new JFrame("SplitPaneFrame"); JLabel leftImage = new JLabel( new ImageIcon( fileOne ) ); Component left = new JScrollPane(leftImage); JLabel rightImage = new JLabel( new ImageIcon( fileTwo ) ); Component right = new JScrollPane(rightImage); JSplitPane split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, left, right); split.setDividerLocation(100); frame.getContentPane().add(split); frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); frame.setSize(300, 200); frame.setVisible(true); } }
Figure 17-10: Using a split paneAdditional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - The JTabbedPane Class
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterIf you've ever right-clicked on the desktop to set your Display Properties in Windows, you already know what a
JTabbedPane
is. It's a container with labeled tabs (e.g., Themes, Screen Saver, Appearance). When you click on a tab, a new set of controls is shown in the body of theJTabbedPane
. In Swing,JTabbedPane
is simply a specialized container.Each tab has a name. To add a tab to theJTabbedPane
, simply calladdTab()
. You'll need to specify the name of the tab as well as a component that supplies the tab's contents. Typically, it's a container holding other components.Even though theJTabbedPane
only shows one set of components at a time, be aware that all the components on all the pages are alive and in memory at one time. If you have components that hog processor time or memory, try to put them into some "sleep" state when they are not showing.The following example shows how to create aJTabbedPane
. It adds standard Swing components to a tab named Controls. The second tab is filled with a scrollable image, which was presented in the previous examples.//file: TabbedPaneFrame.java import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.border.*; public class TabbedPaneFrame { public static void main(String[] args) { JFrame frame = new JFrame("TabbedPaneFrame"); JTabbedPane tabby = new JTabbedPane(); // create the controls pane JPanel controls = new JPanel(); controls.add(new JLabel("Service:")); JList list = new JList( new String[] { "Web server", "FTP server" }); list.setBorder(BorderFactory.createEtchedBorder()); controls.add(list); controls.add(new JButton("Start")); // create an image pane String filename = "Piazza di Spagna.jpg"; JLabel image = new JLabel( new ImageIcon(filename) ); JComponent picture = new JScrollPane(image); tabby.addTab("Controls", controls); tabby.addTab("Picture", picture); frame.getContentPane().add(tabby); frame.setSize(200, 200); frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); frame.setVisible(true); } }
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Scrollbars and Sliders
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapter
JScrollPane
is such a handy component that you may not ever need to use scrollbars by themselves. In fact, if you ever do find yourself using a scrollbar by itself, chances are you really want to use another component called a slider.There's not much point in describing the appearance and functionality of scrollbars and sliders . Instead, let's jump right in with an example that includes both components. Figure 17-12 shows a simple example with both a scrollbar and a slider.Figure 17-12: Using a scrollbar and a sliderHere is the source code for this example://file: Slippery.java import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.event.*; public class Slippery { public static void main(String[] args) { JFrame frame = new JFrame("Slippery v1.0"); Container content = frame.getContentPane(); // unnecessary in 5.0+ JPanel main = new JPanel(new GridLayout(2, 1)); JPanel scrollBarPanel = new JPanel(); final JScrollBar scrollBar = new JScrollBar(JScrollBar.HORIZONTAL, 0, 48, 0, 255); int height = scrollBar.getPreferredSize().height; scrollBar.setPreferredSize(new Dimension(175, height)); scrollBarPanel.add(scrollBar); main.add(scrollBarPanel); JPanel sliderPanel = new JPanel(); final JSlider slider = new JSlider(JSlider.HORIZONTAL, 0, 255, 128); slider.setMajorTickSpacing(48); slider.setMinorTickSpacing(16); slider.setPaintTicks(true); sliderPanel.add(slider); main.add(sliderPanel); content.add(main, BorderLayout.CENTER); final JLabel statusLabel = new JLabel("Welcome to Slippery v1.0"); content.add(statusLabel, BorderLayout.SOUTH); // wire up the event handlers scrollBar.addAdjustmentListener(new AdjustmentListener() { public void adjustmentValueChanged(AdjustmentEvent e) { statusLabel.setText("JScrollBar's current value = " + scrollBar.getValue()); } }); slider.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent e) { statusLabel.setText("JSlider's current value = " + slider.getValue()); } }); frame.pack(); frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); frame.setVisible(true); } }
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Dialogs
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterA dialog is another standard feature of user interfaces. Dialogs are frequently used to present information to the user ("Your fruit salad is ready.") or to ask a question ("Shall I bring the car around?"). Dialogs are used so commonly in GUI applications that Swing includes a handy set of prebuilt dialogs . These are accessible from static methods in the
JOptionPane
class. Many variations are possible;JOptionPane
groups them into four basic types:- Message dialog
- Displays a message to the user, usually accompanied by an OK button.
- Confirmation dialog
- Ask a question and displays answer buttons, usually Yes, No, and Cancel.
- Input dialog
- Asks the user to type in a string.
- Option dialogs
- The most general type. You pass it your own components, which are displayed in the dialog.
A confirmation dialog is shown in Figure 17-13.Figure 17-13: Using a confirmation dialogLet's look at examples of each kind of dialog. The following code produces a message dialog:JOptionPane.showMessageDialog(frame, "You have mail.");
The first parameter toshowMessageDialog()
is the parent component (in this case,frame
, an existingJFrame
). The dialog will be centered on the parent component. If you passnull
for the parent component, the dialog is centered in your screen. The dialogs thatJOptionPane
displays are modal, which means they block other input to your application while they are showing.Here's a slightly fancier message dialog. We've specified a title for the dialog and a message type, which affects the icon that is displayed:JOptionPane.showMessageDialog(frame, "You are low on memory.", "Apocalyptic message", JOptionPane.WARNING_MESSAGE);
Here's how to display the confirmation dialog shown in Figure 17-13:int result = JOptionPane.showConfirmDialog(null, "Do you want to remove Windows now?");
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - File Selection Dialog
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterA
JFileChooser
is a standard file-selection box. As with other Swing components,JFileChooser
is implemented in pure Java, so it can look and act the same on different platforms or take on the native appearance of the operating system, depending on what look and feel is in effect.Selecting files all day can be pretty boring without a greater purpose, so we'll exercise theJFileChooser
in a mini-editor application.Editor
provides a text area in which we can load and work with files. (TheJFileChooser
created byEditor
is shown in Figure 17-14.) We'll stop just shy of the capability to save and let you fill in the blanks (with a few caveats).Figure 17-14: Using a JFileChooserHere's the code:import java.awt.*; import java.awt.event.*; import java.io.*; import javax.swing.*; public class Editor extends JFrame implements ActionListener { private JEditorPane textPane = new JEditorPane(); public Editor() { super("Editor v1.0"); Container content = getContentPane(); // unnecessary in 5.0+ content.add(new JScrollPane(textPane), BorderLayout.CENTER); JMenu menu = new JMenu("File"); menu.add(makeMenuItem("Open")); menu.add(makeMenuItem("Save")); menu.add(makeMenuItem("Quit")); JMenuBar menuBar = new JMenuBar(); menuBar.add(menu); setJMenuBar(menuBar); setSize(300, 300); setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); } public void actionPerformed(ActionEvent e) { String command = e.getActionCommand(); if (command.equals("Quit")) System.exit(0); else if (command.equals("Open")) loadFile(); else if (command.equals("Save")) saveFile(); } private void loadFile () { JFileChooser chooser = new JFileChooser(); int result = chooser.showOpenDialog(this); if (result == JFileChooser.CANCEL_OPTION) return; try { File file = chooser.getSelectedFile(); java.net.URL url = file.toURL(); textPane.setPage(url); } catch (Exception e) { textPane.setText("Could not load file: " + e); } } private void saveFile() { JFileChooser chooser = new JFileChooser(); chooser.showSaveDialog(this); // Save file data... } private JMenuItem makeMenuItem( String name ) { JMenuItem m = new JMenuItem( name ); m.addActionListener( this ); return m; } public static void main(String[] s) { new Editor().setVisible(true); } }
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - The Color Chooser
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterSwing is chock full of goodies.
JColorChooser
is yet another ready-made dialog supplied with Swing; it allows your users to choose colors. The following brief example shows how easy it is to useJColorChooser
:import java.awt.*; import java.awt.event.*; import javax.swing.*; public class LocalColor { public static void main(String[] args) { final JFrame frame = new JFrame("LocalColor v1.0"); final Container content = frame.getContentPane(); // unnecessary in 5.0+ content.setLayout(new GridBagLayout()); JButton button = new JButton("Change color..."); content.add(button); button.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { Color c = JColorChooser.showDialog(frame, "Choose a color", content.getBackground()); if (c != null) content.setBackground(c); } }); frame.setSize(200, 200); frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); frame.setVisible(true); } }
This example shows a frame window with a single button. When you click on the button, a color chooser pops up. After you select a color, it becomes the background color of the frame window.Basically, all we have to do is callJColorChooser
's static methodshowDialog()
. In this example, we specified a parent component, a dialog title, and an initial color value. But you can get away with just specifying a parent component. Whatever color the user chooses is returned; if the user presses the Cancel button,null
is returned.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Chapter 18: More Swing Components
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterIn the previous chapter, we described most of the components that Swing offers for building user interfaces. In this chapter, you'll find out about the rest. These include Swing's text components, trees, and tables. These types of components have considerable depth but are quite easy to use if you accept their default options. We'll show you the easy way to use these components and start to describe the more advanced features of each. Later in this chapter, we'll also give an example of how to implement your own, custom components in Swing.Swing offers sophisticated text components, from plain-text entry boxes to HTML interpreters. For full coverage of Swing's text capabilities, see O'Reilly's Java Swing. In that encyclopedic book, several meaty chapters are devoted to text. It's a huge subject; we'll just scratch the surface here.Let's begin by examining the simpler text components.
JTextField
is a single-line text editor andJTextArea
is a simple, multiline text editor. BothJTextField
andJTextArea
derive from theJTextComponent
class, which provides the functionality they have in common. This includes methods for setting and retrieving the displayed text, specifying whether the text is "editable" or read-only, manipulating the cursor position within the text, and manipulating text selections.Observing changes in text components requires an understanding of how the components implement the Model-View-Controller (MVC) architecture. You may recall from the last chapter that Swing components implement a true MVC architecture. It's in the text components that you first get an inkling of a clear separation between the M and VC parts of the MVC architecture. The model for text components is an object called aDocument
. When you add or remove text from aJTextField
or aJTextArea
, the correspondingDocument
is changed. It's the document itself, not the visual components, that generates text-related events when something changes. To receive notification ofJTextArea
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Text Components
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterSwing offers sophisticated text components, from plain-text entry boxes to HTML interpreters. For full coverage of Swing's text capabilities, see O'Reilly's Java Swing. In that encyclopedic book, several meaty chapters are devoted to text. It's a huge subject; we'll just scratch the surface here.Let's begin by examining the simpler text components.
JTextField
is a single-line text editor andJTextArea
is a simple, multiline text editor. BothJTextField
andJTextArea
derive from theJTextComponent
class, which provides the functionality they have in common. This includes methods for setting and retrieving the displayed text, specifying whether the text is "editable" or read-only, manipulating the cursor position within the text, and manipulating text selections.Observing changes in text components requires an understanding of how the components implement the Model-View-Controller (MVC) architecture. You may recall from the last chapter that Swing components implement a true MVC architecture. It's in the text components that you first get an inkling of a clear separation between the M and VC parts of the MVC architecture. The model for text components is an object called aDocument
. When you add or remove text from aJTextField
or aJTextArea
, the correspondingDocument
is changed. It's the document itself, not the visual components, that generates text-related events when something changes. To receive notification ofJTextArea
changes, therefore, you register with the underlyingDocument
, not with theJTextArea
component itself:JTextArea textArea = new JTextArea(); Document doc = textArea.getDocument(); doc.addDocumentListener(someListener);
As you'll see in an upcoming example, you can easily have more than one visual text component use the same underlyingDocument
data model.In addition,JTextField
components generateActionEvent
s whenever the user presses the Return key within the field. To get these events, just implement theActionListener
interface and register your listener using theAdditional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Focus Navigation
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterWe've brought up the topic of focus many times in our discussion so far, and we've told you that the handling and user navigation of focus is mostly done automatically. This is largely due to a new focus system introduced in Java 1.4. The new focus system is very powerful and can be heavily customized through the use of "focus traversal policy" objects that control keyboard navigation. For typical application behavior, you won't have to deal with this directly, but we'll explain a few features you should know about.Swing handles keyboard focus navigation through the
KeyboardFocusManager
class. This class usesFocusTraversalPolicy
"strategy" objects that implement the actual schemes for locating the next component to receive focus. There are two primaryFocusTraversalPolicy
types supplied with Java. The first,DefaultFocusTraversalPolicy
, is part of the AWT package. It emulates the legacy AWT-style focus management that navigated components in the order in which they were added to their container. The next,LayoutFocusTraversalPolicy
, is the default for all Swing applications. It examines the layout and attempts to provide the more typical navigation from left to right, top to bottom, based on component position and size.The focus traversal policy is inherited from containers and oriented around groups of components known as "root cycles." By default, each individual window andJInternalFrame
is its own root cycle. In other words, focus traverses all of its child components repeatedly (jumping from the last component back to the first), and won't, by default, leave the container through keyboard navigation.The default Swing policy uses the following keys for keyboard navigation:- Forward
- Tab or Ctrl-Tab (Ctrl-Tab also works inside text areas)
- Back
- Shift-Tab or Ctrl-Shift-Tab (Ctrl-Shift-Tab also works inside text areas)
You can define your own focus traversal keys for forward and back navigation, as well as for navigation across root cycles using theAdditional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Tables
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterTables present information in orderly rows and columns. This is useful for presenting financial figures or representing data from a relational database. Like trees, tables in Swing are incredibly powerful and customizable. If you go with the default options, they're also pretty easy to use.The
JTable
class represents a visual table component. AJTable
is based on aTableModel
, one of a dozen or so supporting interfaces and classes in thejavax.swing.table
package.JTable
has one constructor that creates a default table model for you from arrays of data. You just need to supply it with the names of your column headers and a 2D array ofObject
s representing the table's data. The first index selects the table's row; the second index selects the column. The following example shows how easy it is to get going with tables using this constructor://file: DullShipTable.java import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.table.*; public class DullShipTable { public static void main(String[] args) { // create some tabular data String[] headings = new String[] {"Number", "Hot?", "Origin", "Destination", "Ship Date", "Weight" }; Object[][] data = new Object[][] { { "100420", Boolean.FALSE, "Des Moines IA", "Spokane WA", "02/06/2000", new Float(450) }, { "202174", Boolean.TRUE, "Basking Ridge NJ", "Princeton NJ", "05/20/2000", new Float(1250) }, { "450877", Boolean.TRUE, "St. Paul MN", "Austin TX", "03/20/2000", new Float(1745) }, { "101891", Boolean.FALSE, "Boston MA", "Albany NY", "04/04/2000", new Float(88) } }; // create the data model and the JTable JTable table = new JTable(data, headings); JFrame frame = new JFrame("DullShipTable v1.0"); frame.getContentPane().add(new JScrollPane(table)); frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); frame.setSize(500, 200); frame.setVisible(true); } }
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Desktops
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterAt this point, you might be thinking that there's nothing more that Swing could possibly do, but it just keeps getting better. If you've ever wished that you could have windows within windows in Java, Swing makes it possible with
JDesktopPane
andJInternalFrame
. Figure 18-10 shows how this works.Figure 18-10: Using internal frames on a JDesktopPaneYou get a lot of behavior for free fromJInternalFrame
. Internal frames can be moved by clicking and dragging the titlebar. They can be resized by clicking and dragging on the window's borders. Internal frames can be iconified, which means reducing them to a small icon representation on the desktop. Internal frames may also be made to fit the entire size of the desktop (maximized). To you, the programmer, the internal frame is just a kind of special container. You can put your application's data inside an internal frame just as with any other type of container.The following brief example shows how to create the windows shown in Figure 18-10://file: Desktop.java import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.border.*; public class Desktop { public static void main(String[] args) { JFrame frame = new JFrame("Desktop"); JDesktopPane desktop = new JDesktopPane(); for (int i = 0; i < 5; i++) { JInternalFrame internal = new JInternalFrame("Frame " + i, true, true, true, true); internal.setSize(180, 180); internal.setLocation(i * 20, i * 20); internal.setVisible(true); desktop.add(internal); } frame.setSize(300, 300); frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); frame.setContentPane(desktop); frame.setVisible(true); } }
All we've done here is to create aJDesktopPane
and add internal frames to it. When eachJInternalFrame
is constructed, we specify a window title. The fourtrue
values passed in the constructor specify that the new window should be resizable, closable, maximizable, and iconifiable.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Pluggable Look-and-Feel
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterWe mentioned before that Swing components can easily change their appearance, like master spies or thespians. Generally, different kinds of components within an application have coordinated appearances that are similar in some way. For example, they probably use the same font and the same basic color scheme. The collection of appearances and common behavior of GUI components is called a look-and-feel (L&F).Part of the job of designing a GUI for an operating system is designing the L&F. Mac OS, therefore, has its own distinctive L&F, as does Windows. Java offers several different L&F schemes for Swing components. If you're adept at graphic design, you can write your own L&F schemes and easily convince Swing to use them. This chameleon-like ability to change appearance is called pluggable look-and-feel, sometimes abbreviated PLAF (don't pronounce that out loud if others are eating).Seeing is believing. Here's an example that creates a handful of Swing components. Menu items allow you to change the L&F dynamically while the application is running:
//file: QuickChange.java import java.awt.*; import java.awt.event.*; import javax.swing.*; public class QuickChange extends JFrame { public QuickChange() { super("QuickChange v1.0"); createGUI(); } protected void createGUI() { setSize(300, 200); // create a simple File menu JMenu file = new JMenu("File", true); JMenuItem quit = new JMenuItem("Quit"); file.add(quit); quit.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { System.exit(0); } }); // create the Look & Feel menu JMenu lnf = new JMenu("Look & Feel", true); ButtonGroup buttonGroup = new ButtonGroup(); final UIManager.LookAndFeelInfo[] info = UIManager.getInstalledLookAndFeels(); for (int i = 0; i < info.length; i++) { JRadioButtonMenuItem item = new JRadioButtonMenuItem(info[i].getName(), i == 0); final String className = info[i].getClassName(); item.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent ae) { try { UIManager.setLookAndFeel(className); } catch (Exception e) { System.out.println(e); } SwingUtilities.updateComponentTreeUI(QuickChange.this); } }); buttonGroup.add(item); lnf.add(item); } // add the menu bar JMenuBar mb = new JMenuBar(); mb.add(file); mb.add(lnf); setJMenuBar(mb); // add some components JPanel jp = new JPanel(); jp.add(new JCheckBox("JCheckBox")); String[] names = new String[] { "Tosca", "Cavaradossi", "Scarpia", "Angelotti", "Spoletta", "Sciarrone", "Carceriere", "Il sagrestano", "Un pastore" }; jp.add(new JComboBox(names)); jp.add(new JButton("JButton")); jp.add(new JLabel("JLabel")); jp.add(new JTextField("JTextField")); JPanel main = new JPanel(new GridLayout(1, 2)); main.add(jp); main.add(new JScrollPane(new JList(names))); setContentPane(main); setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); } public static void main(String[] args) { new QuickChange().setVisible(true); } }
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Creating Custom Components
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterIn this chapter and the previous, we've worked with different user interface objects. We've used Swing's impressive repertoire of components as building blocks and extended their functionality, but we haven't actually created any new components. In this section, we create an entirely new component from scratch, a dial.Until now, our examples have been fairly self-contained; they generally know everything about what to do and don't rely on additional parts to do processing. Our menu example created a
DinnerFrame
class that had a menu of dinner options, but it included all the processing needed to handle the user's selections. If we wanted to process the selections differently, we'd have to modify the class. A true component separates the detection of user input from the handling of those choices. It lets the user take some action and then informs other interested parties by emitting events.Since we want our new classes to be components, they should communicate the way components communicate: by generating event objects and sending those events to listeners. So far, we've written a lot of code that listened for events but haven't seen an example that generated its own custom events.Generating events sounds like it might be difficult, but it isn't. You can either create new kinds of events by subclassingjava.util.EventObject
, or use one of the standard event types. In either case, you just need to allow registration of listeners for your events and provide a means to deliver events to those listeners. Swing'sJComponent
class provides a protected member variable,listenerList
, you can use to keep track of event listeners. It's an instance ofEventListenerList
; basically it acts like the maître d' at a restaurant, keeping track of all event listeners, sorted by type.Often, you won't need to worry about creating a custom event type.JComponent
has methods that support firing of genericPropertyChangeEvent
s whenever one of a component's properties changes. The example we'll look at next uses this infrastructure to firePropertyChangeEvent
s whenever a value changes.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Chapter 19: Layout Managers
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterA layout manager arranges the child components of a container, as shown in Figure 19-1. It positions and sets the size of components within the container's display area according to a particular layout scheme. The layout manager's job is to fit the components into the available area while maintaining some spatial relationships among them. AWT and Swing come with several standard layout managers that will collectively handle most situations; you can make your own layout managers if you have special requirements.Figure 19-1: A layout manager at workEvery container has a default layout manager. When you make a new container, it comes with a
LayoutManager
object of an appropriate type. You can install a new layout manager at any time with thesetLayout()
method. For example, we can set the layout manager of a Swing container's content pane to a type calledBorderLayout
like so:mycontainer.getContentPane().setLayout( new BorderLayout() );
Notice that although we have created aBorderLayout
, we haven't bothered to save a reference to it. This is typical; after installing a layout manager it usually does its work behind the scenes, interacting with the container. You rarely call the layout manager's methods directly, so you don't usually need a reference (a notable exception isCardLayout
). However, you do need to know what the layout manager is going to do with your components as you work with them.TheLayoutManager
is consulted whenever a container'sdoLayout()
method is called to reorganize the contents. It does its job by calling thesetLocation()
orsetBounds()
methods of the individual child components to arrange them in the container's display area. A container is laid out the first time it is displayed and thereafter whenever the container'srevalidate()
method is called. Containers that are a subclass of theWindow
class (Frame
,JFrame
, andJWindow
) are automatically validated whenever they are packed or resized. Callingpack()
sets the window's size as small as possible while granting all its components their preferred sizes.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - FlowLayout
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapter
FlowLayout
is a simple layout manager that tries to arrange components at their preferred sizes, from left to right and top to bottom in the container. AFlowLayout
can have a specified row justification ofLEFT
,CENTER
, orRIGHT
and a fixed horizontal and vertical padding. By default, a flow layout usesCENTER
justification, meaning that all components are centered within the area allotted to them.FlowLayout
is the default forJPanel
s.The following example adds five buttons to the content pane of aJFrame
using the defaultFlowLayout
://file: Flow.java import java.awt.*; import java.awt.event.*; import javax.swing.*; public class Flow extends JPanel { public Flow() { // FlowLayout is default layout manager for a JPanel add(new JButton("One")); add(new JButton("Two")); add(new JButton("Three")); add(new JButton("Four")); add(new JButton("Five")); } public static void main(String[] args) { JFrame frame = new JFrame("Flow"); frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); frame.setSize(400, 75); frame.setLocation(200, 200); Flow flow = new Flow(); frame.setContentPane(flow); frame.setVisible(true); } }
The result is shown in Figure 19-2.Figure 19-2: A flow layoutTry resizing the window. If it is made narrow enough, some of the buttons will spill over to a second or third row.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - GridLayout
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapter
GridLayout
arranges components into regularly spaced rows and columns. The components are arbitrarily resized to fit the grid; their minimum and preferred sizes are consequently ignored.GridLayout
is most useful for arranging identically sized objects—perhaps a set ofJPanel
s, each using a different layout manager.GridLayout
takes the number of rows and columns in its constructor. If you subsequently give it too many objects to manage, it adds extra columns to make the objects fit. You can also set the number of rows or columns to0
, which means that you don't care how many elements the layout manager packs in that dimension. For example,GridLayout(2,0)
requests a layout with two rows and an unlimited number of columns; if you put ten components into this layout, you'll get two rows of five columns each.The following example sets aGridLayout
with three rows and two columns as its layout manager://file: Grid.java import java.awt.*; import java.awt.event.*; import javax.swing.*; public class Grid extends JPanel { public Grid() { setLayout(new GridLayout(3, 2)); add(new JButton("One")); add(new JButton("Two")); add(new JButton("Three")); add(new JButton("Four")); add(new JButton("Five")); } public static void main(String[] args) { JFrame frame = new JFrame("Grid"); frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); frame.setSize(200, 200); frame.setLocation(200, 200); frame.setContentPane(new Grid()); frame.setVisible(true); } }
The results are shown in Figure 19-3.Figure 19-3: A grid layoutThe five buttons are laid out, in order, from left to right, top to bottom, with one empty spot.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - BorderLayout
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapter
BorderLayout
is a little more interesting. It tries to arrange objects in one of five geographical locations, represented by constants in theBorderLayout
class:NORTH
,SOUTH
,EAST
,WEST
, andCENTER
, optionally with some padding between.BorderLayout
is the default layout for the content panes ofJWindow
andJFrame
objects. Because each component is associated with a direction,BorderLayout
can manage at most five components; it squashes or stretches those components to fit its constraints. As we'll see in the second example, this means that you often want to haveBorderLayout
manage sets of components in their own panels.When we add a component to a container with a border layout, we need to specify both the component and the position at which to add it. To do so, we use an overloaded version of the container'sadd()
method that takes an additional argument as a constraint. The constraint specifies the name of a position within theBorderLayout
.The following application sets aBorderLayout
and adds our five buttons again, named for their locations://file: Border1.java import java.awt.*; import java.awt.event.*; import javax.swing.*; public class Border1 extends JPanel { public Border1() { setLayout(new BorderLayout()); add(new JButton("North"), BorderLayout.NORTH ); add(new JButton("South"), BorderLayout.SOUTH ); add(new JButton("East"), BorderLayout.EAST ); add(new JButton("West"), BorderLayout.WEST ); add(new JButton("Center"), BorderLayout.CENTER ); } public static void main(String[] args) { JFrame frame = new JFrame("Border1"); frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); frame.setSize(300, 300); frame.setLocation(200, 200); frame.setContentPane(new Border1()); frame.setVisible(true); } }
The result is shown in Figure 19-4.Figure 19-4: A border layoutSo, how exactly is the area divided up? Well, the objects atAdditional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - BoxLayout
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterMost layout managers are part of the
java.awt
package and were defined back when Java was first released. Swing adds a couple of new general-purpose layout managers in thejavax.swing
package; one isBoxLayout
. This layout manager is useful for creating simple toolbars or vertical button bars. It lays out components in a single row or column. It is similar toFlowLayout
but does not wrap components into new rows.Although you can useBoxLayout
directly, Swing includes a handy container calledBox
that takes care of the details for you. EveryBox
usesBoxLayout
, but you don't really have to worry about it; theBox
class includes some very useful methods for laying out components.You can create a horizontal or vertical box usingBox
's static methods.Container horizontalBox = Box.createHorizontalBox(); Container verticalBox = Box.createVerticalBox();
Once theBox
is created, you can justadd()
components as usual:Container box = Box.createHorizontalBox(); box.add(new JButton("In the"));
Box
includes several other static methods that create special invisible components that can be used to guide theBoxLayout
. The first of these is glue ; glue is really space between components in theBox
. When theBox
is resized, glue expands or contracts as more or less space is available. The other special invisible component type is a strut . Like glue, a strut represents space between components, but it doesn't resize.The following example creates a horizontalBox
(shown in Figure 19-6) that includes both glue and struts. Play around by resizing the window to see the effect of the glue and the struts.//file: Boxer.java import java.awt.*; import java.awt.event.*; import javax.swing.*; public class Boxer extends JPanel { public static void main(String[] args) { JFrame frame = new JFrame("Boxer"); frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); frame.setSize(250, 250); frame.setLocation(200, 200); Container box = Box.createHorizontalBox(); box.add(Box.createHorizontalGlue()); box.add(new JButton("In the")); box.add(Box.createHorizontalGlue()); box.add(new JButton("clearing")); box.add(Box.createHorizontalStrut(10)); box.add(new JButton("stands")); box.add(Box.createHorizontalStrut(10)); box.add(new JButton("a")); box.add(Box.createHorizontalGlue()); box.add(new JButton("boxer")); box.add(Box.createHorizontalGlue()); frame.getContentPane().add(box, BorderLayout.CENTER); frame.pack(); frame.setVisible(true); } }
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - CardLayout
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapter
CardLayout
is a special layout manager for creating the effect of a "stack" of components. Instead of arranging all of the container's components, it displays only one at a time. You might use this kind of layout to implement a custom-tabbed panel of some kind. In fact, there's probably little reason to use this layout given the SwingJTabbedPane
component, described in Chapter 17. We include it here mainly for completeness.To add a component to aCardLayout
, use a two-argument version of the container'sadd()
method; the extra argument is an arbitrary string that serves as the card's name:add("netconfigscreen", myComponent);
To bring a particular card to the top of the stack, call theCardLayout
'sshow()
method with two arguments: the parentContainer
and the name of the card you want to show. There are also methods—first()
,last()
,next()
, andprevious()
for working with the stack of cards. These are allCardLayout
instance methods. To invoke them, you need a reference to theCardLayout
object itself, not to the container it manages. Each method takes a single argument: the parentContainer
. Here's an example://file: Card.java import java.awt.*; import java.awt.event.*; import javax.swing.*; public class Card extends JPanel { CardLayout cards = new CardLayout(); public Card() { setLayout(cards); ActionListener listener = new ActionListener() { public void actionPerformed(ActionEvent e) { cards.next(Card.this); } }; JButton button; button = new JButton("one"); button.addActionListener(listener); add(button, "one"); button = new JButton("two"); button.addActionListener(listener); add(button, "two"); button = new JButton("three"); button.addActionListener(listener); add(button, "three"); } public static void main(String[] args) { JFrame frame = new JFrame("Card"); frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); frame.setSize(200, 200); frame.setLocation(200, 200); frame.setContentPane(new Card()); frame.setVisible(true); } }
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - GridBagLayout
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapter
GridBagLayout
is a very flexible layout manager that allows you to position components relative to one another using constraints. WithGridBagLayout
(and a fair amount of effort), you can create almost any imaginable layout. Components are arranged at logical coordinates on an abstract grid. We'll call them "logical" coordinates because they really designate positions in the space of rows and columns formed by the set of components. Rows and columns of the grid stretch to different sizes, based on the sizes and constraints of the components they hold.A row or column in aGridBagLayout
expands to accommodate the dimensions and constraints of the largest component it contains. Individual components may also be told to span more than one row or column. Components that aren't as large as their grid cell can be anchored (positioned to one side) within their cell. They can also be set to fill or to expand their size in either dimension. Extra area in the grid rows and columns can be parceled out according to the weight constraints of the components. In this way, you can control how various components will grow and stretch when a window is resized.GridBagLayout
is much easier to use in a graphical WYSIWYG GUI builder environment. That's because working withGridBag
is kind of like messing with the "rabbit ears" antennae on your television. It's not particularly difficult to get the results that you want through trial and error, but writing out hard and fast rules for how to go about it is difficult. In short,GridBagLayout
is complex and has some quirks. It is also simply a bit ugly both in model and implementation. Remember that you can do a lot with nested panels and by composing simpler layout managers within one another. If you look back through this chapter, you'll see some examples of composite layouts; it's up to you to determine how far you should go before making the break from simpler layout managers to a more complex all-in-one layout manager likeGridBagLayout
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Nonstandard Layout Managers
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterWe've covered the basic layout managers; with them, you should be able to create just about any user interface you like.But that's not all, folks. If you want to experiment with layout managers that are undocumented, may change, and may not be available locally on all platforms, look in the
sun.awt
classes. You'll find aHorizBagLayout
, aVerticalBagLayout
, anOrientableFlowLayout
, and aVariableGridLayout
. Furthermore, public domain layout managers of all descriptions are on the Net.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Absolute Positioning
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterIt's possible to set the layout manager to
null
: no layout control. You might do this to position an object on the display at some absolute coordinates. This is usually not the right approach. Components might have different minimum sizes on different platforms, and your interface would not be very portable.The following example doesn't use a layout manager and works with absolute coordinates instead://file: MoveButton.java import java.awt.*; import java.awt.event.*; import javax.swing.*; public class MoveButton extends JPanel { JButton button = new JButton("I Move"); public MoveButton() { setLayout(null); add(button); button.setSize(button.getPreferredSize()); button.setLocation(20, 20); addMouseListener(new MouseAdapter() { public void mousePressed(MouseEvent e) { button.setLocation(e.getX(), e.getY()); } }); } public static void main(String[] args) { JFrame frame = new JFrame("MoveButton"); frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); frame.setSize(250, 200); frame.setLocation(200, 200); frame.setContentPane(new MoveButton()); frame.setVisible(true); } }
Click in the window area, outside of the button, to move the button to a new location. Try resizing the window and note that the button stays at a fixed position relative to the window's upper-left corner.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - SpringLayout
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterThe
SpringLayout
was added in Java 1.4. It supports a combination of absolute positioning and point-to-point attachments between components (kind of like the "glue" of theBoxLayout
).SpringLayout
is useful in GUI builder applications because it's easy to translate manual user placement into these kinds of constraints.SpringLayout
usesSpring
objects to attach edges of components.Spring
s have a range of motion and can be anchored at a coordinate or at a component's edge. Any two component edges can also be connected by aSpring
. The two edges may belong to two different components, in which case, the spring constrains the way the components are placed relative to one another, or they may belong to the same component, in which case, the spring constrains the width or height of the component.We don't coverSpringLayout
here, but you can read about it in O'Reilly's Java Swing.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Chapter 20: Drawing with the 2D API
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterIn previous chapters, we looked at the components and component architecture of graphical user interfaces (GUIs) using Java's Swing and AWT packages. Now, we're going to drop down a level and look at the procedural APIs for rendering graphics in Java applications. These APIs are used by components to paint themselves on the screen and to display icons and graphics. This chapter goes into some detail about Java's sophisticated 2D, resolution-independent drawing API and the core tools for loading and displaying images. In the next chapter, we'll explore dynamic image-processing tools in more detail and look at the classes that let you generate and modify image data, pixel by pixel.The classes you'll use for drawing come from six packages:
java.awt
,java.awt.color
,java.awt.font
,java.awt.geom
,java.awt.image
, andjava.awt.print
. Collectively, these classes make up most of the 2D API and cover the drawing of shapes, text, and images. Figure 20-1 shows a bird's-eye view of these classes. There's much more in the 2D API than we can cover in two chapters. For a full treatment, see Jonathan Knudsen's Java 2D Graphics (O'Reilly).An instance ofjava.awt.Graphics2D
is called a graphics context. It represents a drawing surface such as a component's display area, a page on a printer, or an offscreen image buffer. A graphics context provides methods for drawing three kinds of graphics objects: shapes, text, and images.Graphics2D
is called a graphics context because it also holds contextual information about the drawing area. This information includes the drawing area's clipping region, painting color, transfer mode, text font, and geometric transformation. If you consider the drawing area to be a painter's canvas, you might think of a graphics context as an easel that holds a set of tools and marks off the work area.Figure 20-1: Graphics classes of the 2D APIThere are four ways to acquire aGraphics2D
object. The following list describes them in order from the most common to the least:Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - The Big Picture
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterThe classes you'll use for drawing come from six packages:
java.awt
,java.awt.color
,java.awt.font
,java.awt.geom
,java.awt.image
, andjava.awt.print
. Collectively, these classes make up most of the 2D API and cover the drawing of shapes, text, and images. Figure 20-1 shows a bird's-eye view of these classes. There's much more in the 2D API than we can cover in two chapters. For a full treatment, see Jonathan Knudsen's Java 2D Graphics (O'Reilly).An instance ofjava.awt.Graphics2D
is called a graphics context. It represents a drawing surface such as a component's display area, a page on a printer, or an offscreen image buffer. A graphics context provides methods for drawing three kinds of graphics objects: shapes, text, and images.Graphics2D
is called a graphics context because it also holds contextual information about the drawing area. This information includes the drawing area's clipping region, painting color, transfer mode, text font, and geometric transformation. If you consider the drawing area to be a painter's canvas, you might think of a graphics context as an easel that holds a set of tools and marks off the work area.Figure 20-1: Graphics classes of the 2D APIThere are four ways to acquire aGraphics2D
object. The following list describes them in order from the most common to the least:- From AWT or Swing as the result of a painting request on a component
- In this case, a new graphics context for the appropriate area is created and passed to your component's
paint()
orupdate()
method. (Theupdate()
method really applies only to AWT components, not the newer Swing components.) - Directly from an offscreen image buffer
- In this case, we ask the image buffer for a graphics context directly. We'll use this when we discuss techniques such as double buffering.
-
By copying an existing
Graphics2D
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - The Rendering Pipeline
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterOne of the strengths of the 2D API is that shapes, text, and images are manipulated in many of the same ways. In this section, we'll describe what happens to shapes, text, and images after you give them to a
Graphics2D object
. Rendering is the process of taking some collection of shapes, text, and images and figuring out how to represent them by coloring pixels on a screen or printer.Graphics2D
supports four rendering operations:- Draw a shape's outline with the
draw()
method. - Fill a shape's interior with the
fill()
method. - Draw some text with the
drawString()
method. - Draw an image with any of the many forms of the
drawImage()
method.
The graphics context represented by aGraphics2D
object holds the following properties, whose values are controlled by corresponding accessor methods (e.g.,getFont()
andsetFont()
):- paint
- The current paint (an object of type
java.awt.Paint
) determines what color or pattern will be used to fill a shape. This affects the drawing of shape outlines and text, as well. You can change the current paint usingGraphics2D
'ssetPaint()
method. Note that theColor
class implements thePaint
interface, so you can passColor
s tosetPaint()
if you want to use solid colors. - stroke
Graphics2D
uses the stroke to determine how to draw the outline of shapes that are passed to itsdraw()
method. In graphics terminology, to "stroke" a shape means to take a path defined by the shape and effectively trace it with a pen or brush of a certain size and characteristics. For example, drawing the shape of a circle using a stroke that acts like a solid line would yield a washer or ring shape. The
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - A Quick Tour of Java 2D
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterNext we'll embark on a quick tour of Java 2D, including working with shapes and text. We'll finish with an example of Java 2D in action.The simplest path through the rendering pipeline is filling shapes. For example, the following code creates an ellipse and fills it with a solid color. (This code would live inside a
paint()
method somewhere. We'll present a complete, ready-to-run example a little later.)Shape c = new Ellipse2D.Float(50, 25, 150, 150); // x,y,width,height g2.setPaint(Color.blue); g2.fill(c);
Here,g2
is ourGraphics2D
object. TheEllipse2D
shape class is abstract but is implemented by concrete inner subclasses calledFloat
andDouble
that work with float or double precision, respectively. TheRectangle2D
class, similarly, has concrete subclassesRectangle2D.Float
andRectangle2D.Double
.In the call tosetPaint()
, we tellGraphics2D
to use a solid color, blue, for all subsequent filling operations. Next, the call tofill()
tellsGraphics2D
to fill the given shape.All geometric shapes in the 2D API are represented by implementations of thejava.awt.geom.Shape
interface. This interface defines methods that are common to all shapes, like returning a rectangle bounding box or testing if a point is inside the shape. Thejava.awt.geom
package is a smorgasbord of useful shape classes, includingRectangle2D
,RoundRectangle2D
(a rectangle with rounded corners),Arc2D
,Ellipse2D
, and others. In addition, a few more basic classes injava.awt
areShape
s:Rectangle
,Polygon
, andArea
.Drawing a shape's outline is only a little bit more complicated. Consider the following example:Shape r = new Rectangle2D.Float(100, 75, 100, 100); g2.setStroke(new BasicStroke(4)); g2.setPaint(Color.yellow); g2.draw(r);
Here, we tellGraphics2D
to use a stroke that is four units wide and a solid color, yellow, for filling the stroke. When we calldraw()
,Graphics2D
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Filling Shapes
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapter
Iguana
fills its shapes with a number of colors, using thesetPaint()
method ofGraphics2D
. This method sets the current color in the graphics context, so we set it to a different color before each drawing operation.setPaint()
accepts any object that implements thePaint
interface. The 2D API includes three implementations of this interface, representing solid colors, color gradients, and textures.Thejava.awt.Color
class represents color in Java. AColor
object describes a single color and implements thePaint
interface for filling an area with it. You can create an arbitraryColor
by specifying the red, green, and blue values, either as integers between 0 and 255 or as floating-point values between 0.0 and 1.0. The (somewhat strange)getColor()
method can be used to look up a named color in the system properties table, as described in Chapter 11.TheColor
class also defines a number ofstatic final
color values; these are what we used in theIguana
example. These constants, such asColor.black
andColor.red
, provide a convenient set of basic color objects for your drawings.A color gradient is a smooth blend from one color to another. TheGradientPaint
class encapsulates this idea in a handy implementation of thePaint
interface. All you need to do is specify two points and the color at each point.GradientPaint
takes care of the details so that the color fades smoothly from one point to the other. In the previous example, the ellipse is filled with a gradient this way:g2.setPaint(new GradientPaint(40, 40, Color.blue, 60, 50, Color.white, true));
The last parameter inGradientPaint
's constructor determines whether the gradient is cyclic. In a cyclic gradient, the colors keep fluctuating beyond the two points that you've specified. Otherwise, the gradient just draws a single blend from one point to the other. Beyond each endpoint, the color is solid.A texture is simply an image repeated over and over like a floor tile. This concept is represented in the 2D API with theAdditional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Stroking Shape Outlines
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterJust as a
Graphics2D
object's current paint determines how its shapes are filled, its current stoke determines how its shapes are outlined. The current stroke determines such drawing features as line thickness, line dashing, and end styles. In the old days, lines were one pixel wide and that was that. With Java 2D, line thickness can be set with floating-point accuracy and the results, like everything else, are subject to the rendering pipeline's transformations and scaling.To set the current stroke inGraphics2D
, callsetStroke()
with any implementation of theStroke
interface. Fortunately, the 2D API includes aBasicStroke
class that probably does everything you need. UsingBasicStroke
, you can create dashed lines, control what decoration is added to line ends, and decide how the corners in an outline should be drawn.By default,Graphics2D
uses a solid stroke with a width of 1. In the previousIguana
example, the line width is changed just before the outline of the rounded rectangle is drawn, like so:g2.setStroke(new BasicStroke(4));
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Using Fonts
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterText fonts in Java are represented by instances of the
java.awt.Font
class. AFont
object is constructed from a name, style identifier, and a point size. We can create aFont
object at any time, but it's meaningful only when applied to a particular component on a given display device. Here are a couple of fonts:Font smallFont = new Font("Monospaced", Font.PLAIN, 10); Font bigFont = new Font("Serif", Font.BOLD, 18);
Font names come in three varieties: family names, face names (also called font names), and logical names. Family and font names are closely related. For example, Garamond Italic is a font name for a font whose family name is Garamond.A logical name is a generic name for the font family. The following logical font names should be available on all platforms:Serif
(generic name forTimesRoman
)SansSerif
(generic name forHelvetica
)Monospaced
(generic name forCourier
)Dialog
DialogInput
The logical font name is mapped to an actual font on the local platform. Java's fonts .properties file maps the font names to the available fonts, covering as much of the Unicode character set as possible. If you request a font that doesn't exist, you get the default font.One of the big wins in the 2D API is that it can use most of the fonts you have installed on your computer. The following program prints out a full list of the fonts that are available to the 2D API://file: ShowFonts.java import java.awt.*; public class ShowFonts { public static void main(String[] args) { Font[] fonts; fonts = GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts(); for (int i = 0; i < fonts.length; i++) { System.out.print(fonts[i].getFontName() + " : "); System.out.print(fonts[i].getFamily() + " : "); System.out.print(fonts[i].getName()); System.out.println(); } } }
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Displaying Images
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterSo far, we've worked with methods for drawing simple shapes and displaying text. For more complex graphics, we'll be working with images. In a typical Swing application, the simplest way to display an image in your application is to use an
ImageIcon
with aJLabel
component. Here, we are talking about working with image data at a lower level, for painting. The 2D API has a powerful set of tools for generating and displaying image data. We'll start with the basics of thejava.awt.Image
class and see how to load an image into an application and draw it where you want it. The Java AWT toolkit will handle most of the details for us. In the next chapter, we'll go further to discuss how to manage image loading manually as well as how to create and manipulate raw pixel data, allowing you to create any kind of graphics you can dream up.The core AWT supports images encoded in JPEG, PNG, and GIF. (This includes GIF89a animations so that you can work with simple animations as easily as static images.) If you need to work with other types of images, you can turn to the Java Advanced Imagingjavax.imageio
framework. We'll mention it brieflyhere
and again in the next chapter when we discuss theBufferedImage
class.The ImageIO framework is bundled with Java 1.4 and later. In many ways, it supercedes and replaces the image handling functionality of the core AWT just as Swing extends and replaces the old AWT components. The ImageIO framework is easily extensible for new image types through plug-ins. However, out of the box, all that it adds is the ability to read bitmap (BMP) and wireless bitmap (WBMP) images. Since most Java code can and does use the original AWT functionality, that is what we'll focus on.Thejava.awt.Image
class represents a view of an image. The view is created from an image source that produces pixel data. Images can be from a static source, such as a JPEG file, or a dynamic one, such as a video stream or a graphics engine.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Drawing Techniques
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterNow that we've learned about the basic tools, let's put a few of them together. In this section, we'll look at some techniques for doing fast and flicker-free drawing and painting. If you're interested in animation, this is for you. Drawing operations take time, and time spent drawing leads to delays and imperfect results. Our goals are to minimize the amount of drawing work we do and, as much as possible, to do that work away from the eyes of the user. To do this, we use two techniques: clipping and double buffering. Fortunately, Swing now handles double buffering by default. You won't have to implement this logic on your own, but it's useful to understand it.Our first example,
DragImage
, illustrates some of the issues in updating a display. Like many animations, it has two parts: a constant background and a changing object in the foreground. In this case, the background is a checkerboard pattern, and the object is a small, scaled image we can drag around on top of it, as shown in Figure 20-4:import java.awt.*; import java.awt.event.*; import javax.swing.*; public class DragImage extends JComponent implements MouseMotionListener { static int imageWidth=60, imageHeight=60; int grid = 10; int imageX, imageY; Image image; public DragImage(Image i) { image = i; addMouseMotionListener(this); } public void mouseDragged(MouseEvent e) { imageX = e.getX(); imageY = e.getY(); repaint(); } public void mouseMoved(MouseEvent e) {} public void paint(Graphics g) { Graphics2D g2 = (Graphics2D)g; int w = getSize().width / grid; int h = getSize().height / grid; boolean black = false; for (int y = 0; y <= grid; y++) for (int x = 0; x <= grid; x++) { g2.setPaint(black ? Color.black : Color.white); black = !black; g2.fillRect(x * w, y * h, w, h); } g2.drawImage(image, imageX, imageY, this); } public static void main(String[] args) { String imageFile = "L1-Light.jpg"; if (args.length > 0) imageFile = args[0]; // Turn off double buffering //RepaintManager.currentManager(null).setDoubleBufferingEnabled(false); Image image = Toolkit.getDefaultToolkit().getImage( DragImage.class.getResource(imageFile)); image = image.getScaledInstance( imageWidth,imageHeight,Image.SCALE_DEFAULT); JFrame frame = new JFrame("DragImage"); frame.getContentPane().add( new DragImage(image) ); frame.setSize(300, 300); frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); frame.setVisible(true); } }
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Printing
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterEarlier in this chapter, we hinted at the possibility that you could draw the same stuff on the screen and the printer. It's true; all you really need to do is get a
Graphics2D
object that represents a printer rather than an area of the screen. Java's printing API provides the necessary plumbing. There isn't room here to describe the whole Printing API, but we will provide you with a short example that will let you get your feet wet (and your paper flowing).The printing classes are tucked away in thejava.awt.print
package. You can print anything that implements thePrintable
interface. This interface has only one method—you guessed it,print()
, which is like thepaint()
methods we've already worked with. It accepts aGraphics
object that represents the drawing surface of the printer's page. It also accepts aPageFormat
object that encapsulates information about the paper on which you're printing. Finally,print()
is passed the number of the page that is being rendered. All Swing components implementPrintable
for you; you can override it in your own components to customize their printed appearance or to do arbitrary printing.Yourprint()
implementation should either render the requested page or state that it doesn't exist. You can do this by returning special values fromprint()
, eitherPrintable.PAGE_EXISTS
orPrintable.NO_SUCH_PAGE
.You can control a print job, including showing print and page setup dialogs, using thePrinterJob
class. The following class enables you to get something on paper. In this example, we work both sides of the printing equation: implementing a simplePrintable
interface to generate our data and printing it with thePrinterJob
API.//file: UnbelievablySimplePrint.java import java.awt.*; import java.awt.print.*; public class UnbelievablySimplePrint implements Printable { private static Font sFont = new Font("Serif", Font.PLAIN , 64); public int print(Graphics g, PageFormat Pf, int pageIndex) throws PrinterException { if (pageIndex > 0) return NO_SUCH_PAGE; Graphics2D g2 = (Graphics2D)g; g2.setFont(sFont); g2.setPaint(Color.black); g2.drawString("Save a tree!", 96, 144); return PAGE_EXISTS; } public static void main(String[] args) { PrinterJob job = PrinterJob.getPrinterJob(); job.setPrintable(new UnbelievablySimplePrint()); if (job.printDialog()) { try { job.print(); } catch (PrinterException e) {} } System.exit(0); } }
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Chapter 21: Working with Images and Other Media
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterUntil this point, we've confined ourselves to working with the high-level drawing commands of the
Graphics2D
class, using images in a hands-off mode. In this section, we'll clear up some of the mystery surrounding images and see how they can be created and transformed. The classes in thejava.awt.image
package handle images and their internals; Figure 21-1 shows the important classes in this package.First, we'll return to our discussion of image loading and see how we can get more control over image data using anImageObserver
to watch as it's processed asynchronously by GUI components. We'll also see how to use theMediaTracker
utility to handle the details for us. Then, we'll move on to the good stuff and have a look atBufferedImage
, which is an image whose pixel data is exposed to you through a memory buffer. If you're interested in creating sophisticated graphics, rendered images, or video, this will teach you about the foundations of image construction in Java.A few notes before we move on: Prior to Java 1.2, creating and modifying images was only possible through theImageProducer
andImageConsumer
interfaces, which, along withImageObserver
, provide low-level, stream-oriented views of the image data. We won't be covering image producers and consumers in this chapter; instead, we'll stick to the new APIs, which are more capable and easier to use in most cases. If you're interested in the older APIs you can find additional coverage and examples using them on the CD accompanying the book.Looking in the other directions, we will also be referring occasionally to thejavax.imageio
package, which is part of the Java Advanced Imaging API (JAI). If you need even more advanced capabilities such as image tiling, loading scaled versions of images over the network, and deferred execution of image data processing for working with really large images, you'll want to look at JAI.Figure 21-1: The java.awt.image packageOne of the challenges in building software for networked applications is that data is not always instantly available. Since some of Java's roots are in Internet applications such as web browsers, its image-handling APIs were designed specifically to accommodate the fact that images might take some time to load over a slow network, providing for detailed information about image-loading progress. While many client applications do not require handling of image data in this way, it's still useful to understand this mechanism if for no other reason than it appears in the most basic image-related APIs. The Swing toolkit adds its own layer of image handling over this with components such asAdditional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Loading Images
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterOne of the challenges in building software for networked applications is that data is not always instantly available. Since some of Java's roots are in Internet applications such as web browsers, its image-handling APIs were designed specifically to accommodate the fact that images might take some time to load over a slow network, providing for detailed information about image-loading progress. While many client applications do not require handling of image data in this way, it's still useful to understand this mechanism if for no other reason than it appears in the most basic image-related APIs. The Swing toolkit adds its own layer of image handling over this with components such as
ImageIcon
, which encapsulates an image source for you. After reading this chapter, you'll have an understanding of how the layers fit together.In the previous chapter, we mentioned that all operations on image data (e.g., loading, drawing, scaling) allow you to specify an "image observer" object as a participant. An image observer implements theImageObserver
interface, allowing it to receive notification as information about the image becomes available. The image observer is essentially a callback that is notified progressively as the image is loaded. For a static image, such as a GIF or JPEG data file, the observer is notified as chunks of image data arrive and also when the entire image is complete. For a video source or animation (e.g., GIF89), the image observer is notified at the end of each frame as the continuous stream of pixel data is generated.The image observer can do whatever it wants with this information. For example, in the last chapter we used the image observer built into the baseComponent
class. Although you probably didn't see it happen in our examples, theComponent
image observer invokedrepaint()
for us each time a new section of the image became available so that the picture, if it had taken a long time to load, would have displayed progressively. A different kind of image observer might have waited for the entire image before telling the application to display it; yet another use for an observer might be to update a loading meter showing how far the image loading had progressed.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Producing Image Data
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterThere are two approaches to generating image data. The high-level method is to treat the image as a drawing surface and use the methods of
Graphics2D
to render things into the image. The second way is to twiddle the bits that represent the pixels of the image data yourself. This is harder, but gives you arbitrary control for handling specific formats or mathematically analyzing or creating image data.Let's begin with the simpler approach, rendering on an image through drawing. We'll throw in a twist to make things interesting: we'll build an animation. Each frame will be rendered as we go along. This is very similar to the double buffering we examined in the last chapter, but this time we'll use a timer, instead of mouse events, as the signal to generate new frames.Swing performs double buffering automatically, so we don't even have to worry about the animation flickering. Although it looks like we're drawing directly to the screen, we're really drawing into an image that Swing uses for double buffering. All we need to do is draw the right thing at the right time.Let's look at an example,Hypnosis
, that illustrates the technique. This example shows a constantly shifting shape that bounces around the inside of a component. When screen savers first came of age, this kind of thing was pretty hot stuff.Hypnosis
is shown in Figure 21-2.Figure 21-2: A simple animationHere is its source code://file: Hypnosis.java import java.awt.*; import java.awt.event.*; import java.awt.geom.GeneralPath; import javax.swing.*; public class Hypnosis extends JComponent implements Runnable { private int[] coordinates; private int[] deltas; private Paint paint; public Hypnosis(int numberOfSegments) { int numberOfCoordinates = numberOfSegments * 4 + 2; coordinates = new int[numberOfCoordinates]; deltas = new int[numberOfCoordinates]; for (int i = 0 ; i < numberOfCoordinates; i++) { coordinates[i] = (int)(Math.random() * 300); deltas[i] = (int)(Math.random() * 4 + 3); if (deltas[i] > 4) deltas[i] = -(deltas[i] - 3); } paint = new GradientPaint(0, 0, Color.blue, 20, 10, Color.red, true); Thread t = new Thread(this); t.start(); } public void run() { try { while (true) { timeStep(); repaint(); Thread.sleep(1000 / 24); } } catch (InterruptedException ie) {} } public void paint(Graphics g) { Graphics2D g2 = (Graphics2D)g; g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); Shape s = createShape(); g2.setPaint(paint); g2.fill(s); g2.setPaint(Color.white); g2.draw(s); } private void timeStep() { Dimension d = getSize(); if (d.width == 0 || d.height == 0) return; for (int i = 0; i < coordinates.length; i++) { coordinates[i] += deltas[i]; int limit = (i % 2 == 0) ? d.width : d.height; if (coordinates[i] < 0) { coordinates[i] = 0; deltas[i] = -deltas[i]; } else if (coordinates[i] > limit) { coordinates[i] = limit - 1; deltas[i] = -deltas[i]; } } } private Shape createShape() { GeneralPath path = new GeneralPath(); path.moveTo(coordinates[0], coordinates[1]); for (int i = 2; i < coordinates.length; i += 4) path.quadTo(coordinates[i], coordinates[i + 1], coordinates[i + 2], coordinates[i + 3]); path.closePath(); return path; } public static void main(String[] args) { JFrame frame = new JFrame("Hypnosis"); frame.getContentPane().add( new Hypnosis(4) ); frame.setSize(300, 300); frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); frame.setVisible(true); } }
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Filtering Image Data
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterAn image filter is an object that performs transformations on image data. The Java 2D API supports image filtering through the
BufferedImageOp
interface. An image filter takes aBufferedImage
as input (the source image) and performs some processing on the image data, producing anotherBufferedImage
(the destination image).The 2D API comes with a handy toolbox ofBufferedImageOp
implementations, as summarized in Table 21-1.Table 21-1: Image operators in the 2D API NameDescriptionAffineTransformOp
Transforms an image geometricallyColorConvertOp
Converts from one color space to anotherConvolveOp
Performs a convolution, a mathematical operation that can be used to blur, sharpen, or otherwise process an imageLookupOp
Uses one or more lookup tables to process image valuesRescaleOp
Uses multiplication to process image valuesLet's take a look at two of the simpler image operators. First, try the following application. It loads an image (the first command-line argument is the filename) and processes it in different ways as you select items from the combo box. The application is shown in Figure 21-6.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Saving Image Data
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterWe've spent a lot of time talking about loading images from files and generating and transforming image data, but nothing about saving it. First, let's remember that saving an image to a file such as a JPG or GIF really implies doing two things: encoding it (highly compressing the data in a way optimized for the type of image) and then writing it to a file, possibly with various metadata. As we mentioned earlier, the core AWT does not provide tools for encoding image data, only decoding it. By contrast, the ImageIO framework has the capability of writing images in any format that it can read.Writing a
BufferedImage
is simply a matter of calling the staticImageIO write()
method:File outFile = new File("/tmp/myImage.png"); ImageIO.write( bufferedImage , "png", outFile );
The second argument is a string identifier that names the image type. You can get the list of supported formats by callingImageIO.getWriterFormatNames()
. We should note that the actual type of the image argument is something calledRenderedImage
, butBufferedImage
implements that interface.More control over the encoding, for example JPG quality settings, can be had by getting anImageWriter
for the output format and usingImageWriteParam
s. The process is similar to that in the reader progress listener snippet from the section "ImageIO."Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Simple Audio
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterNow we'll turn from images and open our ears to audio. The Java Sound API became a core API in Java 1.3. It provides fine-grained support for the creation and manipulation of both sampled audio and MIDI music. There's space here only to scratch the surface by examining how to play simple sampled sound and MIDI music files. With the standard Java Sound support bundled with Java you can play a wide range of file formats including AIFF, AU, Windows WAV, standard MIDI files, and Rich Music Format (RMF) files. We'll discuss other formats (such as MP3) along with video media in the next section.
java.applet.AudioClip
defines the simplest interface for objects that can play sound. An object that implementsAudioClip
can be told toplay()
its sound data,stop()
playing the sound, orloop()
continuously.TheApplet
class provides a handy static method,newAudioClip()
, that retrieves sounds from files or over the network. (And there is no reason we can't use it in a non-applet application.) The method takes an absolute or relative URL to specify where the audio file is located and returns anAudioClip
. The following application,NoisyButton
, gives a simple example://file: NoisyButton.java import java.applet.*; import java.awt.*; import java.awt.event.*; import javax.swing.*; public class NoisyButton { public static void main(String[] args) throws Exception { JFrame frame = new JFrame("NoisyButton"); java.io.File file = new java.io.File( args[0] ); final AudioClip sound = Applet.newAudioClip(file.toURL()); JButton button = new JButton("Woof!"); button.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { sound.play(); } }); Container content = frame.getContentPane(); content.setBackground(Color.pink); content.setLayout(new GridBagLayout()); content.add(button); frame.setVisible(true); frame.setSize(200, 200); frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); frame.setVisible(true); } }
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Java Media Framework
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterGet some popcorn—Java can play movies! To do this, though, we'll need one of Java's standard extension APIs, the Java Media Framework (JMF). The JMF defines a set of interfaces and classes in the
javax.media
andjavax.media.protocol
packages. You can download the latest JMF fromhttps://java.sun.com/products/java-media/jmf/
. To use the JMF, add jmf.jar to your classpath. Or, depending on what version of the JMF you download, a friendly installation program may do this for you.We'll only scratch the surface of JMF here, by working with an important interface calledPlayer
. Specific implementations ofPlayer
deal with different media "container" types, such as Apple QuickTime (.mov) and Windows Video (.avi). For a full list of supported media types and codecs, consult the latest JMF documentation. There are also players for audio types including MP3.Player
s are handed out by a high-level class in the JMF calledManager
. One way to obtain aPlayer
is to specify the URL of a movie.What about Windows media player format as well as MP3?Player player = Manager.createPlayer(url);
Because video files are so large and playing them requires significant system resources,Player
s have a multistep life cycle from the time they're created to the time they actually play something. We'll look at only one step, realizing. In this step, thePlayer
finds out (by looking at the media file) what system resources it needs to play the media file.player.realize();
Therealize()
method returns right away; it kicks off the realizing process in a separate thread. When the player is finished realizing, it sends out an event. Once you receive this event, you can obtain one of twoComponent
s from the Player. The first is a visual component that, for visual media types, shows the media. The second is a control component that provides a prefab user interface for controlling the media presentation. The control normally includes start, stop, and pause buttons, along with volume controls and attendant goodies.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Chapter 22: JavaBeans
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterJavaBeans is a component architecture for Java. It is a set of rules for writing highly reusable software elements that can be linked together in a plug-and-play fashion to build applications. Writing components to the JavaBeans specification means you won't have to write as much custom code to glue them together. It also allows you to leverage JavaBean-aware development tools that can recognize the features of these components automatically. With some integrated development environments (IDEs), it is even possible to build parts of applications just by connecting prefabricated Java beans.In this chapter, we'll use the NetBeans IDE to create simple applications by connecting Java beans visually. We will also create our own reusable beans to add to the palette of components in the IDE. Although this visual type of application design has never quite reached the level it was expected to (we'll talk about some of the reasons why later), it is still very useful in GUI development. Moreover, the fundamental JavaBeans patterns are firmly entrenched in all aspects of the core Java APIs, so understanding them is important. We will cover all of these aspects in this chapter, including hand-coding with Java beans and some related APIs.What exactly is or are JavaBeans? JavaBeans (the architecture) defines a set of rules; Java beans are ordinary Java objects that play by these rules. That is, Java beans are Java objects that conform to the JavaBeans API and design patterns. By doing so, they can be recognized and manipulated within visual application builder environments, as well as by hand coding. Beans live and work in the Java runtime system, as do all Java objects. They communicate with their neighbors using events and other normal method invocations.For examples of Java beans, we need look no further than the
javax.swing
packages. All the familiar components, such asJButton
,JTextArea
,JScrollpane
, etc., are not only suitable items for beans, but are also, in fact, beans. Much of what you learned in Chapter 16 about the Swing components has prepared you for understanding beans. Although most of the Swing components aren't very useful in isolation, in general, beans can also be large and complex application components, such as spreadsheets or document editors. Sun used to have aAdditional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - What's a Bean?
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterWhat exactly is or are JavaBeans? JavaBeans (the architecture) defines a set of rules; Java beans are ordinary Java objects that play by these rules. That is, Java beans are Java objects that conform to the JavaBeans API and design patterns. By doing so, they can be recognized and manipulated within visual application builder environments, as well as by hand coding. Beans live and work in the Java runtime system, as do all Java objects. They communicate with their neighbors using events and other normal method invocations.For examples of Java beans, we need look no further than the
javax.swing
packages. All the familiar components, such asJButton
,JTextArea
,JScrollpane
, etc., are not only suitable items for beans, but are also, in fact, beans. Much of what you learned in Chapter 16 about the Swing components has prepared you for understanding beans. Although most of the Swing components aren't very useful in isolation, in general, beans can also be large and complex application components, such as spreadsheets or document editors. Sun used to have aHotJavaBrowser
bean, a complete web browser whose interface was presented as a Java bean. We'll talk more about exactly what makes a bean a bean in a moment. For now, we want to give you a better sense of how they are used.The ultimate goal of JavaBeans was to allow components to be manipulated visually within a graphical application builder. Beans can be chosen from a palette of tools and manipulated graphically in an application builder's workspace. In this sense, beans resemble the widgets used in a traditional GUI builder: user interface components that can be assembled to make application "screens." In traditional GUI builders, the result is usually some automatically generated code that provides a skeleton on which you hang the meat of your application. GUI builders generally build GUIs, not entire applications.In contrast, Java beans can be not only simple UI components, such as buttons and sliders, but also more complex and abstract components. It is easy to get the impression that beans are, themselves, always graphical objects (like the Swing components that we mentioned), but Java beans can implement any part of an application, including "invisible" parts that perform calculations, storage, and communications. Ideally, we would like to be able to snap together a substantial application using prefabricated beans, without ever writing a line of code. Three characteristics of the JavaBeans architecture aim to make it possible to work with application components at this level:Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - The NetBeans IDE
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterWe can't have a meaningful discussion of beans without spending a little time talking about the builder environments in which they are used. In this chapter, we use the NetBeans IDE Version 4.0 to demonstrate our beans. NetBeans is a popular, pure Java development environment. In this case, the "integrated" in "integrated development environment" means that NetBeans offers powerful source and visual editor capabilities, templates that aid in the creation of various types of Java classes, and the ability to compile, run, and debug applications, all in one tool. In particular, we'll be using the visual development environment of NetBeans to glue together our Java beans and try them out. Other IDEs offer similar capabilities. See Appendix A for a brief comparison of NetBeans and the Eclipse IDE.Because NetBeans is a full-blown production development environment, it has many features we don't use in these examples. For that reason, we can't really provide a full introduction to it here. We will provide only bare-bones directions here for demonstrating the Java beans in this chapter. But we hope that once you get into the tool and start looking around, you will want to learn more.You have to install Java 5.0 before you can install NetBeans. If you installed the JDK from Sun's web site, you may have downloaded a combined JDK and NetBeans bundle, so you may already have it installed. Both the JDK and NetBeans are included on the CD-ROM that accompanies this book (view CD content online at
https://examples.oreilly.com/learnjava3/CD-ROM/).
They can also be downloaded fromhttps://java.sun.com/j2se/
andhttps://www.netbeans.org
, respectively.Follow the simple installation instructions for those packages (you may have to reboot if you installed Java). During the NetBeans installation, it may prompt you for the version of the JDK to use. Choose the Java 5.0 version. When you're all set, launch NetBeans.When you first start NetBeans, a welcome screen appears. Close it for now by clicking the small x on its tab. (If you want to return to this welcome screen later to take the NetBeans tutorials, choose HelpAdditional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Properties and Customizers
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterProperties represent the "state" or "data" content of a bean. These features can be manipulated externally to configure the bean. For a bean that's a GUI component, you might expect its properties to include its size, color, and other features of its basic appearance. Properties are similar in concept to an object's public variables. Like a variable, a property can be a primitive type (such as a number or Boolean), or it can be a complex object type (such as a
String
or a collection of spreadsheet data). Unlike variables, properties are always manipulated using methods to set and get the value; this enables a bean to take action whenever a property changes. By sending an event when a property changes, a bean can notify other interested beans of the change (as discussed later in this chapter).Let's pull a couple of beans into NetBeans and take a look at their properties. Click on aJButton
from the Swing palette, and then click in the workspace. When theJButton
is first loaded by NetBeans, it was inspected to discover its properties. When we select an instance of the button, NetBeans displays these properties in the Properties pane and allows us to modify them.The button has nine basic properties, followed by a few additional groupings. The list called Other Properties adds more detail. There is also a Layout properties section (these are in actuality not properties of theJButton
, but are here for convenience) as well as an Accessibility properties list (for components that have accessibility-related properties). Theforeground
andbackground
properties are colors; their current values are displayed in the corresponding box.font
is the font for the label text; an example of the font is shown.text
is the text of the button's label. You can also set an image icon for the button, the tooltip text that appears when the mouse hovers over the item, and a keyboard-shortcut identifier, called a mnemonicAdditional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Event Hookups and Adapters
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterBeans use events to communicate. As we mentioned in Chapter 16, events are not limited to GUI components but can be used for signaling and passing information in more general applications. An event is simply a notification; information describing the event and other data are wrapped up in a subclass of
EventObject
and passed to the receiving object by a method invocation. Event sources register listeners that want to receive the events when they occur. Event receivers implement the appropriate listener interface containing the method needed to receive the events. This is Java's general event mechanism in a nutshell.It's useful to place an adapter between an event source and a listener. An adapter can be used when an object doesn't know how to receive a particular event; it enables the object to handle the event anyway. The adapter can translate the event into some other action, such as a call to a different method or an update of some data. One of the jobs of NetBeans is to help us hook up event sources to event listeners. Another job is to produce adapter code that allows us to hook up events in more complex ways.Let's face it: jugglers can get annoying. Let's try to get ours under control. Using the Properties pane, change the label of your first button to read "Start." Now click the small Connection Mode icon at the top of the GUI builder (the second icon, showing two items with arrows pointing at one another). After pressing the button, NetBeans is waiting for us to select two components to "hook up." Click first on the Start button and then on theJuggler
. NetBeans pops up the Connection Wizard, indicating the source component (the button) and prompting you to choose from a large list of events (see Figure 22-4). Most of them are standard Swing events that can be generated by any kind ofJComponent
. What we're after is the button's action event. Expand the folder named action, and selectactionPerformed
as the source event. NetBeans indicates at the bottom the name of an event handler method it is going to generate for us. You can leave the method name as is. Click Next to go to the Specify Target Operation screen for theAdditional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Binding Properties
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterBy using a combination of events and adapters, we can connect beans in many interesting ways. We can even "bind" two beans together so that if a property changes in the first bean, the corresponding property is automatically changed in the second bean. In this scenario, the beans don't necessarily have to be of the same type, but, to make sense, the properties do.Close the
Molecule
file and start a new one. Grab twoNumericField
beans from the palette, drop them in the workspace, and select one of them, as shown in Figure 22-7. You'll probably want to set the AbsoluteLayout again. You can also adjust the width of the fields by dragging them at the sides. You'll notice that aNumericField
has many of the standard properties of a Swing component. If you look in the Other Properties section of the Properties pane, you can find an integer property calledvalue
that represents the numeric value of the field. You can set it there or enter a number directly into the field when you run the program.NumericField
rejects nonnumeric text.Figure 22-7: Binding propertiesLet's bind thevalue
property of one of the fields to the other. Activate the Connection Wizard to create a connection between the two fields. Click first onnumericField1
and then onnumericField2
so thatnumericField1
is the source. In the wizard, choose thepropertyChange()
event of the source field. This is the listener method forPropertyChangeEvent
, a generic event sent by beans when one of their properties changes. When a bean fires property-change events in response to changes in a particular property, that property is said to be "bound." This means that it is possible to bind the property to another bean through the generic mechanism. In this case, thevalue
property of ourNumericField
beans is a bound property, so whenever it changes, aPropertyChangeEvent
is fired.Choose Next, and select thevalue
property as the target fornumericField2
. Click Next again, and select the Property radio button on the Parameters screen. Click the "..." editor button to pop up a Select Property dialog. Select the source numeric field (probably namedAdditional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Building Beans
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterNow that you have a feel for how beans look from the user's perspective, let's build some. In this section, we will become the Magic Beans Company. We will create some beans, package them for distribution, and use them in NetBeans to build a very simple application. (The complete JAR file, along with all the example code for this chapter, is on the CD-ROM that accompanies this book and at
https://www.oreilly.com/catalog/learnjava3
.)The first thing we'll remind you of is that absolutely anything can be a bean. Even the following class is a bean, albeit an invisible one:public class Trivial implements java.io.Serializable {}
Of course, this bean isn't very useful: it doesn't have any properties, and it doesn't do anything. But it's a bean nonetheless, and we can drag it into NetBeans as long as we package it correctly. If we modify this class to extendJComponent
, we suddenly have a graphical bean that be seen in the layout, with lots of standard Swing properties, such as size and color information:public class TrivialComponent extends JComponent {}
Next, let's look at a bean that's a bit more useful.We created a niftyDial
component in Chapter 18. What would it take to turn it into a bean? Surprise: it is already a bean! TheDial
has a number of properties that it exposes in the way prescribed by JavaBeans . A get method retrieves the value of a property; for example,getValue()
retrieves the dial's current value. Likewise, a set method (setValue()
) modifies the dial's value. The dial has two other properties, which also have get and set methods:minimum
andmaximum
. This is all theDial
needs to inform a tool such as NetBeans what properties it has and how to work with them. BecauseDial
is aJComponent
, it also has all the standard Swing properties, such as color and size. TheJComponent
provides the set and get methods for all its properties.To use ourDial
, we'll put it in a Java package namedmagicbeans
and store it in a JAR file that can be loaded by NetBeans. The source code, which can be found on the accompanying CD (view its content online atAdditional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Limitations of Visual Design
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterThe last example proved that we can create at least a trivial application by hooking beans together in a mostly visual way. In other development environments, this kind of bean hookup would have been even more streamlined. For example, Sun's "BeanBox" experimental Java bean container, introduced with Java 1.1, took a different approach from NetBeans. It allowed the developer to work with "live" Java bean instances, dynamically generating adapter code at runtime and relying solely on object serialization to save the resulting work. This kind of design is, in a sense, the real goal of the JavaBeans architecture. It is true "what you see is what you get" (WYSIWYG) programming. However, pure visual design without the ability to integrate handwritten code, as we can do in NetBeans, has not yet proven to scale beyond these kinds of simple applications, and pure visual programming environments have thus far failed to catch on. Meanwhile, Sun is working on a replacement for BeanBox called BeanBuilder. You can learn more about it at
https://java.sun.com/products/javabeans/beanbuilder/
.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Serialization Versus Code Generation
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterIf you've been keeping an eye on the NetBeans source window while we've been working, you may have noticed the code that is being generated when you modify properties of beans. By default, NetBeans generates method calls to set values on beans in the
initComponents()
method. For example, if you set the value of one of yourNumericField
beans to42
in the Properties pane, this value gets hardcoded into the application as an initial value of the bean by a call tosetValue()
on the bean object at initialization time. But if you click on the Code button in the Properties pane, you'll see that we have another option. This area holds properties that govern how NetBeans generates the application code. By changing the Code Generation property from Generate Code to Serialize, you change NetBeans' behavior. Instead of generating method calls in the source code, it saves your fully configured bean as a serialized object and then generates the appropriate code to load the freeze-dried bean into the application from a file.Try changing the code generation property for aJuggler
bean to Serialize. Switching to the source-code view and looking at theinitComponents()
method, you'll see a line for that bean that uses the staticBeans.instantiate()
method to load a serialized copy of the bean.NetBeans treats the serialized bean file as part of the source code and will regenerate it whenever it saves the source file. But to run this example, we have to first do a manual build. Select Build → Build Main Project, then you can run the file as before with the Run File context menu. The reason for the explicit build is to prompt NetBeans to copy the serialized bean file from the source folder of your source file over to the compiled classes directory (it should be smart enough to do this itself). You should see the serialized bean file, named something like: LearnJava1_juggler1.ser alongside your source file (and deployed to the classes directory). You can run the example and confirm that it behaves exactly like the code-generated version. (This is pretty neat if you think about it.)Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Customizing with BeanInfo
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterSo far, everything NetBeans has known about our beans has been determined by low-level reflection—that is, by looking at the methods of our classes. The
java.Beans.Introspector
class gathers information on a bean using reflection, then analyzes and describes a bean to any tool that wants to know about it. The introspection process works only if the class follows the JavaBeans naming conventions for its methods; furthermore, it gives us little control over exactly what properties and events appear in NetBeans menus. For example, we've seen that NetBeans by default shows all the stuff we inherit from the base Swing component. We can change that by creatingBeanInfo
classes for our beans. ABeanInfo
class provides the JavaBeans introspector with explicit information about the properties, methods, and events of a bean; we can even use it to customize the text that appears in menus in NetBeans (and in other IDEs).ABeanInfo
class implements theBeanInfo
interface. That's a complicated proposition; in most situations, the introspector's default behavior is reasonable. Instead of implementing theBeanInfo
interface, we extend theSimpleBeanInfo
class, which implements allBeanInfo
's methods. We can override specific methods to provide the information we want; when we don't override a method, we'll get the introspector's default behavior.In the next few sections, we'll develop theDialBeanInfo
class that provides explicit information about ourDial
bean.We'll start out by describing theDial
's properties. To do so, we must implement thegetPropertyDescriptors()
method. This method simply returns an array ofPropertyDescriptor
objects—one for each property we want to publicize.To create aPropertyDescriptor
, call its constructor with two arguments: the property's name and the class. In the following code, we create descriptors for theDial
'svalue
,minimum
, andmaximum
properties. We next call a few methods of thePropertyDescriptor
class to provide additional information about each property. If our methods were bound (generatedAdditional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Hand-Coding with Beans
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterSo far, we've seen how to create and use beans within a bean application builder environment. That is the primary motivation for JavaBeans, at least in GUI development. But beans are not limited to being used by automated tools. There's no reason we can't use beans in handwritten code. You might use a builder to assemble beans for the user interface of your application and then load that serialized bean or a collection of beans in your own code, just as NetBeans does when told to use object serialization. We'll give an example of that in a moment.Beans are an abstraction over simple Java classes. They add, by convention, features that are not part of the Java language. To enable certain additional capabilities of JavaBeans, we have to use some special tools that take the place of basic language operations. Specifically, when working with beans, we are provided with replacements for three basic Java operations: creating an object with
new
, checking the type of an object with theinstanceof
operator, and casting a type with acast
expression. In place of these, use the corresponding static methods of thejava.beans.Beans
class, shown in Table 22-1.Table 22-1: Methods of the java.beans.Beans class OperatorEquivalentNew
Beans.instantiate(classloader, name)
Instanceof
Beans.isInstanceOf(object, class)
Beans.instantiate()
is thenew
operation for beans. It takes a class loader and the name of a bean class or serialized bean as arguments. Its advantage over the plainAdditional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - BeanContext and BeanContextServices
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterSo far we've talked about some sophisticated mechanisms for connecting Java beans together at design time and runtime. However, we haven't talked at all about the environment in which Java beans live. To build advanced, extensible applications, we'd like a way for Java beans to find each other or "rendezvous" at runtime. The
java.beans.beancontext
package provides this kind of container environment. It also provides a generic "services" lookup mechanism for beans that wish to advertise their capabilities. These mechanisms have existed for some time, but they haven't found much use in the standard Java packages. Still, they are interesting and important facilities that you can use in your own applications.You can find a full explanation and example of how to use the bean context to find beans and listen for services in the expanded material on the CD-ROM that comes with the book or on this book's web site.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - The Java Activation Framework
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterThe Java Activation Framework (JAF) is a standard extension that can be used by beans that work with many external data types, such as media retrieved from files and streams. It is essentially a generalized content/protocol handler mechanism for JavaBeans. The JAF is an extensible set of classes that wrap arbitrary, raw data sources to provide access to their data as streams or objects, identify the MIME type of the data, and enumerate a registered set of "commands" for operating on the data.The JAF provides two primary interfaces:
DataSource
andDataHandler
. TheDataSource
acts like the protocol handlers we discussed in Chapter 14. It wraps the data source and determines a MIME type for the data stream. TheDataHandler
acts like a content handler, except it provides a great deal more than access to the data. ADataHandler
is constructed to wrap aDataSource
and interpret the data in different forms. It also provides a list of command operations that can be used to access the data.DataHandler
also implements thejava.awt.datatransfer.Transferable
interface, allowing data to be passed among application components in a well-defined way.The JAF hasn't been used much outside the JavaMail API, but you can find out more about JAF from Sun athttps://java.sun.com/beans/glasgow/jaf.html
.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Enterprise JavaBeans
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterEnterprise JavaBeans is a very big topic, and we can't do more than provide a few paragraphs of insight here. If you want more information, see Enterprise JavaBeans by Richard Monson-Haefel (O'Reilly). The thrust of EJB is to take the JavaBeans philosophy of portable, pluggable components and extend it to the server side to accommodate the sorts of things that multitiered, networked and database-centric applications require. Although EJB pays homage to the basic JavaBeans concepts, it is much larger and more specialized. It doesn't have a lot in common with the kinds of things we've been talking about in this chapter. EJBs are server-side components for networked applications. EJBs and plain Java beans are both reusable, portable components that can be deployed and configured for specific environments. But in the case of EJBs, the components encapsulate access to business logic and database tables instead of GUI and program elements.EJB ties together a number of other Java enterprise-oriented APIs, including database access, transactions, and name services, into a single component model for server applications. EJB imposes a lot more structure on how you write code than plain old Java beans. It does so to allow the server-side EJB container to take on a lot of responsibility and optimize your application's activities without you having to write a lot of code. Here are a few things Enterprise JavaBeans tackles:
- Object life cycle and remote access
- Container-managed persistence
- Transaction management
- Server resource pooling and management
- Deployment configuration
EJB divides the world into two camps: entity beans , which represent data in a database, and session beans, which implement services and operations over entity beans. These correspond well to the second and third tiers in a three-tiered business application. "Business logic" is represented by session bean services, and database access is made transparent through automated object mapping by entity beans.Many aspects of EJB behavior can be controlled through "deployment descriptors" that customize bean behavior for the target environment. The result is a high level of abstraction over ordinary business-specific code. It allows powerful, networked business application components to be packaged and reused in the sort of way that ordinary beans are reused to build client-side applications.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Chapter 23: Applets
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterOne of the original promises of Java was that applications could be delivered over the network to your computer as needed. Instead of buying a shrink-wrapped box containing a word processor, installing it, and upgrading it every few years, it should be possible to use the software directly from the Internet, safely and on any platform. This new model of software distribution would be a boon for both free software and for commercial products that could offer a new pay-per-use sales model. Unfortunately, this revolutionary idea has been hampered by the realities of a slow Internet and the uneven progress of Java on the client side (for reasons both technical and political). Even so, Java has maintained a toehold in this arena through small downloadable applications called applets.An applet is a Java program that runs in the context of a web page. Like an image or hyperlink it "owns" some rectangular area of the user's screen. It can draw whatever it wants and respond to keyboard and mouse events in that area. When the web browser loads a page that contains a Java applet, it knows how to load the classes of the applet and run them.This chapter describes how applets work and how to incorporate them into web pages. We'll also describe how to use Sun's Java Plug-in to take advantage of the latest Java features. Finally, we'll cover the details of creating signed applets, which can step outside the typical applet security restrictions to do client-side things, such as reading and writing files.The potential for applets to add dynamic content to web pages was one of the driving forces behind the spread of the Java programming language. Prior to Java's introduction in 1994, there was really no standard way to do this; even the now ubiquitous animated GIF images were not yet widely supported. Sun's HotJava Java-based web browser was the first to support applets. It was Java's original "killer application." Later, in 1995, Netscape announced that it would support the Applet API in its browsers, and soon after that Microsoft jumped on the bandwagon. For a while, it seemed that Java would flourish on the Web. But there have been some bumps along the road.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - The Politics of Applets
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterThe potential for applets to add dynamic content to web pages was one of the driving forces behind the spread of the Java programming language. Prior to Java's introduction in 1994, there was really no standard way to do this; even the now ubiquitous animated GIF images were not yet widely supported. Sun's HotJava Java-based web browser was the first to support applets. It was Java's original "killer application." Later, in 1995, Netscape announced that it would support the Applet API in its browsers, and soon after that Microsoft jumped on the bandwagon. For a while, it seemed that Java would flourish on the Web. But there have been some bumps along the road.Many problems, both technical and political, plagued the early years of Java's use in client-side applications. Performance issues were to be expected in such a young language. But what really crippled Java early on was the nonportable and buggy AWT, Java's original GUI toolkit. Many people overlook the fact that Java's success as a portable language is in large part a result of just how much of the Java API is implemented in Java. You might be surprised to learn just how many Java internals involve no native code—everything from cryptography to DNS is done in Java—requiring no porting for new platforms. Similarly, the renaissance of Java GUI applications seen in recent years is due almost entirely to the introduction of the pure Java Swing GUI toolkit. In contrast, the original AWT system was based on native code, which had to be ported to each new system, taking into account subtle and tricky platform dependencies. AWT was effectively a large, graphical C program that Java talked to through a set of interfaces and Java was, to some extent, unfairly painted as nonportable and buggy by association.Java faced other, less technical obstacles as well. Netscape forced the original AWT upon the world when it insisted that Java be released with "native look and feel" in lieu of a less capable, but portable initial toolkit. Later, Microsoft effectively stuck us with this by freezing the level of the Applet API in its browsers at Java 1.1. Applets have been stuck with AWT while lawsuits between Sun and Microsoft have dragged on. The result is that support for applets in web browsers is a mess. There are a lot of applets on the Web today, but they only hint at Java's original promise. There is, however, some light on the horizon.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - The JApplet Class
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterA
JApplet
is something like a SwingJPanel
with a mission. It is a GUI container that has some extra structure to allow it to be used in an "alien" environment, such as a browser. Applets also have a life cycle that lets them act more like an application than a static component, such as a paragraph of text or an image. Although applets tend to be relatively simple, there's no inherent restriction on their complexity, other than download speed. There's no reason you couldn't write a big application like a word processor as an applet (but that would probably be better suited for Java Web Start, which installs and manages versions locally).Thejava.applet.Applet
class defines the core functionality of an applet. It was used early on with AWT. Thejavax.swing.JApplet
class is a simple extension ofApplet
that adds the plumbing necessary for Swing.Structurally, an applet is a sort of wrapper for your Java code. In contrast to a standalone graphical Java application, which starts up from amain()
method and creates a GUI, an applet itself is a component that expects to be dropped into someone else's GUI. Thus, an applet can't run by itself; it runs in the context of a web browser or a special applet-viewer program (which we'll talk about later). Instead of having your application create aJFrame
to hold your GUI, you stuff your application inside aJApplet
(itself is aContainer
) and let someone else add your applet to their GUI.Applets are placed on web pages with the<applet>
HTML tag, which we'll cover later in this chapter. At its simplest, you just specify the name of the applet class and a size in pixels for the applet:<applet code="AnalogClock" width="100" height="100"></applet>
Pragmatically, an applet is an intruder into someone else's environment and therefore has to be treated with suspicion. The web browsers that run applets impose restrictions on what the applet is allowed to do. The restrictions are enforced by an applet security manager. The browser provides everything the applet needs through an applet context—the API the applet uses to interact with its environment.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Using the Java Plug-in
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterThe disadvantage of the
<applet>
tag is that you generally have to rely on the browser's Java interpreter. This is bad for two reasons:- The version of Java that is included in popular browsers lags the current version of Java by years and Java has never been fully supported in Internet Explorer (IE).
- Historically, Microsoft's version of Java has had its own bugs and idiosyncrasies, which were different from the bugs and idiosyncrasies of Sun's version. Microsoft is also in the process of dropping its support for Java in general, so it is unclear what the future holds for IE.
At the time of this writing, most common versions of Netscape and IE are stuck with a Java 1.1 environment. Modern versions of the Netscape and Firefox web browsers as well as Mac OS X's Safari support current versions of Java when they are installed. However, Mac OS X will not support Java 5.0 until its 10.4 release. As a developer, you will want to use modern features of Java including Swing, Collections, etc., on all platforms. So what can we do?We might take the state of Java in the browser to indicate that applets are dead. But the Java Plug-in might just save the day. A plug-in is simply a loadable application module that is used to support new content types in a web browser. All major browsers have a plug-in mechanism that allows the browser to be extended in this way.You're probably familiar with plug-ins of one type or another. The browser gives control for a part of a web page to another piece of code. For example, you can view movies in your browser using Apple's QuickTime plug-in. You can view interactive multimedia with Macromedia's Shockwave plug-in. The idea is very similar to applets; basically the browser hands-off responsibility for some rectangular area on the screen to someone else's code. The Java Plug-in is simply a Java runtime environment implemented as a browser plug-in.Applets that use the Java Plug-in can take advantage of the very latest Java platform features. With the Plug-in, Java developers can specify the version of Java they require, and their applets should run in exactly the same way in any browser using it. The browser isn't even really running the applet anymore; the Plug-in takes care of it.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Java Web Start
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterThe Java Web Start API is an interesting alternative to using applets. Java Web Start uses the Java Network Launching Protocol (JNLP) to transparently download and install Java applications locally. All the user has to do is to click on the install link on a web page. The installed applications can then be launched just like any installed application, by clicking on an icon on the desktop or through the Start menu, but they continue to be managed by the Java security policy unless authorized otherwise by the user. Web Start applications also automatically check for upgrades and update themselves over the net. Java Web Start is a form of zero administration client installation, which implies that the client doesn't have to do any work to install or maintain the application. JNLP applications may be signed, allowing the user to grant them fine-grained privileges, or unsigned. But even unsigned JNLP applications can take advantage of standard APIs that prompt the user for permission to perform basic operations, such as opening files and printing.Packaging your application to use JNLP is relatively easy, but we won't get into it here. The process mainly involves creating a JNLP deployment file that lists your JARs and specifies any special permission they require. You must then include an appropriate link in your web page that uses Web Start. The first time a user tries to install a JNLP application, they will have to install the Java Plug-in. Thereafter, the Java Web Start component manages all JNLP installs. See
https://java.sun.com/products/javawebstart/
for more information.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Using Digital Signatures
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterDigital signatures provide a way to authenticate documents and other data. They solve one of the Internet's biggest problems: given that you've received a message from Ms. X, how do you know that the message really came from Ms. X and not an imposter? Just as important for Java, let's say that you've downloaded a great new applet written by your favorite author, Pat Niemeyer, and you'd like to grant it some additional privileges, so that it can do something cool for you. You trust that this particular author wouldn't intentionally distribute something harmful. But how do you know that this person really is who he says he is? And what if you downloaded the applet from a third-party location, like an archive? How can you be sure that someone hasn't modified the applet since the author wrote it? With Java's default security policies for web browsers, such an applet can't do anything serious, but when we're talking about granting additional privileges to applets coming from trusted sites, you would be in for trouble—if it weren't for digital signatures.Like their inky analogs, digital signatures associate a name with an item in a way that is difficult to forge. In reality, a digital signature is much more difficult to forge than a traditional signature. Furthermore, digital signatures provide another benefit: they allow you to authenticate the contents of a document, proving that it hasn't been altered in transit. In other words, you know who the sender is, and that the data you received is exactly what the sender sent. Some malicious person can't clip out a digital signature, modify the original document (or applet), and attach the old signature to the result. And he can't generate a new signature; at least, he can't generate a signature claiming that the document came from its original sender. (He could, of course, attach his own signature, but that would be like signing the stick-up note you hand to the bank teller.)Digital signatures are based on public-key cryptography, which is well beyond the scope of this book. However, the basics are important and interesting. In a public-key system, there are two pieces of information: a public key and a private one. The keys have a special, asymmetric relationship, such that a message encrypted with one key can only be decrypted with the other key. Furthermore, if you know only one key, it is very difficult to compute the other. Therefore, if I give you my public key, you can use it to create an encrypted message that only I can read. No one else, including you, has enough information to go through the process of decrypting the encoded message, so it's safe to send it over untrusted networks. Furthermore, I can (and probably will) give my public key to anyone in the world, since the public key only lets people send me messages; it doesn't let them read my messages.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Conclusion
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterIn this chapter, we covered some of the events that led to the current, fractured applet world and set the scene as it is. The Java Plug-in is currently your best option for running Java in the browser. New technologies such as Java Web Start are starting to provide alternatives for client-side deployment that may also be appealing. Although it is tempting to try to use minimalist Java 1.1 applets as a workaround for deployment issues, it's really a losing proposition. It's best to take control of the issue from the start and use the plug-in unless you have total control of the browser environment of your users.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Chapter 24: XML
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterEvery now and then, an idea comes along that in retrospect seems just so simple and obvious that everyone wonders why it hadn't been seen all along. Often when that happens, it turns out that the idea isn't really all that new after all. The Java revolution began by drawing on ideas from all the programming languages that came before it. XML—the Extensible Markup Language—does for content what Java did for programming: providing a portable language for describing data.XML is a simple, common format for representing structured information as text. The concept of XML follows the success of HTML as a universal document presentation format and generalizes it to handle any kind of data. In the process, XML has not only recast HTML but is transforming the way that businesses think about their information. In the context of a world driven more and more by documents and data exchange, XML's time has come.XML and HTML are called markup languages because of the way they add structure to plain-text documents—by surrounding parts of the text with tags that indicate structure or meaning, much as someone with a pen might highlight a sentence and add a note. While HTML predefines a set of tags and their structure, XML is a blank slate in which the author gets to define the tags, the rules, and their meanings.Both XML and HTML owe their lineage to Standard Generalized Markup Language (SGML)—the mother of all markup languages. SGML has been used in the publishing industry for many years (including at O'Reilly). But it wasn't until the Web captured the world that it came into the mainstream through HTML. HTML started as a very small application of SGML, and if HTML has done anything at all, it has proven that simplicity reigns.HTML flourished but eventually showed its limitations. Documents using HTML have an unhealthy mix of both structural information (such as
<head>
and<body>
) and presentation information (for an egregious example,<blink>
). Mixing the model and the user interface in this way limits the usefulness of HTML as a format for data exchange; it's hard for a machine to understand. XML documents consist purely of structure, and it is up to the reader of the document to apply meaning. As we'll see in this chapter, several related languages exist to help interpret and transform XML for presentation or further processing.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - A Bit of Background
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterXML and HTML are called markup languages because of the way they add structure to plain-text documents—by surrounding parts of the text with tags that indicate structure or meaning, much as someone with a pen might highlight a sentence and add a note. While HTML predefines a set of tags and their structure, XML is a blank slate in which the author gets to define the tags, the rules, and their meanings.Both XML and HTML owe their lineage to Standard Generalized Markup Language (SGML)—the mother of all markup languages. SGML has been used in the publishing industry for many years (including at O'Reilly). But it wasn't until the Web captured the world that it came into the mainstream through HTML. HTML started as a very small application of SGML, and if HTML has done anything at all, it has proven that simplicity reigns.HTML flourished but eventually showed its limitations. Documents using HTML have an unhealthy mix of both structural information (such as
<head>
and<body>
) and presentation information (for an egregious example,<blink>
). Mixing the model and the user interface in this way limits the usefulness of HTML as a format for data exchange; it's hard for a machine to understand. XML documents consist purely of structure, and it is up to the reader of the document to apply meaning. As we'll see in this chapter, several related languages exist to help interpret and transform XML for presentation or further processing.When Tim Berners-Lee began postulating the Web back at CERN in the late 1980s, he wanted to organize project information using hypertext. When the Web needed a protocol, HTTP—a simple, text-based client-server protocol—was invented. So, what exactly is so enchanting about the idea of plain text? Why, for example, didn't Tim turn to the Microsoft Word format as the basis for Web documents? Surely a binary, non-human-readable format and protocol would be more efficient? Since the Web's inception, there have now been literally trillions of HTTP transactions. Was it really a good idea for them to use (English) words like "GET" and "POST"?Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - XML Basics
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterThe basic syntax of XML is extremely simple. If you've worked with HTML, you're already halfway there. As with HTML, XML represents information as text using tags to add structure. A tag begins with a name sandwiched between less-than (<) and greater-than (>) characters. Unlike HTML, XML tags must always be balanced; in other words, an opening tag must always be followed by a closing tag. A closing tag looks just like the opening tag but starts with a less-than sign and a slash (</). An opening tag, closing tag, and any content in between are collectively referred to as an element of the XML document. Elements can contain other elements, but they must be properly nested (all tags started within an element must be closed before the element itself is closed). Elements can also contain plain text or a mixture of elements and text (called mixed content). Comments are enclosed between
<!—
and—>
markers. Hereare
a few examples:<!-- Simple --> <Sentence>This is text.</Sentence> <!-- Element --> <Paragraph><Sentence>This is text.</Sentence></Paragraph> <!-- Mixed --> <Paragraph> <Sentence>This <verb>is</verb> text.</Sentence> </Paragraph> <!-- Empty --> <PageBreak></PageBreak>
An empty tag can be written more compactly with a single tag ending with a slash and a greater-than sign (/>):<PageBreak/>
An XML element can contain attributes, which are simple name-value pairs supplied inside the start tag.<Document type="LEGAL" ID="42">...</Document> <Image name="truffle.jpg"/>
The attribute value must always be enclosed in quotes. You can use double ("
) or single ('
) quotes. Single quotes are useful if the value contains double quotes.Attributes are intended to be used for simple, unstructured properties or compact identifiers associated with the element data. It is always possible to make an attribute into a child element so, strictly speaking, there is no real need for attributes. But they often make the XML easier to read and more logical. In the case of theAdditional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - SAX
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterSAX is a low-level, event-style API for parsing XML documents. SAX originated in Java but has been implemented in many languages. We'll begin our discussion of the Java XML APIs here, at this lower level, and work our way up to higher-level (and sometimes more convenient) APIs as we go.To use SAX, we'll be drawing on classes from the
org.xml.sax
package, standardized by the W3C. This package holds mainly interfaces common to all implementations of SAX. To perform the actual parsing, we'll need thejavax.xml.parsers
package, which is the standard Java package for accessing XML parsers. Thejava.xml.parsers
package is part of the Java API for XML Processing (JAXP), which allows different parser implementations to be used with Java in a portable way.To read an XML document with SAX, we first register anorg.xml.sax.ContentHandler
class with the parser. TheContentHandler
has methods that are called in response to parts of the document. For example, theContentHandler
'sstartElement()
method is called when an opening tag is encountered, and theendElement()
method is called when the tag is closed. Attributes are provided with thestartElement()
call. Text content of elements is passed through a separate method calledcharacters()
. Thecharacters()
method can be invoked repeatedly to supply more text as it is read, but it often gets the whole string in one bite. The following are the method signatures of these methods of theContentHandler
class.public void startElement( String namespace, String localname, String qname, Attributes atts ); public void characters( char[] ch, int start, int len ); public void endElement( String namespace, String localname, String qname );
Theqname
parameter is the qualified name of the element. This is the element name, prefixed with namespace if it has one. When working with namespaces, thenamespace
andlocalname
parameters are also supplied, providing the namespace and unqualified name separately. (Java 5.0 introduced a newAdditional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - DOM
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterIn the last section, we used SAX to parse an XML document and build a Java object model representing it. In that case, we created specific Java types for each of our complex elements. If we were planning to use our model extensively in an application, this technique would give us a great deal of flexibility. But often it is sufficient (and much easier) to use a "generic" model that simply represents the content of the XML in a neutral form. The Document Object Model (DOM) is just that. The DOM API parses an XML document into a full, memory-resident representation consisting of classes such as
Element
andAttribute
that hold their own values.As we saw in our zoo example, once you have an object model, using the data is a breeze. So a generic DOM would seem like an appealing solution, especially when working mainly with text. The only catch in this case is that DOM didn't evolve first as a Java API, and it doesn't map well to Java. DOM is very complete and provides access to every facet of the original XML document, but it's so generic (and language-neutral) that it's cumbersome to use in Java. In our example, we'll start by making a couple of helper methods to smooth things over. Later, we'll also mention a native Java alternative to DOM called JDOM that is more pleasant to use.The core DOM classes belong to theorg.w3c.dom
package. The result of parsing an XML document with DOM is aDocument
object from this package (see Figure 24-1). TheDocument
is a factory and a container for a hierarchical collection ofNode
objects, representing the document structure. A node has a parent and may have children, which can be traversed using itsgetChildNodes()
,getFirstChild()
, orgetLastChild()
methods. A node may also have "attributes" associated with it, which consist of a named map of nodes.Figure 24-1: The parsed DOMSubtypes ofNode
—Element
,Text
, andAttr
—represent elements, text, and attributes in XML. Some types of nodes (including these) have a text "value." For example, the value of aText
node is the text of the element it represents. The same is true of anAdditional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - XPath
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterXPath is an expression language for addressing parts of an XML document. You can think of XPath expressions as sort of like regular expressions for XML. They let you "pull out" parts of an XML document based on patterns. In the case of XPath, the patterns are more concerned with structural information than with character content and the values returned may be either simple text or "live" DOM nodes. With XPath, we can query an XML document for all of the elements with a certain name or in a certain parent-child relationship. We can also apply fairly sophisticated tests or predicates to the nodes, which allows us to construct complex queries such as this one: give me all of the
Animal
s with aWeight
greater than the number 400 and aTemperament
ofirritable
whoseanimalClass
attribute ismammal
.The full XPath specification has many features and includes both a compact and more verbose syntax. We won't try to cover it all here, but the basics are easy and it's important to know them because XPath expressions are at the core of XSL transformations and other APIs that refer to parts of XML documents. The full specification does not make great bedtime reading but can be found athttps://www.w3.org/TR/xpath
.An XPath expression addresses aNode
in an XML document tree. The node may be an element (possibly with children) like<Animal>...</Animal>
or it may be a lower-level document node representing an attribute (e.g.,animalClass="mammal"
), a CDATA block, or even a comment. All of the structure of an XML document is accessible through the XPath syntax. Once we've addressed the node, we can either reduce the content to a text string (as we might with a simple element likeName
) or we can access it as a proper DOM tree to further read or manipulate it.Table 24-2 shows the most basic node-related syntax.Table 24-2: Basic node-related syntax SyntaxExampleAdditional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - XInclude
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterXInclude is a very simple but sorely needed "import" facility for XML documents. Like XPath, the ability to use the XInclude standard from Java just arrived in Java 5.0. With the XInclude directive, you can easily include one XML document in another either as XML or as plain (and escaped) text. This means that you can break down your documents into as many files as you see fit and reference the pieces in a simple, standard way. We should note that it has been possible to do this in the past, in a way, using XML entity declarations, but they were fraught with problems. XInclude is simpler and does what its name implies, including the specified document at the current location; you just have to declare the proper namespace for the new
<include>
element. Here is an example:<Book xmlns:xi="https://www.w3.org/2001/XInclude"> <Title>Learning Java</Title> <xi:include href="chapter1.xml"/> <xi:include href="chapter2.xml"/> <xi:include href="chapter3.xml"/> ... </Book>
We've used the namespace identifierxi
to qualify the<include>
elements that we use to import the chapters of our book. By default, the file is imported as XML content, which means that the parser incorporates the included document as part of our document. The resulting DOM or SAX view will show the merged documents as one. Alternatively, we can use theparse
attribute to specify that we want the target included as text only. In this case, the text is automatically escaped for us like a CDATA section. For example, we could use it to include an XML example in our book without danger of corrupting our file:<Example> <Title>The Zoo Inventory Example</Title> <xi:include parse="text " href="zooinventory.xml"/> </Example>
Here, the entire zooinventory.xml file will be included as nicely escaped text for us (not added to our document as XML).XInclude also allows for "fallback" content to be specified using a nestedfallback
element. Thefallback
element may point to another file or simply hold XML to be used if the included file can't be found. For example:Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Validating Documents
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapter"Words, words, mere words, no matter from the heart."William Shakespeare, Troilus and CressidaIn this section, we talk about DTDs and XML Schema, two ways to enforce rules in an XML document. A DTD is a simple grammar for an XML document, defining which tags may appear where, in what order, with what attributes, etc. XML Schema is the next generation of DTD. With XML Schema, you can describe the data content of the document as well as the structure. XML Schemas are written in terms of primitives, such as numbers, dates, and simple regular expressions, and also allow the user to define complex types in a grammar-like fashion. The word schema means a blueprint or plan for structure, so we'll refer to DTDs and XML Schema collectively as schema where either applies. The term XML Schema is also a bit overloaded because there are now several competing languages (syntaxes) for describing XML in addition to the official W3C XML Schema standard.DTDs, although much more limited in capability, are still currently more widely used. This may be partly due to the complexity involved in writing XML Schemas by hand. The W3C XML Schema standard is verbose and cumbersome, which may explain why several alternative syntaxes have sprung up. In Java 5.0, a new
javax.xml.validation
API was added to standardize XML validation in a pluggable way. Out of the box, Java 5.0 supports only DTDs and W3C XML Schema, but new schema languages can be added in the future.XML's validation of documents is a key piece of what makes it useful as a data format. Using a schema is somewhat analogous to the way Java classes enforce type checking in the language. A schema defines document types. Documents conforming to a given schema are often referred to as instance documents of the schema.This type safety provides a layer of protection that eliminates having to write complex error-checking code. However, validation may not be necessary in every environment. For example, when the same tool generates XML and reads it back, validation should not be necessary in normal operation. It is invaluable, though, during development. Often, document validation is used during development and turned off in production environments.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - JAXB and Code Generation
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterWe've said that the ultimate goal of XML is automated binding of XML to Java classes. With automated binding, no fragile parsing code is created by the developer and just one schema is used for both the document and the object models. While many tools do just this, none is really ideal in terms of capabilities and ease of use. This is not entirely the fault of the tool vendors. Many aspects of mapping XML to Java constructs and back are tricky. For example, if an XML document can contain one of several types of elements at some point, what is the best way to represent that in Java?Several tools available today bridge XML and Java. The one we'll discuss here is the standard Java API for XML Binding (JAXB, not to be confused with JAXP, the parser API). JAXB is a standard extension that is provided as part of the Java Web Services Developer Pack (JWSDP), though it is also useful outside of the web services arena. You can download JAXB from
https://java.sun.com/xml/jaxb
. Compiling the examples in this section requires several of the JAR files from the JAXB lib and JWSDP "shared" lib directories to be in your classpath. To simplify this, we've provided an Ant build file along with the example code for these examples. You can find this and all of the source code on the CD accompanying this book.JAXB generates Java source code. It can work with either DTDs or XML Schema and generates Java classes that match the structure of the XML. At runtime, JAXB-generated classes can read an XML document and parse it into the object model it has defined or you can go the other way, populating your object model and then writing it out to XML. In both cases, JAXB can validate the data to make sure it matches the schema. This may sound like the DOM interface, but, in this case, we're not using generic classes—we're using classes custom-generated for our model. For example, in the case of our zooinventory.xml file, we'll have classes likeInventory
,Animal
, andFoodRecipe
to work with, each having the expected setter and getter methods. This means that our workflow centers more around writing the XML Schema, with the job of creating the classes done for us.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Transforming Documents with XSL/XSLT
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterEarlier in this chapter, we used a
Transformer
object to copy a DOM representation of an example back to XML text. We mentioned that we were not really tapping the potential of theTransformer
. Now, we'll give you the full story.Thejavax.xml.transform
package is the API for using the XSL/XSLT transformation language. XSL stands for Extensible Stylesheet Language. Like Cascading Stylesheets for HTML, XSL allows us to "mark up" XML documents by adding tags that provide presentation information. XSL Transformation (XSLT) takes this further by adding the ability to completely restructure the XML and produce arbitrary output. XSL and XSLT together comprise their own programming language for processing an XML document as input and producing another (usually XML) document as output. (From here on in, we'll refer to them collectively as XSL.)XSL is extremely powerful, and new applications for its use arise every day. For example, consider a web portal that is frequently updated and which must provide access to a variety of mobile devices, from PDAs to cell phones to traditional browsers. Rather than recreating the site for these and additional platforms, XSL can transform the content to an appropriate format for each platform. More generally, rendering content from XML is simply a better way to preserve your data and keep it separate from your presentation information. XSL can be used to render an entire web site in different styles from files containing "pure data" in XML, much like a database. Multilingual sites also benefit from XSL to lay out text in different ways for different audiences.You can probably guess the caveat that we're going to issue: XSL is a big topic worthy of its own books (see, for example, O'Reilly's Java and XSLT by Eric Burke, a fellow St. Louis author), and we can only give you a taste of it here. Furthermore, some people find XSL difficult to understand at first glance because it requires thinking in terms of recursively processing document tags. Don't be put off if you have trouble following this example; just file it away and return to it when you need it. At some point, you will be interested in the power transformation can offer you.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Web Services
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterAs we saw in our web services examples in Chapters 14 and 15, one of the most interesting directions for XML is web services. A web service is simply an application service supplied over the network, making use of XML to describe the request and response. Normally, web services run over HTTP and use an XML-based protocol called SOAP (Simple Object Access Protocol), an evolving W3C standard. The combination of XML and HTTP provides a universally accessible interface for services.SOAP and other XML-based remote procedure call mechanisms can be used in place of Java RMI for cross-platform communications and as an alternative to CORBA. There is a lot of excitement surrounding web services, and it is likely that they will grow in importance in coming years. To learn more about Java APIs related to web services, check out the networking chapters of this book and take a look at
https://java.sun.com/webservices/
.That's it for our brief introduction to XML. There is a lot more to learn about this exciting new area, and many of the APIs are evolving rapidly. We hope we've given you a good start.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - The End of the Book
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterWith this chapter, we also wrap up the main part of our book. We hope that you've enjoyed Learning Java. This, the third edition of Learning Java, is really the fifth edition of the series that began almost ten years ago with Exploring Java. It's been a long and amazing trip watching Java develop in that time and we thank those of you who have come along with us over the years. As always, we welcome your feedback to help us keep making this book better in the future. Ready for another 10 years of Java?Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Appendix A: The Eclipse IDE
- Content preview·Buy reprint rights for this chapterThis is a book about the Java language and as such we've tried to avoid talking too much about specific tools and applications. But of course, we've had to make some exceptions where the real world of Java programming and de facto standards dictate. An example of this is the Apache Ant build tool that we discussed briefly in Chapter 15. Ant has become a de facto standard for building Java applications and something that every Java programmer should at least be aware of. A more challenging topic to cover is that of Java integrated development environments (IDEs).A wide array of Java IDEs are available, with greatly varying features. Like all applications with a great deal of interest, IDEs are constantly changing and improving. Throughout this book, rather than distract from the topic at hand with screenshots of one IDE or another, we've chosen to refer only to simple command-line tools. In the real world, many if not most Java developers now use IDEs, so our approach paints a bit of a skewed picture of the process. We aim to rectify the situation here by introducing the Eclipse IDE and showing how to use it to load and explore all of the example code from this book.IDEs offer many benefits as well as a few drawbacks, especially for the new Java programmer. The benefits include an all-in-one view of Java source code with syntax highlighting, navigation help, source control, integrated documentation, building, refactoring, and deployment all at your fingertips. The downside, historically at least, has been that the all-in-one tool tends to become an all-or-nothing tool that locks users into the product and makes them all but helpless without it. IDEs tend to encourage an overly simplistic project layout with no structure or partitioning to help humans understand it. IDEs can also become hairballs of state and information about the project that cannot be easily shared with other developers or across projects. Many of these problems are being addressed by the latest generation of IDEs, and, for most people, the benefits far outweigh the negatives.
Section A.1: The IDE Wars
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - The IDE Wars
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterComparing IDEs on features alone is futile because all modern IDEs are based on a plug-in architecture that allows new tools to be added by third parties. Saying that an IDE has feature X is just an invitation for someone to retort that their IDE has plug-ins for X and Y. Still, it is worth taking a moment to draw some comparisons here (if we dare). In this book, we have used both the NetBeans 4.x and Eclipse 3.x editors. How do they stack up? The short answer is that at the time of this writing, Eclipse is more popular and a bit more polished at the expense of being platform-dependent whereas the latest release of NetBeans offers a few more advanced features out of the box.A big distinction between the two is that Eclipse is not a pure-Java application. It has native code for each platform, which means that it won't necessarily look and feel the same on all platforms. The upside is that Eclipse on the PC is very polished. The downside is that on other platforms, things may not be as smooth and some features and plug-ins are not available. NetBeans, on the other hand, is a pure-Java application. It may lack some subtle niceties on some platforms, but, in general, it should behave the same everywhere. Another difference is that Eclipse is based on an alternative Java graphics toolkit called SWT that uses native components. Some people use SWT in their own applications as a Swing alternative to get improved performance.Out of the box, NetBeans also offers two features that Eclipse doesn't: a visual application builder and a web application development environment. Of course, you can add those to Eclipse, but you must choose from (possibly pay-ware) alternatives. Another important feature of NetBeans 4.x is that it uses a fully externalized Ant build process. This means that you can build your application inside or outside of the IDE in exactly the same way. This is an important advance and it will be interesting to see if Eclipse adopts it in the future. With that said, let's move on to Eclipse....Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Getting Started with Eclipse
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterLet's get started. First, you'll need to install Eclipse. You can get Version 3.1 from the CD accompanying this book or you can download the latest version from
https://eclipse.org/
. Simply unpack the zip file to a location of your choice and then launch the application.The first time you run Eclipse you'll be prompted to select a workspace. This is a root directory to hold new projects that you create within Eclipse. The default location is inside the application's folder itself, probably not what you want. Pick a location and click OK.Eclipse greets you with the Welcome Screen. Close this window by closing the Welcome tab within the application. If you want to come back later and go through the Eclipse tutorials and related help topics, you can get this window back by choosing Help → Welcome.One last thing before we move on: Eclipse stores all of its configuration information in the configuration folder inside the Eclipse installation directory. If, at any point in this introduction, you feel that things are not right and you want to start from scratch, you can quit the application and remove this folder. You may also wish to remove your workspace items as they hold per-project state. Less drastically, if you wish to reset all of the application windows to their default locations, you can choose Window → Reset Perspective. We'll talk more about perspectives later.Before we talk about the IDE itself, let's load the examples from this book. You can find a ZIP file containing all of the examples from this book nicely packaged as an Eclipse project on the CD accompanying this book or athttps://www.oreilly.com/catalog/learnjava3
. The Eclipse version of the examples is calledexamples-eclipse.zip
. (The fileexamples.zip
holds the same examples but packaged slightly differently and without the Eclipse project files.)First, create a new project to hold the examples using the File → New Project menu item. In the New Project wizard, select Java Project as the project type and click Next. Give the project a name (we usedLearningJava
). The default location for the project folder will be in the workspace area that you designated earlier, but you can change this if you wish. Click Finish when you're done. (If Eclipse asks if you wish to set the "project compliance settings" to Java 5.0, you should answerAdditional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Using Eclipse
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterThe first thing we need to do is set up the IDE for browsing and editing our Java source code. Choose Window → Open Perspective → Java to put Eclipse into the Java editing perspective. A perspective in Eclipse is an arrangement of different tools, menu bars, and shortcuts geared toward a particular kind of task, such as Java editing or CVS repository browsing. You can open additional tools and move thingsFigure A-1: The import projects dialog boxaround to your liking, but the predefined perspectives give you a good start. Now the Learning Java examples appear in Eclipse, as shown in Figure A-2.On the left is the Package Explorer. It shows a tree view of the Java packages, libraries, and resources of our project. Click the folder handles to expand the tree and see source folders for each chapter in the book.The bottom area holds tabs related to Java editing. The tab that is open in Figure A-2, Problems, shows errors and warnings associated with our project code. Eclipse has already compiled our code in the background. In general, you don't have to tell it to do so. You'll also notice red Xs on some of the source folders and files. These files have errors. We'll talk about why some of our examples are being flagged in a moment. The other tabs, Javadoc and Declaration, give information about the file we're editing or the source code item selected. The Declaration tab can show a preview of the source for an item selected in the main editor window without requiring you to open it explicitly.To clear up some of those red Xs, we need to make sure Eclipse is in Java 5.0-compatible mode. Choose Window → Preferences → Java → Compiler and set the CompilerFigure A-2: Learning Java examples in Eclipse's Java editing perspectiveCompliance Level to 5.0. Click OK and select Yes to rebuild the source. (It is also possible to set the compiler level on a per-project basis through the project preferences.)If there are still some red Xs left, double-click the README-Eclipse.txt file in the project tree to read the latest explanations for these issues. Some of these issues relate to generating source code or installing additional libraries to make the examples work properly.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Eclipse Features
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterEclipse has too many interesting features to really do them justice here, but we'll mention a few to show you why people love this IDE.Of course, you've noticed all the color coding and meta-information present when viewing Java source code in Eclipse. You can customize all of this behavior to suit your taste through the Window → Preferences → Java → Editor → Syntax Coloring panel. Many other options can be set through the Window → Preferences → Java → Code Style and Editor panes.What may not be immediately obvious is that editing is also enhanced. When typing, try pressing Ctrl-Space to attempt autocompletion or have Eclipse present you with relevant options. For example, instead of typing
JButton
, try typingJBu
plus Ctrl-Space. Eclipse completes the name for you. If the portion of the name you type is ambiguous, a drop-down list appears, similar to that shown in Figure A-5.Figure A-5: Using completion in EclipseEclipse also provides abbreviations for common items. Try typingsysout
and pressing Crtl-Space. Eclipse expands this toSystem.out.println()
and places the cursor in the parentheses automatically. If you type a quotation mark, Eclipse closes the quotation for you. Note the green bar it places after the closing quote. Pressing Tab takes you to that point so that you don't have to use the arrow keys. Pressing Tab again takes you to the next green bar spot, the end of the line.Eclipse can offer fixes for simple problems in your code when it detects them. To see suggested fixes, click on the red X next to a problem line. Eclipse presents a dropdown menu of possible fixes for the problem. Selecting an option shows you the code changes Eclipse will make before you choose it.For example, try changing the name of one of theJButton
s in our Calculator toJBButton
. Now, click the red X and a screen similar to Figure A-6 appears. Eclipse offers several possible corrections; the best one is to fix the misspelling and change it back toJButton
. Of course, if we'd really meant to refer to a new kind of button, we could choose the option to create the new class right there and Eclipse would help us do that by creating a skeleton for us.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Conclusion
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterThis appendix provides the briefest of introductions to the sorts of things that you can do in Eclipse and other Java IDEs. Please investigate more on your own to learn what these tools can do to increase your productivity as a Java developer. You should also compare Eclipse, NetBeans, and other editing environments such as jEdit (
https://jedit.org
) to see which you prefer. And don't forget to read more about Apache Ant, the de facto standard for building Java applications.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Appendix B: BeanShell: Simple Java Scripting
- Content preview·Buy reprint rights for this chapterIn this book, we (in this case, I, Pat) have avoided talking about many third-party tools that aren't part of the standard JDK. I'm going to make an exception here to mention a nifty, free Java tool called BeanShell. As its name suggests, BeanShell can be used as a Java "shell." It allows you to type standard Java syntax—statements, expressions, and even classes—on the command line and see the results immediately. With BeanShell, you can try out bits of code as you work through the book. (The current release of BeanShell doesn't support all of the new Java 5.0 syntax, but check for updates that will.) You can access all Java APIs and even create graphical user interface components and manipulate them "live." BeanShell uses only reflection, so there is no need to compile class files.I wrote BeanShell while developing the examples for this book, and I think it makes a good companion to have along on your journey through Java. BeanShell is an open source software project, so the source code is included on the CD-ROM that accompanies this book (view CD content online at
https://examples.oreilly.com/learnjava3/CD-ROM/
). You can always find the latest updates and more information at its official home:https://www.beanshell.org
. In recent years, BeanShell has become fairly popular. It is part of the Java Development Environment for Emacs (JDEE) and has been distributed with the NetBeans and Sun Java Studio IDEs as well as BEA's WebLogic application server. I hope you find it both useful and fun!Section B.1: Running BeanShell
Section B.2: Java Statements and Expressions
Section B.3: BeanShell Commands
Section B.4: Scripted Methods and Objects
Section B.5: Changing the Classpath
Section B.6: Learning More . . .
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Running BeanShell
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterAll you need to run BeanShell is the Java runtime system (Version 1.1 or greater) and the bsh JAR file. Under Windows, you can launch a graphical desktop for BeanShell by simply double-clicking the JAR file icon. More generally, you can add the JAR to your classpath:
Unix: export CLASSPATH=$CLASSPATH:bsh.jar Windows: set classpath %classpath%;bsh.jar
You can then run BeanShell interactively in either a GUI or command-line mode:java bsh.Console // run the graphical desktop java bsh.Interpreter // run as text-only on the command line
Running BeanShell with the GUI console brings up a simple, Swing-based, desktop that allows you to open multiple shell windows with basic command history, line editing, and cut-and-paste capability. There are some other GUI tools available as well, including a simple text editor and class browser. Alternately, you can run BeanShell on the command line, in text-only mode.You can run BeanShell scripts from files, like so:% java bsh.Interpreter myfile.bsh
Within some versions of the NetBeans and Sun Java Studio IDEs, you can create BeanShell script files using the New File wizard or run any file with a .bsh extension just as you would execute Java code.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Java Statements and Expressions
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterAt the prompt or in a BeanShell script, you can type standard Java statements and expressions. Statements and expressions are all of the normal things that you'd include in a Java method: variable declarations and assignments, method calls, loops, and conditionals. You can declare classes in the usual way if you want to, but BeanShell allows you to write statements outside of a class or method in an unstructured way as well.You can type statements exactly as they would appear in Java. You also have the option of working in a more scripting-language-like fashion, with "loosely typed" variables and arguments. That is, you can simply be lazy and not declare the types of variables that you use (both primitives and objects). BeanShell will still give you an error if you attempt to misuse the actual contents of the variable. If you do declare types of variables or primitives, BeanShell will enforce them.Here are some examples:
foo = "Foo"; four = (2 + 2)*2/2; print( foo + " = " + four ); // print() is a bsh command // do a loop for (i=0; i<5; i++) print(i); // pop up an AWT frame with a button in it button = new JButton("My Button"); frame = new JFrame("My Frame"); frame.getContentPane().add( button, "Center" ); frame.pack(); frame.setVisible( true );
If you don't like the idea of "loosening" Java syntax at all, you can turn off this feature of BeanShell with the following command:setStrictJava( true );
By default, BeanShell imports all of the core Java packages for you. You can import your own classes using the standard Java import declaration:import mypackage.*;
In addition to regular package, class, and static imports, BeanShell can also import the methods and variables of an object instance into the current context using theimportObject()
command. For example:Map map = new HashMap(); importObject( map ); put("foo", "bar"); print( get("foo") ); // "bar"
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - BeanShell Commands
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterBeanShell comes with a number of useful built-in commands in the form of Java methods. These commands are implemented as BeanShell scripts, and are supplied in the bsh JAR file. You can make your own commands by defining methods in your own scripts or adding them to your classpath. See the BeanShell user's manual for more information.One important BeanShell command is
print()
, which displays values.print()
does pretty much the same thing asSystem.out.println()
except it ensures the output always goes to the command line (if you have multiple windows open).print()
also displays some types of objects (such as arrays) more verbosely than Java would. Another very useful command isshow()
, which toggles on and off automatic printing of the result of every line you type. (You can turn this on if you want to see every result value.)Here are a few other examples of BeanShell commands:-
source()
,run()
- Reads a script into this interpreter, or runs it in a new interpreter
-
frame()
- Displays an AWT or Swing component in a frame
-
load()
,save()
- Loads or saves serializable objects (such as JavaBeans)
-
cd()
-
cat()
-
dir()
-
pwd()
- etc.
- Unix-like shell commands
-
exec()
- Runs a native application
-
addClassPath()
-
reloadClasses()
- Modifies the classpath or reload classes
-
javap()
- Prints a javap-style class description for the class or object specified
See the BeanShell user's manual for a full list of commands.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! -
- Scripted Methods and Objects
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterYou can declare and use methods in BeanShell, just as you would inside a Java class:
int addTwoNumbers( int a, int b ) { return a + b; } sum = addTwoNumbers( 5, 7 ); // 12
BeanShell methods may also have dynamic (loose) argument and return types.add( a, b ) { return a + b; } foo = add(1, 2); // 3 foo = add("Hello ", "Kitty"); // "Hello Kitty"
In BeanShell, as in JavaScript and Perl, method closures can take the place of classes for scripting objects (but in BeanShell you can also use the regular class syntax). You can turn the context of a method call into an object reference by having the method return the special valuethis
. You can then use thethis
reference to refer to any variables that were set during the method call. To be useful, an object may also need methods; so in BeanShell, methods may also contain methods at any level. Here is a simple example:user( n ) { name = n; reset() { print( "Reset user:"+name ); } return this; // return user as object } bob = user("Bob" ); print( bob.name ); // "Bob" bob.reset(); // prints "Reset user: Bob"
This example assigns the context of theuser()
method to the variablebob
and refers to the fieldbob.name
and the methodbob.reset().
If you find this strange, don't worry. The most common reason you'd want to script an object is to implement a Java interface, and you can do that using the standard Java anonymous inner class syntax, as we'll discuss next or just use a regular class. BeanShell gives you a lot of options.One of the most powerful features of BeanShell is that you can "script" any interface type (provided you are running Java 1.3 or greater). BeanShell-scripted objects can automatically implement any required interface type. All you have to do is implement the necessary method (or at least the ones that are going to be invoked). You can use this feature either by explicitly referring to a BeanShell script using athis
-style reference as described earlier, or by using the standard Java anonymous inner class syntax. Here is an example:Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Changing the Classpath
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterWithin BeanShell, you can add to your classpath and even reload classes:
addClassPath("mystuff.jar"); addClassPath("https://examples.oreilly.com/learnjava3/magicbeans.jar");
To reload all classes in the classpath, simply use:reloadClasses();
You can do more elaborate things as well, such as reloading individual classes, if you know what you're doing. See the user manual for more details.Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing! - Learning More . . .
- Content preview·Buy PDF of this chapter|Buy reprint rights for this chapterBeanShell has many more features than I've described here. You can embed BeanShell into your applications as a lightweight scripting engine, passing live Java objects into and out of scripts. You can even run BeanShell in a remote server mode, which lets you work in a shell inside your running application, for debugging and experimentation. There is also a BeanShell servlet that can be used for running scripts inside an application server.BeanShell is small (only about 200 KB) and it's free, licensed under the GNU Library General Public License and the Sun Public License. You can learn more by checking out the full user's manual and FAQ on the web site. If you have ideas, bug fixes, or improvements, please consider joining the developer's mailing list.Please feel free to send feedback, using the book's web page,
https://www.oreilly.com/catalog/learnjava3
. Enjoy!Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Return to Learning Java
About O'Reilly | Contact | Jobs | Press Room | How to Advertise | Privacy Policy
© 2007, O'Reilly Media, Inc.
All trademarks and registered trademarks appearing on oreilly.com are the property of their respective owners.