본문 바로가기
  • 코딩, 허쌤이 떠먹여 줄게
BackEnd/Java

8_1. 회차 은행 어플리케이션 프로그램

by 허쌤 2026. 1. 14.

public class Account {
private String ano; //계좌번호
private String owner; //계좌주
private int balance; //잔고
public Account(String ano, String owner, int balance) {
this.ano = ano;
this.owner = owner;
this.balance = balance;
}

public String getAno() {
    return ano;
}
public void setAno(String ano) {
    this.ano = ano;
}
public String getOwner() {
    return owner;
}
public void setOwner(String owner) {
    this.owner = owner;
}
public int getBalance() {
    return balance;
}
public void setBalance(int balance) { //잔액변경
    this.balance = balance;
}

}

package a0113.Account3;

import java.util.Scanner;

public class BankApp {

//Account acc = new Account("123-123", "이순신", 10000);
// 객체를 하나만 만든다.
//Account 객체를 100개를 관리하고 싶다.

private static Account[] accountsArray = new Account[100];
//Account 객체 100를 관리하는 배열을 만든다.
private static Scanner scanner = new Scanner(System.in);
public static void main(String[] args) {
boolean run = true;
while (run) {
System.out.println("-------------------------------------------------------------------");
System.out.println("1.계좌생성 | 2.계좌목록 | 3. 예금 | 4. 출금 | 5.계좌이체 | 6. 종료");
System.out.println("-------------------------------------------------------------------");
System.out.print("선택> ");
int selNum = 0;
try{
selNum = Integer.parseInt(scanner.nextLine());
}catch(Exception e){

        }
        //a 라고 문자를 입력해도 
        //에외처리 - 에러발생해도 프로그램 계속실행 - while

        switch(selNum){
            case 1 : createAccount();
            break;
            case 2 : accountList();
            break;
            case 3 : deposit();
            break;
            case 4 : withdraw();
            break;
            case 5 : transfer();
            break;
            case 6:
                System.out.println("프로그램 종료");
                run = false;
                break;
        }

    }

}

private static void transfer() {
System.out.println("-----------");
System.out.println("계좌이체");
System.out.println("-----------");
System.out.print("출금 계좌번호: ");
String ano = scanner.nextLine();
System.out.print("입금 계좌번호: ");
String send = scanner.nextLine();
Account account = findAccount(ano);
Account sendAccount = findAccount(send);
if(account == null || sendAccount == null){
System.out.println("결과 : 계좌가 없습니다.");
return;
}
System.out.print("이체금액 : ");
int money = 0;
try {
money = Integer.parseInt(scanner.nextLine());
if(money<=0){
System.out.println("이체 금액은 1원이상이여야 합니다.");
return;
}
if(account.getBalance() <= money){
//잔액보다 찾는 금액이 많으면 잔액부족
System.out.println("잔액부족입니다.");
return;
}
account.setBalance(account.getBalance() - money); //보낸사람 객체에서 잔액 - 이체금액
sendAccount.setBalance(sendAccount.getBalance() + money);//받는사람 객체에서 잔액 + 이체금액
System.out.println("이체성공");
} catch (NumberFormatException e) {//숫자 에러(문자가 들어왔을때)
System.out.println("잘못된입력 입니다. 숫자를 입력해 주세요.");
}

}

private static void withdraw() {
System.out.println("-----------");
System.out.println("출금");
System.out.println("-----------");
System.out.print("계좌번호: ");
String ano = scanner.nextLine();
Account account = findAccount(ano);
if(account == null){
System.out.println("결과 : 계좌가 없습니다.");
return;
}
System.out.print("출금액 : ");
try {
int money = Integer.parseInt(scanner.nextLine());
if(money<=0){
System.out.println("출금액은 1원이상이여야 합니다.");
return;
}
if(account.getBalance() <= money){
//잔액보다 찾는 금액이 많으면 잔액부족
System.out.println("잔액부족입니다.");
return;
}
account.setBalance(account.getBalance() - money);
System.out.println("결과 :출금완료 현재잔액 :"+ account.getBalance() + "원");
} catch (NumberFormatException e) {//숫자 에러(문자가 들어왔을때)
System.out.println("잘못된입력 입니다. 숫자를 입력해 주세요.");
}
}

private static void deposit() {//3. 예금
System.out.println("-----------");
System.out.println("예금");
System.out.println("-----------");
System.out.print("계좌번호: ");
String ano = scanner.nextLine();
Account account = findAccount(ano);
if(account == null){
System.out.println("결과 : 계좌가 없습니다.");
return;
}
System.out.print("예금액 : ");
try {
int money = Integer.parseInt(scanner.nextLine());
if(money<=0){
System.out.println("예금액은 1원이상이여야 합니다.");
return;
}
account.setBalance(account.getBalance() + money);
} catch (NumberFormatException e) {//숫자 에러(문자가 들어왔을때)
System.out.println("잘못된입력 입니다. 숫자를 입력해 주세요.");
}

}

private static void createAccount() {
System.out.println("------------------");
System.out.println("계좌생성");
System.out.println("------------------");
System.out.print("계좌입력 : ");
String ano = scanner.nextLine();
if(findAccount(ano) != null){
System.out.println("이미 존재하는 계좌번호 입니다.");
return;
}
System.out.print("계좌주: ");
String owner = scanner.nextLine();
System.out.print("초기입금액: ");
int balance = 0; //잔액 0 초기
try {
balance = Integer.parseInt(scanner.nextLine());
if(balance < 0){
System.out.println("초기입금액은 0원 이상이여야 합니다.");
return;
}
Account newAccount = new Account(ano, owner,balance);
for(int i =0; i < accountsArray.length;i++){
if(accountsArray[i] == null){
accountsArray[i] = newAccount;
System.out.println("결과 계좌가 생성되었습니다.");
break;
}

        }

    } catch (Exception e) {
       System.out.println("잘못된 입력입니다. 숫자를 입력하세요" );
    }

}
private static void accountList(){
System.out.println("---------------");
System.out.println("계좌목록");
System.out.println("---------------");
for(int j =0; j < accountsArray.length;j++ ){
if(accountsArray[j] != null){
System.out.printf("%s %4s %d\n", accountsArray[j].getAno(),accountsArray[j].getOwner(),accountsArray[j].getBalance());
}
}
}

private static Account findAccount(String ano) { //계좌번호 유무 찾는 메소드
Account account = null;
//반환 될 값 초기화
for(int k =0; k < accountsArray.length;k++ ){
if(accountsArray[k] != null){
String dbAno = accountsArray[k].getAno();
if(dbAno.equals(ano)){
account = accountsArray[k];
break;
}
}
}
return account;
}

}

