안녕하세요, 여행벌입니다.

오늘은 static 선언을 이용한 클래스 변수, 클래스 메소드의 정의 방법 및 특징에 대해서 알아보겠습니다.


클래스 변수 (static 변수)

 지난 포스팅부터 계속 등장하던 '인스턴스 변수'는 인스턴스가 생성되었을 때, 생성된 인스턴스 안에 존재하는 변수입니다. 그러나 '클래스 변수'는 인스턴스의 생성과 상관없이 존재하는 변수입니다. 

 

 "클래스 변수는 클래스를 정의할 때 생성되는 변수입니다.

라서, 클래스 변수는 선언된 클래스의 모든 인스턴스가 공유하게 됩니다."

 

 같은 의미로 클래스 변수는 인스턴스 내에 존재하는 변수가 아니라 '어떠한 인스턴스에도 속하지 않는 상태로 클래스 정의시 메모리 공간에 딱 하나만 존재하게 되는 변수' 라고도 표현할 수 있습니다.

 클래스 변수도 저번 포스팅에서 다루었던 '접근 수준 지시자'의 규칙을 그대로 적용받기 때문에 public으로 선언되면 어디서든 접근이 가능하고 아래와 같이 default 로 선언되면 같은 패키지 내에서만 접근이 가능합니다. 그럼, 클래스 변수의 특징을 예제를 통해서 익혀보도록 하겠습니다.

package Hello;

class Example{
	static int n = 0;
	
	public void printN() {
		System.out.println("현재 n : " + n);
	}
}

public class test{
	public static void main(String args[]) {
		Example ex1 = new Example();
		ex1.n++;
		ex1.printN();
		Example.n++;
		ex1.printN();
	}
}


  클래스 변수 n과 n의 값을 출력해주는 메소드를 가지고 있는 클래스 Example을 만들고, 인스턴스를 생성해 n의 값을 1 증가시켜주고 출력을 진행했습니다. 그 후, Example.n++; 명령어를 수행하고 다시 한 번 메소드를 통해 n의 값을 출력했습니다. 결과는 다음과 같습니다.

 결과는 다음과 같습니다.

 

 "Example.n 과 같이 클래스 변수는 클래스의 이름을 통해서도 접근이 가능한 것을 알 수 있습니다."

 

package Hello;

class Example{
	static int n = 0;
	
	public void printN() {
		System.out.println("현재 n : " + n);
	}
}

public class test{
	public static void main(String args[]) {
		Example ex1 = new Example();
		ex1.n++;
		ex1.printN();
		Example.n++;
		ex1.printN();
		Example ex2 = new Example();
		ex2.printN();
	}
}


 이번에는 인스턴스를 하나 더 생성하고 클래스 변수의 특징을 알아보겠습니다. ex2 라는 인스턴스를 하나 더 만든 후, n의 값을 출력해보았습니다.

 다른 인스턴스인 ex2 에서 n 의 값을 출력해도 ex1의 n의 값과 동일한 것을 확인할 수 있습니다.

 

"클래스 변수는 모든 인스턴스가 공유하는 변수인 것을 확인할 수 있습니다."

 

 따라서 자연스럽게 우리는 클래스 변수가 인스턴스의 생성과 상관이 없는 것을 알 수 있습니다. 그럼, 클래스 변수는 언제 메모리에 할당되고 초기화가 될까요??

 다음 예제를 확인해보겠습니다.

package Hello;

class Example{
	static int n = 0;
	
	public void printN() {
		System.out.println("현재 n : " + n);
	}
}

