1. "Hello, World!"
  2. Variables and Types
  3. Arrays
  4. While, If, For
  5. ...Problem Set 0
  6. Static Methods
  7. Static Fields
  8. String Conversion
  9. Objects
  10. Threading
  11. Strings
  12. ...Problem Set 1.5
  13. Packages
  14. Complex Numbers
  15. Abstract classes
  16. Interfaces
  17. Autoboxing
  18. ...Problem Set 1
  19. enum
  20. Inner Classes
  21. Polymorphism
  22. Tanks!
  23. Callbacks
  24. Exceptions
  25. File I/O
  26. ...Problem Set 2
  27. Regular Expressions

Abstract classes

Sometimes it is useful to put off defining the methods of a class. In this case we do it in order to create a complex number without deciding ahead of time what its internal representation should be.

complex/Complex.java
1package complex;
2 
3public abstract class Complex {
4    abstract public double re();
5    abstract public double im();
6    abstract public double ang();
7    abstract public double rad();
8 
9    public Complex add(Complex c) {
10        return new Cart(re()+c.re(),im()+c.im());
11    }
12    public Complex mul(Complex c) {
13        return new Polar(rad()*c.rad(),ang()+c.ang());
14    }
15    public Complex sqrt() {
16        return new Polar(Math.sqrt(rad()),0.5*ang());
17    }
18    public String toString() {
19        return "("+re()+"+"+im()+"i)";
20    }
21}

Note the use of keyword "abstract" both on the class name and on the public methods that have not been specified.

In the code above we perform our addition, multiplication, or find a sqrt() with either the polar or Cartesian methods, depending on which is easier for us to write. Better yet, we only have to write each of these methods once, and re-use them by inheritance.

complex/Cart.java
1package complex;
2 
3public class Cart extends Complex {
4    private double reim;
5    public Cart(double re,double im) {
6        this.re = re;
7        this.im = im;
8    }
9    public double re() { return re; }
10    public double im() { return im; }
11    public double rad() { return Math.sqrt(re*re+im*im); }
12    public double ang() { return Math.atan2(im,re); }
13}

For each representation of a complex number, we only need to fill in the four methods for obtaining the "coordinates."

complex/Polar.java
1package complex;
2 
3public class Polar extends Complex {
4    private double radang;
5    public Polar(double rad,double ang) {
6        this.rad = rad;
7        this.ang = ang;
8    }
9    public double re() { return rad*Math.cos(ang); }
10    public double im() { return rad*Math.sin(ang); }
11    public double rad() { return rad; }
12    public double ang() { return ang; }
13}
$ javac complex/Polar.java

Now that we've got all our classes defined, we can do a compile. Java is smart enough that it will know it needs class Complex and Cart, and it will automatically find the source files and compile them for us.

TryComplex.java
1import complex.*;
2 
3public class TryComplex {
4    public static void main(String[] args) {
5        Complex a = new Cart(3,4);
6        Complex b = new Cart(5,12);
7        Complex c = a.add(b); // c = a + b
8        Complex d = c.mul(b); // d = (a + b)*b
9        System.out.println("a="+a);
10        System.out.println("b="+b);
11        System.out.println("c="+c);
12        System.out.println("d="+d);
13        System.out.println("sqrt(a)="+a.sqrt());
14    }
15}
$ javac TryComplex.java
$ java TryComplex
a=(3.0+4.0i)
b=(5.0+12.0i)
c=(8.0+16.0i)
d=(-152.0+176.0i)
sqrt(a)=(2.0+1.0i)

Now we try out our new classes, printing out various values. Nifty!