BankAccount account = new BankAccount(); account.balance = 100.25; account.number = 1234; account.name = "Bob";This four step operation is clearly less than conventient. Fortunately, Java provides us with a way to set the values of the pieces of a new BankAccount object at creation time. It's called the constructor. A constructor is like a special method whose only purpose is to initialize the instance variables of a new object. Here's an example:
class BankAccount { int number; double balance; String name; BankAccount(int acctNumber, double initBalance, String acctName) { this.number = acctNumber; this.balance = initBalance; this.name = acctName; } }Notice that the name of the constructor is the same as the name of the class, and that the constructor does not specifiy a return type. In a sense, the return type of the constructor is the type of the class itself. Let's use our new constructor:
BankAccount account = new BankAccount(1234, 100.25, "Bob");That's it! Notice that the constructor is only used as part of a "new" expression. When the new object is created, it is invoked to set the values of the instance variables of the new object. What happens if we try this now?
BankAccount anAccount = new BankAccount();The compiler will not like this. The reason is that when we define a class, Java provides us with a "default" constructor (with no arguments). However, if we go on and define a constructor that takes arguments, then Java no longer lets us use the default constructor. (At this point, if want an argument-less constructor then we must explicitly provide one. We'll see how in a later lesson.) This seems annoying, but why might it actually be a good thing?
class BankAccount { int number; double balance; String name; BankAccount(int acctNumber, double initBalance, String acctName) { this.number = acctNumber; this.balance = initBalance; this.name = acctName; } void deposit(double amount) { this.balance = this.balance + amount; } double getBalance() { return this.balance; } void withdraw(double amount) { this.balance = this.balance - amount; } void transferFrom(BankAccount other, double amount) { other.withdraw(amount); this.deposit(amount); } }The first two methods don't contain any real mysteries. Can you see a potential problem with the third method (withdraw)? Would a real bank be happy with this kind of account? We need for our BankAccount object to do something reasonable in the case that there is not enough money in the account. We'll present some solutions for managing situations such as these in the next lesson.
Finally, the transferFrom method shows us an example of a method that relies on other methods we have written. This method takes two arguments: another BankAccount object and an amount to transfer. It first withdraws the specified amount from the other account, and then deposits that amount into the receiver account. Now let's look at some BankAccount objects in action:
BankAccount account1 = new BankAccount(1234, 225.34, "Bill"); BankAccount account2 = new BankAccount(23455, 125.0, "George"); account1.transferFrom(account2, 75.0); double newBalance = account2.getBalance();What are the new balances of the two accounts after the above statements are evaluated?
As a trivial example, consider the different ways we could represent the balance of a BankAccount object:
We can enforce the visibility rules in Java by modifying our
declarations with the keywords public
and
private
. As a rule of thumb, we'll want to make all
instance variables private and most of our methods public:
public class BankAccount { private int number; private double balance; private String name; public BankAccount(int acctNumber, double initBalance, String acctName) { this.number = acctNumber; this.balance = initBalance; this.name = acctName; } public void deposit(double amount) { this.balance = this.balance + amount; } // And so on with our other methods... }Now let's see what happens when we try to directly access instance variables of a BankAccount object:
BankAccount account = new BankAccount(1234, 225.34, "Bill"); account.balance = 1000.0; // ERROR!!The compiler or interpreter will not allow this kind of access now, and will flag the error as such. Notice also that we also labeled the class itself as being public. This allows our class to be used anywhere within the universe of Java objects.
/** The BankAccount class implements a simple bank account. @author Ben Dugan @version 11/11/2001 */ public class BankAccount { private int number; private double balance; private String name; /** Create a new BankAccount object, with the given initial values. @param acctNumber an account number to use @param initBalance an initial balance @param acctName the name of the account owner */ public BankAccount(int acctNumber, double initBalance, String acctName) { this.number = acctNumber; this.balance = initBalance; this.name = acctName; } /** Increase the balance by the given amount. @param amount the amount to deposit */ public void deposit(double amount) { this.balance = this.balance + amount; } /** Answer the current balance. @return the current balance */ public double getBalance() { return this.balance; } /** Decrease the balance by the given amount. This method does not guard against overdrawing the account. @param amount the amount to withdraw */ public void withdraw(double amount) { this.balance = this.balance - amount; } /** Transfer money between accounts. @param other a BankAccount to tranfer from @param amount an amount to transfer */ public void transferFrom(BankAccount other, double amount) { other.withdraw(amount); this.deposit(amount); } }Notice that we are using a new style of writing comments. Any text between /* and */ is ignored by Java compilers or interpreters. Furthermore, by starting our comments with an additional asterisk (/**) we are saying that we want these comments to be consumed by a documentation generating tool that can consume our program text file and produce nicely formatted, human readable documentation about our class. We are also making use of special tags, such as @author, @version, @param and @return, which tell the documentation tool that we are expressing information regarding the author, the version number of the class, a parameter, or the return value, respectively. The documentation tool will lay out and format these pieces of documentation differently.