Return-Path: <env_23407496-686162560@hermes.sun.com>
Received: from pacific-carrier-annex.mit.edu by po10.mit.edu (8.9.2/4.7) id OAA01079; Wed, 9 Oct 2002 14:49:08 -0400 (EDT)
Received: from hermes.sun.com (hermes.sun.com [64.124.140.169])
	by pacific-carrier-annex.mit.edu (8.9.2/8.9.2) with SMTP id OAA11602
	for <alexp@mit.edu>; Wed, 9 Oct 2002 14:49:07 -0400 (EDT)
Date: 9 Oct 2002 09:37:20 -0800
From: "JDC Tech Tips" <JDC_Tech_Tips@hermes.sun.com>
To: alexp@mit.edu
Message-Id: <23407496-686162560@hermes.sun.com>
Subject: Core Java Technologies Tech Tips, Oct. 8, 2002 (Regular Expression Groups, Anonymous Classes)
Mime-Version: 1.0
Content-Type: text/html; charset=us-ascii
Content-Transfer-Encoding: 7bit
X-Mailer: SunMail 1.0

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>
Core Java Technologies Technical Tips
</title>

<style type="text/css">

CODE {color: #333333; font-family: Verdana, Courier, Monospace; font-size: 10pt}
PRE {color: #333333; font-family: Verdana, Courier, Monospace; font-size: 10pt}
BODY, div, span {color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 10pt}
td, th {color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 10pt}
tr {color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 10pt}
table {font-family: Arial, Helvetica, sans-serif; font-size: 10pt}
p {color: #333333; font-family: arial,helvetica,sans-serif; font-size: 10pt}
li {color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 10pt}
br {color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 10pt}
div {color: #666699; font-family: Arial, Helvetica, sans-serif; font-size: 10pt}
sup {font-family: Arial, Helvetica, sans-serif; font-size: 5pt}
h3 {color: #666699; font-family: Arial, Helvetica, sans-serif; font-size: 11pt}
h4, b {color: #666699; font-family: Arial, Helvetica, sans-serif; font-size: 10pt}
blockquote, input, select {color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 10pt}
ul, ol {color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 10pt}
a:link {font-size: 10pt; font-family: Arial, Helvetica, sans-serif; color:#666699 }
span.purple {font-weight: bold; color: #666699; font-family: Arial, Helvetica, sans-serif; font-size: 10pt}
span.small {font-size: 8pt; font-family: Arial, Helvetica, sans-serif; color:#333333 }
span.link {font-size: 8pt; font-family: Arial, Helvetica, sans-serif; color:#666699 }
</style>

</head>

<body bgcolor="#ffffff">
<a name="top"></a>
<table border="0" cellpadding="0" cellspacing="0" width="611">
<tr>
<td colspan="3" bgcolor="#cccccc" width="1"><img src="http://developer.java.sun.com/images/pixel.gif" width="1" height="1" border="0" alt="image"></td>
</tr>

<tr>
<td bgcolor="#cccccc" width="1"><img src="http://developer.java.sun.com/images/pixel.gif" width="1" height="1" border="0" alt="image"></td>

<td>
<table border="0" cellpadding="0" cellspacing="0" width="611">
<tr>
<td colspan="2"><a href="http://developer.java.sun.com?s=06&w=41" target="_blank"><img src="http://developer.java.sun.com/images/headers/core_ttips_hdr.jpg" width="611" height="160" alt="Core Java Technologies Technical Tips" border="0"></a></td>
</tr>

<tr>
<td colspan="2" bgcolor="#cccccc" width="1"><img src="http://developer.java.sun.com/images/pixel.gif" width="1" height="1" border="0" alt="image"></td>
</tr>

<!-- ================== -->
<!-- Start Main Content -->
<!-- ================== -->

<tr>
<td height="20">&nbsp;&nbsp;&nbsp;<a href="http://developer.java.sun.com/developer/TechTips/txtarchive/2002/Oct02_GlenM.txt?s=06&w=41" style="text-decoration:none;" target="_blank">View this issue as simple text</a></td>
<td align="right" height="20"><span class="purple">October 8, 2002</span>&nbsp;&nbsp;&nbsp;&nbsp;</td>
</tr>

<tr><td colspan="2">

<FORM METHOD="GET" ACTION="http://search.java.sun.com/search/java/">
<table border="0" cellpadding="10" cellspacing="0" width="100%">
<tr>
<td>
        
<table border="0" cellpadding="3" cellspacing="0" width="100%">
<tr> 
<td align="left" VALIGN="middle" width="20%"><h3>In this Issue</h3></td>
              
<td valign="middle" align="right" width="70%">
<font size="2">
<INPUT TYPE="text" SIZE="15" MAXLENGTH="128" NAME=qt></FONT></td>
            
<td VALIGN="middle" WIDTH="55">
<INPUT TYPE="image" SRC="http://developer.java.sun.com/images/v4a_search.gif" ALT="Search" value="search" BORDER="0" WIDTH="55"></td>
</tr>
</table>

</FORM>

<p>
Welcome to the Core Java<sup>TM</sup> Technologies Tech Tips, October 8, 
2002. Here you'll get tips on using core Java technologies and 
APIs, such as those in Java 2 Platform, Standard Edition 
(J2SE<sup>TM</sup>).
</p>

<p>
This issue covers:
</p>

<a href="#1"><img src="http://developer.java.sun.com/images/anchor.gif" border="0" alt="">Using Regular Expression Groups</a>
<br>    
<a href="#2"><img src="http://developer.java.sun.com/images/anchor.gif" border="0" alt="">Anonymous Classes</a>
</p>

<p>
These tips were developed using Java 2 SDK, Standard Edition, 
v 1.4. 
</p>

<p>
This issue of the JDC Tech Tips is written by Glen McCluskey.
</p>

<p>
See the Subscribe/Unsubscribe note at the end of this newsletter
to subscribe to Tech Tips that focus on technologies and products 
in other Java platforms.
</p>

<table width="100%" border="0" cellspacing="0" cellpadding="0" align="center">

<!-- Grey Horizontal Line Begins Here -->

<tr>
<td bgcolor="#cccccc" height="1"><img src="http://developer.java.sun.com/images/pixel.gif" width="1" height="1" ALT="Pixel" border="0"></td>
</tr>
</table> 

<!-- Grey Horizontal Line ends Here -->

<a name="1"></a>

<h3>USING REGULAR EXPRESSION GROUPS</h3>

<p>
Regular expressions are a new feature of the Java 2 Platform,
Standard Edition v 1.4. A regular expression is a string pattern 
that you can use to perform sophisticated string searching and 
replacement. For example, the regular expression:
</p>

<pre>
    \d+
</pre>

<p>
means &quot;a sequence of one or more consecutive digit characters&quot;. 
A regular expression is represented by (compiled into) an 
instance of the <code>java.util.regex.Pattern</code> class. Then the related 
<code>Matcher</code> class is used to match input character sequences against 
the pattern.
</p>

<p>
Sometimes when matching is done, all you care about is whether 
the pattern was found somewhere in the input sequence. A common 
application of this is a utility that searches a text file and 
prints lines that match a specified pattern.
</p>

<p>
But sometimes you might want to get more information about a 
match than simply an indication of whether the pattern was found 
in the input. For example, if you're searching for a number, 
using the regular expression illustrated above, you might want to 
retrieve the actual text of the number that was found.
</p>

<p>
This is one situation where regular expression groups are useful. 
A group is a numbered part of a regular expression. For example, 
in the following expression:
</p>

<pre>
    (\d+)zzz
</pre>

<p>
there are two groups. Group 0 always refers to the whole 
expression, and group 1 to the subexpression that starts with the
open parenthesis &quot;(&quot; and ends with the corresponding close 
parenthesis &quot;)&quot;. The text of matched groups is saved by the 
regular expression matcher, and can be retrieved or referenced 
later in the regular expression.
</p>

<p>
Let's illustrate these ideas with an example:

<pre>
    import java.util.regex.*;
    
    public class GroupDemo1 {
        static final String stringlist[] = {
            &quot;abc 123 def&quot;,
            &quot;456 ghi&quot;,
            &quot;jkl789mno&quot;
        };
    
        public static void main(String args[]) {
    
            // compile regular expression pattern for a
            // number consisting of one or more digits
    
            Pattern patt = Pattern.compile(&quot;(\\d+)&quot;);
    
            for (
              int i = 0; i &lt; stringlist.length; i++) {
                String currstr = stringlist[i];
    
                // see if the current string has a match
    
                Matcher match = patt.matcher(currstr);
    
                // if a match, print the string text
                // for the matching group (group 1)
    
                if (match.find()) {
                    System.out.println(&quot;For \&quot;&quot; +
                        currstr + &quot;\&quot; match is: &quot; +
                        match.group(1));
                }
            }
        }
    }
</pre>

<p>
In this demonstration, <code>GroupDemo1</code>, there are some strings with 
embedded numbers in them. The program uses regular expression 
features to search for the numbers, and display the string text 
for each number that it finds. The program creates a <code>Matcher</code> 
object for each input string. Then the program calls the <code>find</code> 
method to see if there is a match against the regular expression 
pattern. If there is a match, the program gets the matching text 
for group 1 from the <code>Matcher</code> and displays it. In this example, 
the regular expression is:
</p>

<pre>
    (\d+)
</pre>

<p>
and group 1 is the text matched by &quot;<code>\d+</code>&quot;. When you run the 
program, you should see the result:
</p>

<pre>
    For &quot;abc 123 def&quot; match is: 123
    For &quot;456 ghi&quot; match is: 456
    For &quot;jkl789mno&quot; match is: 789
</pre>

<p>
Let's look at another example similar to the first one:
</p>

<pre>
    import java.util.regex.*;
    
    public class GroupDemo2 {
        static final String stringlist[] = {
            &quot;abc 123 def 123&quot;,
            &quot;456 ghi&quot;,
            &quot;jkl789mno    789pqr&quot;,
            &quot;123 456&quot;
        };
    
        public static void main(String args[]) {
    
            // compile regular expression pattern for 
            // a number consisting of one or more 
            // digits followed by the same number later 
            // in the string
    
            Pattern patt = 
                        Pattern.compile(&quot;(\\d+).*\\1&quot;);
    
            for (
               int i = 0; i &lt; stringlist.length; i++) {
                String currstr = stringlist[i];
    
                // see if the current string 
                // has a match
    
                Matcher match = patt.matcher(currstr);
    
                // if a match, print the string text
                // for the matching group (group 1)
    
                if (match.find()) {
                    System.out.println(&quot;For \&quot;&quot; +
                        currstr + &quot;\&quot; match is: &quot; +
                        match.group(1));
                }
            }
        }
    }
</pre>

<p>
The <code>GroupDemo2</code> demo is almost the same as <code>GroupDemo1</code>, but with 
a different regular expression:
</p>

<pre>
    (\d+).*\1
</pre>

<p>
For an input sequence to match this expression, it must contain a
number followed by any characters followed by the original number. 
The &quot;<code>\1</code>&quot; is a back reference to the first group in the expression. 
So input of:
</p>

<pre>
    123 abc 123
</pre>

<p>
will match, but:
</p>

<pre>
    123 abc 456
</pre>

<p>
will not.
</p>

<p>
When you run the <code>GroupDemo2</code> program, you should see the result:
</p>

<pre>
    For &quot;abc 123 def 123&quot; match is: 123
    For &quot;jkl789mno    789pqr&quot; match is: 789
</pre>

<p>    
Another way that you can use groups is to do string editing, for
example, replacing the text of a matching group with other text. 
Here's an example:
</p>

<pre>
    import java.util.regex.*;
    
    public class GroupDemo3 {
        static final String stringlist[] = {
            &quot;abc 123 def   123&quot;,
            &quot;456 ghi&quot;,
            &quot;no match&quot;,
            &quot;jkl789mno   789&quot;,
            &quot;&quot;,
            &quot;123.123&quot;,
            &quot;1,2,3,4,5,6,7,8,9,10&quot;
        };
    
        public static void main(String args[]) {
    
            // compile regular expression pattern for 
            // a number consisting of one or more 
            // digits
    
            Pattern patt = Pattern.compile(&quot;(\\d+)&quot;);
    
            for (
              int i = 0; i &lt; stringlist.length; i++) {
                String currstr = stringlist[i];
    
                String outstr;
    
                // see if the current string has 
                // a match
    
                Matcher match = patt.matcher(currstr);
                boolean result = match.find();
    
                // if found a match, then go through 
                // string and replace all matches with 
                // &quot;[matchstring]&quot;
    
                if (result) {
                    StringBuffer strbuf = 
                                    new StringBuffer();
                    do {
                        match.appendReplacement(
                                       strbuf, &quot;[$1]&quot;);
                        result = match.find();
                    } while (result);
                    match.appendTail(strbuf);
                    outstr = strbuf.toString();
                }
    
                // if no match, just point output 
                // at input
    
                else {
                    outstr = currstr;
                }
    
                // display the result
    
                System.out.println(outstr);
            }
        }
    }
</pre>

<p>
The <code>GroupDemo3</code> program finds numbers in the input, as before. 
When a number is found, it takes the text of the number and puts 
&quot;<code>[]</code>&quot; around it. Ultimately, the program produces an output string 
that consists of the input with this editing operation performed 
on it.
</p>

<p>
The <code>appendReplacement</code> and <code>appendTail</code> methods are the key to
performing this operation. The <code>appendReplacement</code> method is used 
to replace matched text in the input with a new string that you 
specify. The string can contain references to groups. For example, 
the <code>GroupDemo3</code> program specifies the replacement string as &quot;<code>[$1]</code>&quot;.
This means to replace matched instances of group 1 with the 
group 1 text surrounded by &quot;<code>[]</code>&quot;, and append the result to an 
output string buffer. When the matching process is exhausted, 
<code>appendTail</code> is used to append the rest of the input to the output.
</p>

<p>
The output of the <code>GroupDemo3</code> program is:
</p>

<pre>
    abc [123] def   [123]
    [456] ghi
    no match
    jkl[789]mno   [789]

    [123].[123]
    [1],[2],[3],[4],[5],[6],[7],[8],[9],[10]
</pre>

<p>
The logic in this demo is very similar to the <code>Matcher.replaceAll</code>
method.
</p>

<p>
For further information about regular expressions, see
the article <a href="http://java.sun.com/jdc/technicalArticles/releases/1.4regex/?s=06&w=41">&quot;Regular
Expressions and the Java Programming 
Language&quot;</a> by Dana Nourie and Mike McCloskey.
</p>

<table width="100%" border="0" cellspacing="0" cellpadding="0" align="center">

<!-- Grey Horizontal Line Begins Here -->

<tr>
<td bgcolor="#cccccc" height="1"><img src="http://developer.java.sun.com/images/pixel.gif" width="1" height="1" ALT="Pixel" border="0"></td>
</tr>
</table> 

<!-- Grey Horizontal Line ends Here -->

<a name="2"></a>

<h3>ANONYMOUS CLASSES</h3>

<p>
If you've done much Java programming, you might have realized 
that it's possible to declare classes that are nested within
other classes. This tip is going to look at one particular kind 
of nesting, which goes by the name &quot;anonymous class&quot;. To get 
started on the discussion, let's look at a simple example:
</p>

<pre>
    class Base {
        void method1() {}
        void method2() {}
    }
    
    class A { // normal class
    
        static class B {} // static nested class
    
        class C {} // inner class
    
        void f() {
            class D {} // local inner class
        }
    
        void g() {
            // anonymous class
            Base bref = new Base() { 
                void method1() {}
            };
        }
    }
</pre>

<p>
The example illustrates various kinds of nested and inner 
classes. A nested class that is not declared static is called an 
inner class. In the example code, B is a nested class, while C is 
a nested class and an inner class.
</p>

<p>
The main focus of this tip is anonymous classes. You can glean 
a few insights about anonymous classes by studying the example 
above. One key idea is that an anonymous class has no name. An 
anonymous class is a subclass of an existing class (<code>Base</code> in this 
example) or an implementation of an interface.
</p>

<p>
Because an anonymous class has no name, it cannot have an 
explicit constructor. Neither can an anonymous class be referred 
to outside its declaring expression, except indirectly through 
a superclass or interface object reference. Anonymous classes 
are never static, never abstract, and always final. Also, each 
declaration of an anonymous class is unique. For example, the
following code declares two distinct anonymous classes:
</p>

<pre>
    Base bref1 = new Base() {
        void method1() {}
    };

    Base bref2 = new Base() {
        void method1() {}
    };
</pre>  

<p>
Each anonymous class is declared within an expression.
</p>

<p>
Let's look at a common situation where you would use an anonymous
class:
</p>

<pre>
    import java.awt.*;
    import java.awt.event.*;
    import javax.swing.*;
    
    public class AnonDemo2 {
        public static void main(String args[]) {
    
            // create a JFrame and add a listener
            // to it to handle window closing
    
            JFrame frame = new JFrame(&quot;AnonDemo2&quot;);
            frame.addWindowListener(
                                  new WindowAdapter() {
                public void windowClosing(
                                       WindowEvent e) {
                    System.exit(0);
                }
            });
    
            // create a JPanel and add it to the frame
    
            JPanel panel = new JPanel();
            panel.setPreferredSize(
                              new Dimension(300, 300));
            frame.getContentPane().add(panel);
    
            // display the frame
    
            frame.pack();
            frame.setVisible(true);
        }
    }
</pre>

<p>
This example displays a <code>JPanel</code> on the screen. The demo adds a
window listener to the <code>JFrame</code> object such that when the user 
closes the window, the application terminates.
</p>

<p>
<code>WindowListener</code> is an interface. An implementing class must define
all the methods specified in the interface. <code>WindowAdapter</code>
implements the interface using dummy methods, like this:
</p>

<pre>
    public abstract class WindowAdapter
        implements WindowListener, WindowStateListener,
        WindowFocusListener
    {
        public void windowOpened(WindowEvent e) {}
        public void windowClosing(WindowEvent e) {}
        public void windowClosed(WindowEvent e) {}
        public void windowIconified(WindowEvent e) {}
        public void windowDeiconified(WindowEvent e) {}
        public void windowActivated(WindowEvent e) {}
        public void windowDeactivated(WindowEvent e) {}
        public void windowStateChanged(WindowEvent e) {}
        public void windowGainedFocus(WindowEvent e) {}
        public void windowLostFocus(WindowEvent e) {}
    }
</pre>

<p>
The demo application, <code>AnonDemo2</code>, needs to override just one of 
these methods, the <code>windowClosing</code> one. So it subclasses the 
adapter class and overrides the single method. The subclass is 
used only once within the application, and contains very simple 
logic. That's why an anonymous class is a good choice in this 
situation. The anonymous class extends the <code>WindowAdapter</code> class to 
override a single method. <code>WindowAdapter</code>, in turn, implements the 
<code>WindowListener</code> class by use of dummy methods that do nothing.
</p>

<p>
Let's look at another example. Suppose that you have a <code>List</code> of 
<code>Integer</code> objects, and you want to sort the list, both in ascending 
order (the default) and in descending order. Here's some code to 
do this:
</p>

<pre>
import java.util.*;

public class AnonDemo3 {
    public static void main(String args[]) {

        // create an ArrayList and add
        // some Integer objects to it

        List list = new ArrayList();
        list.add(new Integer(37));
        list.add(new Integer(-59));
        list.add(new Integer(83));

        // sort the list in the usual (ascending order)

        Collections.sort(list);
        System.out.println(list);

        // sort the list in descending order
        // using a function object implemented
        // via an anonymous class

        Collections.sort(list, new Comparator() {
            public int compare(Object o1, Object o2) {
                int a = ((Integer)o1).intValue();
                int b = ((Integer)o2).intValue();
                return a &lt; b ? 1 : a == b ? 0 : -1;
            }
        });
        System.out.println(list);
    }
}
</pre>

<p>
The program does the first sort in the obvious fashion. Then, to 
sort in descending order, the program must specify a <code>Comparator</code> 
function object. This object implements comparison logic to sort 
<code>Integer</code> objects in descending order.
</p>

<p>
This demo uses an anonymous class, one that implements the
<code>java.util.Comparator</code> interface. If this kind of sorting is done
in only one place in an application, an anonymous class makes 
sense, but if it's done many places, it might make more sense to 
introduce a top-level or static nested class:
</p>

<pre>
    class MyComparator implements Comparator {
        ...
    }
</pre>
    
<p>
and implement the sort logic only once.
</p>

<p>
The output of the program is:
</p>

<pre>
    [-59, 37, 83]
    [83, 37, -59]
</pre>

<p>
Let's look at a final example, one that illustrates a couple of
issues related to the use of anonymous classes:
</p>

<pre>
    class A {
        int afield;
    
        // set value of afield
    
        A(int afield) {
            this.afield = afield;
        }
    
        // get value of afield
    
        int getValue() {
            return afield;
        }
    }
    
    public class AnonDemo4 {
        static A createAnon() {
            final int dlocal = 40;
    
            // return from the f() method an instance
            // of the anonymous class derived from A
    
            // invoke superclass constructor
            return new A(10) {             
                int bfield = 20;
                int cfield;
    
                {
                    cfield = 30;
                }
    
                int getValue() {
                    return afield + bfield + cfield 
                    + dlocal;
                }
            };
        }
    
        public static void main(String args[]) {
            A anonref = createAnon();
    
            System.out.println(anonref.getValue());
        }
    }
</pre>

<p>
In this example, the <code>createAnon</code> method declares an anonymous 
class and returns a superclass (<code>A</code>) reference to an instance of 
the anonymous class. This means that the anonymous class instance 
can be used outside the declaring context (<code>createAnon</code>). Then the 
<code>getValue</code> method is called on the anonymous class object reference.
</p>

<p>
Recall that anonymous classes do not have names, and so, they
cannot have explicit constructors. But there are several ways to 
get around this limitation. When an instance of an anonymous 
class is created, by saying:
</p>

<pre>
    new A(10) {...}
</pre>

<p>
the superclass constructor, <code>A(int)</code>, is automatically called.
</p>

<p>
Instance initialization for the anonymous class instance is 
handled in the normal way, so that
</p>

<pre>
    int bfield = 20;
</pre>

<p>
and
</p>

<pre>
    {
        cfield = 30;
    }
</pre>

<p>
work as usual. These mechanisms can be used to do part of the 
work that might normally be done in a constructor.
</p>

<p>
There's one additional unusual feature of the <code>AnonDemo4</code> example. 
The <code>dlocal</code> variable is declared as final. If the final keyword is 
left off the declaration, this code will evoke a compiler error. 
Why? Because it's possible, as this example illustrates, to refer 
to an anonymous class object outside the context where the class 
was declared. If such a reference is made, what value would 
dlocal have, given that it's a local variable declared in the 
<code>createAnon</code> method? This is a classic programming issue that occurs 
when an invalid stack frame is referenced.
</p>

<p>
To get around this problem, the local variable must be made final,
that is, bound to a particular value which can be used in place 
of the variable (<code>dlocal</code>) itself. So instead of using &quot;<code>dlocal</code>&quot;, 
the value &quot;<code>40</code>&quot; is used.
</p>

<p>
Anonymous classes are very useful tools, but they should not be
overemphasized. Some other kind of class might be a better choice 
if more than one anonymous class in your application uses the 
same logic, or if the logic in such a class is complicated, or if 
you have deep class nesting. Also, anonymous class declarations 
can be hard to read, so you should keep them simple.
</p>

<p>
For further information about anonymous classes,  see section
5.4 Anonymous Inner Classes, in
&quot;<a href="http://java.sun.com/docs/books/javaprog/thirdedition/?s=06&w=41" target="_blank">The Java<sup>TM</sup> 
Programming Language Third Edition</a>&quot; by Arnold, Gosling, and Holmes.
Also see item 18 &quot;Favor static member classes over nonstatic&quot; in 
<a href="http://java.sun.com/docs/books/effective/?s=06&w=41" target="_blank">Effective
Java Programming Language Guide</a>&quot; by Joshua Bloch.
</p>

<table width="100%" border="0" cellspacing="0" cellpadding="0" align="center">

<!-- Grey Horizontal Line Begins Here -->

<tr>
<td bgcolor="#cccccc" height="1"><img src="http://developer.java.sun.com/images/pixel.gif" width="1" height="1" ALT="Pixel" border="0"></td>
</tr>
</table> 

<!-- Grey Horizontal Line ends Here -->
<br>

<span class="small">IMPORTANT: Please read our Terms of Use, Privacy, and Licensing 
policies:<br>
<a href="http://www.sun.com/share/text/termsofuse.html?s=06&w=41" target="_blank"><span class="link">http://www.sun.com/share/text/termsofuse.html</span></a><br>
<a href="http://www.sun.com/privacy/?s=06&w=41" target="_blank"><span class="link">http://www.sun.com/privacy/</span></a><br> 
<a href="http://developer.java.sun.com/berkeley_license.html?s=06&w=41" target="_blank"><span class="link">http://developer.java.sun.com/berkeley_license.html</span></a>
</span><br><br>


<span class="small">
Comments? Send your feedback on the Core Java<sup>TM</sup> Technologies Tech Tips to: <a href="mailto:jdc-webmaster@sun.com?s=06&w=41"><span class="link">jdc-webmaster@sun.com</span></a>
</span><br><br>

<span class="small">
Subscribe to the following newsletters for the latest information about technologies and products in other Java platforms:
</span><br><br>

<span class="small">
  - Enterprise Java Technologies Tech Tips. Get tips on using
    enterprise Java technologies and APIs, such as those in the
    Java 2 Platform, Enterprise Edition (J2EE<sup>TM</sup>).<br>
  - Wireless Developer Tech Tips. Get tips on using wireless
    Java technologies and APIs, such as those in the Java 2 
    Platform, Micro Edition (J2ME<sup>TM</sup>).<br><br>
</span>
   
<span class="small">
  To subscribe to these and other JDC publications:<br>
  - Go to the JDC Newsletters and Publications page, 
    choose the newsletters you want to <a href="http://developer.java.sun.com/subscription/?s=06&w=41" target="_blank"><span class="link">subscribe</span></a> to and click &quot;Update&quot;.<br>
  - To unsubscribe, go to the <a href="http://developer.java.sun.com/subscription/?s=06&w=41" target="_blank"><span class="link">subscriptions page</span></a>, uncheck the appropriate checkbox, and click &quot;Update&quot;.
</span><br><br>

<span class="small">ARCHIVES: You'll find the Core Java Technologies Tech Tips archives at:<br>
<a href="http://java.sun.com/jdc/TechTips/?s=06&w=41" target="_blank"><span class="link">http://java.sun.com/jdc/TechTips/index.html</span></a>
</span><br><br>

<span class="small">Copyright 2002 <a href="http://www.sun.com?s=06&w=41" target="_blank"><span class="link">Sun Microsystems, Inc.</span></a> All rights reserved.
<br>901 San Antonio Road, Palo Alto, California 94303 USA.
</span><br><br>

<span class="small">This document is protected by copyright. For more information, see:
<br><a href="http://java.sun.com/jdc/copyright.html?s=06&w=41" target="_blank"><span class="link">http://java.sun.com/jdc/copyright.html</span></a>
</span><br><br>

<span class="small">
Core Java Technologies Tech Tips<br>
October 8, 2002
</span><br><br>

<span class="small">Sun, Sun Microsystems, Java, Java Developer Connection, J2SE, J2EE, and J2ME are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.
</span><br><br>

<!-- ================ -->
<!-- End Main Content -->
<!-- ================ -->

<center>
<a href="http://www.sun.com?s=06&w=41" target="_blank"><img src="http://developer.java.sun.com/images/lgsun.gif" border="0" alt="Sun Microsystems, Inc."></a>
</center>

</td>
</tr>
</table>

</td></tr>
</table>
</td>

<td bgcolor="#cccccc" width="1"><img src="http://developer.java.sun.com/images/pixel.gif" width="1" height="1" border="0" alt=""></td>
</tr>
<tr>
<td colspan="3" bgcolor="#cccccc" width="1"><img src="http://developer.java.sun.com/images/pixel.gif" width="1" height="1" border="0" alt=""></td>
</tr>
</table>

<table bgcolor = "#efefef"><tr><td><a href="http://bulkmail.sun.com/servlet/PreferenceServlet?action=change&pref_name=content-type&pref_value=text&id=23407496-686162560">Please send me newsletters in text.</a><br><a href="http://bulkmail.sun.com/unsubscribe?23407496-686162560">Please unsubscribe me from this newsletter.</a><img src="http://bulkmail2.sun.com/OTServlet?id=23407496-686162560" width=1 height=1></td></tr></table></body>
</html>		

