목차
05 클래스와 객체 II
5.1 객체의 생성과 소멸
참조 변수와 대입 연산
- 기초 변수의 값을 다른 변수에 대입하게 되면 변수의 값이 복사된다.
(오른쪽 변수의 값이 복사되어서 왼쪽 변수로 대입) - 참조 변수의 경우
Television tv1 = new Television();
Television tv2 = tv1;
- 언뜻 보기에 서로 다른 객체를 참조하는 것 같지만, 실제로는 동일한 객체를 참조
객체의 소멸과 가비지 컬렉션
- 자바에는 객체를 생성하는 연산자는 있지만, 객체를 삭제하는 연산자는 없다.
- 자바에서 객체들은 new 연산자에 의하여 히프 메모리에서 할당된다.
- 메모리는 무한 하지 않기 때문에 JVM에서 사용되지 않는 객체들을 삭제하여 메모리를 확보하는 것이 필요하다.
- 가비지 컬렉션 : 자동 메모리 삭제 시스템
가비지 컬렉션
- 가비지 컬레터는 히트 메모리에서 더 이상 필요 없는 객체를 찾아 지우는 작업을 한다.
- 가비지 컬렉터가 수행되면 가비지 컬렉터를 제외한 나머지 자바 애플리케이션은 모든 동작을 멈춘다.
- 가바지 컬렉터가 작업을 완료한 이후에 중단한 작업을 다시 시작한다.
- 이때, 사용자는 잠시 컴퓨터 서비스가 중단되는 것처럼 느낄 수 있음
- 가비지 컬렉터는 JVM의 중요한 부분이고, JVM 중 가장 대표적인 것은 오라클사의 HotSpot이다.
- HotSpot은 많은 가비지 컬렉션 옵션을 제공하고, 모든 가비지 컬렉터는 동일한 기본 프로세스를 따른다.
- 첫 번째 단계에서 참조되지 않은 객체가 식별되고 가비지 수집 준비가 된것으로 표시됨
- 두 번째 단계에서는 표시된 객체 삭제, 이후 압축할 수 있다.
가비지 컬렉션 요청
- 개발자는 System 객체의 gc() 메소드를 호출하여서 가비지 컬렉션을 요청할 수 있다.
- 하지만, 가비지 컬렉터가 수행되면 모든 다른 애플리케이션이 멈추기 때문에
가비지 컬렉터의 실행 여부는 전적으로 JVM이 판단한다. - 따라서 비결정적이며 런타임에 가비지 수집이 발생할 때를 예측할 방법이 없다.
- 가비지 컬렉션을 조정하는 가장 좋은 방법은 JVM을 실행할 때 플래그를 설정 하는 것.
5.2 인수 전달 방법
메소드를 호출할 때, 인수가 전달되는 방법은 기본적으로 "값에 의한 호출(call-by-value)"이다.
이때는 인수의 값이 복사되어 매개 변수로 전달된다.
하지만 전달되는 인수가 객체인 경우에 주의할 점이 있다.
기초형 값이 전달되는 경우
- 전달하는 인수가 기초형 변수인 경우에는 호출자가 전달하는 인수의 값이 매개 변수로 복사된다.
- 인수의 복사본이 만들어지고 매개 변수를 변경하여도 메소드 외부에 있는 인수에 영향을 주지 않는다.
객체가 전달되는 경우
- 객체를 메소드로 전달하게 되면 객체의 참조값만 복사되어서 전달되어
메소드의 매개 변수도 동일한 객체를 참조하게 된다. - 매개 변수를 통하여 객체의 내용을 변경하게 되면 인수가 가리키는 객체도 변경된다.
배열이 전달되는 경우
- 배열 원소가 메소드로 전달된다면 값이 복사되어 전달
- 배열 전체가 전달된다면 참조값이 복사되어 전달
5.3 정적 멤버
여러 개의 객체가 하나의 변수를 공유해야 되는 경우가 있는데, 이러한 멤버를 정적 멤버(static memer) 또는 클래스 멤버(class member)라고 한다.
필드를 정의할 때 앞에 static을 붙이면 정적 멤버, 메소드 앞에 static을 붙이면 정적 메소드가 된다.
이외에도 static 키워드는 자바에서 다양하게 사용된다.
정적 멤버
- 객체마다 별도로 소유하는 멤버는 인스턴스 멤버
- 다른 객체와 공유하는 멤버는 정적 멤버
인스턴스 멤버 vs 정적 멤버
- 정적 변수는 클래스당 하나만 생성되는 변수
- 정적 변수는 객체 없이도 사용이 가능하다.
정적 변수의 생성 시기
- 클래스가 자바 가상 기계에 적재되는 순간 생성된다.
- 정적 변수는 프로그램이 종료되어야 비로소 소멸된다.
정적 메소드
- 객체를 생성할 필요 없이 메소드를 사용할 수 있다.
예제 (정적 메소드 활용하기)
nk값을 계산하는 power() 메소드와 절대값 메소드를 제공하는 MyMath 클래스 만들기
package practice;
public class MyMath {
public static int power(int n, int k) {
int result = 1;
for (int i = 0; i < k; i++) {
result *= n;
}
return result;
}
public static int abs(int n) {
return n < 0 ? -n : n;
}
}
package practice;
public class MyMathTest {
public static void main(String[] args) {
System.out.println("10의 3승은 : " + MyMath.power(10, 3));
}
}
정적 변수의 활용
- 정적 변수는 상수를 정의하는 용도로 사용된다.
- 정적 메소드는 정적 멤버만 사용할 수 있다. 인스턴스 멤버 사용 X
- 정적 메소드에서 정적 메소드를 호출하는 것은 가능하다.
- 정적 메소드는 this를 사용할 수 없다.
final 키워드
- 상수를 정의할 때 static과 final 수식어를 동시에 사용하는 경우가 많다.
정적 블록
- 클래스가 메모리에 로드될 때 한번만 실행되는 문장들의 집합.
- 일반적으로 정적 변수들을 초기화하는 용도로 많이 사용된다.
LAB
싱글톤 패턴
객체 중에는 전체 시스템을 통틀어서 딱 하나만 존재하여야 하는 것들이 있다. 이럴 때 사용하는 것이 싱글톤 패턴.
즉, 하나의 프로그램 내에서 하나의 인스턴스만을 생성.
이러한 경우에은 객체를 생성 할 때 new를 사용하지 않고 정적 메소드 getInstance()를 호출
package practice;
class Single{
private static Single instance = new Single();
private Single() {}
public static Single getInstance() {
return instance;
}
}
public class SingleTest {
public static void main(String[] args) {
Single obj1 = Single.getInstance();
Single obj2 = Single.getInstance();
System.out.println(obj1);
System.out.println(obj2);
}
}
practice.Single@4e50df2e
practice.Single@4e50df2e
getInstance() 호출이 반복적으로 이뤄져도 처음 생성된 객체의 참조값을 계속하여 반환해준다.
생성자의 접근 제어가 private으로 되어 있어 외부에서 생성자 호출을 통한 객체 생성도 불가능
5.4 객체 배열
- 객체 배열에는 객체에 대한 참조값이 저장되어 있음
동적 객체 배열
- 자바 표준 배열은 크기가 결저오디면 변경하기가 힘들어서 동적 배열을 많이 사용함
- ArrayList 클래스를 이용하고 객체 배열이라고 해서 딱히 다를건 없음
- 참조변수명.add(new 생성자);
Summary
- 객체가 자신을 가리키는 참조값을 잃으면 사용이 불가능해진다. 이런 객체들은 정리 대상으로 표시되며 나중에 가용 메모리가 부족해지면 가비지 컬렉터에 의하여 삭제된다.
- 메소드로 기초형의 값을 전달하면 복사되지만, 메소드에 객체를 전달하면 객체의 참조값이 전달된다. 메소드 안에서는 객체 참조값을 이용하여 객체 원본을 변경할 수 있다.
- 인스턴스 멤버란 객체마다 하나씩 생성되는 멤버이다.
- 정적 멤버는 모든 객체를 통틀어서 하나만 생성된다. 객체를 생성하지 않고 클래스 이름만으로 접근할 수 있다.
- 정적 멤버를 선언하려면 앞에 static을 붙인다.
- 정적 메소드에서는 정적 멤버에만 접근이 가능하다. 인스턴스 멤버는 사용할 수 없다.
- 객체 배열은 객체를 저장하는 배열이다. 배열 자체도 객체이므로 먼저 배열 객체를 생성하고 배열 요소에 객체를 생성하여 채워야 한다.
- 동적 객체 배열을 생성하려면 ArrayList를 사용한다.
Programming
ATM 구현 계좌는 Account 클래스 다음과 같은 사용자 인터페이스
PIN을 입력하시오 : 1234
1. 현금 입금
2. 현금 인출
3. 계좌 이체
4. 종료
번호를 선택하세요 : 1
입금액 : 1000000
현재 잔액은 1000000입니다.
------------------------------
번호를 선택하세요 : 3
이체액 : 30000
이체 계좌 번호 : 1010000
이체되었습니다.
------------------------------
Account 클래스
package basic.practice;
public class Account {
private static int accountNumberCount = 101000;
private String name;
private String pinNumber;
private int accountNumber;
private int balance;
public Account(String name, String pinNumber) {
this.name = name;
this.pinNumber = pinNumber;
this.accountNumber = ++accountNumberCount;
}
// getter
public static int getAccountNumberCount() {
return accountNumberCount;
}
public String getPinNumber() {
return pinNumber;
}
public int getAccountNumber() {
return accountNumber;
}
public String getName() {
return name;
}
public int getBalance() {
return balance;
}
// 0. pinNumber 확인
public static Account checkPinNumber(String name, String pinNumber, Account[] account) {
for (int i = 0; i < account.length; i++) {
if (account[i].getName().equals(name) && account[i].getPinNumber().equals(pinNumber)) {
System.out.println("확인되었습니다.");
return account[i];
}
}
System.out.println("잘못된 입력입니다.");
return null;
}
// 1. 현금 입금
public void deposit(Account account, int money) {
balance += money;
}
// 2. 현금 인출
public void withdraw(Account account, int money) {
if (balance < money) {
System.out.println("잔액이 부족합니다.");
return;
}
balance -= money;
}
// 3. 계좌 이체
public void transfer(Account toAccount, int money) {
if (this.balance < money) {
System.out.println("잔액이 부족합니다.");
return;
}
this.withdraw(this , money);
toAccount.deposit(toAccount, money);
System.out.println("이체되었습니다.");
}
// 계좌 번호로 계좌 찾기
public Account findAccount(int accountNumber, Account[] account) {
for (int i = 0; i < account.length; i++) {
if (account[i] != null && accountNumber == account[i].getAccountNumber()) {
return account[i];
}
}
System.out.println("해당하는 계좌가 없습니다.");
return null;
}
}
ATM 클래스
package basic.practice;
import java.util.Scanner;
public class ATM {
public static void main(String[] args) {
Account[] accountList = new Account[100];
accountList[0] = new Account("홍길동", "1234");
accountList[1] = new Account("이순신", "1111");
accountList[2] = new Account("강감찬", "1212");
final int DEPOSITE = 1;
final int WITHDRAW = 2;
final int TRASNFER = 3;
final int END = 4;
boolean flag = true;
Scanner sc = new Scanner(System.in);
System.out.println("이름을 입력하세요");
String name = sc.nextLine();
System.out.println("pin을 입력하세요");
String pin = sc.nextLine();
Account user = Account.checkPinNumber(name, pin, accountList);
if (user != null) {
while (flag) {
System.out.println("\n1. 현금 입금");
System.out.println("2. 현금 출금");
System.out.println("3. 계좌 이체");
System.out.println("4. 종료");
System.out.println("번호를 선택하세요 : ");
int choice = sc.nextInt();
sc.nextLine();
if (choice == DEPOSITE) {
System.out.print("입금액 : ");
int money = sc.nextInt();
sc.nextLine();
user.deposit(user, money);
System.out.println("현재 잔액은 " + user.getBalance() + "입니다.");
System.out.println("------------------------------");
} else if (choice == WITHDRAW) {
System.out.println("출금액 : ");
int money = sc.nextInt();
sc.nextLine();
user.withdraw(user, money);
System.out.println("현재 잔액은 " + user.getBalance() + "입니다.");
System.out.println("------------------------------");
} else if (choice == TRASNFER) {
System.out.println("이체액 : ");
int money = sc.nextInt();
sc.nextLine();
System.out.println("이체 계좌 번호 : ");
int accountNumber = sc.nextInt();
sc.nextLine();
Account toAccunt = user.findAccount(accountNumber, accountList);
user.transfer(toAccunt, money);
} else if (choice == END) {
System.out.println("프로그램을 종료합니다.");
flag = false;
} else {
System.out.println("잘못된 입력입니다.");
}
}
} else {
System.out.println("프로그램을 종료합니다.");
}
sc.close();
}
}
결과
이름을 입력하세요
홍길동
pin을 입력하세요
1234
확인되었습니다.
1. 현금 입금
2. 현금 출금
3. 계좌 이체
4. 종료
번호를 선택하세요 :
1
입금액 : 10000
현재 잔액은 10000입니다.
------------------------------
1. 현금 입금
2. 현금 출금
3. 계좌 이체
4. 종료
번호를 선택하세요 :
5000
잘못된 입력입니다.
1. 현금 입금
2. 현금 출금
3. 계좌 이체
4. 종료
번호를 선택하세요 :
2
출금액 :
5000
현재 잔액은 5000입니다.
------------------------------
1. 현금 입금
2. 현금 출금
3. 계좌 이체
4. 종료
번호를 선택하세요 :
2
출금액 :
1000
현재 잔액은 4000입니다.
------------------------------
1. 현금 입금
2. 현금 출금
3. 계좌 이체
4. 종료
번호를 선택하세요 :
3
이체액 :
1000
이체 계좌 번호 :
101002
이체되었습니다.
1. 현금 입금
2. 현금 출금
3. 계좌 이체
4. 종료
번호를 선택하세요 :
4
프로그램을 종료합니다.
'Java > 교재 정리' 카테고리의 다른 글
07 추상 클래스, 인터페이스, 중첩 클래스 (1) | 2024.04.26 |
---|---|
06 상속 (1) | 2024.04.23 |
04 클래스와 객체 I (0) | 2024.04.15 |
03 조건문, 반복문, 배열 (0) | 2024.04.14 |
02 자바 프로그래밍 기초 (0) | 2024.04.12 |