은행 애플리케이션 데이터 흐름 시각화

📌 프로그램 구조

클래스 구조

┌─────────────────────────────────────┐
│     BankApplication (메인 클래스)    │
├─────────────────────────────────────┤
│ - accountsArray: Account[100]       │
│ - scanner: Scanner                  │
├─────────────────────────────────────┤
│ + main()                            │
│ - createAccount()                   │
│ - accountList()                     │
│ - deposit()                         │
│ - withdraw()                        │
│ - transfer()                        │
│ - findAccount()                     │
└─────────────────────────────────────┘
              │
              │ 사용
              ▼
┌─────────────────────────────────────┐
│        Account (계좌 클래스)         │
├─────────────────────────────────────┤
│ - ano: String (계좌번호)            │
│ - owner: String (계좌주)            │
│ - balance: int (잔액)               │
├─────────────────────────────────────┤
│ + getAno()                          │
│ + getOwner()                        │
│ + getBalance()                      │
│ + setBalance()                      │
└─────────────────────────────────────┘

1️⃣ 배열 구조

accountsArray 초기 상태

┌─────────────────────────────────────────────────────────┐
│          accountsArray (Account[100])                   │
├─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬──────┤
│ [0] │ [1] │ [2] │ [3] │ ... │[99] │     │     │      │
├─────┼─────┼─────┼─────┼─────┼─────┼─────┼─────┼──────┤
│null │null │null │null │ ... │null │     │     │      │
└─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴──────┘
     ↑
   모든 요소가 null (초기 상태)

