CISC 3115
Modern Programming Techniques
Lecture 1
Classes — Composition, Arrays & Containers, Mutability


Overview

Revisiting Constructors: A Point Class

We will now illustrate a variety of class-related concepts and techniques, using a set of related classes: points, lines, and pairs of lines. Here is some documentation reviewing those concepts: Some supporting documentation … and here is a quick synopsis of the most relevant ideas:

Points (Points)

Model a point in 2-dimensional space (i.e., the 2D plane). A point is represented as a pair of values (we'll stick with integers … at least for now) representing the x and y components of the point.

The class should have the methods:

import java.util.Scanner;

public class Point {
	Point(int x, int y) {
		this.x = x;
		this.y = x;
	}

	public String quadrantStr() {
		switch (quadrant()) {
			case 0: return "Origin";
			case 1: return "Quadrant 1"; 
			case 2: return "Quadrant 2";
			case 3: return "Quadrant 3"; 
			case 4: return "Quadrant 4"; 
			case 5: return "Positive x axis"; 
			case 6: return "Positive y axis"; 
			case 7: return "Negative x axis"; 
			case 8: return "Negative y axis"; 
			default: return "???";
		}
	}
			
	public int quadrant() {
		if (x == 0 && y == 0) return 0;
		if (x > 0 && y > 0) return 1;
		if (x < 0 && y > 0) return 2;
		if (x < 0 && y < 0) return 3;
		if (x > 0 && y < 0) return 4;
		if (x > 0 && y == 0) return 5;
		if (x == 0 && y > 0) return 6;
		if (x < 0 && y == 0) return 7;
		if (x == 0 && y < 0) return 8;
		return -1;
	}

	public String toString() {return "(" + x + ", " + y + ")";}

	public static Point read(Scanner scanner) {
		if (!scanner.hasNextInt()) return null;
		int x = scanner.nextInt();
		int y = scanner.nextInt();
		return new Point(x, y);
	}

	private int x, y;
	public static final Point ORIGIN = new Point(0, 0); 
}

Notes

import java.io.*;
import java.util.*;

public class PointApp {
	public static void main(String [] args) throws Exception {
		Scanner scanner = new Scanner(new File("points.data"));

		System.out.println(" --- From the file");
		System.out.println();

		while (scanner.hasNextInt()) {
			int 
				x = scanner.nextInt(),
				y = scanner.nextInt();
			doIt(x, y);
		}

		Random r = new Random(12345);

		System.out.println();
		System.out.println(" --- Some random points between (-9, -9) and (9, 9)");
		System.out.println();

		for (int i = 1; i <= 20; i++) {
			int 
				x = r.nextInt(19)-9,
				y = r.nextInt(19)-9;
			doIt(x, y);
		}
	}


	public static void doIt(int x, int y) throws Exception{
		System.out.println(x + " " + y);

		Point p =  new Point(x, y);
		System.out.println("p: " + p);

		System.out.println("Quadrant: " + p.quadrantStr() + " (" + p.quadrant() + ")");
	}
}

Notes

Composition — Objects as Instance Variables

Consequences of Composition

Composition & Constructors

When using composition, there is often a chaining in the constructors similar to that of toString and equals
class Name {
	Name(String last, String first) {…}

	…

	private String last, first;

class Person {
	Person(int age, Name name) {
		this.age = age;
		this.name = name;
	}

	Person(int age, String last, String first) {this(age, new Name(last, first));}

	…

	private Name name;
	private int age;
}

static — Class Members

Scoping Rules

Within the methods of a class, one can access the private variables of another instance of the same class scope: the places in a program where a variable can be referenced without qualification (i.e., just using the variable's name)
class C {
	void f1() {
		int i;
		…
		System.out.println(i);
		…
	}

	void f2(int i) {
		…
		System.out.println(i);
		…
	}

	void f3() {
		…
		System.out.println(i);
		…
	}

	int i;
}
		

An interesting Example of Scoping Rules in Action — Another Use of this

Here is a variation on the Name constructor:
class Name {
	Name(String last, String first) {
		…	
	}
	String last, first;
}

Data Access Within the Class

Scope of Fields (Class/Instance Methods/Variables/Constants)

A Counter class

class Counter {
	void up() {...}
	void down() {...}

	int val;
}
	

A Window class

class Window {
	void move(int newX, int newY) {...}
	void resize(int new width, int newHeight) {...}
	void setFgColor(Color newFgColor) {...}
	Color getFgColor() {...}
	void setBgColor(Color newBgColor) {...}
	Color getBgColor() {...}
	void insert(String newText, int where) {...}
	
	int width, height;
	int x, y;
	Color fgColor, bgColor;
	String text;
}
				
  • An object can thus be thought of as a programming mechanism that 'binds' data together with the methods that operate upon that data

    Modelling Related and Hierarchical Things: Points, Lines & Line Pairs (03 Points, Lines, Line Pairs)

    Lines (Lines)

    Model a line in 2-dimensional space (i.e., the 2D plane). A line is represented as two pair of values (i.e., points)

    We will support the methods:

    public class Line {
    	Line(Point endPoint1, Point endPoint2) {
    		this.endPoint1 = endPoint1;
    		this.endPoint2 = endPoint2;
    	}
    
    	Line(int x1, int y1, int x2, int y2) {this(new Point(x1, y1), new Point(x2,  y2));}
    
    	public double length() {return Math.sqrt((Math.pow(endPoint1.getX() - endPoint2.getX(), 2) + Math.pow(endPoint1.getY() - endPoint2.getY(), 2)));}
    	public boolean isVertical() {return endPoint1.getX() == endPoint2.getX();}
    	public double slope() {return (endPoint1.getY() - endPoint2.getY()) / (double)(endPoint2.getX() - endPoint1.getX());}
    
    	public static Line read(Scanner scanner) {
    		Point p1 = Point.read(scanner);
    		if (p1 == null) return null;
    		Point p2 = Point.read(scanner);
    		return new Line(p1, p2);
    	}
    
    	public String toString() {return endPoint1 + " - " + endPoint2;}
    
    	private Point endPoint1, endPoint2;
    }
    

    Notes

    public class Point {
    
    	…
    
    	public int getX() {return x;}
    	public int getY() {return y;}
    
    	…
    
    	private int x, y;
    }
    

    import java.io.*;
    import java.util.*;
    
    public class LineApp {
    	public static void main(String [] args) throws Exception {
    		Scanner scanner = new Scanner(new File("lines.data"));
    
    		while (scanner.hasNextInt()) {
    			int 
    				x1 = scanner.nextInt(),
    				y1 = scanner.nextInt(),
    				x2 = scanner.nextInt(),
    				y2 = scanner.nextInt();
    			doIt(x1, y1, x2, y2);
    		}
    		
    		Random r = new Random(12345);
    
    		System.out.println();
    		System.out.println(" --- Some random points between 0 and 9");
    		System.out.println();
    
    		for (int i = 1; i <= 20; i++) {
    			int 
    				x1 = r.nextInt(19)-9,
    				y1 = r.nextInt(19)-9,
    				x2 = r.nextInt(19)-9,
    				y2 = r.nextInt(19)-9;
    			doIt(x1, y1, x2, y2);
    		}
    	}
    
    	public static void doIt(int x1, int y1, int x2, int y2) throws Exception {
    		System.out.println(x1 + ", " + y1 + ", " + x2 + ", " + y2);
    
    		Point p1 = new Point(x1, y1);
    		Point p2 = new Point(x2, y2);
    		Line line = new Line(p1, p2);
    
    		System.out.println("p1: " + p1 + " p2: " + p2);
    		System.out.println("line: " + line);
    
    		printQuadrantInfo(p1);
    		printQuadrantInfo(p2);
    
    		System.out.println("The length of the line is: " + line.length());
    		if (line.isVertical())
    			System.out.println("Vertical line, no slope");
    		else
    			System.out.println("The slope of the line is: " + line.slope());
    		System.out.println();
    	}
    
    	public static void printQuadrantInfo(Point p) {
    		System.out.println(p + " Quadrant: " + p.quadrantStr() + " (" + p.quadrant() + ")");
    	}
    }
    

    Notes
    • We create the Line object in doIt usinf the two-argument (endpoints) constructor. We could have done it using the four-argument (x/y/ values) constructor:
      Line line = new Line(x1, y1, x2, y2);
      		
      • Notice, however, that doing so does not provide us with variables p1 and p2 for the endpoints.
      • The only reason our app is able to print out quadrant info or even just the poins is because it created the Point objects. Had we used the four-arg constructor (where the x/y values are passed), we would not have access to the Point objects (created in that Line constructor.

    Line Pairs(Line Pair)

    Model a pair of lines in 2-dimensional space (i.e., the 2D plane). A pair of lines line is represented as four pair of values (i.e., two lines of two endpoints)

    We will support the methods:

    • isParallel
    • isPerpendicular

    public class LinePair {
    	LinePair(Line l1, Line l2) {
    		line1 = l1;
    		line2 = l2;
    	}
    
    	public boolean isParallel() {return line1.slope() == line2.slope();}
    	public boolean isPerpendicular() {return line1.slope() == -1/line2.slope();}
    
    	public static LinePair read(Scanner scanner) {
    		Line line1 = Line.read(scanner);
    		if (line1 == null) return null;
    		Line line2 = Line.read(scanner);
    		return new LinePair(line1, line2);
    	}
    
    	public String toString() {return "line1: " + line1 + "/" + "line2: " + line2;}
    
    	Line line1, line2;
    }
    

    Notes
    • There really is no other intuitive constructor; there would be no reason to create a LinePair from anything other than two Lines (i.e, on would not create a pair of lines by supplying the four endpoints or the eight x/y values)
    • The read method is completely analogous to that of Line. Note 'handing off' at each level to the next level down … this is another form of 'chaining', 'delegation', or 'leveraging'.

    import java.io.*;
    import java.util.*;
    
    public class LinePairApp {
    	public static void main(String [] args) throws Exception {
    		Scanner scanner = new Scanner(new File("line_pairs.data"));
    
    		while (scanner.hasNextInt()) {
    			int 
    				x11 = scanner.nextInt(),
    				y11 = scanner.nextInt(),
    				x12 = scanner.nextInt(),
    				y12 = scanner.nextInt(),
    		
    				x21 = scanner.nextInt(),
    				y21 = scanner.nextInt(),
    				x22 = scanner.nextInt(),
    				y22 = scanner.nextInt();
    			doIt(x11, y11, x12, y12, x21, y21, x22, y22);
    		}
    	}
    	
    	public static void doIt(int x11, int y11, int x12, int y12, int x21, int y21, int x22, int y22) throws Exception {
    		System.out.println("x11: " + x11 + " y11: " + y11 + " x12: " + x12 + " y12: " + y12 + " / " + 
    						" x21: " + x21 + " y21: " + y21 +  "x22: " + x22 + " y22: " + y22);
    
    		Point p1 = new Point(x11, y11);
    		Point p2 = new Point(x12, y12);
    		Line line1 = new Line(p1, p2);
    		Point p3 = new Point(x21, y21);
    		Point p4 = new Point(x22, y22);
    		Line line2 = new Line(p2, p2);
    		LinePair linePair = new LinePair(line1, line2);
    
    		System.out.println("linr pair: " + linePair);
    
    		printQuadrantInfo(p1);
    		printQuadrantInfo(p2);
    		printQuadrantInfo(p3);
    		printQuadrantInfo(p4);
    
    		System.out.println("The length of the first line is: " + line1.length());
    		System.out.println("The length of the second line is: " + line2.length());
    		double m1 = line1.slope();
    		double m2 =  line2.slope();
    		System.out.println("The slope of the first line is: " + m1);
    		System.out.println("The slope of the second line is: " + m2);
    
    		if (linePair.isParallel()) System.out.println("The two lines are parallel");
    		else if (linePair.isPerpendicular()) System.out.println("The two lines are perpendicular");
    		System.out.println();
    	}
    
    	public static void printQuadrantInfo(Point p) {
    		System.out.println(p + ") Quadrant: " + p.quadrantStr() + " (" + p.quadrant() + ")");
    	}
    }
    

    Notes
    • Not much to say … basically same as LineApp
    import java.io.*;
    import java.util.*;
    
    public class LinePair {
    	public static void main(String [] args) throws Exception {
    		Scanner scanner = new Scanner(new File("line_pairs.data"));
    
    		while (scanner.hasNextInt()) {
    			int 
    				x11 = scanner.nextInt(),
    				y11 = scanner.nextInt(),
    				x12 = scanner.nextInt(),
    				y12 = scanner.nextInt(),
    		
    				x21 = scanner.nextInt(),
    				y21 = scanner.nextInt(),
    				x22 = scanner.nextInt(),
    				y22 = scanner.nextInt();
    			doIt(x11, y11, x12, y12, x21, y21, x22, y22);
    		}
    	}
    	
    	public static void doIt(int x11, int y11, int x12, int y12, int x21, int y21, int x22, int y22) throws Exception {
    		System.out.println("(" + x11 + ", " + y11 + ") - (" + x12 + ", " + y12 + ")" + " / " + 
    						"(" + x21 + ", " + y21 + ") - (" + x22 + ", " + y22 + ")");
    
    		printQuadrantInfo(x11, y11);
    		printQuadrantInfo(x12, y12);
    		printQuadrantInfo(x21, y21);
    		printQuadrantInfo(x22, y22);
    
    		System.out.println("The length of the first line is: " + length(x11, y11, x12, y12));
    		System.out.println("The length of the second line is: " + length(x21, y21, x22, y22));
    		double m1 = slope(x11, y11, x12, y12);
    		double m2 =  slope(x21, y21, x22, y22);
    		System.out.println("The slope of the first line is: " + m1);
    		System.out.println("The slope of the second line is: " + m2);
    		if (isParallel(x11, y11, x12, y12, x21, y21, x22, y22)) System.out.println("The two lines are parallel");
    		else if (isPerpendicular(x11, y11, x12, y12, x21, y21, x22, y22)) System.out.println("The two lines are perpendicular");
    		System.out.println();
    	}
    
    	public static void printQuadrantInfo(int x, int y) {
    		System.out.println("(" + x + ", " + y + ") Quadrant: " + quadrantStr(x, y) + " (" + quadrant(x, y) + ")");
    	}
    
    	public static String quadrantStr(int x, int y) {
    		switch (quadrant(x, y)) {
    			case 0: return "Origin";
    			case 1: return "Quadrant 1"; 
    			case 2: return "Quadrant 2";
    			case 3: return "Quadrant 3"; 
    			case 4: return "Quadrant 4"; 
    			case 5: return "Positive x axis"; 
    			case 6: return "Positive y axis"; 
    			case 7: return "Negative x axis"; 
    			case 8: return "Negative y axis"; 
    			default: return "???";
    		}
    	}
    			
    	public static int quadrant(int x, int y) {
    		if (x == 0 && y == 0) return 0;
    		if (x > 0 && y > 0) return 1;
    		if (x < 0 && y > 0) return 2;
    		if (x < 0 && y < 0) return 3;
    		if (x > 0 && y < 0) return 4;
    		if (x > 0 && y == 0) return 5;
    		if (x == 0 && y > 0) return 6;
    		if (x < 0 && y == 0) return 7;
    		if (x == 0 && y < 0) return 8;
    		return -1;
    	}
    
    
    	public static double length(int x1, int y1, int x2, int y2) {return Math.sqrt((Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2)));}
    	public static double slope(int x1, int y1, int x2, int y2) {return (y2 - y1) / (x2 - x1);}
    	public static boolean isParallel(int x11, int y11, int x12, int y12, int x21, int y21, int x22, int y22) {return slope(x11, y11, x12, y12) == slope(x21, y21, x22, y22);}
    	public static boolean isPerpendicular(int x11, int y11, int x12, int y12, int x21, int y21, int x22, int y22) {return slope(x11, y11, x12, y12) == -1/slope(x21, y21, x22, y22);}
    }
    
    -->

    Modelling Many Thing with Many Elements: Phonebook (Phonebook)

    Given the file, "phonebook.text" containing phone entries in the format last-name phone-number, write an application that allows the user to look up a phone number via the last name. You can assume no two entries have the same last name.

    An Overview

    This example goes a step further than the previous ones in that there are two 'multiple's here: the multiple attributes of the entries of the phone book (name and number), and multiple entries forming the phonebook. What follows is a standard way of structuring and implementing such a situation. The will be three classes:

    PhonebookEntry

    class PhonebookEntry {
    	PhonebookEntry(String name, String number) {
    		this.name = name;
    		this.number = number;
    	}
    
    	String getName() {return name;}
    	String getNumber() {return number;}
    
    	public String toString() {return name + ": " + number;}
    
    	public static PhonebookEntry read(Scanner scanner) {
    		if (!scanner.hasNext()) return null;
    		String name = scanner.next();
    		String number = scanner.next();
    		return new PhonebookEntry(name, number);
    	}
    
    	String name;
    	String number;
    }
    

    Notes

    Phonebook

    import java.io.*;
    import java.util.*;
    
    public class Phonebook {
    	public static Phonebook read(Scanner scanner)  {
    		Phonebook phonebook = new Phonebook();
    		PhonebookEntry entry = PhonebookEntry.read(scanner);
    		while (entry != null) {
    			phonebook.add(entry);
    			entry = PhonebookEntry.read(scanner);
    		}
    		return phonebook;
    	}
    
    	public void add(PhonebookEntry entry) {
    		if (size == CAPACITY) {
    			System.out.println("Phonebook capacity exceeded - increase size of underlying array");
    			System.exit(1);
    		}
    		entries[size] = entry;
    		size++;
    	}
    
    	public String lookup(String name) {
    		for (int i = 0; i < size; i++)
    			if (entries[i].getName().equals(name)) return entries[i].getNumber();
    		return null;
    	}
    
    	public String toString() {
    		String result = "{";
    		for (int i = 0; i < size; i++)
    			result += entries[i].getName() + ":" + entries[i].getNumber() + (i < size-1 ? ", " : "");
    		result += "}";
    		return result;
    	}
    
    	private static final int CAPACITY = 100;
    	private PhonebookEntry [] entries = new PhonebookEntry[CAPACITY];
    	private int size = 0;
    }
    
    
    
    

    Notes

    PhonebookEntry

    import java.io.*;
    import java.util.*;
    
    public class PhonebookApp {
    	public static void main(String [] args) throws Exception {
    		final String FILENAME = "phonebook.text";
    
    		Scanner scanner = new Scanner(new File(FILENAME));
    
    		Phonebook phonebook = Phonebook.read(scanner);
    
    		System.out.println(phonebook);
    		System.out.println();
    
    		Scanner keyboard = new Scanner(System.in);
    
    		System.out.print("name? ");
    		while (keyboard.hasNext()) {
    			String name = keyboard.next();
    			String number = phonebook.lookup(name);
    			if (number != null) 
    				System.out.println(name + ": " + number);
    			else
    				System.out.println(name + ": *** not found");
    			System.out.print("name? ");
    		}
    	}
    }
    

    Notes

    Sample Test Run

    For example if the file phonebook.text cntains:

    Arnow       123-456-7890
    Harrow      234-567-8901
    Jones       345-678-9012
    Augenstein  456-789-0123
    Sokol       567-890-1234
    Tenenbaum   678-901-2345
    Weiss       789-012-3456
    Cox         890-123-4567
    Langsam     901-234-5678
    Thurm       012-345-6789
    

    Here is a sample execution of the program.
    User input is in bold. Your program should replicate the prompts and output:

    {Arnow:123-456-7890, Harrow:234-567-8901, Jones:345-678-9012, Augenstein:456-789-0123, Sokol:567-890-1234, Tenenbaum:678-901-2345, Weiss:789-012-3456, Cox:890-123-4567, Langsam:901-234-5678, Thurm:012-345-6789}

    name? Weiss
    Weiss: 789-012-3456
    name? Arnow
    Arnow: 123-456-7890
    name? Washington
    Washington: *** not found
    name? Jones
    Jones: 345-678-9012
    name? Thrum
    Thrum: *** not found
    name? Thurm
    Thurm: 012-345-6789
    name?
    Notes

    Returning to Our BankAccounts App

    import java.io.File;
    import java.util.Scanner;
    
    class BankAccountsApp {
    	public static void main(String [] args) throws Exception {
    		Scanner scanner = new Scanner(new File("bank_actions.text"));
    
    		final int CAPACITY = 100;
    		BankAccount [] accounts = new BankAccount[CAPACITY];
    		int size = 0;
    
    		while (scanner.hasNextInt()) {
    			int id = scanner.nextInt();
    			String action = scanner.next();
    			int amount;
    
    			BankAccount account = find(accounts, size, id);
    			if (account == null) {
    				account = new BankAccount();
    				account.setId(id);
    				size = add(accounts, size, account, CAPACITY);
    				System.out.println("Added account " + account.getId() + " with balance of " + account.getBalance());
    			}
    
    			switch (action) {
    				case "D":
    					amount = scanner.nextInt();
    					account.deposit(amount);
    					System.out.println("Balance of account " + account.getId() + " after deposit of $" + amount + ": $" + account.getBalance());
    					break;
    				case "W":
    					amount = scanner.nextInt();
    					account.withdraw(amount);
    					System.out.println("Balance of account " + account.getId() + " after withdrawal of $" + amount + ": $" + account.getBalance());
    					break;
    				default:
    					System.out.println("*** Error *** unknown action: " + action);
    			}
    		}
    		System.out.println();
    		print(accounts, size);
    	}	
    
    	public static BankAccount find(BankAccount [] accounts, int size, int id) {
    		for (int i = 0; i < size; i++) 
    			if (accounts[i].getId() == id) return accounts[i];
    		return null;
    	}
    
    	public static int add(BankAccount [] accounts, int size, BankAccount account, int capacity) {
    		if (size == capacity) {
    			System.err.println("Capacity reached; make arrays larger");
    			System.exit(1);
    		}
    		accounts[size] = account;
    		return size+1;
    	}
    		
    	public static void print(BankAccount [] accounts, int size) {
    		for (int i = 0; i < size; i++)
    			System.out.println(accounts[i].getId() + ": $" + accounts[i].getBalance());
    	}
    
    }
    

    Notes

    Arrays of Objects

    As mentioned above, a class definition introduces a new type into the system, whose name is that of the class. Just as we would with any other type, we may have occasion to declare an array of instances of a class.

    Declaring an Array of Objects

    Creating an Array of Objects

    Analogous to creating an object of a class, creating an array object involves the new operator:

    String [] stringArr = new String[20];	// Creates an array of 20 String references and assign the 
    								//	reference to the array object to stringArr
    Name [] nameArr = new Name[100];		// Creates an array of 100 Name references and assigns the 
    								//	reference to the array object to nameArr
    

    Populating the Array with Instances of the Class

    Once the array reference has been assigned a reference to an array object, the elements (which are only reference locations) of the array can be populated by creating instances of the class and assigning their references to the elements of the array:

    final int CAPACITY = 100;
    Name [] names = new Name[CAPACITY];
    
    names[0] = new Name("Gerald", "Weiss");
    names[1] = new Name("David", "Arnow");
    names[2] = new Name("Yedidyah", "Langsam");
    …
    

    or more typically, the contents of the array would be read in from a file using a read method, which reads the data from the file, creates the object (which is initialized via the constructor being passed the data), and returns its reference:

    final int CAPACITY = 100;
    Name [] names = new Name[CAPACITY];
    int size = 0;
    
    Scanner scanner = new Scanner(new File("names.text"));
    
    Name name = Name.read(scanner);		
    while (name != null) {
    	if (size >= CAPACITY) {
    		System.out.println("Too many names in file -- increase the size of your array");
    		System.exit(1);
    	}
    	names[size++] = name;
    	name = Name.read(scanner);		
    }
    

    Working With Arrays

    Once the array has been populated, you use it as you would any other array:
    void print(Name [] names, int size) {
    	for (int i = 0; i < size, i++)
    		System.out.println(names[i] + (i < size-1 ? ", " : ""));
    }
    
    boolean contains(Name [] names, int size, Name name) {
    	for (int i = 0; i < size, i++)
    		if (names[i].equals(name)) return true;
    	return false;
    }
    

    Arrays as Instance Variables (Arrays in Objects)

    We've seen that a class can be used as the element type of an array. We can also have an array be an instance variable of an object.
    class FootballTeam {
    	…
    	private Player [] offensiveSquad = new Player[11];
    	private Player [] defensiveSquad = new Player[11];
    	private Player [] specialSquad = new Player[3];
    }
    

    class Arr {
    	…
    	private int [] arr = new int[100];
    	private int size = 0;
    }
    

    BankAccounts Once Again

    The BankAccounts Class

    import java.io.File;
    import java.util.Scanner;
    
    class BankAccounts {
    	public BankAccount find(int id) {
    		for (int i = 0; i < size; i++) 
    			if (accounts[i].getId() == id) return accounts[i];
    		return null;
    	}
    
    	public void add(BankAccount account) {
    		if (size == CAPACITY) {
    			System.err.println("Capacity reached; make arrays larger");
    			System.exit(1);
    		}
    		accounts[size] = account;
    		size++;
    	}
    		
    	public void print(int [] ids, int [] balances, int size) {
    		for (int i = 0; i < size; i++)
    			System.out.println(ids[i] + ": $" + balances[i]);
    	}
    
    	private static final int CAPACITY = 100;
    	private BankAccount [] accounts = new BankAccount[CAPACITY];
    	private int size = 0;
    }
    

    Notes

    The App

    import java.io.File;
    import java.util.Scanner;
    
    class BankAccountsApp {
    	public static void main(String [] args) throws Exception {
    		Scanner scanner = new Scanner(new File("bank_actions.text"));
    
    		BankAccounts accounts = new BankAccounts();
    
    		while (scanner.hasNextInt()) {
    			int id = scanner.nextInt();
    			String action = scanner.next();
    			int amount;
    
    			BankAccount account = accounts.find(id);
    			if (account == null) {
    				account = new BankAccount();
    				account.setId(id);
    				accounts.add(account);
    				System.out.println("Added account " + account.getBalance() + " with balance of " + account.getBalance());
    			}
    
    			switch (action) {
    				case "D":
    					amount = scanner.nextInt();
    					account.deposit(amount);
    					System.out.println("Balance of account " + account.getId() + " after deposit of $" + amount + ": $" + account.getBalance());
    					break;
    				case "W":
    					amount = scanner.nextInt();
    					account.withdraw(amount);
    					System.out.println("Balance of account " + account.getId() + " after withdrawal of $" + amount + ": $" + account.getBalance());
    					break;
    				default:
    					System.out.println("*** Error *** unknown action: " + action);
    			}
    		}
    	}	
    }
    

    Notes

    An Array Class

    We'll now present a more 'complete' class that operates like an array. Create a class that encapsulates (contains as private data and thus protects) the data needed to maintain an array: This is our first example of a container or collection class.

    We lose some things by moving from an array to a class:

    We gain quite a bit, though

    Modelling Things with Several (Logically-Related) Elements: A Container (02-Container)

    Write an app that reads values from a file and places them into a container, i.e., a data entity that contains other items of data. The methods to be provided are:

    class Container {
    	public int add(int value) {
    		values[size] = value;
    		size++;
    		return size;
    	}
    
    	public int size() {return size;}
    
    	public boolean isEmpty() {return size() == 0;}
    
    	public int find(int value) {
    		for (int i = 0; i < size; i++)
    			if (values[i] == value) return i;
    		return -1;
    	}
    
    	public int get(int index) {return values[index];}
    
    	public String toString() {
    		String result = "{";
    		for (int i = 0; i < size; i++)
    			result += values[i] + (i < size-1 ? ", " : "");
    		return result + "}";
    	}
    	
    	private static final int CAPACITY = 100;
    	private int [] values = new int[CAPACITY];
    	private int size = 0;
    }
    
    Notes

    Summary

    Notes

    import java.io.File;
    import java.util.Scanner;
    
    class ContainerApp {
    	public static void main(String [] args) throws Exception {
    		Scanner scanner = new Scanner(new File("container_actions.text"));
    
    		Container container = new Container();
    
    		while (scanner.hasNext()) {
    			String action = scanner.next();
    			int value;
    			int index;
    
    			switch (action) {
    				case "A":
    					value = scanner.nextInt();
    					container.add(value); 
    					System.out.print("After adding " + value + ": " + container);
    					break;
    
    				case "F":
    					value = scanner.nextInt();
    					int pos = container.find(value);
    					if (pos >= 0) 
    						System.out.println(value + " is at position " + pos + " of the container");
    					else
    						System.out.println(value + " is not in the container");
    					break;
    
    				case "G":
    					index = scanner.nextInt();
    					value = container.get(index);
    					System.out.println("The value at location " + index + " is " + value);
    					break;
    
    				default:
    					System.out.println("*** Error *** unknown action: " + action);
    			}
    		}
    	}	
    }
    

    Basic Class Design

    A Taxonomy of Classes

    Inner Classes

    class Phonebook {
    	static class PhonebookEntry {
    		…
    	}
    	…
    }
    

    Mutable vs Immutable Classes

    Some classes are deliberately designed so that their objects — once initialized — cannot be modified

    Immutable Classes

    class ImmutableColor {
    	public ImmutableColor(int r, int g, int b) {
    		this.r = r;
    		this.g = g;
    		this.b = b;
    	}
    	…
    	public ImmutableColor lighter() {
    		if (r < 255 && g < 255 && b < 255) 
    			return new ImmutableColor(r+1, g+1, b+1)
    		else
    			return null;	
    	}
    
    	private final int r, g, b;
    }
    
    Notes

    Mutable Classes

    class MutableColor {
    	public MutableColor(int r, int g, int b) {
    		this.r = r;
    		this.g = g;
    		this.b = b;
    	}
    	…
    	public MutableColor makeLighter() {
    		if (r < 255 && g < 255 && b < 255)  {
    			r++;
    			g++;
    			b++
    			return this;
    		}
    		else
    			return null;	
    	}
    
    	private int r, g, b;
    }
    
    Notes

    Criteria for Mutability/Immutability

    <>Files Used in This Lecture