Return-Path: <env_197041071928150221@hermes.sun.com>
Received: from pacific-carrier-annex.mit.edu by po10.mit.edu (8.9.2/4.7) id SAA10072; Tue, 6 Aug 2002 18:24:37 -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 SAA00803
	for <alexp@mit.edu>; Tue, 6 Aug 2002 18:24:36 -0400 (EDT)
Date: 6 Aug 2002 12:24:33 -0800
From: "JDC Tech Tips" <body_197041071928150221@hermes.sun.com>
To: alexp@mit.edu
Message-Id: <197041071928150221@hermes.sun.com>
Subject: Core Java Technologies Tech Tips, August 6, 2002 (Prime Numbers, Overloading)
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>
Technical Tips
</title>
</head>

<body bgcolor="#ffffff">
<a name="top"></a>
<table border="0" cellpadding="0" cellspacing="0" width="640">
<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>

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

<td>
<table border="0" cellpadding="0" cellspacing="0" width="640">
<tr>
<td colspan="2">
<img src="http://developer.java.sun.com/images/core_java_ttips_header.gif" width="640" alt="" border="0"></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=""></td>
</tr>

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

<tr bgcolor="#59588d">
<td height="20">&nbsp;&nbsp;&nbsp;<a href="http://developer.java.sun.com/developer/TechTips/txtarchive/2002/Aug02_GlenM.txt?s=06&w=32" style="text-decoration:none;"><font face="verdana" size="2" color="ffffff">View this issue as simple text</font></a></td>
<td align="right" height="20"><font face="verdana" size="2" color="ffffff"><b>August 6, 2002</b></font>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</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=""></td>
</tr>

<tr><td colspan="2">

<table border="0" cellpadding="10" cellspacing="0" width="640">
<tr><td>

<FORM METHOD="GET" ACTION="http://search.java.sun.com/search/java/">
<table BORDER="0" CELLPADDING="0" CELLSPACING="0" WIDTH="100%">
<tr>
<td>
        
<table BORDER="0" CELLPADDING="0" CELLSPACING="0">
<TR> 
<td  align="left" VALIGN="middle"><img src="http://developer.java.sun.com/images/issue.gif" border="0" alt=""></td>
              
<td VALIGN="middle" align="right" WIDTH="100%">
<FONT SIZE="2">
<INPUT TYPE="text" SIZE="15" MAXLENGTH="128" NAME=qt></FONT></td>
            
<td VALIGN="middle" WIDTH="55" align="right">
<INPUT TYPE="image" SRC="http://developer.java.sun.com/images/search.button.gif" ALT="Search" value="search" BORDER="0" WIDTH="55"></td>
</tr>
</table>
</td></tr>
</table>
</FORM>

<p>
<a href="#1"><img src="http://developer.java.sun.com/images/anchor.gif" border="0" alt=""><font face="verdana" size="2" color="#666699">Generating Prime Numbers</font></a>
<br>    
<a href="#2"><img src="http://developer.java.sun.com/images/anchor.gif" border="0" alt=""><font face="verdana" size="2" color="#666699">When Not to Overload Methods</font></a>
</p>

<p>
<font face="verdana" size="2" color="#000000">These tips were developed using Java<font size="-2"><sup>TM</sup></font> 2 SDK, Standard Edition, v 1.4.</font>
</p>

<p>
<font face="verdana" size="2" color="#000000">This issue of the Core Java Technologies Tech Tips is written by Glen McCluskey.</font>
</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>
<p>
<font face="verdana" size="3"><b>Generating Prime Numbers</b></font>
</p>


<p>
<font face="verdana" size="2" color="#000000">
A prime number is an integer greater than 1, with only itself and 1 as divisors. The first few primes are 2, 3, 5, 7, 11, and 13.</font>
</p>

<p><font face="verdana" size="2" color="#000000">
This tip examines two ways of generating primes. The first approach works for relatively small (32-bit) prime numbers. The second uses the <code>BigInteger</code> class to generate large primes (typically hundreds or thousands of digits).</font>
</p>

