# 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 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();

}

@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.
*/
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);

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) {
}

@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();

// OR using the copy constructor
}

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();

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

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

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;
}

}

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);
}
}