I have a program nearly complete - it creates a bank object which creates within it customers and accounts of multiple types and can successfully load this information to display on the screen. The problem is that I am now trying to deposit or withdraw a given balance which has already been created, but I am unable to because "Non-Static Method Cannot be referenced from static context." which I know generally means that the instance has not been created yet, but in this case it has. It's just that I can't seem to do anything with it and I don't know why.

Here's what I have so far. It compiles and it runs. It's just the processTransactionsInFile() method in the Main.java class which is incomplete. (see line 247 of Main.ajava - I commented out the portions giving me trouble) oh, and the withdraw/deposit methods are in Account.java. I have been wracking my head on this for a few days and could really use some direction at least. Since I am not sure where my problem is I am posting the entire intact program code below:

Main.java class:

package mp04;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Main 
{
    private final static String INPUT_ACCOUNT_FILE = "accountInfo.txt";
    private final static String INPUT_TRANSACTIONS_FILE = "transactions.txt";


    // If I don't initialize the bank object at the class level it won't be accessible by the other methods.
    protected static Bank bank = new Bank();


    public static void main(String[] args) 
    {

        // I used the following to trouble shoot file names and location.

//        File file = new File(".");
//        for(String fileNames : file.list()) System.out.println(fileNames);

        // Open file
        try 
            {
            loadAccountInformationFromFile();
            } 
        catch (Exception e) 
            {
                    System.err.println("error: " + e.getMessage()); 
                    System.exit(1);
            }

        try 
            {
            processTransactionsInFile();
            }
        catch (Exception e) 
            {
                    System.err.println("error: " + e.getMessage()); 
                    System.exit(1);
            }

        displayBankRecords();



//        System.out.printf("%s\n%s\n%s", "Customer list:","--------------", bank.customerList());
//        System.out.println("");
//        System.out.printf("%s\n%s\n%s", "Account list:","-------------", bank.accountList());
//        System.out.printf("\n%s\n%s\n%s", "Bank record:","------------", bank);
//        System.out.println("");
    }
        protected static void loadAccountInformationFromFile() throws Exception 
        {
            // These correspond with the positions of the contents of the text file.
            // This is based on the knowledge that each line has only 5 values,
            // but in practice I could easily add an additional variable with an
            // additional number value and it would definately work.

            // They may be the same, but setting them differently allows me some
            // versatility in future edits.
            final int ACCOUNT_NUMBER = 0;
            final int FIRST_NAME = 1;
            final int LAST_NAME = 2;
            final int BALANCE = 3;
            final int LAST_VARIABLE = 4; 

            final int ACCOUNT_NUMBER_COUNT = 0;
            final int FIRST_NAME_COUNT = 1;
            final int LAST_NAME_COUNT = 2;
            final int BALANCE_COUNT = 3;
            final int LAST_VARIABLE_COUNT = 4; 

            List<String> accountNumbers = new ArrayList<>();
            List<String> firstNames = new ArrayList<>();
            List<String> lastNames = new ArrayList<>();
            List<String> balances = new ArrayList<>();
            List<String> lastVariables = new ArrayList<>();

        try (Scanner account = new Scanner(new File(INPUT_ACCOUNT_FILE))) 
        {
            do {

                String[] temp1 = account.next().split(",");


                if (ACCOUNT_NUMBER_COUNT == ACCOUNT_NUMBER)
                {
                    accountNumbers.add(temp1[ACCOUNT_NUMBER]);
                }
                if (FIRST_NAME_COUNT == FIRST_NAME)
                {
                    firstNames.add(temp1[FIRST_NAME]);
                }
                if (LAST_NAME_COUNT == LAST_NAME)
                {
                    lastNames.add(temp1[LAST_NAME]);
                }
                if (BALANCE_COUNT == BALANCE)
                {
                    balances.add(temp1[BALANCE]);
                }
                if (LAST_VARIABLE_COUNT == LAST_VARIABLE)
                {
                    lastVariables.add(temp1[LAST_VARIABLE]);
                }

            } while (account.hasNext());
        }

            // Given the above logic, each ArrayList would have to be the same size.
            int arraySize = lastVariables.size();

            // Given that the Checking Account class has a definate boolean value
            // whereas the Savings Account class requires a double which can be
            // anything I can use the boolean to sort the data being sent to bank.

            for (int i=0; i < arraySize; i++)
            {
                // Alternatively, I could have focused on the fact that a 1
                // seems to prefix a checking account while a 2 is for savings.
                if (("N".equals(lastVariables.get(i))) || ("Y".equals(lastVariables.get(i))))
                {                    
                    // convert the String ArrayLists to the correct variable types to be
                    // accepted by the Bank class without changing it.

                    String accountNumberString = accountNumbers.get(i);
                    int accountNumberInt = Integer.parseInt(accountNumberString);

                    String firstNameString = firstNames.get(i);
                    String lastNameString = lastNames.get(i);

                    String balanceString = balances.get(i);
                    double balanceDouble = Double.parseDouble(balanceString);

                    String lastVariableString = lastVariables.get(i);

                    // Initialize boolean as anything to avoid compiler error
                    boolean freeChecks = true;

                    if (lastVariableString == "N")
                    {
                        freeChecks = Boolean.parseBoolean("false");
                    }
                    else
                    {
                        freeChecks = Boolean.parseBoolean("true");
                    }

                    bank.openAccount(new CheckingAccount(accountNumberInt, new Customer(firstNameString, lastNameString),balanceDouble,freeChecks));

                } 
                else 
                {

                    // convert the String ArrayLists to the correct variable types to be
                    // accepted by the Bank class without changing it.

                    String accountNumberString = accountNumbers.get(i);
                    int accountNumberInt = Integer.parseInt(accountNumberString);

                    String firstNameString = firstNames.get(i);
                    String lastNameString = lastNames.get(i);

                    String balanceString = balances.get(i);
                    double balanceDouble = Double.parseDouble(balanceString);

                    String lastVariableString = lastVariables.get(i);
                    double interestDouble = Double.parseDouble(lastVariableString);

                    bank.openAccount(new SavingsAccount(accountNumberInt, new Customer(firstNameString, lastNameString),balanceDouble,interestDouble));

                }
            }

              // Used the following to test to make sure that the ArrayLists work:
//            System.out.println(accountNumbers.get(0));
//            System.out.println(firstNames.get(4));

        }




//        Add the method void processTransactionsInFile(). This void method declares that it
//throws an Exception object, which the caller (main()) will handle. This method will open the
//input file, transactions.txt, and process each transaction.

        protected static void processTransactionsInFile() throws Exception
        {
            final int ACCOUNT_NUMBER_COUNT = 1;
            final int TRANSACTION_COUNT = 0;

            final int ACCOUNT_NUMBER = 1;
            final int TRANSACTION = 0;

            List<String> transactionList = new ArrayList<>();
            List<String> accountNumberList = new ArrayList<>();



            try (Scanner transactions = new Scanner(new File(INPUT_TRANSACTIONS_FILE))) 
            {
                do {

                    String[] temp1 = transactions.next().split(",");

                    if (ACCOUNT_NUMBER_COUNT == ACCOUNT_NUMBER)
                        {
                            transactionList.add(temp1[ACCOUNT_NUMBER]);
                        }
                    if (TRANSACTION_COUNT == TRANSACTION)
                        {
                            accountNumberList.add(temp1[TRANSACTION]);
                        }         

                    } while (transactions.hasNext());
            }

            // test:
             System.out.println(accountNumberList.get(1));
             System.out.println(accountNumberList.get(2));

            int arraySize = transactionList.size();


                for (int i=0; i < arraySize; i++)
                    {

                        String transactionString = transactionList.get(i);
                        double transactionDouble = Double.parseDouble(transactionString);

                        String accountNumberString = accountNumberList.get(i);
                        int accountNumberInt = Integer.parseInt(accountNumberString);

                        // bank.getAccountWithNumber(accountNumberInt);

                        System.out.println(transactionDouble);

                        if (transactionDouble < 0)
                            {
                                // This doesn't work
                                //Account.withdraw(transactionDouble);
                            }
                        else
                            {
                                //Account.deposit(transactionDouble);
                            }
                     }

             // Used the following to test to make sure that the ArrayLists work:
//             System.out.println(transactionList.get(1));



        }

        private static void displayBankRecords()
        {

        System.out.printf("%s\n%s\n%s\n%s", "Bank Record:","--------------", "Customers:(" + bank.getCustomerSize() + ") " , bank.customerList());
        System.out.println("");
        System.out.printf("%s\n%s\n%s\n%s", "Account list:","-------------", "Accounts:(" + bank.getAccountSize() + ") " , bank.accountList());
        }

}