2️⃣ 계좌 생성 (createAccount)

실행 흐름

사용자 입력
    ↓
계좌번호: "123-456"
계좌주: "홍길동"
초기입금액: 10000
    ↓
findAccount("123-456") 호출
    ↓
배열에서 계좌 찾기
    ↓
계좌가 없으면 → 새 Account 객체 생성
    ↓
배열의 빈 자리(null)에 저장

메모리 구조 변화

1단계: Account 객체 생성

┌─────────────────────────────────────┐
│         Heap 메모리                  │
├─────────────────────────────────────┤
│                                     │
│  ┌───────────────────────────────┐ │
│  │   Account 객체                │ │
│  │   ano: "123-456"              │ │
│  │   owner: "홍길동"             │ │
│  │   balance: 10000              │ │
│  └───────────┬───────────────────┘ │
│              │                      │
└──────────────┼──────────────────────┘
               │ 참조
               │
┌──────────────▼──────────────────────┐
│    accountsArray[0]                 │
│    = newAccount                     │
└─────────────────────────────────────┘

2단계: 배열에 저장

accountsArray 초기 상태:
┌─────┬─────┬─────┬─────┬─────┬─────┐
│ [0] │ [1] │ [2] │ [3] │ ... │[99] │
├─────┼─────┼─────┼─────┼─────┼─────┤
│null │null │null │null │ ... │null │
└─────┴─────┴─────┴─────┴─────┴─────┘

createAccount() 실행 후:
┌─────┬─────┬─────┬─────┬─────┬─────┐
│ [0] │ [1] │ [2] │ [3] │ ... │[99] │
├─────┼─────┼─────┼─────┼─────┼─────┤
│     │null │null │null │ ... │null │
│ Acc │     │     │     │     │     │
│객체 │     │     │     │     │     │
│참조 │     │     │     │     │     │
└─────┴─────┴─────┴─────┴─────┴─────┘
   ▲
   │
┌───┴──────────────────────────────┐
│ Account 객체                      │
│ ano: "123-456"                   │
│ owner: "홍길동"                   │
│ balance: 10000                    │
└───────────────────────────────────┘

여러 계좌 생성 시

계좌 3개 생성 후:

accountsArray:
┌─────┬─────┬─────┬─────┬─────┬─────┐
│ [0] │ [1] │ [2] │ [3] │ ... │[99] │
├─────┼─────┼─────┼─────┼─────┼─────┤
│ Acc1│ Acc2│ Acc3│null │ ... │null │
│참조 │참조 │참조 │     │     │     │
└──┬──┴──┬──┴──┬──┴─────┴─────┴─────┘
   │     │     │
   │     │     └─► Account { ano: "789", owner: "이영희", balance: 5000 }
   │     │
   │     └─► Account { ano: "456", owner: "김철수", balance: 20000 }
   │
   └─► Account { ano: "123-456", owner: "홍길동", balance: 10000 }

3️⃣ 계좌 찾기 (findAccount)

실행 흐름

findAccount("123-456") 호출
    ↓
┌─────────────────────────────────────┐
│ 배열을 처음부터 끝까지 순회         │
│ (for문: k = 0 ~ 99)                │
└───────────┬─────────────────────────┘
            │
            ▼
┌─────────────────────────────────────┐
│ accountsArray[k]가 null인가?        │
│ → null이면 다음 요소로              │
│ → null이 아니면 계좌번호 비교       │
└───────────┬─────────────────────────┘
            │
            ▼
┌─────────────────────────────────────┐
│ accountsArray[k].getAno()           │
│ .equals("123-456") ?                │
│ → 같으면: 해당 Account 반환         │
│ → 다르면: 다음 요소로               │
└─────────────────────────────────────┘

시각적 표현

배열 탐색 과정:

accountsArray:
┌─────┬─────┬─────┬─────┬─────┐
│ [0] │ [1] │ [2] │ [3] │ ... │
├─────┼─────┼─────┼─────┼─────┤
│ Acc1│ Acc2│ Acc3│null │ ... │
│참조 │참조 │참조 │     │     │
└──┬──┴──┬──┴──┬──┴─────┴─────┘
   │     │     │
   │     │     │
   ▼     ▼     ▼
