Classes + Variable Length Parameters

Example 1

Classes: Fibonacci, Main

Fibonacci

import java.math.BigInteger;

// class is final, so may not be extended
public final class Fibonacci {
    /**
     * Static collection of first "sequenceSize" Fibonacci numbers.
     */
    public static BigInteger[] fib;

    /**
     * Number of numbers in the Fibonacci sequence. Final, so cannot be changed.
     */
    public static final int sequenceSize = 101;

    /**
     * Static method to initialise and calculate the first 101 Fibonacci numbers and store in the fib array.
     */
    public static void calculate() {
        // static method may ONLY access static fields and methods!

        // allocate enough space to hold 101 numbers, numbered 0..100
        fib = new BigInteger[sequenceSize];

        // starting the sequence at zero (not one)
        fib[0] = fib[1] = BigInteger.ONE;

        // calculate fibonacci sequence
        for (int n = 2; n < sequenceSize; n++) {
            fib[n] = fib[n - 2].add(fib[n - 1]);
        }
    }

    /**
     * Non-static method to display calculated Fibonacci numbers.
     */
    public void display() {
        // non-static method MAY access static fields and methods.
        for (int n = 0; n < sequenceSize; n++) {
            System.out.println("fib(" + n + ") = " + fib[n]);
        }
    }
}

Main

public class Main {
    public static void main(String[] args) {
        // may call calculate, since method is <b>static</b>.
        Fibonacci.calculate();
        System.out.println("Number of Fibonacci numbers = " + Fibonacci.sequenceSize);
        System.out.println("fib(10)=" + Fibonacci.fib[10]);

        /*
        May NOT call: Fibonacci.display(); since method is non-static and requires
        an OBJECT on which to be called.
         */
        Fibonacci f = new Fibonacci();
        // calculate was already called, so shared .fib has been calculated already
        System.out.println("fib(20)=" + f.fib[20]);
        f.display();
    }
}

Example 2

Classes: Invoice, Main, Stack

Invoice

import java.util.ArrayList;

public class Invoice {
    public static final float VAT = 0.14f;

    // STATIC means that an invoice entry object is NOT bound to the outer object,
    // i.e. it may be instantiated without the outer object (unlike the stack's node).
    public static class InvoiceEntry {
        private int quantity;
        private String description;
        private float unitCost;

        public InvoiceEntry(int quantity, String description, float unitCost) {
            this.quantity = quantity;
            this.description = description;
            this.unitCost = unitCost;
        }

        public int getQuantity() {
            return quantity;
        }

        public void setQuantity(int quantity) {
            this.quantity = quantity;
        }

        public String getDescription() {
            return description;
        }

        public void setDescription(String description) {
            this.description = description;
        }

        public float getUnitCost() {
            return unitCost;
        }

        public void setUnitCost(float unitCost) {
            this.unitCost = unitCost;
        }

        public float cost() {
            // MAY access static fields and methods from a static class
            float cost = quantity * unitCost * (1 + VAT);
            return Math.round(cost * 100.0f) / 100.0f ;
        }

        @Override
        public String toString() {
            return quantity + " x " + description + " @ R" + unitCost + " + VAT = R" + cost();
        }
    }

    protected ArrayList<InvoiceEntry> entries = new ArrayList<InvoiceEntry>();

    public void add(InvoiceEntry entry) {
        entries.add(entry);
    }

    public InvoiceEntry remove(int index) {
        return entries.remove(index);
    }

    public float total() {
        float total = 0;

        // FOR-EACH entry in entries
        for(InvoiceEntry entry : entries)
            total += entry.cost();

        return total;
    }

    @Override
    public String toString() {
        return entries.toString() + ", total = R" + total();
    }
}

Stack

    protected class Node {
        public Object value = null;
        public Node prev = null;

        public Node(Object value) {
            // this (Node)'s value is set to parameter
            this.value = value;
        }

        /**
         * Push self onto the stack
         */
        public void push() {
            // prev = object field, top = outer class field
            prev = top;

            /*
            this refers to THIS node (not the stack), if you require a reference to the
            stack (outer class), it is Stack.this
             */
            top = this;
        }
    }

    protected Node top = null;

    public void push(Object value) {
        Node newNode = new Node(value);
        newNode.push();
    }

    public Object pop() {
        if(top == null)
            return null;
        else {
            Node oldTop = top;
            top = oldTop.prev;
            return oldTop.value;
        }
    }

    public void display() {
        Node current = top;
        while(current != null) {
            System.out.println(current.value);
            current = current.prev;
        }
    }
}

Main

public class Main {
    public static void main(String[] args) {
        Stack stack = new Stack();

        /*
        cannot say new Stack.Node as node MUST be inside the
        outer class, i.e. a Node cannot exist without a Stack.
         */

        /*
        FYI integers, strings, booleans converted to objects, which have a
        toString method which is used whenever a String version is required.
         */
        System.out.println("Adding values to stack...");
        stack.push("Hello");
        stack.push("World");
        stack.push(1);
        stack.push(2);
        stack.push(true);

        System.out.println("Displaying values on stack...");
        stack.display();

        System.out.println("Popping values off stack...");
        stack.pop();
        stack.pop();

        System.out.println("Displaying values on stack...");
        stack.display();


        System.out.println("Displaying invoices...");
        Invoice inv1 = new Invoice();
        Invoice inv2 = new Invoice();
        // entry created independent of a specific invoice object
        Invoice.InvoiceEntry entry = new Invoice.InvoiceEntry(5, "Tex Chocolate Bar", 5.75f);
        inv1.add(entry);
        inv2.add(entry);
        inv2.add(new Invoice.InvoiceEntry(7, "Smarties", 6.12f));

        System.out.println(inv1);
        System.out.println(inv2);

    }
}

