static — Class MembersPoint.ORIGIN
static final`
Color.RED, Color.BLACK for a Color class
The keyword static specifies that the declared variable is a class variable i.e., a single copy exists for the
entire class.
ORIGIN
public is done by qualifying it with the class' name; e.g. Point.ORIGIN
this inside the class and a receiver outside the class, but as this is confusing (it makes it look as if it might be an instance variable)
this is discouraged
Color class' predefined color constants
static final Color BLACK = new Color(0, 0, 0);
Calendar class' month names
static final int 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;
}
class C {
C() {
…
instancesCreated++;
}
…
static int instancesCreated = 0;
}
instancesCreated belongs to the class, not to any one object.
static to indicate them as such
Math class' abs method
read method for a class-- reads data, and uses it to call new,
invoking constructor with the data.
static Point read(Scanner scanner) {
int x = scanner.nextInt();
int y = scanner.nextInt();
return new Point(x, y);
}
The whole point of this method is to read in the data necessary to create a Point object,
create the object, and return its reference
Point — again, as part of responsibility-driven programming
static int getInstancesCreated() {return instancesCreated;}
class C {
void f1() {
int i; // local scope
…
System.out.println(i);
…
}
void f2(int i) { // local scope (parameter)
…
System.out.println(i);
…
}
void f3() {
…
System.out.println(i);
…
}
int i; // class scope
}
{}'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;
}
private
main) that don't even have their own instance variables:
class C {
C(int val) {this.val = val;}
…
C add(C otherC) {
return new C(this.val + otherC.val); // 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.
}
}
main out to its own app class:
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 22
}
}
int where the type specifies the legal values
(the integers) and their operations (+, -, *, /, %).
main and Applicationsmain method, even if it is not intended to be launched as an application
main can be used as a 'demo' method, i.e., it can illustrate how the clas
is used, e.g.,
public static void main(String [] args) {
Counter c = new Counter();
for (int i = 1; i <= 10; i++)
c.up();
System.out.println(c);
while (c.getVal()) != 0) // assuming a getter has been defined
c.down();
System.out.println(c);
}
class Counter {
…
public statuc void main(String [] args) {…}
}
we usually place outside in its own class:
class CounterApp {
…
public statuc void main(String [] args) {…}
}
main from accessing private instance variables of the case (as mentioned above)
static for the first time in a context we can explain.
read Methodstatic method — we'll call it read
read accepts a Scanner and returns an object of the class for which we are writing
this method
null value
null represent the absence of an object reference
null:
Counter c; … if (c == null) …
null as the receiver throws a NullPointerException
null
BankAccount object:
class BankAccount {
…
static BankAccount read(Scanner scanner) {
if (!scanner.hasNextInt()) return null;
int id = scanner.nextInt();
int balance = scanner.nextInt();
return new BankAccount(id, balance);
}
…
private int id;
private int balance;
}
read method creates and object from input, upon entry to the method, no such object yet exists.
static
Scanner is an int (for the id)
null is returned
read MethodBankAccount bankAccount = BankAccount.read(scanner); while (bankAccount != null) { System.out.println(ba); bankAccount = BankAccount.read(scanner);
while loop until a null is returned
null valuenull in Java is a literal representing the absence of a reference
BankAccount ba = null;
null may be assigned to a reference variable of any type (i.e., any class or array type).
null results in a NullPointerException being thrown.
BankAccount ba = null;
ba.deposit(100); // results in NullPointerException
null in the absence of any explicit initialization:
class SomeClass {
…
private String s; // s is initialized to null
null if the object does not appear inthe array.
BankAccounts AppBankAccount class with id and balance instance variables, and the (by now) usual toString and read methods, code an app
that reads in and processes multiple bank accounts:
class BankAccount {
BankAccount(int id) {this.id = id;}
public void deposit(int amount) {balance += amount;}
public void withdraw(int amount) {balance -= amount;}
public int getBalance() {return balance;}
public int getId() {return id;}
public String toString() {return "account #"+ id + " balance: $" + balance;}
private int balance = 0;
private int id;
}
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 = scanner.nextInt();
BankAccount account = search(accounts, size, id);
if (account == null) {
account = new BankAccount(id);
size = add(accounts, size, account, CAPACITY);
System.out.println("Added " + account);
}
switch (action) {
case "D":
account.deposit(amount);
System.out.println("After deposit of $" + amount + ": " + account);
break;
case "W":
account.withdraw(amount);
System.out.println("After withdrawal of $" + amount + ": " + account);
break;
default:
System.out.println("*** Error *** unknown action: " + action);
}
}
System.out.println();
System.out.println("=== Accounts ===");
print(accounts, size);
}
public static BankAccount search(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());
}
}
getBalance method.
getId
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 BankAccounts.
add returns the position where the new account was inserted, and that is then used as the new value of size
size are local to the app's main method.
add method does indeed insert accounts sequentially, that is not
an absolute necessesity, and if the insertion occurred in a different manner, this would not work
BankAccounts is not an object class … it has not instance variables; rather it's an application class. Further, the main logic is in main. The code is
structured much like that in 1115, and thus the methods are static, i.e., the main focus with regard to the array of bank accounts are on the procedures rather than objects.
1001 D 200 1030 D 100 1030 W 50 1001 W 70
Added account #1001 balance: $0 After deposit of $200: account #1001 balance: $200 Added account #1030 balance: $0 After deposit of $100: account #1030 balance: $100 After withdrawal of $50: account #1030 balance: $50 After withdrawal of $70: account #1001 balance: $130 === Accounts === 1001: $130 1030: $50
int [] intArr; String [] stringArr; Name [] nameArr; PhonebookEntry [] entries;
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 tostringArrName [] 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;
}
BankAccountsApp to a BankAccounts ClassBankAccounts Class
import java.io.File;
import java.util.Scanner;
class BankAccounts {
public BankAccount search(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 String toString() {
String result = "";
for (int i = 0; i < size; i++)
result += accounts[i] + "\n";
return result;
}
private static final int CAPACITY = 100;
private BankAccount [] accounts = new BankAccount[CAPACITY];
private int size = 0;
}
search and add
have much simpler signatures now that they have a receiving object (the BankAccounts object).
static in the declaration of CAPACITY
print of the previous app can now be turned into a toString
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 = scanner.nextInt();
BankAccount account = accounts.find(id);
if (account == null) {
account = new BankAccount();
account.setId(id);
accounts.add(account);
System.out.println("Added " + account);
}
switch (action) {
case "D":
account.deposit(amount);
System.out.println("After deposit of $" + amount + ": " + account);
break;
case "W":
account.withdraw(amount);
System.out.println("After withdrawal of $" + amount + ": " + account);
break;
default:
System.out.println("*** Error *** unknown action: " + action);
}
}
}
}
accounts variable is now BankAccounts ref variable; in the
previews implementation it was an array ref variable.
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 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.
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 class
Phonebook class and then come back and add them (remember, true class design
is an iterative process)
read method … it follows the logic outlined above
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
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 PhonebookeEntry objects by delegating that task to the PhonebookEntry class THe task of this
read method is to then add the entry to the phonebook via the add method..
add method performs the insertion of the entry into the array instance variable (we call it the underlying array or container)
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
PhonebookApp
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
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.
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();