12.5. Layout Managers

 
[Page 382 ( continued )]

11.5. Case Study: The Rational Class

A rational number is a number with a numerator and a denominator in the form a/b , where a is the numerator and b is the denominator. For example, 1/3 , 3/4 , and 10/4 are rational numbers .

A rational number cannot have a denominator of , but a numerator of is fine. Every integer a is equivalent to a rational number a/1 . Rational numbers are used in exact computations involving fractions; for example, 1/3 = 0.33333 .... This number cannot be precisely represented in floating-point format using data type double or float . To obtain the exact result, it is necessary to use rational numbers.

Java provides data types for integers and floating-point numbers, but not for rational numbers. This section shows how to design a class to represent rational numbers.


[Page 383]

Since rational numbers share many common features with integers and floating-point numbers, and Number is the base class for numeric wrapper classes, it is appropriate to define Rational as a subclass of Number . Since rational numbers are comparable, the Rational class should also implement the Comparable interface. Figure 11.12 illustrates the Rational class and its relationship to the Number class and the Comparable interface.

Figure 11.12. The properties, constructors, and methods of the Rational class are illustrated in UML.

A rational number consists of a numerator and a denominator. There are many equivalent rational numbers; for example, 1/3 = 2/6 = 3/9 = 4/12. For convenience, 1/3 is used in this example to represent all rational numbers that are equivalent to 1/3. The numerator and the denominator of 1/3 have no common divisor except 1, so 1/3 is said to be in lowest terms.

To reduce a rational number to its lowest terms, you need to find the greatest common divisor (GCD) of the absolute values of its numerator and denominator, and then divide both numerator and denominator by this value. You can use the method for computing the GCD of two integers n and d , as suggested in Listing 4.6, GreatestCommonDivisor.java. The numerator and denominator in a Rational object are reduced to their lowest terms.

As usual, let us first write a test program to create two Rational objects and test its methods. Listing 11.6 is a test program. Its output is shown in Figure 11.13.

Figure 11.13. The program creates two Rational objects and displays their addition, subtraction, multiplication, and division.