public class test{
	public static void main(String args[]) {
		Example.n++;
		Example ex1 = new Example();
		ex1.printN();
	}
}

 이번에는 인스턴스 생성하기 전에 클래스 명을 이용해 클래스 변수에 접근했습니다. 결과는 다음과 같습니다.

 인스턴스를 생성하기도 전에 클래스 변수에 접근해 1을 증가시키는 코드가 제대로 작동한 것을 확인할 수 있습니다. 즉, 클래스 변수는 인스턴스 생성 이전에 메모리 공간에 존재하는 것을 확인할 수 있습니다.

 

 "클래스 변수는 클래스가 정의되는 순간 메모리 공간에 할당되고 초기화됩니다."

 

 그럼 클래스 변수는 언제 사용하면 좋을까요?? 모든 인스턴스가 참조해야하는 값이지만, 인스턴스가 각각 지녀야할 필요는 없을 때 클래스 변수를 이용하면 됩니다. 예를 들어, 환율과 관련된 클래스를 정의할 때, 모든 인스턴스가 각각 현재 환율을 저장하고 있을 필요는 없습니다. 따라서, 환율을 static으로 선언해 클래스 변수로 만들어 놓는다면 메모리를 아낄 수 있습니다.

클래스 메소드 (static 메소드)

 클래스 메소드는 클래스 변수와 마찬가지로 메소드에 static 선언이 들어간 것을 의미합니다. 또, 동일하게 인스턴스 생성 이전부터 접근이 가능하고 어느 인스턴스에 속하지 않습니다.

package Hello;

class Example{
	static int n = 0;
	
	public void printN() {
		System.out.println("현재 n : " + n);
	}
	public static void staticPrintN() {
		System.out.println("현재 n : " + n);
	}
}

public class test{
	public static void main(String args[]) {
		Example.n++;
		Example.staticPrintN();
	}
}


 클래스 변수와 마찬가지로 인스턴스 생성과 관계없이 클래스 명으로 접근할 수 있고, 결과는 아래와 같습니다.

 그럼 클래스 메소드는 어떤 경우에 사용하면 좋을까요?? 다음과 같은 경우에는 클래스 메소드로 정의하는 것이 더 좋습니다.

 

외부에 기능을 제공하기 위한 메소드

인스턴스 변수의 값을 참조하거나 수정하지 않는 메소드 / 인스턴스 메소드를 호출하지 않는 메소드

 

 하나씩 왜 클래스 메소드로 사용하면 좋은지 생각해보겠습니다.

 먼저, 오로지 기능을 제공하기 위한 메소드는 인스턴스 생성이 따로 필요없이 우리는 메소드(기능)만 이용하면 됩니다. 따라서, 클래스 메소드로 선언하는 것이 더 현명합니다. 우리가 자주 사용하면 Math 클래스는 기능 제공을 위한 목적으로 만들어진 클래스입니다.  따라서, 메소드와 변수들이 모두 Static으로 선언되어있습니다.

package Hello;

import java.lang.Math.*;

public class test{
	public static void main(String args[]) {
		System.out.println(Math.PI); // Math클래스의 PI static 변수
		Syttem.out.println(Math.abs(-1)); // Math클래스의 abs static 메소드
	}
}

 그 다음으로, 클래스 메소드는 인스턴스 변수의 값을 참조하거나 수정하지 않아야 되고 인스턴스 메소드를 호출하면 안된다고 했습니다. 그 이유는 간단합니다. 클래스 메소드는 인스턴스 생성과 상관 없이 참조할 수 있습니다. 하지만, 인스턴스 변수는 인스턴스 생성 시 선언되는 변수이므로 클래스 메소드에서 인스턴스 변수를 참조하거나 수정하면 에러가 날 수 밖에 없습니다. 마찬가지로 인스턴스 메소드도 인스턴스 생성 전까지 선언되지 않으므로 참조할 수 없습니다.

Static 초기화 블록

 위에서 클래스 변수는 모든 인스턴스가 공유해야하는 상황에서 유용하게 사용할 수 있다고 했습니다. 그럼, 클래스 변수는 어떻게 초기화를 해야될까요?? 생성자를 이용해서 초기화를 하면 인스턴스 생성 시 초기화가 진행되므로, 적절하지 않습니다. 따라서 자바에서는 "Static 초기화 블록" 을 지원해줍니다.