<p><font face="verdana" size="2" color="#000000">
Here's an example of where prime numbers are used. Suppose that you're working on a custom hash table scheme. You know that there will be about 1000 entries in the table, and you want the table to be no more than two thirds full, relative to the number of slots available. This implies a table size of 1500. A common hash table algorithm uses a table size that's prime, in order to reduce the number of collisions. So you need to find a prime number with a value near 1500. How can you do this? Here's one way:</font>
</p>

<font face="verdana" size="2" color="#000000">
<pre>
    public class PrimeDemo1 {
    
        // check whether a number is prime
    
        static boolean isPrime(int n) {
    
            // 2 is the smallest prime
    
            if (n &lt;= 2) {
                return n == 2;
            }
    
            // even numbers other than 2 are not prime
    
            if (n % 2 == 0) {
                return false;
            }
    
            // check odd divisors from 3
            // to the square root of n
    
            for (int i = 3, end = (int)Math.sqrt(n);
            i &lt;= end; i += 2) {
                if (n % i == 0) {
                    return false;
                }
            }
    
            return true;
        }
    
        // find the smallest prime &gt;= n
    
        static int getPrime(int n) {
            while (!isPrime(n)) {
                n++;
            }
            return n;
        }
    
        public static void main(String args[]) {
            System.out.println(getPrime(1500));
        }
    }
</pre>
</font>



<p><font face="verdana" size="2" color="#000000">
The <code>PrimeDemo1</code> program defines an <code>isPrime</code> method. The method handles the special case of 2 (which is prime). It then screens out other positive even numbers (which are not prime, because they have 2 as a divisor). The <code>isPrime</code> method then tries odd divisors starting at 3 and going up to the square root of the number.</font>
</p>

<p><font face="verdana" size="2" color="#000000">
The output of the program is:</font>
</p>

<font face="verdana" size="2" color="#000000">
<pre>
    1511
</font>
</pre>

<p><font face="verdana" size="2" color="#000000">
that is, 1511 is the smallest prime of value 1500 or above.</font>
</p>

<p><font face="verdana" size="2" color="#000000">
This approach does the job, and is reasonably fast. But it has a couple of shortcomings. One problem is that you can't use the program to generate prime numbers above 32 bits (about 10 decimal digits). (To convert a number of bits to an approximate number of decimal digits, multiply by log10(2), or 0.301).</font>
</p>

<p><font face="verdana" size="2" color="#000000">
Some applications require very long primes, such as 2048 bits (approximately 615 digits). An example is encryption, which relies on the idea that the product of two large primes cannot readily be factored into those primes -- except by a brute-force attack using very large amounts of computer time.</font>
</p>

<p>
<font face="verdana" size="2" color="#000000">
Even if the <code>PrimeDemo1</code> program could somehow represent very long numbers, there is another problem. Trying all odd divisors up to the square root is a hopelessly inefficient technique for generating prime numbers, when the numbers are really big. Here, another approach is required.
</font>
</p>

<p><font face="verdana" size="2" color="#000000">
There is indeed a very fast way to generate large primes, but with a catch. The generated numbers are probably prime, but there is a slight chance that they might not be. The standard set by ANSI X9.80 specifies a certainty for use in private-key encryption: the probability that a generated prime is actually prime is greater than 1 minus 1/2 to the 100th power. So there's less than a 1 in 2 to the 100th power chance that a generated number is not prime. 1 in 2 to the 100th power is about 1 in 1.27 times 10 to the 30th power, which is indeed a very low probability.</font>
</p>

<p><font face="verdana" size="2" color="#000000">
Given this background, how do you actually generate a big prime? Here's a simple example:</font>
</p>

<font face="verdana" size="2" color="#000000">
<pre>
    import java.math.BigInteger;
    import java.util.Random;
    
    public class PrimeDemo2 {
        public static void main(String args[]) {
            Random rnd = new Random(0);
    
            // obtain a 100-bit probable prime, 
            // with the probability that the number 
            // is composite at less than 
            // 1 in 2 to the 100th power
    
            BigInteger prime = 
                    BigInteger.probablePrime(100, rnd);
    
            System.out.println(prime);
        }
    } 
