The classpath specifies where to look for class
files. Can be specified for execution (java).
A package is a way to qualify the name of a class or
group of classes. It also imposes a condition on where the
.java and .class files for the class can be. A package name is
typically a directory path with all the "/" (or "\") directory
separators replaced by "." The fully qualified class name
includes the package name, another ".", and then the class name.
A package statement at the beginning of a .java file
declares the class to be in the named package. If there is no
package statement, the class is in the default package
which has no name.
Specifying the classpath[2] [top]
The classpath can be specified by setting the environment
variable CLASSPATH.
The -classpath (or -cp) option for the java and javac
tools can also specify the classpath. The classpath
specified in this way takes precedence over the CLASSPATH
setting.
The command to use is javac:
javac argument
But the argument to use depends on the current
working directory. It must specify the java
file.
The working directory can be any directory as long as you
specify the location of the java file.
If the BankAccount.java is in
c:\user\csc224\bankproj\src\bank
and the current directory is c:\user\csc224, the command
javac bankproj/src/bank/BankAccount.java
will generate the BankAccount.class file in the same directory
as BankAccount.java.
To override this default location and place the BankAccount.class in
the bin directory:
c:\user\csc224\bankproj\bin\bank
use the javac option -d
javac -d bankproj/bin bankproj/src/bank/BankAccount.java
Note:
- The bankproj\bin directory must already exist; it will
not be created by javac.
- On the other hand, javac will create (if necessary) the
package subdirectory bank of bankproj\bin and place the
BankAccount.class file in that directory.
The java program (i.e., the java virtual machine) expects its
argument to be a fully qualified class name.
java options fully_qualified_class_name
If the class is not in a package (i.e., no package statement),
the fully qualified name is just the class name.
If the
class is in a package, the fully qualified name includes
the package and the class name.
So in the example, the
fully qualified name is
bank.Bank
Note that unlike the
argument to the javac command, the argument to java
is not the relative or absolute path to the .class
file!
1. Inheritance can be viewed as a technique for creating a new class from
an existing class.
2. Classes define "types". If B is a new class created by
inheritance from an existing class A, the informally:
- "type" B is a kind of A
- B is a subtype of A
public class BankAccount
{
private double balance;
public BankAccount()
{
balance = 0.0;
}
public BankAccount(double initialAmount) {
balance = initialAmount;
}
public void deposit(double amount)
{
balance += amount;
}
public double getBalance()
{
return balance;
}
public void withdraw(double amount) {
if (balance >= amount) {
balance -= amount;
} else {
throw new IllegalArgumentException("Insufficent funds");
}
}
public String toString()
{
return String.format("BankAccount(balance = %.2f)", balance);
}
}
public class SavingsAccount extends BankAccount
{
private double interestRate;
public SavingsAccount(double amount, double rate)
{
super(amount);
interestRate = rate;
}
public void postInterest()
{
double balance = getBalance();
double interest = balance * interestRate/100;
deposit(interest);
}
public double getRate()
{
return interestRate;
}
void setRate(double newRate)
{
interestRate = newRate;
}
public String toString()
{
return String.format("Savings Account(balance = %.2f, rate = %.3f)",
getBalance(), interestRate);
}
}
public class BankApp
{
public static void main(String[] args)
{
BankAccount b1 = new BankAccount(1000);
BankAccount b2 = new BankAccount(20000);
SavingsAccount s1 = new SavingsAccount(500, 2.5);
b1.deposit(100);
b2.deposit(1000);
s1.postInterest();
s1.deposit(100);
System.out.println(b1);
System.out.println(b2);
System.out.println(s1);
}
Sample run:
java BankApp
BankAccount(balance = 1100.00)
BankAccount(balance = 21000.00)
Savings Account(balance = 612.50, rate = 2.500)
}
A SavingsAccount is a kind of BankAccount. It has a balance,
etc.
public class BankApp2
{
public static void printAccounts(BankAccount[] acct)
{
for(int i = 0; i < acct.length; i++) {
System.out.println(acct[i]);
}
}
public static void main(String[] args)
{
BankAccount[] b = new BankAccount[3];
BankAccount b1 = new BankAccount(1000);
BankAccount b2 = new BankAccount(20000);
SavingsAccount s1 = new SavingsAccount(500, 2.5);
b[0] = b1;
b[1] = b2;
b[2] = s1;
System.out.println("Original Balances:");
printAccounts(b);
// Make deposits:
for(int i = 0; i < b.length; i++) {
b[i].deposit(100);
}
System.out.println("\nNew Balances:");
printAccounts(b);
}
}
Sample run:
java BankApp2
Original Balances:
BankAccount(balance = 1000.00)
BankAccount(balance = 20000.00)
Savings Account(balance = 500.00, rate = 2.500)
New Balances:
BankAccount(balance = 1100.00)
BankAccount(balance = 20100.00)
Savings Account(balance = 600.00, rate = 2.500)
Suppose we wish to add a half point to the interest rate for b[2].
We can't write
BankAccount[] b = new BankAccount[3];
double newRate = b[2].getRate() + 0.5;
b[2].setRate( newRate);
We get errors at both b[2].getRate() and b[2].setRate because the
declared type of b[2] is BankAccount, not SavingsAccount.
Any SavingsAccount is a kind of BankAccount
but
A BankAccount is not necessarily a SavingsAccount.
We can try a cast:
((SavingsAccount) b[2]).getRate()
This is called a "downcast" because SavingsAccount is a
subclass of BankAccount and we are casting the type to a subtype.
BankAccount
|
|
SavingsAccount
The cast above works, but this one will not:
((SavingsAccount) b[1]).getRate()
because at runtime, b[1] is not a SavingsAccount, it is only a
BankAccount. An exception is thrown:
ClassCastException
BankAccount a;
What type can be assigned to a?
Answer(s): BankAccount and SavingsAccount
E.g., both of these are allowed:
a = new BankAccount(50000); // right sides is the same type
or
a = new SavingsAccount(3000, 2.75); // right side is a subtype
We say that BankAccount is a polymorphic type because at run
time it can hold references of different types (at different times).
With polymorphic types, you might expect to want to check the runtime
type:
Here is a new version of the printAccounts function:
public static void printAccounts2(BankAccount[] acct)
{
String str = null;
for(int i = 0; i < acct.length; i++) {
if ( acct[i] instanceof SavingsAccount ) {
str = String.format("Savings Account(balance = %.2f, rate = %.3f)",
getBalance(), interestRate);
} else if (acct[i] instanceof BankAccount) {
str = String.format("BankAccount(balance = %.2f)", balance);
}
System.out.println(str);
}
}
Note: This is not as "reusable" as this version:
public static void printAccounts(BankAccount[] acct)
{
String str = null;
for(int i = 0; i < acct.length; i++) {
str = acct[i].toString(); // Which toString()?
System.out.println(str);
}
}
The selection of which toString() at run time is called
dynamic dispatch
dynamic => runtime
dispatch => select which implementation (of toString)
The dynamic dispatch feature of object oriented languages is also
called polymorphism. The reason this is the same idea as use
for polymorphic types is that the same expression can have different
meanings at run time:
BankAccount a;
Expression Meaning
a At run time can reference type BankAccount
or SavingsAccount
a.toString() At run time can use the implementation of
toString() in BankAccount or the one in
SavingsAccount depending on the run time
type of a.
Recall that an Interface looks like a class, but there are no data
members, and no implementations of methods - just the method
prototypes (return type, name, list of argument types).
An Interface still defines a "type", but we cannot directly
create instances of an interface.
Example:
interface Comparable<T>
{
public int compareTo(T other);
}
What does it mean for a class toimplement an
interface?
class X implements Comparable<X>
{
}
It means
a. class X must include the method int compareTo(X other) and with
an implementation.
b. It means that for any variable of type X can be compared to any
other variable of type X.
A class can inherit from exactly one other class.
E.g., SavingsAccount inherits from (extends) BankAccount:
public class SavingsAccount extends BankAccount ...
This form of inheritance means that
1. A SavingsAccount instance has each one of the data members defined
in BankAccount (all data members are "inherited")
2. A SavingsAccount instance inherits all the methods (and their
implementations) defined in BankAccount.
Java Facts:
a. A class can inherit from only one class
b. A class can inherit from multiple interfaces
c. A class can do both a. and b.
E.g.,
public class Y extends X implements I, J
{
}
X and Y are classes
I and J are interfaces
interface Iterator
{
public boolean hasNext();
public Object next();
public void remove();
}
This will be developed in the lecture.