class example{
	static String date;
	static {
		LocalDate today = LocalDate.now();
		date = today.toString();
	}
}

  다음과 같이 static 초기화 블록을 사용하면 클래스 변수를 선언과 동시에 초기화 할 수 있고, 클래스 로딩 시 단 한 번 실행됩니다.


  

안녕하세요, 여행벌입니다.

오늘은 자바에서 지원하는 네 가지 종류의 '접근 수준 지시자' 인 public, protected, private, default 지시자에 대해서 다뤄보겠습니다.


Private 지시자

 private 지시자는 정보 은닉을 위해 사용합니다. 자바에서 말하는 '정보'란 클래스의 '인스턴스 변수' 를 의미합니다. private 지시자를 이용하면 인스턴스 변수 혹은 인스턴스 메소드를 클래스 내부에서만 접근이 가능하도록 할 수 있습니다. 그럼 왜 private 지시자가 등장했는지 다음 예제를 통해서 이해해보겠습니다.

package Hello;

public class BankAccount {
	public String accountInfo; // 계좌번호
	public int balance; // 현재 잔액
	// 생성자
	public BankAccount(String info, int money){
		accountInfo = info;
		balance = money;
	}
	// 계좌 번호를 알려주는 메소드(기능)
	public void printAccountInfo() {
		System.out.println("게좌 번호는 : " + accountInfo + "입니다");
	}
	// 잔고를 알려주는 메소드(기능)
	public void printBalance() {
		System.out.println("현재 계좌 잔고는 : " + balance + "입니다");
	}
	// 입금하는 메소드(기능)
	public void deposit(int amount) {
		System.out.println(amount + "원을 입금하셨습니다.");
		balance += amount;
	}
	// 출금하는 메소드(기능)
	public void withdraw(int amount) {
		if(amount > balance)
			System.out.println("잔고보다 많은 금액을 인출하려고 합니다.");
		else {
			System.out.println(amount + "원을 출금하셨습니다.");
			balance -= amount;
		}
	}
    

 저번 포스팅에서 정의했던 은행 계좌 클래스입니다. 인스턴스 변수로는 계좌번호를 나타내는 String 변수와 현재 잔액을 나타내는 int 변수가 있습니다. 또, 생성자를 이용해 인스턴스를 생성하며 변수를 초기화하고 있는 것을 볼 수 있습니다.

 우리는 balance 변수가 잔액을 나타내고 있으므로, 음수가 아니길 원합니다. ( 물론, 잔고가 마이너스 일 수도 있지만, 마이너스 통장이 아니라고 가정하겠습니다. ) 하지만, 우리는 다음과 같이 balance 변수를 음수로 초기화 할 수 있습니다.

    public static void main(String args[]) {
    	BankAccount account = new BankAccount("1002-000-0000", -1000);
    	account.printAccountInfo();
    	account.printBalance();
    }

 이건 우리가 원하는 상황이 아니므로, 다음과 같이 메소드를 추가하고 생성자를 수정해 balance 변수에 음수를 넣을 수 없게 만들어보겠습니다.

	public BankAccount(String info, int money){
		accountInfo = info;
		balance = setBalance(money);
	}
	public int setBalance(int money) {
		if(money < 0) return 0;
		else return money;
	}

 생성자 함수에서 입력 받는 초기 값을 setBalance 메소드를 통해서 음수라면 0으로 return 하도록 만들었습니다. 이러면 우리가 인스턴스 생성 시 음수 값을 입력하더라도 우리가 원하는대로 작동한다고 생각할 수 있습니다. 하지만, 다음과 같이 인스턴스를 생성하고 변수에 접근해 값을 변경한다면 막을 수 없습니다.

    public static void main(String args[]) {
    	BankAccount account = new BankAccount("1002-000-0000", 10000);
    	account.balance = -1000;
    }

