Point
Class(x, y)
>0, >0)
,
<0, >0)
, <0, <0)
, >0, <0)
), 4 axes (>0, 0)
,
0, >0)
, <0, 0)
, 0, <0)
), and the origin ((0, 0)
).
Points
)The class should have the methods:
quadrant
: returns a numeric value between 0 and 8 corresponding to the quadrant or
axis the point lies on
quadrantStr
: returns a String
value corresponding to the quadrant/axis the point lies on
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); }
Point
instance will have its own individual values
for x
and y
; furthermore x
and y
need to be
initialized with these values upon object creation, thus requiring a constructor
new
operation. As such, it has no return type
(it's not called, so doesn't doesn't have anywhere to return a value to), nor is its name a choice of the programmer (since they don't call it).
As such, the name of the constructor is the name of the class; this works out well in the
syntax and semantics of the constructor, as we will see.
Point
class, we need a method that accepts two integers which are then assigned to
x
and y
; given the above naming discussion we have:
Point(int …, int …) { x = …; y = …; }
Point
).
this
see below
a
and b
are parameters to the method and thus
local variables, while x
and y
are instance variables and declared in the class-body.
class Point { Point(int a, int b;) { … } … private int x, y; }
new
expression.
Point p = new Point(12, 14); // create the Point (12, 14)
quadrant
within quadrantStr
. This is an(other) example of
leveraging where we take advantage of logic in another method.
read
method follows the logic as presented in Lecture 1: we check for more data and return null
if there is none; otherwise we read the
values to be passed to the constructor into local variables, create the Point object passing those values, and return the reference to the newly created object.
ORIGIN
. We wish to have a 'well-known' / predefined object for the origin (it IS special after all), so we create
an Point
object corresponding to it and assign its reference to a well-named variable. There's no need for more than one such object, i.e., we don't want to
have a new origin object for each instance, so we declare it static
.
Point
object) all over the place.
Line
and LinePair
classes.
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() + ")"); } }
Point
class with some 'well-known values' (from the file):
Random
objejct's nextInt
call is the range of the random number generated (0 &helliop; argument
);
here, I chose a value that would (in conjunction with the -9
applied to the return value)
produce integers in the range -9 … 9
r.nextInt
random number generating method returns a value between 0 and 18
(the argument minus 1). Substracting 9
gives us a value between -9 and 9.
doIt
method.
Name
class, a Student
class would contain an instance
variable of type Name
. (Similarly if the was an Address
class)
class Name { … } … class Student { … private Name name; private Address address; }
String
class, a Name
class would contain an
instance variable of type String
for the last name (similarly for first name).
class Name { … private String last, first; }
Employee
class, a Department
class might contain an array
of Employee
objects.
Employee
class probably contains a Name
field
class Employee { … Name name; } … class Department { … private Employee [] employees; }
class Patient { … public String toString() { return name + " (" + dateOfBirth + ")"; } public boolean equals(Patient other) { return name.equals(other.name) && dateOfBirth.equals(other.dateOfBirth); } … private Name name; private Date dateOfBirth; }
toString
and equals
null
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 Membersthis
or instance variable (or methods) allowed
static
keyword — the method/variable is static, i.e., it's
not dependent on any particular instance/object of the class.
final
)
Color
class' predefined color constants
static final Color BLACK = new Color(0, 0, 0);
Calendar
class' month names
static final String JANUARY = 1, FEBRUARY = 2. … DECEMBER = 12;
class Employee { Employee(String name) { this.name = name; this.id = nextId; nextId++; } ... ... String name; // instance variable int id; // instance variable - individual Employee's id static int nextId=1001; // class variable - next id to be assigned; }
Math
class' abs
method
Integer
class' parseInt
method
main
method (called from 'nowhere'-- no receiving object)
main
read
method for a class-- reads data, and uses it to call new
,
invoking constructor with the data.
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; }
{}
's.
{}
's (i.e., within the block) are said to be
local to the block.
Name name = new Name("Weiss", "Gerald"); name.getFirst();when the method
getFirst
is entered as a result of the call, the instance variable first
is the one belonging to the receiver, i.e., the object referred to by the variable name
(with the
value "Gerald"
).
class Name { Name(String last, String first) { … } … String last, first; }
this
Name
constructor:
class Name { Name(String last, String first) { … } String last, first; }
Name(String last, String first) {...}
?
Name(String last, String first) { this.last = last; this.first = first; }
this
specifies the receiver and
this this.first
is an explicit (i.e., qualified)
referral to the instance variable of the class (rather than the local parameter of the same name).
private
class C { C(int val) {this.val = val;} … C add f(C otherC) { return new(val + otherC.val C); // Legal and common } … public String toString() {return val;} … private int val; public static void main(String [] args) { … C c1 = new C(10); c1.val = 12; // Legal, but definitely not recommended. } }
class CApp { public static void main(String [] args) { … C c1 = new C(10), c2 = new C(12); //c1.val = 12; // Here (outside the class) it's simply illegal C c3 = c1.add(c2); System.out.println(c3); // prints 23 } }
Counter
classval
containing the value of the counter
up
, that increments the counter's value by 1
down
, that decrements the counter's value by 1
class Counter { void up() {...} void down() {...} int val; }
Window
classwidth
, that will contain the width (in pixels) of the window
height
, that will contain the height (in pixels) of the window
x
, that will contain the horizontal position (in pixels) of the window
y
, that will contain the vertical position (in pixels) of the window
fgcolor
, that will contain the text color of the window (where Color is itself a
class)
bgcolor
, that will contain the background color of the window (where Color is itself a
class)
text
, that will contain the text currently in the window
move
that changes the position of the window
resize
that changes the size of the window
setFgColor
that changes the text color of the window
getFgColor
that returns the text color of the window
setBgColor
that changes the background color of the window
getBgColor
that returns the background color of the window
insert
that will insert text into the window
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; }
03 Points, Lines, Line Pairs
)
Lines
)We will support the methods:
length
: returns the length of a line
isVertical
: returns whether a line is vrtical (infinite slope)
slope
: returns the slope of a line
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; }
line
object wither using a pair
of Point
objects, or by providing the x/y values for the two endpoints
Line line = new Line()
)?
Point
object,
however, they are in accessible being declared private
in that class.
public
but we are willing to provide access to their
values (but not the ability to modify them).
getX
and getY
providing such access.
Point
class and add these two methods (see below)
read
methods follows the usual logic, but here the values for the constructor are themselves objects (Point
s)
rather than primitives, which will be read in using their own read
method. (With primitives we used the Scanner's own
methods for reading in primitives, such as int
- We read in the first
Point
— a return value of null
indicates no more data and we in turn return null
to our caller; otherwise we read in the second Point
(we're assuming if the first Point
is there, so is the second),
create the Line
object, and return it.
getEndPoint1
and getEndPoint2
?
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() + ")"); } }
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.
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 Pair
)We will support the methods:
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;
}
LinePair
from anything other than two Line
s (i.e, on would not
create a pair of lines by supplying the four endpoints or the eight x/y values)
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() + ")"); } }
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);} }-->
Phonebook
)"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.
PhonebookEntry
PhonebookEntry
class that will model the entry, i.e., a name and number
Phonebook
class. This will model the collection of entries and will essentially be a partially-populated
array.
Container
class above. In fact, we COULD make use of that class
but at this stage of our OOP knowledge it would prove to be more of a distraction than anything else
PhonebookApp
class. As with the earlier app classes in this lecture, this app class will illustrate use of the
Phonebook
object.
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; }
toString
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; }
Phonebook() {} // nothing to do
Counter
and Container
fell into this category as well. It wasn't until Point
, which required a per-instance x/y
value that we needed to introduce constructors.
read
method here as we are populating the phonebook and a general rule is to place methods in the class
they operate on (are responsible for).
read
method reads in the values (name and number strings) that will be used to construct an entry in the phone book, creates the
entry object with them, and inserts it into the array.
lookup
method iterates through the array, comparing the name again the name being searched for and if found, returns the corresponding number.
If the number cant be found, it returns the value null
.
null
is the value representing the lack of a reference to an object. It is assigned to a variable that
is currently not referencing anything. It is often used as a 'failure' value for searches in the same sense that -1, i.e.,
representing a non-existent value.
find
and return the position in the array?
toString
method leverages the toString
of the PhonebookEntry
toString
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? "); } } }
toString
of Phonebook
.
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:
BankAccounts
Appimport 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()); } }
BankAccount
.
getBalance
method.
getId
as well as setId
methoda
BankAccounts
(non-class) example, we needed to return the index of the sought-after element since we were dealing with parallel arrays. This
is no longer the case … we wish to return the object being loooked for, i.e., a BankAccount
.
-1
is no longer appropriate for an unsuccessful search; rather we return the special value null
that represents the absence of an object.
null
back from search
, we create a new BankAccount
object and then
add it to the array of BankAccount
s.
int [] intArr; String [] stringArr; Name [] nameArr;
System.out.println(intArr[0]);
results in a NullPointerException
String
)
new
operator:
String [] stringArr = new String[20]; // Creates an array of 20 String references and assign the // reference to the array object tostringArr
Name [] nameArr = new Name[100]; // Creates an array of 100 Name references and assigns the // reference to the array object tonameArr
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); }
read
method is typically defined as a static
method (because no object has been created yet), that
reads the values to be passed to the constructor into local variables, then creates the object (passing those values to the constructor via the new
statement) and returns the reference to the new object as the return value of the method.
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; }
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 AgainBankAccounts
Classimport 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; }
static
in the declaration of CAPACITY
a bit later.
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); } } } }
find
and add
have much simpler signatures now that they have a receiving object (the BankAccounts
object).
accounts
variable is now BankAccounts
ref variable; in the
previews implementation it was an array ref variable.
Array
ClassWe lose some things by moving from an array to a class:
Array
instance.
02-Container
)add
— adds a value to the container
find
— searches the container for a value and returns the location at which the value was found and -1
otherwise
get
— returns the value at a specified position in the container
size
— returns the number of elements in the container
isEmpty
— returns true
if the container has no elements; false
otherwise
toString
— returns a string-representation of the container with surrounding {}
's and commas between the elements
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; }
CAPACITY
) as well as a size
(size
)
add
we must return the new value of size
(because of call-by-value), yet the contents of the values
array does indeed change (the new element is in the array upon returning from the method.
isEmpty
in terms of size
.
get
values
and size
work hand-in-hand to realize the container
values
array and
size
variable of two different containers.
final
) named CAPACITY
,
initialize it to the capacity (physical size) to be used for all array instance variables, and use it exclusively wherever the capacity value is
required
CAPACITY
variable created with every instance we created (they're all going to contain 100
),
so we declare it static
, (lacking change) — which means only one CAPACITY
variable is created and shared
by the entire class (i.e., all instances).
static
), as they operate at the class (rather than instance) level
static
in method headers. There also, static
meant that the method is not tied to any
particular set of instance variables
CAPACITY
to be private
as we have decided that it is nobody's business what the capacity of the array is. Were we to decide differently,
we have a couple of choices:
CAPACITY
public
Container.CAPACITY
private
and introduce a method named getCapacity
(thus an outside caller can obtain the value, but not modify it).
CAPACITY
— a static
variable, it is also declared static
as it does not access or interact with instance variables.
Container.getCapacity()
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); } } } }
class Phonebook { static class PhonebookEntry { … } … }
a + b
, the result of the operation is
a new value
a += b
, the result of the operation is
stored in the left operand
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; }
final
in the declaration of the instance variables. This is because they will not be modified once initialized in the
constructor.
final
variables do not need to be initialized at point of declaration; they can be given their initial (and only) value within
the constructor.
Color
object (rather than modifying the receiver).
null
if the color cannot be made lighter
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; }
makeLighter
) to better reflect the semantics of the method
MutableColor color = new MutableColor(100, 34, 67); System.out.print(color.makelighter().makeLighter().makeMoreTransparent();