Q: How to call methods from an extended class? public class Account {
    double currentBalance;
    
    Account(double currentBalance) {
        this.currentBalance = currentBalance; 
    }
    
    double getBalance() {
        return(this.currentBalance);
    }
    
     void deposit(double amount) {
        this.currentBalance += amount;
    }

    void withdraw(double amount) {
        this.currentBalance -= amount;
    }
    
    public String toString() {
        return("Your current account balance is: $" + this.currentBalance);
    }
}

 public class SavingsAccount extends Account {
    double interestRate;

    SavingsAccount(double interestRate, double amount) {
        super(amount);
        this.interestRate = interestRate;
    }

    void addInterest(double interestRate) {
        this.currentBalance = this.currentBalance + (this.currentBalance * (interestRate / 100));
    }
    
    public String toString() {
        return("Your current account balance is: $" + this.currentBalance + ". Your interest rate is: " + this.interestRate + "%");
    }
}

public class AccountTester {
    public static void main(String[] args) {
        System.out.println("Welcome to the COMP 251 BANK");
        
        Account[] acc = new Account[10];

        acc[0] = new Account (100000); // initial amount of 100k
        System.out.println(acc[0].toString());
        
        acc[0].deposit(50000); //deposit 50k
        System.out.println("Current balance after depositing is: " + "$" + acc[0].getBalance());
        
        acc[0].withdraw(10000);
        System.out.println("Current balance after withdrawing is: " + "$" + acc[0].getBalance());
        
        System.out.println();
        System.out.println("CHECKING ACCOUNT");

        acc[1] = new CheckingAccount(10000,50000); //overdraft limit of 1000, initial amount of 50k
        System.out.println(acc[1].toString());
        
        acc[1].deposit(20000); //I dont know what to do about the chequeDeposit 
        System.out.println("Current balance after depositing is: " + "$" + acc[1].getBalance()); 
        
        System.out.println();
        System.out.println("SAVINGS ACCOUNT");

        acc[2] = new SavingsAccount(10, 50000);
        System.out.println(acc[2].toString());

        acc[2].deposit(10000);
        System.out.println("Current balance after depositing is: " + "$" + acc[2].getBalance()); 
        
        acc[2].addInterest();
    }
}

I'm still new to this so I'm sorry if this is a bad question but I tried playing around with each class and I still can't figure out how to use the addInterest method I created in the SavingsAccount class that extends the Account class. I tried SavingsAccount.addInterest but I get a static reference error. I thought acc[2].addInterest would work but it says its undefined for the type Account.

A: You need to cast acc[2] to SavingsAccount before calling the method.
((SavingsAccount) acc[2]).addInterest();

It is called downcasting and here is an explanation of it.

A: You're trying to invoke a child class' method, addInterest from a base class reference.
In fact, your array has been declared as an array of Account objects

Account[] acc = new Account[10];

This class does not offer the addIntereset method, even though your arr[2] contains a SavingAccount instance, Java in fact will only be able to know this at run-time. At compile time, your syntax must be compliant with the declared type (Account).
To work around this problem you have two solutions: creating a generic addInterest method in your base class which your child classes will override or cast your arr[2] to a SavingAccount instance.
With the first approach, you're offering an addInterest method from the base class, so whatever instance is going to call the method (an actual Account or a subtype), it will always be able to invoke it.
public class Account {
    
    public void addInterest(double interest){
        //Account implementation
    }
}

public class SavingAccount {
    
    @Overrride
    public void addInterest(double interest){
        //SavingAccount implementation
    }
}

So, in your main you could type with no errors:
Account[] arr = new Account[10];
arr[0] = new Account();
arr[0].addInterest(5);  //No error, dynamic dispatch will call Account's implementation

arr[1] = new SavingAccount();
arr[1].addInterest(10);  //No error, dynamic dispatch will call SavingAccount's implementation

With the second approach instead, you need to make sure that what you're downcasting corresponds to the subtype of your casting.
//Randomly assigning to acc an Account instance or a SavingAccount instance
Account acc = Math.round(Math.random()) == 0 ? new Account() : new SavingAccount();

//Making sure to downcast acc to SavingAccount with the instanceof operator
if (acc instanceof SavingAccount){
    SavingAccount savAcc = (SavingAccount) acc;
    savAcc.addInterest(5);
}