Bank.java class:

package mp04;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class Bank 
{ 
    private List<Customer> customers = new ArrayList<>();
    private List<Account> accounts = new ArrayList<>();

    public int getCustomerSize()
    {
        return customers.size();
    }

        public int getAccountSize()
    {
        return accounts.size();
    }

    public Customer getCustomerAtIndex(int index) 
        { 
            return customers.get(index); 
        }
    public Account getAccountAtIndex(int index)   
        { 
            return accounts.get(index);  
        }

    public Account getAccountWithNumber(int accountNumber)
    {   
        return accounts.get(accountNumber);  
    }

    public void addCustomer(Customer o) 
    {
        //Each time this method is called it will add to the array
        customers.add(o);
    }

    // Added the addAccount() method when dynamic arrays are used.
    // Need to remove addAccount() for the new UML
    private void addAccount(Account o) 
    {
        //Each time this method is called it will add to the array
        accounts.add(o);
    }

    public void openAccount(Account o) 
    {

        addAccount(o);

        // I needed an extra boolean in order to make use of the .equals() method.
        // there were too many errors as it was and not enough example in the book.

        boolean compare = true;

        for(int i = 0; i < customers.size(); i++)
        {
            if (o.getOwner().equals(getCustomerAtIndex(i)) == true)
                {
                    compare = false;
                }
        }

        if (compare == true)
        {
            addCustomer(o.getOwner());
        }


    }

    public String customerList() 
    {
        String list = Arrays.toString(customers.toArray()).replace(", O", "O").replace(", O", "O");
        return list.substring(1,list.length()-1);

        // Using just the following causes brackets to appear
//                return list;

        // The following approach removed the brackets, but there were still extra commas
//                return list.substring(1,list.length()-1);

        // The following approach removed the extra commas, but also removed the commas I wanted so I couldn't use it
//                String list = Arrays.toString(customers.toArray()).replace(",", "").replace(",", "");
        // In order to make it work without using StringBuilder I focused on the fact that each line starts with N and made it work that way.
        // However, I consider this to be a poor approach. If the toString() class in Customer.java is changed the code will break so I am notating there

    }

    public String accountList() 
    { 
        String account = Arrays.toString(accounts.toArray()).replace(", [", "[").replace(", [", "[");
        return account.substring(1,account.length()-1);



    }

    @Override
    public String toString() 
    {
        return "Customers(" + customers.size() + ")\n" + customerList() + "\n" +
                "Accounts(" + accounts.size() + ")\n" + accountList();
    }
}