</pre>
</font>

<p><font face="verdana" size="2" color="#000000">
This program generates a 100-bit prime, using the passed-in <code>Random</code> object as a source of random values. The output of the program is:</font>
</p>

<font face="verdana" size="2" color="#000000">
<pre>
    689572171629632424814677540353
</pre>
</font>

<p><font face="verdana" size="2" color="#000000">
The <code>probablePrime</code> method generates a 100-bit number, and then subjects that number to certain tests of primality, called the Miller-Rabin and Lucas-Lehmer tests.</font>
</p>

<p>
<font face="verdana" size="2" color="#000000">
How fast does <code>probablePrime</code> run? Let's look at a final example to help answer this question:
</font>
</p>

<font face="verdana" size="2" color="#000000">
<pre>
    import java.math.BigInteger;
    import java.util.Random;

    public class PrimeDemo3 {
        public static void main(String args[]) {
            for (int numBits = 100; 
                numBits &lt;= 300; numBits += 100) {
                generatePrimes(100, numBits);
            }
        }

        static Random rnd = new Random();

        // Generate numPrimes probable primes 
        // of numBits length.
        
        static void generatePrimes(
                         int numPrimes, int numBits) {
            long start = System.currentTimeMillis();
            for (int i = 1; i &lt;= numPrimes; i++) {
                BigInteger.probablePrime(numBits, rnd);
            }
            long elapsed = 
                    System.currentTimeMillis() - start;
            System.out.println(
                   &quot;ms to generate &quot; + numBits 
                    + &quot; bit prime  = &quot;
                    + (elapsed / numPrimes));
        }
    } 
</pre>
</font>

<p><font face="verdana" size="2" color="#000000">
When you run the program, you should get results like this (your results might differ depending on your operating environment):
</font>
</p>

<font face="verdana" size="2" color="#000000">
<pre>
    ms to generate 100 bit prime  = 31
    ms to generate 200 bit prime  = 111
    ms to generate 300 bit prime  = 235
</pre>
</font>

<p><font face="verdana" size="2" color="#000000">
These results show that it took 31 milliseconds to generate a 100-bit prime, 111 milliseconds to generate a 200-bit prime, and 235 milliseconds to generate a 300-bit prime. Clearly, the time it takes to generate primes is not linear in relation to the number of bits.</font>
</p>

<p><font face="verdana" size="2" color="#000000">
There are a number of other prime-related features in <code>BigInteger</code>. For example, there's a method named <code>isProbablePrime</code> that you can use to test an existing <code>BigInteger</code> value for primality.</font>
</p>



<p><font face="verdana" size="2" color="#000000">
For more information about generating prime numbers, see section 4.5.4, &quot;Factoring Into Primes&quot;, and section 6.4, &quot;Hashing&quot; in &quot;<a href="http://www-cs-faculty.stanford.edu/~knuth/taocp.html"><font face="verdana" size="2" color="#666699">The Art of Computer Programming</font></a>&quot; by Donald Knuth. Also, see &quot;<a href="http://java.sun.com/j2se/1.4/docs/guide/math/enhancements14.html?s=06&w=32"><font face="verdana" size="2" color="#666699">Enhancements to java.math</font></a>&quot;.</font>
</p>

<table width="100%" border="0" cellspacing="0" cellpadding="0" align="center">
<tr>
<td>
<div align="right">
<a href="#top"><font face="verdana" size="2" color="#666699">back to top</font><img src="http://developer.java.sun.com/images/back_to_top.gif" border="0" alt=""></a>
</div>
</td></tr>

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

<!-- 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>
<p>
<font face="verdana" size="3"><b>When Not to Overload Methods</b></font>
</p>

<p>
<font face="verdana" size="2" color="#000000">
Suppose that you are writing a Java application, and you have some code like this that uses overloading for <code>methodA</code> and <code>methodB</code>:</font>
</p>