 이때, private 지시자를 활용해야합니다.

package Hello;

public class BankAccount {
	private String accountInfo; // 계좌번호
	private int balance; // 현재 잔액
	// 생성자
	public BankAccount(String info, int money){
		accountInfo = info;
		balance = setBalance(money);
	}
	public int setBalance(int money) {
		if(money < 0) return 0;
		else return money;
	}
	// 계좌 번호를 알려주는 메소드(기능)
	public void printAccountInfo() {
		System.out.println("게좌 번호는 : " + accountInfo + "입니다");
	}
	// 잔고를 알려주는 메소드(기능)
	public void printBalance() {
		System.out.println("현재 계좌 잔고는 : " + balance + "입니다");
	}
	// 입금하는 메소드(기능)
	public void deposit(int amount) {
		System.out.println(amount + "원을 입금하셨습니다.");
		balance += amount;
	}
	// 출금하는 메소드(기능)
	public void withdraw(int amount) {
		if(amount > balance)
			System.out.println("잔고보다 많은 금액을 인출하려고 합니다.");
		else {
			System.out.println(amount + "원을 출금하셨습니다.");
			balance -= amount;
		}
	}
    public static void main(String args[]) {
    	BankAccount account = new BankAccount("1002-000-0000", 10000);
    	account.balance = -1000;
    }
}

 다음과 같이 정보 은닉을 원하는 인스턴스 변수에 private 지시자를 이용하면 클래스 내부에서만 접근이 가능합니다. 즉, setBalance 메소드와 생성자를 제외하고 balance 변수에 접근할 수 없게 되므로, 우리는 항상 balance 변수에 0 또는 양수가 저장되는 것을 보장받을 수 있습니다.

 이처럼 private 지시자를 이용하면 정보 은닉을 할 수 있고, 정보 은닉은 객체지향언어에서 굉장히 중요한 부분 중 하나입니다.

Public 지시자 / Default 지시자

 public 지시자는 클래스 정의 에서도 쓰이고, private 지시자와 마찬가지로 인스턴스 멤버인 인스턴스 변수와 인스턴스 메소드를 대상으로 사용할 수 있습니다. default 지시자도 마찬가지로 클래스 정의 에서도 쓰이고, 인스턴스 멤버를 대상으로 사용할 수 있습니다. default 지시자는 아무런 지시자도 없을 때, 기본 적으로 자바 컴파일러가 default 지시자를 적용합니다.

 먼저, 클래스에 다음과 같이 public이 정의가 된다면 이는 위치에 상관없이 어디서든 해당 클래스의 인스턴스를 생성할 수 있다는 뜻입니다.

public class A{
	// ~코드~
}

 public 없이 클래스를 정의하면 자동으로 default 지시자가 적용되고 이는 뒤에서 알아보겠습니다.

 즉, public 지시자를 이용해 클래스를 정의하면 같은 패키지가 아니더라도 어디서든 인스턴스 생성이 가능합니다! 이와 반대로 default 지시자를 이용하면 같은 패키지 내에서만 인스턴스 생성이 가능합니다.

 인스턴스 멤버를 대상으로 public 지시자를 이용해도 비슷합니다. 즉, public 으로 선언된 인스턴스 변수와 인스턴스 메소드는 동일 패키지가 아니더라도 사용할 수 있습니다.

package package1;

public class A{
	public void Hello() {
		System.out.println("안녕하세요");
	}
	void Bye() {
		System.out.println("안녕히가세요");
	}
}
package package2;

public class B{
	public void Hello(package1.A a) {
		A.Hello(); // 호출 가능! public 클래스 && public 매소드 이므로
		A.Bye(); // 호출 불가능! default 메소드 이므로
	}
}

 다음과 같이 서로 다른 패키지에서 클래스를 하나씩 정의했다고 하면 A 클래스의 Hello 메소드는 public 이지만 Bye 메소드는 default 이므로 B 클래스 내부에서 Hello 메소드는 호출이 가능하지만, Bye 메소드는 호출이 불가능합니다.

Protected 지시자