Customer.Java class:

package mp04;

import java.util.Objects;

public class Customer 
{
    private String first;
    private String last;

    public Customer(String first, String last) 
    {
        setFirst(first);
        setLast(last);
    }

    public final String getFirst() { return first;                         }
    public final String getLast()  { return last;                          }
    public String getName()  
        { 
            return getLast() + ", " + getFirst(); 
        }

    public final void setFirst(String first) 
        {
        this.first = first;
        }

    public final void setLast(String last) { this.last = last; }

    @Override
    public int hashCode() 
    {
        int hash = 7;
        hash = 37 * hash + Objects.hashCode(this.first);
        hash = 37 * hash + Objects.hashCode(this.last);
        return hash;
    }

    @Override
    public boolean equals(Object name) 
    {
        if (name == null) {
            return false;
        }
        if (getClass() != name.getClass()) {
            return false;
        }
        final Customer other = (Customer) name;
        if (!Objects.equals(this.first, other.first)) {
            return false;
        }
        if (!Objects.equals(this.last, other.last)) {
            return false;
        }
        return true;
    }



    @Override
    public String toString() 
    {
        // CAUTION: The Bank.java class depends on this return starting with O amd emdomg with "\n"
        // If this changes be sure to change the customerList() method in Bank.java class accordingly.
        return "Owner: " + getName() + "\n";
    }


}