<font face="verdana" size="2" color="#000000">
<pre>
    public class OverDemo1 {
    
        // overload methodA between short/int
    
        static void methodA(short s) {
            System.out.println(
                              &quot;methodA(short) called&quot;);
        }
        static void methodA(int i) {
            System.out.println(&quot;methodA(int) called&quot;);
        }
    
        // overload methodB between float/double
    
        static void methodB(float f) {
            System.out.println(
                              &quot;methodB(float) called&quot;);
        }
        static void methodB(double d) {
            System.out.println(
                             &quot;methodB(double) called&quot;);
        }
    
        public static void main(String args[]) {
    
            // call methodA with char argument
    
            methodA('a');
    
            // call methodB with int argument
    
            methodB(Integer.MAX_VALUE);
        }
    }
</pre>
</font>


<p>
<font face="verdana" size="2" color="#000000">
What happens when this code is executed? First, <code>methodA</code> is called with a char argument. A char data type is 16 bits, so it seems logical that <code>methodA(short)</code> will be called. That's because the short type is 16 bits as well.</font>
</p>

<p>
<font face="verdana" size="2" color="#000000">
Next, <code>methodB</code> is called with an int argument. The int and float types are both 32 bits. Because a float type uses part of the bits for an exponent, it cannot fully represent a large int value without loss of precision. So <code>methodB(double)</code> seems like the logical choice, right?</font>
</p>

<p>
<font face="verdana" size="2" color="#000000">
Actually, this analysis is wrong in both cases. When you run the <code>OverDemo1</code> program, the result is:</font>
</p>

<font face="verdana" size="2" color="#000000">
<pre>
    methodA(int) called

    methodB(float) called
</pre>
</font>

<p><font face="verdana" size="2" color="#000000">
The point of this tip is not to discuss the intricacies of overloading, but simply to present the idea that most Java programmers don't fully understand how overloading works. It's smart to write your code so that they don't have to worry about these intricacies. This tip presents several ways to write code that avoids overloading issues. But first, let's look at one more example that illustrates how method overloading can be confusing:</font>
</p>

<font face="verdana" size="2" color="#000000">
<pre>
    class A {
        void f() {
            System.out.println(&quot;A.f called&quot;);
        }
    }
    
    class B extends A {
        void f() {
            System.out.println(&quot;B.f called&quot;);
        }
    }
    
    public class OverDemo2 {
        static void classifyObject(A a) {
            System.out.println(&quot;classify as A&quot;);
        }
    
        static void classifyObject(B b) {
            System.out.println(&quot;classify as B&quot;);
        }
    
        public static void main(String args[]) {
    
            // create a B object referenced
            // by an A reference
    
            A aref = new B();
    
            // classify the object 
            // using overloaded methods
    
            classifyObject(aref);
    
            // call the f() method for the object
    
            aref.f();
        }
    }
</pre>
</font>

<p><font face="verdana" size="2" color="#000000">
The <code>OverDemo2</code> program creates a <code>B</code> object with an <code>A</code> reference pointing at it. The program then calls the <code>classifyObject</code> method to indicate whether the <code>A</code> object or the <code>B</code> object is referenced by <code>aref</code>. Then the program calls the <code>f</code> method on the object. If you run this program, the result is:</font>
</p>

<font face="verdana" size="2" color="#000000">
<pre>
    classify as A

    B.f called
</pre>
</font>

<p><font face="verdana" size="2" color="#000000">
The <code>classifyObject</code> method indicates that the <code>A</code> object is being referenced, but the <code>f</code> method call is on the <code>B</code> object. Which is right?
</font>
</p>

<p><font face="verdana" size="2" color="#000000">
This example illustrates a major source of confusion with method overloading, a confusion that stems from the difference between overloading and overriding. The choice of which overloaded method to call is made by the compiler. In the <code>OverDemo2</code> example above, <code>classifyObject</code> is called with the aref argument, of type <code>A</code>. The fact that <code>aref</code> references a <code>B</code> object is ignored, meaning that <code>classifyObject(A)</code> is called. By contrast, the choice of which <code>f</code> method to call is made dynamically when the program is executed, based on the actual type of object (which is a <code>B</code>). The <code>f</code> method in <code>B</code> overrides, not overloads, the corresponding method in <code>A</code>.</font>
</p>