 protected 지시자는 인스턴스 멤버를 대상으로만 선언이 가능하고 다음 두 가지 특징을 가집니다.

● protected 선언은 default 선언이 허용하는 접근을 모두 허용한다.

● protected 선언은 default 선언이 허용하지 않는 '한 영역' 에서의 접근도 허용한다.

 protceted 지시자를 이용하면 다른 패키지 내에서도 상속 관계라면 인스턴스 멤버에 접근이 가능합니다!

package package1;

public class A{
	int num; // default 지시자
}
package package2;

public class B extends package1.A{
	public void Hello(int n) {
		num = n; // default 지시자로 선언된 상속된 변수를 접근 --> 에러
	}
}

 다음과 같이 서로 다른 2개의 package가 있다고 합시다. class B는 package1의 class A를 상속하지만, 인스턴스 변수인 num 이 default 지시자로 다른 패키지 내에서는 접근이 불가능합니다. 따라서 위의 코드는 에러가 발생합니다. 이때, protected 지시자를 이용하면 문제를 해결할 수 있습니다.

package package1;

public class A{
	protected int num; // default 지시자
}

 위와 같이 A 클래스의 인스턴스 변수를 protected 지시자로 선언하면 다른 패키지 내에서도 상속 관계가 형성된다면 인스턴스 멤버를 참조할 수 있습니다.

 

 이처럼 4개의 접근 수준 지시자는 정말 중요한 개념이고 꼭 사용되는 개념입니다. 마지막으로, 4가지 지시자를 정리하고 마무리 해보겠습니다.

지시자 클래스 내부 동일 패키지 상속 받은 클래스 이외의 영역
private O X X X
default O O X X
protected O O O X
public O O O O

 

안녕하세요, 여행벌입니다.

오늘은 자바 클래스에서 중요한 역할을 하는 '생성자' 혹은 '생성자 메소드' 에 대해서 다뤄보겠습니다.


생성자(Constructor)

 클래스는 데이터 + 메소드로 이루어진 집합체라고 저번 포스팅에서 설명했습니다. 생성자는 생성자 메소드로 일종의 메소드입니다! 그러나 다음과 같은 부분에서 일반적인 메소드와 차이가 있습니다.

● 생성자의 이름은 클래스의 이름과 동일해야 한다.

● 생성자는 값을 반환하지 않고 반환형도 표시하지 않는다.

 위의 두 조건이 생성자가 되기 위한 조건입니다. 위의 조건을 모두 만족하면 자바 컴파일러에 의해서 생성자로 인식하게 됩니다.

 그럼 생성자는 어떤 역할을 할까요?? 생성자는 클래스에 있는 인스턴스 변수(데이터) 를 초기화 하는 역할을 진행합니다! 즉, 인스턴스 생성 과정에서 초기화를 위해 자동으로 호출되는 일종의 메소드입니다.

 

 저번 포스팅에서 정의했던 계좌 클래스를 불러와서 생성자를 만들어보겠습니다.

package Hello;

public class BankAccount {
	private String accountInfo = "1002-***-******"; // 계좌번호
	private int balance = 0; // 현재 잔액
	// 계좌 번호를 알려주는 메소드(기능)
	public void printAccountInfo() {
		System.out.println("게좌 번호는 : " + accountInfo + "입니다");
	}
	// 잔고를 알려주는 메소드(기능)
	public void printBalance() {
		System.out.println("현재 계좌 잔고는 : " + balance + "입니다");
	}
	// 입금하는 메소드(기능)
	public void deposit(int amount) {
		System.out.println(amount + "원을 입금하셨습니다.");
		balance += amount;
	}
	// 출금하는 메소드(기능)
	public void withdraw(int amount) {
		if(amount > balance)
			System.out.println("잔고보다 많은 금액을 인출하려고 합니다.");
		else {
			System.out.println(amount + "원을 출금하셨습니다.");
			balance -= amount;
		}
	}
	public static void main(String args[]) {
		BankAccount account1 = new BankAccount();
		account1.printAccountInfo();
		account1.printBalance();
		account1.deposit(10000);
		account1.printBalance();
		account1.withdraw(9000);
		account1.printBalance();
	}
}

