Next: None. Up: Subclasses. Previous: Overriding methods.


Conversions

Textbook: Section 11.4

Implicit conversion

Like with primitive types, Java recognizes a hierarchy among the object types (classes). It will freely convert to a more general type (a parent class) when appropriate. For example, say we define the following class to represent a bank.

public class Bank {
    public static final int MAX_ACCOUNTS = 100;
    private Account[] accounts;
    private int num_accounts;

    public Bank() {
        accounts = new Account[MAX_ACCOUNTS];
        num_accounts = 0;
    }

    public void addAccount(Account acct) {
        accounts[num_accounts] = acct;
        ++num_accounts;
    }

    public Account getAccount(int index) {
        return accounts[index];
    }
}
Java has no problem with the following.
    Bank bank = new Bank();
    bank.addAccount(new SavingsAccount(0.02));
When we call addAccount(), the compiler wanted an Account as a parameter. It saw a SavingsAccount. But SavingsAccount is a subclass of Account, so it automatically converts SavingsAccount into an Account. (It's not actually converted at all - the Account still ``knows'' it's a SavingsAccount, and the interest rate is still saved with it. But, as far as Bank is concerned, it's just an Account.)

Incidentally, this feature of Java is called polymorphism - objects automatically change form as circumstances warrant.

Explicit conversion

But of course Java won't convert down the inheritance hierarchy.

    bank.getAccount(0).addInterest(); // won't compile
This won't compile, since getAccount(0) returns an Account, and as far as Java knows, it doesn't have a method called addInterest(). (It actually does, but the Java compiler can't verify that it does - all it knows is that getAccount() returns an Account.)

Sometimes you'll run into a case where you as the programmer are confident of what the object's type actually is because of some reasoning you've gone through. And you want to do something to it based on that type. In our example so far, for example, we're confident that the bank only holds SavingsAccounts, so we should be allowed to call addInterest().

In this case, you can use explicit conversion - using the casting operator we already saw for the primitive types.

    ((SavingsAccount) bank.getAccount(0)).addInterest(); // ok

The instanceof operator

What if you're not sure about an object has a specific type, but you want to do something if it has the type? This is what the instanceof operator is for: It tells you whether an object's actual type is what you think it is. For example, if we wanted to add any interest due to account 0, but we're not sure that it's a SavingsAccount, we could test whether it is first as follows.

    if(bank.getAccount(0) instanceof SavingsAccount) {
        ((SavingsAccount) bank.getAccount(0)).addInterest();
    }

The instanceof operator recognizes an object as being of a given type, even if that type is a superclass of the actual type of the object. If mine is an InvestmentAccount, the following are all true.

mine instanceof InvestmentAccount
mine instanceof SavingsAccount
mine instanceof Account
!(mine instanceof Bank)


Next: None. Up: Subclasses. Previous: Overriding methods.