Example 3: Interface and Anonymous Class

Classes: Person, Main

Person

public interface Person {
    void display();

    String getName();
    void setName(String name);
}

Main

public class Main {
    public static void display(Person person) {
        System.out.println("Main.display started...");
        person.display();
        System.out.println("Main.display ended...");
    }

    public static void main(String[] args) {
        // define a new class AND instantiate it, storing a reference to the new object in p
        Person p = new Person() {
            private String name = "unknown";

            @Override
            public void display() {
                System.out.println("Person's name is " + name);
            }

            @Override
            public String getName() {
                return name;
            }

            @Override
            public void setName(String name) {
                this.name = name;
            }
        };

        // use interface methods defined
        p.setName("Bob");
        p.display();

        // define AND create an object as passed through as a parameter. Since no reference to it is stored, this
        // object will be disposed of when the method returns. Note, completely different implementation from
        // previous one.
        display(new Person() {
            @Override
            public void display() {
                System.out.println("Another person's name is Sally.");
            }

            @Override
            public String getName() {
                return null;
            }

            @Override
            public void setName(String name) {
            }
        });
        // pay special attention to brackets
    }
}

Example 4: Clone and copy groups

Classes: Person, People, Main

Person

public class Person {
    private String surname, firstName;

    public Person(String firstName, String surname) {
        this.surname = surname;
        this.firstName = firstName;
    }

    /**
     * Copy constructor (copies the values of an existing object into a new one).
     * @param person The person being copied.
     */
    public Person(Person person) {
        surname = person.surname;
        firstName = person.firstName;
    }

    public String getSurname() {
        return surname;
    }

    public void setSurname(String surname) {
        this.surname = surname;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    // clone is protected by default, can promote to public (can make something more visible, but not
    // less visible). By default, throws an exception, i.e. cannot be cloned.
    // shallow copy, since does not have any other complex objects.
    @Override
    public Object clone() throws CloneNotSupportedException {
        // create a new object and copy the the values from this object into it.
        Person temp = new Person(this);
        return temp;
    }

    @Override
    public String toString() {
        return firstName + " " + surname;
    }
}

People

/**
 * A collection of person objects.
 */
public class People {
    // we will discuss generics soon!
    private ArrayList<Person> people;

    public People() {
        people = new ArrayList<Person>();
    }

    public void add(String firstName, String surname) {
        people.add(new Person(firstName, surname));
    }

    @Override
    public String toString() {
        return people.toString();
    }

    @Override
    public Object clone() throws CloneNotSupportedException {
        // need to perform a deep copy, since has complex data

        People temp = new People();

        // clone each contained person to new container
        // this is the FOR-EACH syntax that can be used for collections, it reads FOR-EACH person in the
        // people collection, do something
        for(Person person : people) {
            // create a clone of person
            Person p = (Person) person.clone();
            temp.people.add(p);

            // OR using the copy constructor
            // temp.people.add(new Person(person));
        }

        return temp;
    }
}

Main

public class Main {
    public static void main(String[] args) throws CloneNotSupportedException {
        // create a new person
        Person bob = new Person("Billy", "Bob");

        // calls toString method when displaying
        System.out.println(bob);

        Person sam = (Person) bob.clone();
        sam.setFirstName("Sam");
        System.out.println(sam);

        // create and display a person collection
        People people = new People();
        people.add("Billy", "Bob");
        people.add("Sam", "Bob");
        people.add("Uncle", "Bob");
        people.add("John", "Doe");
        people.add("Jane", "Doe");

        System.out.println("People");
        System.out.println(people);
        System.out.println();

        // create a deep COPY, modify and display it
        People people2 = (People) people.clone();
        people2.add("Another", "Person");

        System.out.println("People (after clone and modification)");
        System.out.println(people);
        System.out.println();

        System.out.println("People2");
        System.out.println(people2);
        System.out.println();
    }
}

Example 5: Variable length parameter

Classes: Main

public class Main {
    public static void main(String[] args) {
        new Main();
    }

    public int sum(int... numbers) {
        int total = 0;

        // FOR-EACH n in the numbers array
        for(int n : numbers) {
            total += n;
        }

        return total;
    }

    public int lengthLargerThan(int minLength, String... strings) {
        int count = 0;

        // iterating through string array
        for(int i=0; i<strings.length; i++) {
            if(strings[i].length() >  minLength)
                count++;
        }

        return count;
    }

    public Main() {
        // using the variable length parameter method
        int s = sum(1, 2, 3, 4, 5, 6, 7);
        System.out.println("Sum = " + s);

        int t = lengthLargerThan(3, "abc", "1234", "defghi", "ababababa", "ab");
        System.out.println("Count = " + t);
    }
}