Account.java class:

package mp04;

// Note: The Account class is a super class. I don't need getters and setters
// in any account type for this reason.

import java.text.DateFormat;
import java.util.Date;

public class Account 
{
    private int accountNumber;
    private Date dateOpened;
    private Customer owner;
    private double currentBalance;

    // For my own future reference: # in UML means protected
    protected Account(int accountNumber, Customer owner, double currentBalance) 
    { 
        setDateOpened(new Date()); 

        setAccountNumber(accountNumber);
        setOwner(owner);
        setCurrentBalance(currentBalance);
    }

    public int getAccountNumber() { return accountNumber; }
    public Customer getOwner()    { return owner;         }
    public double getCurrentBalance() { return currentBalance; }

    private void setAccountNumber(int accountNumber) { this.accountNumber = accountNumber; }
    private void setOwner(Customer owner)            { this.owner = owner;                 }
    private void setCurrentBalance(double currentBalance) { this.currentBalance = currentBalance; }

    //Note to self: The UML for this line was
    //
    //      +withdraw(amount: double): double
    //

    public double withdraw(double amount)
   {
        setCurrentBalance(currentBalance - amount);
        return currentBalance;
   }

    public double deposit(double amount)
    {
        setCurrentBalance(currentBalance + amount);
        return currentBalance;
    }

    public Date getDateOpened()                  { return dateOpened;            }
    private void setDateOpened(Date dateOpened)  { this.dateOpened = dateOpened; }

    @Override
    public String toString() 
    {
        DateFormat df = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.SHORT);


        // CAUTION: The Bank.java class depends on this return starting with [ amd emdomg with "\n"
        // If this changes be sure to change the accountList() method in Bank.java class accordingly.
        return "[" + getAccountNumber() + "], " +
               "Opened: " + df.format(getDateOpened()) + 
               ", " + owner +
               "Balance: $" + currentBalance;
    }  
}

CheckingAccoung.java class:

package mp04;

public class CheckingAccount extends Account 
{
    private boolean freeChecks;
    private String freeChecksValue = "";

        public CheckingAccount(int accountNumber, Customer owner, double currentBalance, boolean freeChecks) 
    {
        super(accountNumber, owner, currentBalance);

        // This is the accessor
        this.freeChecks = freeChecks;
    }        

    @Override
    public String toString() 
    {

        if (freeChecks == true)
                {
                    freeChecksValue = "Yes";
                }
        else
                {
                    freeChecksValue = "No";
                }

        return super.toString() + ", " + "Free Checks: " + freeChecksValue + "\n\n";
    }
}

SavingsAccount.java class:

package mp04;

public class SavingsAccount extends Account
{
    private double interestRate;

        public SavingsAccount(int accountNumber, Customer owner, double currentBalance, double interestRate) 
    {
          super(accountNumber, owner, currentBalance);

          // This is the accessor:
          this.interestRate = interestRate;
    }    

    private void setInterestRate(double interestRate) 
        { 
            this.interestRate = interestRate; 
        }

    public double getInterestRate() 
        { 
            return interestRate; 
        }

    @Override
    public String toString() 
    {
          return super.toString() + ", " + "Interest Rate: " + interestRate + "%\n\n";
    }
}

accountInfo.txt :

10100,Adam,Apple,500.00,N
10101,Breatrice,Bagel,2000.00,Y
20100,Chris,Cucumber,5000.00,0.02
20101,David,Dakon,3500.00,0.02
10102,Ethel,Endame,1000.00,Y
20103,Adam,Apple,6000.00,0.02

transactions.txt :

10100,500.00
10101,-250.00
20100,450.00
20101,-100.00
10102,-300.00
20103,1000.00

The above runs and shows the following output (where everything before the Bank Account label in the text is just tests to verify I am collecting the data from the transactions file properly) :

run:
10101
20100
500.0
-250.0
450.0
-100.0
-300.0
1000.0
Bank Record:
--------------
Customers:(5) 
Owner: Apple, Adam
Owner: Bagel, Breatrice
Owner: Cucumber, Chris
Owner: Dakon, David
Owner: Endame, Ethel