<p><font face="verdana" size="2" color="#000000">
How do you avoid problems with overloading? One approach is to not overload at all. Instead, give methods different names, corresponding to the types of their parameters. For example, the <code>OverDemo1</code> program above could be rewritten like this:</font>
</p>

<font face="verdana" size="2" color="#000000">
<pre>
    public class OverDemo3 {
    
        static void methodShort(short s) {
            System.out.println(&quot;methodShort called&quot;);
        }
    
        static void methodInt(int i) {
            System.out.println(&quot;methodInt called&quot;);
        }
    
        static void methodFloat(float f) {
            System.out.println(&quot;methodFloat called&quot;);
        }
    
        static void methodDouble(double d) {
            System.out.println(&quot;methodDouble called&quot;);
        }
    
        public static void main(String args[]) {
    
            // call methodInt with char argument
    
            methodInt('a');
    
            // call methodFloat with int argument
    
            methodFloat(Integer.MAX_VALUE);
        }
    }
</pre>
</font>

<p><font face="verdana" size="2" color="#000000">
There is no overloading in this code, so which methods are called is very clear. A similar technique is used in some of the standard library classes such as <code>DataOutputStream</code>.</font>
</p>

<p><font face="verdana" size="2" color="#000000">
Another approach to eliminating confusion with overloading is to specify a different number of parameters for each of a set of overloaded methods. Alternatively, make sure that the parameter types are radically different from each other. Let's look at a final example to see how this works:</font>
</p>

<font face="verdana" size="2" color="#000000">
<pre>
    class MyDate {
    
        // construct date from string 
        // like &quot;January 17, 1959&quot;
    
        public MyDate(String s) {
            // ...
        }
    
        // construct date from month/day/year
    
        public MyDate(int month, int day, int year) {
            // ...
        }
    
        // construct date from number of days 
        // since 1/1/1800
    
        public MyDate(int numdays) {
            // ...
        }
    }
</pre>
</font>

<p><font face="verdana" size="2" color="#000000">
In this example, the <code>MyDate</code> constructor is overloaded. It's not possible to give the various constructors different names, as illustrated in the earlier example, so they must be distinguished some other way.</font>
</p>

<p><font face="verdana" size="2" color="#000000">
The first and second constructors have different numbers of parameters, so it's easy to tell them apart. The first and third constructors both have a single parameter, but in one case it's a String, and in the other case an int, so it's easy to distinguish these.</font>
</p>

<p><font face="verdana" size="2" color="#000000">
Note that even with <code>MyDate</code> structured this way, there are still potential problems with understanding the code. For example, a statement like this:</font>
</p>

<font face="verdana" size="2" color="#000000">
<pre>
    MyDate d = new MyDate(10, 12, 1959);
</pre>
</font>

<p><font face="verdana" size="2" color="#000000">
might be interpreted two different ways by someone who reads the 
code. The interpretation depends on whether the person reading 
the code is accustomed to specifying the month number before or 
after the day number. What date is being referred to here, October 12 or December 10? It's possible that additional work needs to be done to make this class easier to use. An enumerated type could be used to specify the month. Static factory methods could be used for creating dates. Unlike for constructors, you can give static factory methods distinct names that describe their function.</font>
</p>

<p><font face="verdana" size="2" color="#000000">
Some examples of parameter types not radically different from each other include:</font>
</p>

<ul>
<li><font face="verdana" size="2" color="#000000">char vs. int</font></li>
<li><font face="verdana" size="2" color="#000000">int vs. float/double</font></li>
<li><font face="verdana" size="2" color="#000000">classes in a related hierarchy (A vs. B in the example above)</font></li>
<li><font face="verdana" size="2" color="#000000">Object vs. array types like int[]</font></li>
</ul>

