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 |