┌────┐ ┌────┐ ┌────┐
│123 │ │456 │ │789 │
│홍  │ │김  │ │이  │
│1000│ │2000│ │5000│
└────┘ └────┘ └────┘

findAccount("456") 실행:
   ↓
[0] 비교: "123" ≠ "456" → 다음
[1] 비교: "456" = "456" → 찾음! ✅
   ↓
accountsArray[1] 반환

4️⃣ 예금 (deposit)

실행 흐름

사용자 입력
    ↓
계좌번호: "123-456"
예금액: 5000
    ↓
findAccount("123-456") 호출
    ↓
Account 객체 찾기
    ↓
계좌가 없으면 → "계좌가 없습니다."
    ↓
계좌가 있으면 → 잔액 증가
    account.setBalance(
        account.getBalance() + money
    )

메모리 변화

예금 전

┌─────────────────────────────────────┐
│ Account 객체 (accountsArray[0])     │
├─────────────────────────────────────┤
│ ano: "123-456"                      │
│ owner: "홍길동"                      │
│ balance: 10000  ←─── 현재 잔액      │
└─────────────────────────────────────┘

예금 실행

account.setBalance(account.getBalance() + money)
         ↓
account.setBalance(10000 + 5000)
         ↓
account.setBalance(15000)
         ↓

예금 후

┌─────────────────────────────────────┐
│ Account 객체 (accountsArray[0])     │
├─────────────────────────────────────┤
│ ano: "123-456"                      │
│ owner: "홍길동"                      │
│ balance: 15000  ←─── 증가된 잔액    │
└─────────────────────────────────────┘

5️⃣ 출금 (withdraw)

실행 흐름

사용자 입력
    ↓
계좌번호: "123-456"
출금액: 3000
    ↓
findAccount("123-456") 호출
    ↓
Account 객체 찾기
    ↓
계좌가 없으면 → "계좌가 없습니다."
    ↓
계좌가 있으면 → 잔액 확인
    account.getBalance() >= money?
    ↓
    잔액 부족 → "잔액이 부족합니다."
    ↓
    잔액 충분 → 잔액 감소
    account.setBalance(
        account.getBalance() - money
    )

메모리 변화

출금 전

┌─────────────────────────────────────┐
│ Account 객체                        │
├─────────────────────────────────────┤
│ balance: 15000  ←─── 현재 잔액      │
└─────────────────────────────────────┘

출금 검증 및 실행

1. 잔액 확인: 15000 >= 3000? → ✅ 충분
2. 잔액 감소: 15000 - 3000 = 12000
3. balance 필드 업데이트

출금 후

┌─────────────────────────────────────┐
│ Account 객체                        │
├─────────────────────────────────────┤
│ balance: 12000  ←─── 감소된 잔액    │
└─────────────────────────────────────┘

6️⃣ 계좌 이체 (transfer)

실행 흐름

사용자 입력
    ↓
출금 계좌번호: "123-456"
입금 계좌번호: "456"
이체금액: 5000
    ↓
findAccount("123-456") → account
findAccount("456") → sendAccount
    ↓
두 계좌 모두 존재하는가?
    ↓
    없으면 → "계좌가 없습니다."
    ↓
    있으면 → 출금 계좌 잔액 확인
    account.getBalance() >= money?
    ↓
    잔액 부족 → "잔액이 부족합니다."
    ↓
    잔액 충분 → 이체 실행
    account.setBalance(account.getBalance() - money)
    sendAccount.setBalance(sendAccount.getBalance() + money)

메모리 변화

이체 전 상태

출금 계좌 (accountsArray[0]):
┌─────────────────────────────────────┐
│ Account 객체                        │
├─────────────────────────────────────┤
│ ano: "123-456"                      │
│ owner: "홍길동"                      │
│ balance: 12000  ←─── 출금 계좌      │
└─────────────────────────────────────┘