 클래스의 이름이 BankAccount 이므로 생성자 조건에 의해 생성자 메소드의 이름은 BankAccount 가 되고, 인스턴스 변수가 계좌번호와 현재 잔액 2가지가 있으므로 매개 변수로 String, int 를 입력받아야합니다. 또, 값을 반환하지 않고 반환형도 표시하지 않아야되므로 다음과 같이 생성자를 만들 수 있습니다.

public BankAccount(String info, int money){
	accountInfo = info;
	balance = money;
}

 최종적으로 다음과 같이 생성자를 포함한 클래스를 만들 수 있습니다.

package Hello;

public class BankAccount {
	private String accountInfo = "1002-***-******"; // 계좌번호
	private int balance = 0; // 현재 잔액
	// 생성자
	public BankAccount(String info, int money){
		accountInfo = info;
		balance = money;
	}
	// 계좌 번호를 알려주는 메소드(기능)
	public void printAccountInfo() {
		System.out.println("게좌 번호는 : " + accountInfo + "입니다");
	}
	// 잔고를 알려주는 메소드(기능)
	public void printBalance() {
		System.out.println("현재 계좌 잔고는 : " + balance + "입니다");
	}
	// 입금하는 메소드(기능)
	public void deposit(int amount) {
		System.out.println(amount + "원을 입금하셨습니다.");
		balance += amount;
	}
	// 출금하는 메소드(기능)
	public void withdraw(int amount) {
		if(amount > balance)
			System.out.println("잔고보다 많은 금액을 인출하려고 합니다.");
		else {
			System.out.println(amount + "원을 출금하셨습니다.");
			balance -= amount;
		}
	}
    
}

 위에서 생성자는 인스턴스를 만들 때 인스턴스 변수를 초기화하는 역할을 한다고 했습니다. 그러면 어떻게 생성자를 이용해 인스턴스를 선언할 수 있을까요??

    public static void main(String args[]) {
    	BankAccount account = new BankAccount("1002-000-0000", 1000);
    	account.printAccountInfo();
    	account.printBalance();
    }

 위와 같이 인스턴스를 생성할 때, 생성자 함수에 매개 변수를 같이 입력해주면 됩니다.

 결과는 다음과 같이 인스턴스를 선언하기만 했는데 초기화가 되어있는 것을 확인할 수 있습니다.

디폴트 생성자(Default Constructor)

 인스턴스를 생성하면서 인스턴스 변수를 초기화하는 생성자에 대해서 위에서 다뤄보았습니다. 그러면 저번 포스팅에서 다뤘던 생성자가 없는 클래스들은 제대로된 클래스가 아닐까요?? 먼저, 모든 인스턴스 생성의 마지막 단계는 생성자 호출입니다. 즉, 생성자 호출이 생략된 인스턴스는 인스턴스가 아닙니다. 

 그럼 우리가 생성자 없이 정의했던 클래스들은 모두 잘못 정의된 클래스인데 에러가 나지않고 컴파일이 진행된 것일까요??

 생성자를 생략한 상태의 클래스를 정의하면 자바 컴파일러가 '디폴트 생성자' 라는 것을 클래스 정의에 자동으로 넣어줍니다. 그래서 생성자가 없어도 에러가 나지 않고 클래스 정의가 진행된 것입니다.

 위와 같이 생성자 없기 클래스를 정의하면 아래와 자동으로 디폴트 생성자가 추가되어 다음과 같은 클래스가 정의됩니다.

public class BankAccount{
	private String accountINfo ="";
	private int balance;
	public BacnkAccount() { 
		// Empty 실제로 비어 있음.
	}; 
	public void printAccountInfo() {
		// ~ 코드 ~
	}
	public void printBalance() {
		// ~ 코드 ~
	}
	public void deposit(int amount) {
		// ~ 코드 ~
	}
	public void withdraw(int amount) {
		// ~ 코드 ~
	}
}

   

안녕하세요, 여행벌입니다.

오늘은 자바에서 가장 중요한 개념인 클래스와 메소드, 객체에 대해서 알아보겠습니다.


클래스

