CSC 102 Lecture Notes Week 4
Converting between Java Types
Inheritance
Shape s = new Rectangle; // Put a rectangle into a general Shape variable Rectangle r = (Rectangle) s; // Put that object into a Rectangle variable
Shape s = new Rectangle; Circle c = (Circle) s;
r instanceof Shape // true r instanceof Circle // false
Shape s = getSomeShape(); // Call a method that returns any shape,
// e.g., from a user's input
// Check what type of shape it is, before doing a cast
if (s instanceof Rectangle) {
System.out.println("width = " + ((Rectangle) s).getWidth());
}
else if (s instanceof Circle) {
System.out.println("radius = " + ((Circle) s).getRadius());
}
Now on to the new subject of inheritance in Java,
as covered in Horstmann Chapter 10
import java.text.DecimalFormat;
/****
*
* Class BankAccount is a simple banking example based on the example of the
* same name from Horstmann Chapter 10. It has a balance that can be changed
* by deposit and withdrawal methods. It also provides a method to get the
* current balance.
*
*/
public class BankAccount {
/** The current balance of this bank account. */
private double balance;
/**
* Construct a bank account with a zero balance.
*/
public BankAccount() {
balance = 0;
}
/**
* Construct a bank account with the given initial balance.
*/
public BankAccount(double balance) {
this.balance = balance;
}
/**
* Deposit the given amount of money into this bank account.
*/
public void deposit(double amount) {
if (amount < 0) {
throw new IllegalArgumentException();
}
balance = balance + amount;
}
/**
* Withdraw the given amount of money from this bank account.
*/
public void withdraw(double amount) {
if ((balance - amount < 0) || (amount < 0)) {
throw new IllegalArgumentException();
}
balance = balance - amount;
}
/**
* Get the current balance of this bank account.
*/
public double getBalance() {
return balance;
}
/**
* Transfer the given amount from this account to the given other account.
*/
public void transfer(double amount, BankAccount other) {
withdraw(amount);
other.deposit(amount);
}
}
/****
*
* A SavingsAccount extends a BankAccount by adding functionality for an
* account to earn interest. A SavingsAccount has an interest rate, with a
* method to compute the interest and add it to the account balance.
*
*/
public class SavingsAccount extends BankAccount {
private double interestRate;
/**
* Construct a savings account with the given interest rate.
*/
public SavingsAccount(double rate) {
interestRate = rate;
}
/**
* Add the earned interest to this account.
*/
public void addInterest() {
double interest = getBalance() * interestRate / 100;
deposit(interest);
}
}
/****
*
* A CheckingAccount extends a BankAccount by adding functionality for
* transaction fee charges. CheckingAccount specializes the BankAccount
* deposit and withdraw methods to perform transaction counting.
* CheckingAccount also provides , and a method to deduct the chareges from the
* account.
*/
public class CheckingAccount extends BankAccount {
/** Number of transactions before transaction fees start */
private static final int FREE_TRANSACTIONS = 3;
/** Dollar amount of transaction fee (what a rip off) */
private static final double TRANSACTION_FEE = 2.0;
/** Count of transactions since last fee deduction */
private int transactionCount;
/**
* Construct a checking account with the given balance.
* @param initialBalance the initial balance
*/
public CheckingAccount(double initialBalance) {
// Construct the superclass.
super(initialBalance);
// Initialize transaction count in this subclass.
transactionCount = 0;
}
/**
* Deposit the given amount of money into this checking account and
* increment the transaction count by 1.
*/
public void deposit(double amount) {
// Call the parent class deposit method to update the balance.
super.deposit(amount);
// Increment this transaction count
transactionCount++;
}
/**
* Withdraw the given amount of money from this checking account and
* increment the transaction count by 1.
*/
public void withdraw(double amount) {
// Call the parent class withdraw method to update the balance.
super.withdraw(amount);
// Increment this transaction count
transactionCount++;
}
/**
* Deduct the accumulated fees and reset the transaction count.
*/
public void deductFees() {
if (transactionCount > FREE_TRANSACTIONS) {
double fees = TRANSACTION_FEE *
(transactionCount - FREE_TRANSACTIONS);
super.withdraw(fees);
}
transactionCount = 0;
}
//
// Note that getBalance is not specialized, since it works the same for a
// checking account as for a regular bank account.
//
}
public CheckingAccount(double initialBalance) {
// Construct the superclass.
//
// NOTE: We explicitly call the parent constructor via super. This means
// the initial balance is set.
//
super(initialBalance);
// Initialize transaction count in this subclass.
//
// NOTE: Since transactionCount is a non-inherited data field, we need to
// do its initialization explicitly here (there's no way that the
// parent class can initialize it).
//
transactionCount = 0;
}
public SavingsAccount(double rate) {
//
// Initialize the non-inherited data field.
//
// NOTE: In contrast to the CheckingAccount constructor, this constructor
// does not explicitly call super. This means that the default
// parameterless version of the parent constructor is automatically
// called. This is a general rule of Java. I.e., when a child
// constructor does not explicitly call its parent constructor via
// super, Java calls the default version of the parent constructor on
// the child's behalf. In such cases, the parent class MUST define a
// default constructor, otherwise the compiler gives an error.
//
interestRate = rate;
}
public void deposit(double amount) {
//
// Call the parent class deposit method to update the balance.
//
// NOTE: Calling this.deposit here is a big mistake (see Page 428); we need
// to use super.deposit to access the parent version of the deposit
// method.
//
// NOTE ALSO: We cannot use the following in this version of deposit
// because balance is a private data field of BankAccount:
//
// balance = balance + amount;
//
// The balance field is inherited by CheckingAccount, but its
// name is not visible due to its private protection. Hence,
// we need to call the public method BankAccount.deposit to
// effect the change to balance.
//
super.deposit(amount);
//
// Increment this transaction count.
//
// NOTE: Here we are referring to this.transactionCount, since there is no
// such data field in the parent class.
//
transactionCount++;
}
/****
*
* This is a simple testing program for the chapter 10 examples of BankAccount
* and its subclasses. This program includes code from the book's
* AccountTester class, plus some additional code to discuss during 102
* lecture.
*
*/
public class BankAccountChapter10Tester {
public static void main(String[] args) {
/*
* Create a savings and checking account.
*/
SavingsAccount momsSavings = new SavingsAccount(0.5);
CheckingAccount harrysChecking = new CheckingAccount(100);
/*
* Make a savings deposit.
*/
momsSavings.deposit(10000);
/*
* Transfer some funds, then withdraw.
*/
momsSavings.transfer(2000, harrysChecking);
harrysChecking.withdraw(1500);
harrysChecking.withdraw(80);
/*
* Transfer and withdraw some more.
*/
momsSavings.transfer(1000, harrysChecking);
harrysChecking.withdraw(400);
/*
* Compute interest for the savings account, deduct fees for the
* checking.
*/
momsSavings.addInterest();
harrysChecking.deductFees();
/*
* Print some results.
*/
System.out.println();
System.out.println("Mom's savings balance: "
+ momsSavings.getBalance());
System.out.println("Expected: 7035.0");
System.out.println();
System.out.println("Harry's checking balance: "
+ harrysChecking.getBalance());
System.out.println("Expected: 1116.0");
/*
* Here are some illustrations of polymorphism.
*/
BankAccount momsSavingsB = momsSavings;
Object momsSavingsO = momsSavings;
System.out.println();
System.out.print("Savings balances: " +
((SavingsAccount)momsSavingsO).getBalance() + " ");
System.out.println(((SavingsAccount)momsSavingsO).getBalance());
System.out.println("Expected: 7035.0 7035.0");
/*
* Here are some calls that generate errors. Convince yourself that
* you understand why. (They're commented out so the program will
* compile.)
*/
// SavingsAccount emptySavings = new SavingsAccount();
// CheckingAccount emptyChecking = new CheckingAccount();
// momsSavings = (SavingsAccount) harrysChecking;
// CheckingAccount momsChecking = (CheckingAccount) momsSavings;
BankAccount mom2 = momsSavings;
// CheckingAccount momsChecking = (CheckingAccount) mom2;
/*
* An important point of method overriding is that the appropriate
* version of an overridden method be called. For example, when we
* call deposit on a CheckingAccount object, we want to be sure to get
* the version of deposit declared in CheckingAccount, not the more
* general version in BankAccount. And we want this even if we are
* referring to a CheckingAccount from a BankAccount variable.
*
* HOWEVER, suppose we'd like to call the general version of a method
* explicitly? How could we do this?
*/
BankAccount checking = (BankAccount) new CheckingAccount(100);
checking.deposit(100); // Which deposit are we calling here?
((BankAccount) checking).deposit(200); // What about here?
}
}
/****
*
* This is a version of the BankAccount class that implements the Comparable
* interface. It has exactly two differences with the original definition of
* BankAccount:
*
* (1) implementation of Comparable<BankAccount>
* (2) addition of the compareTo method
*
* See lecture notes Week 4 for some discussion.
*
*/
public class BankAccount implements Comparable<BankAccount> {
. . .
/**
* Compare this account with the given other account, using balance as the
* basis of comparison.
*/
public int compareTo(BankAccount other) {
if (balance < other.balance) return -1;
if (balance == other.balance) return 0;
return 1;
}
}
| Interface | Abstract Class | |
| keyword | interface | abstract class |
| inherits-from keyword | implements | extends |
| data fields | none | allowed |
| methods | all abstract | can be declared abstract |
| method bodies | none | allowed |
| multiple inheritance | yes | no |