입금 계좌 (accountsArray[1]):
┌─────────────────────────────────────┐
│ Account 객체                        │
├─────────────────────────────────────┤
│ ano: "456"                          │
│ owner: "김철수"                      │
│ balance: 20000  ←─── 입금 계좌      │
└─────────────────────────────────────┘

이체 실행 과정

1단계: 출금 계좌 잔액 감소
   account.setBalance(12000 - 5000)
   account.setBalance(7000)

2단계: 입금 계좌 잔액 증가
   sendAccount.setBalance(20000 + 5000)
   sendAccount.setBalance(25000)

이체 후 상태

출금 계좌 (accountsArray[0]):
┌─────────────────────────────────────┐
│ Account 객체                        │
├─────────────────────────────────────┤
│ ano: "123-456"                      │
│ owner: "홍길동"                      │
│ balance: 7000  ←─── 5000 감소       │
└─────────────────────────────────────┘

입금 계좌 (accountsArray[1]):
┌─────────────────────────────────────┐
│ Account 객체                        │
├─────────────────────────────────────┤
│ ano: "456"                          │
│ owner: "김철수"                      │
│ balance: 25000  ←─── 5000 증가      │
└─────────────────────────────────────┘

총액: 7000 + 25000 = 32000 (변화 없음 ✅)

7️⃣ 계좌 목록 (accountList)

실행 흐름

accountList() 호출
    ↓
배열을 처음부터 끝까지 순회
(for문: j = 0 ~ 99)
    ↓
accountsArray[j] != null?
    ↓
    null이면 → 다음 요소로
    ↓
    null이 아니면 → 계좌 정보 출력
    System.out.printf("%s %4s %4d\n",
        accountsArray[j].getAno(),
        accountsArray[j].getOwner(),
        accountsArray[j].getBalance()
    )

시각적 표현

accountsArray 상태:
┌─────┬─────┬─────┬─────┬─────┬─────┐
│ [0] │ [1] │ [2] │ [3] │ ... │[99] │
├─────┼─────┼─────┼─────┼─────┼─────┤
│ Acc1│ Acc2│ Acc3│null │ ... │null │
└──┬──┴──┬──┴──┬──┴─────┴─────┴─────┘
   │     │     │
   ▼     ▼     ▼
출력   출력   출력

출력 결과:
123-456 홍길동 7000
456     김철수 25000
789     이영희 5000

8️⃣ 전체 데이터 흐름도

프로그램 실행 흐름

┌─────────────────────────────────────┐
│         프로그램 시작                │
│      (main 메서드 실행)              │
└───────────┬─────────────────────────┘
            │
            ▼
┌─────────────────────────────────────┐
│      메뉴 표시 및 선택               │
│  1.계좌생성 2.목록 3.예금            │
│  4.출금 5.이체 6.종료               │
└───────────┬─────────────────────────┘
            │
    ┌───────┴───────┐
    │               │
    ▼               ▼
┌────────┐    ┌─────────┐
│ case 1 │    │ case 2  │
│ 계좌생성│    │ 계좌목록 │
└───┬────┘    └────┬────┘
    │              │
    ▼              ▼
┌─────────────┐  ┌─────────────┐
│Account 객체 │  │ 배열 순회    │
│생성 및 배열 │  │ 계좌 정보    │
│에 저장      │  │ 출력        │
└─────────────┘  └─────────────┘

    │               │
    ▼               ▼
┌────────┐    ┌─────────┐
│ case 3 │    │ case 4  │
│ 예금   │    │ 출금    │
└───┬────┘    └────┬────┘
    │              │
    ▼              ▼
┌─────────────┐  ┌─────────────┐
│계좌 찾기    │  │계좌 찾기    │
│잔액 증가    │  │잔액 감소    │
└─────────────┘  └─────────────┘

    │               │
    └───────┬───────┘
            │
            ▼
        ┌────────┐
        │ case 5 │
        │ 계좌이체│
        └───┬────┘
            │
            ▼
        ┌─────────────┐
        │출금계좌 찾기 │
        │입금계좌 찾기 │
        │출금계좌 감소 │
        │입금계좌 증가 │
        └─────────────┘