 클래스(Class)는 유사한 특성을 지닌 객체들을 묶어 놓은 집합체라고 간단하게 표현할 수 있습니다.

 또, 클래스는 데이터(Data) + 메소드(Method) 라고 얘기할 수 있습니다. 프로그램 상에서 유지하고 관리해야 할 데이터와 데이터를 처리하고 조작하는 기능인 메소드를 같이 묶어 놓은 것입니다. 데이터는 '변수의 선언' 을 통해 유지 및 관리가 되고, 변수에 저장된 데이터는 '메소드의 호출'을 통해 처리가 됩니다.

 즉, 유사한 특성을 지닌 데이터와 그 데이터를 다루는 기능들이 묶여 있는 것! 이라고 이해하시면 될 것 같습니다.

 

 계좌를 나타내는 클래스를 만들어 보겠습니다. 데이터로는 계좌 번호와 현재 잔액이 필요할 것이고, 메소드(기능)으로는 입금, 출금, 계좌 번호 확인, 잔액 확인이 필요할 것입니다.

package Hello;

public class BankAccount {
	private String accountInfo = "1002-***-******"; // 계좌번호
	private int balance = 0; // 현재 잔액
	// 계좌 번호를 알려주는 메소드(기능)
	public void printAccountInfo() {
		System.out.println("게좌 번호는 : " + accountInfo + "입니다");
	}
	// 잔고를 알려주는 메소드(기능)
	public void printBalance() {
		System.out.println("현재 계좌 잔고는 : " + balance + "입니다");
	}
	// 입금하는 메소드(기능)
	public void deposit(int amount) {
		System.out.println(amount + "원을 입금하셨습니다.");
		balance += amount;
	}
	// 출금하는 메소드(기능)
	public void withdraw(int amount) {
		if(amount > balance)
			System.out.println("잔고보다 많은 금액을 인출하려고 합니다.");
		else {
			System.out.println(amount + "원을 출금하셨습니다.");
			balance -= amount;
		}
	}
	public static void main(String args[]) {
		BankAccount account1 = new BankAccount();
		account1.printAccountInfo();
		account1.printBalance();
		account1.deposit(10000);
		account1.printBalance();
		account1.withdraw(9000);
		account1.printBalance();
	}
}

 코드를 뜯어보겠습니다.

"BankAccount" 라는 이름의 계좌를 나타내는 클래스를 만들고, 그 안에 계좌번호와 현재 잔고를 나타내는 데이터를 2개 선언하고, 계좌 번호, 현재 잔고를 출력하는 메소드 2개와 입금, 출금을 하는 메소드 2개와 main 메소드가 선언되어있는 것을 확인할 수 있습니다. main 메소드는 뒤에서 자세히 다뤄보겠습니다.

 이렇듯 클래스는 "데이터" + "메소드" 의 집합체이고 위와 같이 클래스를 정의할 수 있습니다.

인스턴스 변수, 인스턴스 메소드

 위에서 우리는 다음과 같이 클래스를 선언했습니다. 

 이때, 데이터에 해당하는 accountInfo / balance 를 "인스턴스 변수" 라 하고 메소드를 "인스턴스 메소드" 라고 부릅니다.

· 인스턴스 변수 : 클래스 내에 선언된 변수

· 인스턴스 메소드 : 클래스 내에 정의된 메소드

인스턴스 변수는 메소드 내부가 아니라 클래스 내부에 선언된 변수입니다. 따라서 "같은 클래스 내에 위치한 메소드 내에서 접근이 가능" 합니다.

클래스 인스턴스화

 클래스는 붕어빵 틀에 많이 비유하고는 합니다. 우리가 위와 같이 클래스를 정의하면 우리는 클래스라는 틀을 이용해 "인스턴스" 를 찍어 내야 사용이 가능합니다. 즉, 클래스를 인스턴스화해서 "인스턴스" 를 만들고, "인스턴스"는 이제 실제 메모리 공간에 존재하게 됩니다.