Listing 11.6. TestRationalClass.java
(This item is displayed on page 384 in the print version)
 1   public class   TestRationalClass { 2  /** Main method */  3   public static void   main(String[] args) { 4  // Create and initialize two rational numbers r1 and r2.  5  Rational r1 =   new   Rational(   4   ,   2   );  6  Rational r2 =   new   Rational(   2   ,   3   );  7 8  // Display results  9 System.out.println(r1 +   " + "   + r2 +   " = "   +  r1.add(r2)  ); 10 System.out.println(r1 +   " - "   + r2 +   " = "   +  r1.subtract(r2)  ); 11 System.out.println(r1 +   " * "   + r2 +   " = "   +  r1.multiply(r2)  ); 12 System.out.println(r1 +   " / "   + r2 +   " = "   +  r1.divide(r2)  ); 13 System.out.println(r2 +   " is "   +  r2.doubleValue()  ); 14 } 15 } 


[Page 384]

The main method creates two rational numbers, r1 and r2 (lines 5 “6), and displays the results of r1 + r2 , r1 - r2 , r1 * r2 , and r1 / r2 (lines 9 “12). To perform r1 + r2 , invoke r1.add(r2) to return a new Rational object. Similarly, r1.subtract(r2) is for r1 - r2 , r1.multiply(r2) for r1 * r2 , and r1.divide(r2) for r1 / r2 .

The doubleValue() method displays the double value of r2 (line 13). The doubleValue() method is defined in java.lang.Number and overridden in Rational .

Note that when a string is concatenated with an object using the plus sign ( + ), the object's string representation from the toString() method is used to concatenate with the string. So r1 + " + " + r2 + " = " + r1.add(r2) is equivalent to r1.toString() + " + " + r2.toString() + " = " + r1.add(r2).toString() .

The Rational class is implemented in Listing 11.7.

Listing 11.7. Rational.java
(This item is displayed on pages 384 - 386 in the print version)
 1    public class   Rational   extends   Number   implements   Comparable  { 2  // Data fields for numerator and denominator  3   private long   numerator =     ; 4   private long   denominator =   1   ; 5 6  /** Construct a rational with default properties */  7    public   Rational()  { 8   this   (     ,   1   ); 9 } 10 11  /** Construct a rational with specified numerator and denominator */  12    public   Rational(   long   numerator,   long   denominator)  { 13   long   gcd = gcd(numerator, denominator); 14   this   .numerator = ((denominator >     ) ?   1   :   -1   ) * numerator / gcd; 15   this   .denominator = Math.abs(denominator) / gcd; 16 } 17 18  /** Find GCD of two numbers */  19   private static long   gcd(   long   n,   long   d) { 20   long   n1 = Math.abs(n); 21   long   n2 = Math.abs(d); 22   int   gcd =   1   ; 23 

[Page 385]
 24   for   (   int   k =   1   ; k <= n1 && k <= n2; k++) { 25   if   (n1 % k ==     && n2 % k ==     ) 26 gcd = k; 27 } 28 29   return   gcd; 30 } 31 32  /** Return numerator */  33   public long   getNumerator() { 34   return   numerator; 35 } 36 37  /** Return denominator */  38   public long   getDenominator() { 39   return   denominator; 40 } 41 42  /** Add a rational number to this rational */  43    public   Rational add(Rational secondRational)  { 44   long   n = numerator * secondRational.getDenominator() + 45 denominator * secondRational.getNumerator(); 46   long   d = denominator * secondRational.getDenominator(); 47   return new   Rational(n, d); 48 } 49 50  /** Subtract a rational number from this rational */  51    public   Rational subtract(Rational secondRational)  { 52   long   n = numerator * secondRational.getDenominator() 53 - denominator * secondRational.getNumerator(); 54   long   d = denominator * secondRational.getDenominator(); 55   return new   Rational(n, d); 56 } 57 58  /** Multiply a rational number to this rational */  59    public   Rational multiply(Rational secondRational)  { 60   long   n = numerator * secondRational.getNumerator(); 61   long   d = denominator * secondRational.getDenominator(); 62   return new   Rational(n, d); 63 } 64 65  /** Divide a rational number from this rational */  66    public   Rational divide(Rational secondRational)  { 67   long   n = numerator * secondRational.getDenominator(); 68   long   d = denominator * secondRational.numerator; 69   return new   Rational(n, d); 70 } 71 72  /** Override the toString() method */  73   public   String toString() { 74   if   (denominator ==   1   ) 75   return   numerator +   ""   ; 76   else   77   return   numerator +   "/"   + denominator; 78 } 79 80  /** Override the equals method in the Object class */  81   public boolean   equals(Object parm1) { 

[Page 386]
 82   if   ((   this   .subtract((Rational)(parm1))).getNumerator() ==     ) 83   return true   ; 84   else   85   return false   ; 86 } 87 88  /** Override the hashCode method in the Object class */  89   public int   hashCode() { 90   return new   Double(   this   .doubleValue()).hashCode(); 91 } 92 93  /** Override the abstract intValue method in java.lang.Number */  94   public int   intValue() { 95   return   (   int   )doubleValue(); 96 } 97 98  /** Override the abstract floatValue method in java.lang.Number */  99   public float   floatValue() { 100   return   (   float   )doubleValue(); 101 } 102 103  /** Override the doubleValue method in java.lang.Number */  104   public double   doubleValue() { 105   return   numerator *   1   .     / denominator; 106 } 107 108  /** Override the abstract longValue method in java.lang.Number */  109   public long   longValue() { 110   return   (   long   )doubleValue(); 111 } 112 113  /** Override the compareTo method in java.lang.Comparable */  114   public int   compareTo(Object o) { 115   if   ((   this   .subtract((Rational)o)).getNumerator() >     ) 116   return   1   ; 117   else if   ((   this   .subtract((Rational)o)).getNumerator() <     ) 118   return   -   1   ; 119   else   120   return     ; 121 } 122 } 

The rational number is encapsulated in a Rational object. Internally, a rational number is represented in its lowest terms (line 13), and the numerator determines its sign (line 14). The denominator is always positive (line 15).

The gcd() method (lines 19 “30 in the Rational class) is private; it is not intended for use by clients . The gcd() method is only for internal use by the Rational class. The gcd() method is also static, since it is not dependent on any particular Rational object.

The abs(x) method (lines 20 “21 in the Rational class) is defined in the Math class that returns the absolute value of x .

Two Rational objects can interact with each other to perform add, subtract, multiply, and divide operations. These methods return a new Rational object (lines 43 “70).

The methods toString , equals , and hashCode in the Object class are overridden in the Rational class (lines 73 “91). The toString() method returns a string representation of a Rational object in the form numerator/denominator , or simply numerator if denominator is 1. The equals(Object other) method returns true if this rational number is equal to the other rational number. By contract, if two objects are equal, their hash codes must be the same. For this reason, you should override hashCode whenever the equals method is overridden.


[Page 387]

The abstract methods intValue , longValue , floatValue , and doubleValue in the Number class are implemented in the Rational class (lines 94 “111). These methods return int , long , float , and double value for this rational number.

The compareTo(Object other) method in the Comparable interface is implemented in the Rational class (lines 114 “121) to compare this rational number to the other rational number.

Tip

The get methods for the properties numerator and denominator are provided in the Rational class, but the set methods are not provided, so the contents of a Rational object cannot be changed once the object is created. The Rational class is immutable . A well-known example of an immutable class is the String class. The wrapper classes introduced in §10.5, "Processing Primitive Data Type Values as Objects," are also immutable.


Tip

The numerator and denominator are represented using two variables . It is possible to use an array of two integers to represent the numerator and denominator. See Exercise 11.2. The signatures of the public methods in the Rational class are not changed, although the internal representation of a rational number is changed. This is a good example to illustrate the idea that the data fields of a class should be kept private so as to encapsulate the implementation of the class from the use of the class.


 


Introduction to Java Programming-Comprehensive Version
Introduction to Java Programming-Comprehensive Version (6th Edition)
ISBN: B000ONFLUM
EAN: N/A
Year: 2004
Pages: 503

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net