9️⃣ 핵심 개념 시각화

배열과 객체의 관계

┌─────────────────────────────────────────┐
│       accountsArray (Stack)             │
├─────────────────────────────────────────┤
│ [0] → Account 객체 (주소: 0x100)        │
│ [1] → Account 객체 (주소: 0x200)        │
│ [2] → Account 객체 (주소: 0x300)        │
│ [3] → null                              │
│ ...                                     │
│[99] → null                              │
└────┬────┬────┬──────────────────────────┘
     │    │    │
     │    │    │ 참조
     ▼    ▼    ▼
┌────┐ ┌────┐ ┌────┐
│Acc1│ │Acc2│ │Acc3│ (Heap)
│0x100│ │0x200│ │0x300│
└────┘ └────┘ └────┘

데이터 변경의 전파

예금 실행 시:

사용자 입력: 계좌번호 "123-456", 예금액 5000
    ↓
findAccount("123-456")
    ↓
accountsArray[0] 반환 (Account 객체 참조)
    ↓
account.setBalance(account.getBalance() + 5000)
    ↓
Account 객체의 balance 필드 변경
    ↓
accountsArray[0]이 참조하는 객체의 값이 변경됨
    ↓
같은 객체를 참조하는 모든 곳에서 변경된 값이 반영됨

🔟 메모리 상태 변화 타임라인

시나리오: 계좌 생성 → 예금 → 출금 → 이체

초기 상태

accountsArray: 모두 null

1. 계좌 생성 (홍길동, 10000원)

accountsArray[0] → Account { "123-456", "홍길동", 10000 }

2. 계좌 생성 (김철수, 20000원)

accountsArray[0] → Account { "123-456", "홍길동", 10000 }
accountsArray[1] → Account { "456", "김철수", 20000 }

3. 예금 (홍길동 계좌에 5000원)

accountsArray[0] → Account { "123-456", "홍길동", 15000 } ← 변경
accountsArray[1] → Account { "456", "김철수", 20000 }

4. 출금 (홍길동 계좌에서 3000원)

accountsArray[0] → Account { "123-456", "홍길동", 12000 } ← 변경
accountsArray[1] → Account { "456", "김철수", 20000 }

5. 이체 (홍길동 → 김철수, 5000원)

accountsArray[0] → Account { "123-456", "홍길동", 7000 } ← 변경
accountsArray[1] → Account { "456", "김철수", 25000 } ← 변경

💡 핵심 정리

데이터 저장 방식

  • 배열: Account 객체들의 참조를 저장
  • 객체: Heap 메모리에 실제 데이터 저장
  • 참조: 배열의 각 요소는 객체의 주소를 가짐

데이터 접근 방식

  • 직접 접근: accountsArray[0] → Account 객체
  • 간접 접근: findAccount() → 배열 탐색 → Account 객체 반환

데이터 변경

  • 배열 요소 변경: accountsArray[i] = newAccount (객체 교체)
  • 객체 필드 변경: account.setBalance() (객체 내부 변경)

중요 포인트

  1. 배열은 참조를 저장: Account 객체가 아니라 객체의 주소(참조)를 저장
  2. 객체 공유: 같은 Account 객체를 참조하면 같은 데이터를 공유
  3. 참조 변경: accountsArray[i] = null 또는 다른 객체로 변경 가능
  4. 필드 변경: account.setBalance()로 객체의 내부 상태만 변경

📚 관련 개념

  • 배열 (Array)
  • 객체 참조 (Object Reference)
  • 메모리 구조 (Stack vs Heap)
  • 메서드 호출과 파라미터 전달
  • 객체 상태 변경 (State Change)

'BackEnd > Java' 카테고리의 다른 글

배열-vs-ArrayList-비교  (0) 2026.01.16
8_2 .학생 관리 시스템 실습 문제  (0) 2026.01.15
5_1 . 이차원 배열 연습문제  (0) 2026.01.06
15장. 미니 프로젝트 & 실습  (0) 2026.01.04
Java와 데이터베이스 연동  (0) 2026.01.04