<p><font face="verdana" size="2" color="#000000">
Overloading is a useful technique, but it pays to be cautious. You don't want to end up with code that's impossible to read, or that takes advantage of arcane rules that few programmers understand. It should be possible for an average reader to look at your code and know exactly what method is being called at any point.</font>
</p>

<p><font face="verdana" size="2" color="#000000">
For more information about alternatives to overloading methods, see item 1 &quot;Consider providing static factory methods instead of constructors&quot; and item 26 &quot;Use overloading judiciously&quot; in &quot;<a href="http://java.sun.com/docs/books/effective/?s=06&w=32"><font face="verdana" size="2" color="#666699">Effective Java Programming Language Guide</font></a>&quot; by Joshua Bloch; and Section 5.3 &quot;Method Invocation Conversion&quot; and Section 15.12.2 &quot;Compile-Time Step 2: Determine Method Signature&quot; in &quot;<a href="http://java.sun.com/docs/books/jls/?s=06&w=32"><font face="verdana" size="2" color="#666699">The Java Language Specification Second Edition</font></a>&quot; by Gosling, Joy, Steele, and Bracha.</font>
</p>

<table width="100%" border="0" cellspacing="0" cellpadding="0" align="center">
<tr>
<td>
<div align="right">
<a href="#top"><font face="verdana" size="2" color="#666699">back to top</font><img src="http://developer.java.sun.com/images/back_to_top.gif" border="0" alt=""></a>
</div>
</td></tr>

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

<!-- 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 -->

<p>
<font face="verdana" color="#999999" size="2">IMPORTANT: Please read our Terms of Use, Privacy, and Licensing
policies:</font><br>
<a href="http://www.sun.com/share/text/termsofuse.html?s=06&w=32"><font face="verdana" size="2" color="#666699">http://www.sun.com/share/text/termsofuse.html</font></a><br>
<a href="http://www.sun.com/privacy/?s=06&w=32"><font face="verdana" size="2" color="#666699">http://www.sun.com/privacy/</font></a><br>
<a href="http://developer.java.sun.com/berkeley_license.html?s=06&w=32"><font face="verdana" size="2" color="#666699">http://developer.java.sun.com/berkeley_license.html</font></a>
</p>

<P>
<font face="verdana" color="#999999" size="2">Comments? Send your feedback on the Core Java Technologies Tech Tips to: <a href="mailto:jdc-webmaster@sun.com"><font face="verdana" size="2" color="#666699">jdc-webmaster@sun.com</font></a></font>
</P>

<P>
<font face="verdana" color="#999999" size="2">Go to the <a href="http://developer.java.sun.com/subscription/?s=06&w=32"><font face="verdana" size="2" color="#666699">subscriptions page</font></a> to subscribe or unsubscribe to this newsletter.</font>
</P>

<p>
<font face="verdana" color="#999999" size="2">ARCHIVES: You'll find the Core Java Technologies Tech Tips archives at:</font><br>
<a href="http://developer.java.sun.com/developer/JDCTechTips/?s=06&w=32"><font face="verdana" size="2" color="#666699">http://developer.java.sun.com/developer/JDCTechTips/</font></a>
</p>

<P>
<font face="verdana" color="#999999" size="2">Copyright 2001 <a href="http://www.sun.com?s=06&w=32"><font face="verdana" size="2" color="#666699">Sun Microsystems, Inc.</font></a> All rights reserved. 901 San Antonio Road, Palo Alto, California 94303 USA.</font>
</P>


<P>
<font face="verdana" color="#999999" size="2">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.</font>
</P>

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

<center>
<a href="http://www.sun.com?s=06&w=32"><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=197041071928150221">Please send me newsletters in text.</a><br><a href="http://bulkmail.sun.com/unsubscribe?197041071928150221">Please unsubscribe me from this newsletter.</a><img src="http://bulkmail2.sun.com/OTServlet?id=197041071928150221" width=1 height=1></td></tr></table></body>
</html>		