Account list:
-------------
Accounts:(6) 
[10100], Opened: Oct 2, 2015 12:26 PM, Owner: Apple, Adam
Balance: $500.0, Free Checks: Yes

[10101], Opened: Oct 2, 2015 12:26 PM, Owner: Bagel, Breatrice
Balance: $2000.0, Free Checks: Yes

[20100], Opened: Oct 2, 2015 12:26 PM, Owner: Cucumber, Chris
Balance: $5000.0, Interest Rate: 0.02%

[20101], Opened: Oct 2, 2015 12:26 PM, Owner: Dakon, David
Balance: $3500.0, Interest Rate: 0.02%

[10102], Opened: Oct 2, 2015 12:26 PM, Owner: Endame, Ethel
Balance: $1000.0, Free Checks: Yes

[20103], Opened: Oct 2, 2015 12:26 PM, Owner: Apple, Adam
Balance: $6000.0, Interest Rate: 0.02%

However, the desired expected output after properly withdrawing/depositing transactions shows a different balance.

Edited 1 Year Ago by Elliander_1

You say you have a "Non-Static Method Cannot be referenced from static context.", but you forgot to tell us which line that was referring to.
But then you say you have incorrect output - which is impossible if you have the "Non-Static Method Cannot be referenced from static context." because that means the compile failed so you don; have anything to execute

@JamesCherrill I thought that was clear. I said that everything compiles and works without implementing the deposit/withdraw feature and that this is in the processTransactionsInFile() method in the Main.java class. I even commented out the problem area within the code and commented that it is the part that doesn't work. Obviously there would be no compiler errors if a problem area is commented out. See line 247 of Main.java - I edited the question accordingly.

Edited 1 Year Ago by Elliander_1

You don't need to post ALL of your code. Most of us don't have the time to read through it all. The error says enough. You are trying to access a member function without going through an instance of the object class where it is defined. IE, if method xyzzy() is defined as a member function of class Foo, then you cannot invoke it as Foo::xyzzy(). You need an instance of Foo, as in:

Foo bar = new Foo; bar.xyzzy();

I found my answer. My code has three problems:

In Main.java I should use:

Account account = bank.getAccountWithNumber(accountNumberInt);

Instead of what I was using:

bank.getAccountWithNumber(accountNumberInt);

I also had to change this snippet from the Main.java class:

                        if (transactionDouble < 0)
                            {
                                account.withdraw(transactionDouble);
                            }
                        else
                            {
                                account.deposit(transactionDouble);

                            }
                     }

To reflect the change in how I was loading the account numbers. This change alone caused an index error, but was fixed by changing the Bank.java class to either:

    public Account getAccountWithNumber(int accountNumber)
    {   
     for(Account account : accounts) {
      if(account.getAccountNumber() == accountNumber) {
       return account;
      }
     }
        return null;  
    }

or:

    public Account getAccountWithNumber(int accountNumber)
    {     
         return accounts.stream().filter(a -> a.getAccountNumber() == accountNumber).findFirst().get();
    }

Either works, but not what I was using:

public Account getAccountWithNumber(int accountNumber)
    {   
        return accounts.get(accountNumber);  
    }

After making all of these changes everything works perfectly. However, cleaning up my code this worked better than my if logic:

        try (Scanner transactions = new Scanner(new File(INPUT_TRANSACTIONS_FILE))) 
        {
            do {

                String[] temp1 = transactions.next().split(",");

                transactionList.add(temp1[ACCOUNT_NUMBER]);
                accountNumberList.add(temp1[TRANSACTION]); 

                } while (transactions.hasNext());
        }

I also had to change an N == variable to N.equals(variable)

Edited 1 Year Ago by Elliander_1

@rubberman Creating a new object would not have helped because the object was already created. The issue I was having was in loading the already created object, which I eventually figured out.

I didn't expect anyone to read all of the code, but by posting all of it and highlighting where my issue is that generally makes it easier for someone to spot what I might have missed. It also helps others who may find the code later since it gives a more complete picture of the problem and solution.

This article has been dead for over six months. Start a new discussion instead.