 위와 같이 우리는 클래스를 인스턴스화해 "인스턴스"를 생성할 수 있습니다. 클래스를 기반으로 만들어진 "인스턴스"를 가리켜 "객체" 라고도 표현합니다. 자바가 객체지향언어인 이유가 클래스 기반 언어이기 때문입니다.

 키워드 'new'를 통해서 인스턴스를 생성하면 생성된 인스턴스의 주솟값이 반환되고, 이렇듯 인스턴스를 담는 변수를 "참조변수"라고 합니다. 즉 참조변수에는 생성된 인스턴스의 주솟값이 저장되는 셈입니다.

참조변수의 특성

· 참조변수는 인스턴스를 참조한다.

· 참조변수는 인스턴스를 가리킨다.

 참조변수는 인스턴스의 주솟값을 저장하고 있습니다. 따라서, 하나의 인스턴스를 다음과 같이 둘 이상의 참조변수가 동시에 참조하는 것도 가능합니다.

account1, account2 라는 이름을 가진 참조변수를 2개 선언하고, account2 참조변수는 account1 이 가리키는 인스턴스를 그대로 참조하는 코드입니다. 따라서, account1에 deposit 메소드를 이용해 "1000" 을 입금하면, account2가 참조하는 인스턴스의 잔고가 1000원으로 증가한 것 이므로 결과는 다음과 같습니다.

참조변수의 매개변수 선언

 메소드를 호출할 때 값을 전달할 수 있고, 이를 우리는 "매개변수" 라고 합니다. 참조변수 또한 매개변수로 메소드에 전달할 수 있습니다.

 다음과 같이 메소드의 매개변수로 참조변수인 BankAccount 를 전달할 수 있고, 매개변수를 이용해 메소드를 호출할 수 있습니다.

참조변수에 null 대입

 참조변수가 가리키는 인스턴스와의 관계를 끊고 아무런 인스턴스도 참조하지 않도록 하고 싶으면 참조변수에 null을 대입하면 됩니다.

 참조변수 account1에 null을 대입하면 참조하는 인스턴스와의 관계가 끊깁니다.

메소드

 메소드란 클래스 내에서 "기능" 을 담당하는 부분입니다. 메소드는 기본 적으로 어떤 값을 전달받고, 어떤 값을 돌려줍니다. 물론 어떤 값을 전달 안받아도 되고, 값을 돌려주지 않아도 되는 기능들은 값을 전달받거나, 전달하는 과정이 생략돼도 됩니다.

 인사를 해주는 메소드를 만들어보았습니다. 어떤 값을 전달받을 필요도, 전달할 필요도 없으므로 다음과 같이 값을 전달하는 부분은 void 로, 값을 전달받는 부분은 비어있는 것을 확인할 수 있습니다.

 "Input" 이라고 박스친 부분이 메소드에서 값을 전달받는 부분이고, 이때 전달받는 값을 "매개변수" 라고 합니다. 또, "Output" 이라고 박스친 부분이 메소드에서 기능을 다 수행하고 값을 돌려주는 부분입니다.

 이번에는 나이와 이름을 입력받고 인사를 하는 메소드를 만들어 보겠습니다.

 int 형 매개변수, String 형 매개변수 age와 name을 전달받아 인사하는 메소드입니다.

 이번에는 값을 반환하는 메소드를 만들어 보겠습니다. 간단하게 숫자 2개를 입력받아 합친 값을 돌려주는 메소드를 만들어 보겠습니다.

 우리는 int 형 매개변수 2개를 입력받고, int 형을 돌려줄 것이기 때문에 void 대신 반환형의 자료형인 int 를 Output 에 명시한 것을 확인할 수 있습니다. 이처럼 값을 반환하는 메소드는 어떤 값을 반환하는지 자료형을 명시해줘야 합니다.


 

+ Recent posts