제이제이
article thumbnail

 

클래스와 인스턴스


🤔 클래스란?

  • 클래스란 객체를 정의하는 틀 또는 설계도입니다.

-> 클래스(Class) = 데이터(Data) + 메소드(Method)로 구성되어 있습니다.

 

1. 데이터(Data) = 프로그램 상에서 유지되고 관리해야 할 데이터

2. 메소드(Method) = 데이터를 처리하고 조작하는 기능

  • 데이터는 "변수"를 통해 유지 및 관리되고, 변수에 저장된 값(데이터)들은 "메소드의 호출"을 통해 처리가 됩니다.

 

  • 다음의 코드를 통해 살펴봅시다.

 

💻 예시 코드

public class BankAccountPO {
   static int balance = 0; //예금 잔액

    public static void main(String[]args){
        deposit(10000); //입금 진행
        checkMyBalance(); //잔액 확인
        withdraw(3000); //출금 진행
        checkMyBalance(); //잔액 확인
    }

    //입금을 담당하는 메소드
    public static int deposit(int amount){
            balance +=amount;
            return balance;
    }

    //출금을 담당하는 메소드
    public static int withdraw(int amount){
        balance -= amount;
        return balance;
    }

    //예금 조회를 담당하는 메소드
    public static int checkMyBalance(){
        System.out.println("잔액: " + balance);
        return balance;
    }

}

 

📸 출력 결과

잔액: 10000
잔액: 7000

 

👩🏻‍🏫 설명

  • 위의 예를 살펴보면 클래스의 처음에 다음과 같이 변수를 선언하였습니다.
public class BankAccountPO{
	static int balance = 0; //예금 잔액(클래스 변수)

}

 

  • 그리고 메소드 deposit(입금) ,withdraw(출금),chekMy Balanc(예금조회)를 통해서 선언된 클래스 변수 balance의 데이터 값에 접근하는 것을 확인할 수 있습니다.

 

해당 코드를 통해 우리는 2가지 사실을 알 수 있습니다.

1. 변수 balance가 가지고 있는 값은 프로그램에서 사용하는 데이터이다.

2. 메소드 deposit(입금) ,withdraw(출금),chekMy Balanc(예금조회)는 프로그램에서 데이터를 가지고 무엇인가를 수행하는 "기능”의 역할을 한다.

 

  • 또한 더 크게 넓혀 다음과 같이 생각할 수 있습니다.
“메소드 deposit(입금) ,withdraw(출금),chekMy Balanc(예금조회)는 변수 balance를 위한 메소드이다”
“변수 balance의 값들은 메소드들(입금, 출금, 예금 조회)와 긴밀한 관계가 있다."

 

  • 이처럼 클래스는 연관되어 있는 변수와 메소드들을 묶기 위해 사용합니다.

-> 클래스를 이용하면 변수 balance, 변수와 관련된 모든 메소드를 하나로 묶을 수 있습니다.

 

  • 아래와 같은 코드들을 클래스 정의라고 합니다.

 

💻 예시 코드

	/*
	 클래스 정의
	*/

classs BankAccount{  
		int balance = 0; //예금 잔액
		public int deposit(int amount) { //변수 balance와 연관 있는 메소드

		return balance;
	}
		public int withdraw(int amount) { //변수 balance와 연관 있는 메소드
			balance -= amount;
			return balance;
	}
		public int checkMyBalance(){ //변수 balance와 연관 있는 메소드
			System.out.println("잔액: "+ balance);
		return balance;
	}

}

 

클래스의 구성과 인스턴스화

  • 위에서 본 클래스 BankAccount의 클래스 정의를 뜯어 봅시다.
class BankAccount{
	//인스턴스 변수
	int balance = 0;

	//인스턴스 메소드
	public int deposit(int amount) {....}
        public int withdraw(int amount) {....}
	public int checkMyBalance () {....}
}

 

  • 클래스 내부에 위치한 변수와 메소드를 가리켜 각각 다음과 같이 부릅니다.

1. 인스턴스 변수 = 클래스 내에 선언된 변수

2. 인스턴스 메소드 = 클래스 내에 정의된 메소드

 

  • 인스턴스 변수는 메소드 내부에 선언된 것이 아니기에 지역변수가 아닙니다.
  • 따라서 다음과 같은 특징을 가집니다.

-> "인스턴스 변수는 같은 클래스 내에 위치한 메소드 내에서 접근이 가능하다"

 

👨🏻‍🏫 추가 설명 - 필드

  • 인스턴스 변수는 다음과 같이 불리기도 합니다.

-> 멤버 변수, 필드(Field)

 

  • 클래스를 객체를 정의하는 틀 또는 설계도라고 설명했습니다.
  • 이번에는 다음의 설명을 통해 클래스를 자세하게 이해해봅시다.

 

예시

  • 클래스 = 붕어빵 모향의 틀,

-> 우리는 붕어빵 틀을 통해 붕어빵을 만들어 낼 수 있습니다.

-> 붕어빵 틀은 붕어빵이 아니듯이 클래스를 정의 했더라도 그 안에 위치한 변수나 메소드를 사용할 수 있는 것은 아닙니다.

-> 틀을 이용해 빵을 만들 듯이 인스턴스(객체)라는 것을 찍어내야 사용이 가능합니다.

 

  • 아래의 코드를 살펴 봅시다.
 new BankAccount(); //클래스 BankAccount의 인스턴스화

 

👩🏻‍🏫 설명

  • 위의 문장을 실행하면 BankAcoount에 정의된 메소드를 담고 있는 인스턴스(객체)라는 것이 생성됩니다.
  • 인스턴스(객체)가 만들어져 실제 메모리 공간에 존재하게 됩니다.

 

다시 한번 아래의 코드를 살펴봅시다.

new BankAccount() ; //BankAccount 인스턴스 1
new BankAccount(); //BankAccount 인스턴스 2

 

👩🏻‍🏫 설명

  • 위와 같이 인스턴스를 생성해 냈습니다. 하지만 메모리상에 인스턴스를 만들기만해서는 사용할 수 없습니다.
  • 인스턴스를 참조할 무엇인가를 필요합니다. 이것을 가리켜 “참조 변수”라고 합니다.

 

👨🏻‍🏫 추가설명 - 인스턴스와 객체

객체란?

  • 물리적으로 존재할 수 있거나, 추상적으로 생각할 수 있는 것 중 "자신만의 속성을 가지고 있고 다른 것과 식별 가능한 것"을 의미합니다.

 

인스턴스란?

  • 클래스를 이용하여 힙 영역에 생성한 새로운 인스턴스를 의미합니다.

-> 즉, 인스턴스란 클래스를 이용해 구현한 것을 의미합니다.

 

  • 클래스 BankAccount의 참조 변수를 선언하는 방법은 다음과 같습니다.
BankAccount myAcnt; //참조변수 myAcnt의 선언

 

  • 즉, 다음과 같이 참조변수를 선언하고 이를 통해서 새로 생성되는 인스턴스(객체)를 가리키게 할 수 있습니다.
BankAccount myAcnt1; //1. 참조변수 myAcnt1 선언
BankAccount myAcnt2; //1. 참조변수 myAcnt2 선언

//2. 참조변수 myAcnt1이 새로 생성되는 인스턴스를 가리킴
myAcnt1 = new BankAccount();

//2. 참조변수 myAcnt2가 새로 생성되는 인스턴스를 가리킴
myAcnt2 = new BankAccount();

 

👩🏻‍🏫 설명

  • 키워드 new를 통해 객체를 생성하면 생성된 인스턴스의 주솟값이 반환됩니다.
  • 참조 변수는 생성된 객체의 주소값이 저장됩니다.
  • 또한 다음과 같이 참조 변수의 선언과 인스턴스의 생성을 한 문장으로 표현할 수 있습니다.
BankAccount myAcnt1 = new BankAccount();
BankAccount myAcnt2 = new BankAccount();

 

  • 그리고 참조변수를 이용해서 해당 인스턴스의 메소드를 호출하는 방법은 다음과 같습니다.
myAcnt1.deposit(1000); //myAcnt1이 참조하는 인스턴스의 deposit 호출
myAcnt2.deposit(2000); //myAcnt2가 참조하는 인스턴스의 deposit 호출

 

  • 다음의 코드를 통해 자세히 살펴 봅시다.

💻 예시 코드

class BankAccount{
    int balance = 0; //예금 잔액

    public int deposit(int amount){
        balance += amount;
        return balance;
    }

    public  int withdraw(int amount){
        balance -= amount;
        return balance;
    }

    public int checkMyBalance(){
        System.out.println("잔액: " + balance);
        return balance;
    }

}

public class BankAccountOO {

    public static void main(String []args) {
        //2개의 인스턴스 생성
        BankAccount yoon = new BankAccount();
        BankAccount park = new BankAccount();

        //각 인스턴스를 대상으로 예금을 진행
        yoon.deposit(5000);
        park.deposit(3000);

        //각 인스턴스를 대상으로 출금을 진행
        yoon.withdraw(2000);
        park.withdraw(2000);

        //각 인스턴스를 대상으로 잔액을 조회
        yoon.checkMyBalance();
        park.checkMyBalance();
    }
}

 

📸 출력 결과

잔액: 3000
잔액: 1000

 

👩🏻‍🏫 설명

  • 위의 코드를 통해 실행해보면 참조변수 yoon과 park이 가리키는 인스턴스가 서로 다른 인스턴스임을 알 수 있습니다.

 

참조변수의 특성


  • 앞서 살펴 봤던 변수는 저장된 값(데이터)를 바꿀 수 있었습니다. 마찬가지로 참조변수도 변수입니다.
  • 따라서 참조변수도 변수가 가진 특성과 동일하게 참조하는 인스턴스를 변경할 수 있습니다.
BankAccount yoon = new BankAccount();
~~
yoon = new BankAccount(); //yoon이 새 인스턴스를 참조한다.
~~~

 

  • 또한 다음과 같이 참조변수가 가지고 있는 값을 다른 참조변수에 대입하여 하나의 인스턴스를 둘 이상의 참조변수가 동시에 참조하는 것도 가능합니다.

 

BankAccount ref1 = new BankAccount();
BankAccount ref2 = ref1;

 

다음의 코드를 통해서 살펴 봅시다.

💻 예시 코드

class  BankAccount2{
    int balance = 0;

    public int deposit(int amount){
        balance += amount;
        return balance;
    }

    public int withdraw(int amount){
        balance -= amount;
        return balance;
    }

    public int checkMyBalance(){
        System.out.println("잔액: " + balance);
        return balance;
    }
}

public class DupRef {
    public static void main(String[]args){
        BankAccount2 ref1 = new BankAccount2();
        BankAccount2 ref2 = ref1; //ref1이 참조하는 대상을 ref2도 참조

        ref1.deposit(3000);
        ref2.deposit(2000);
        ref1.withdraw(400);
        ref2.withdraw(300);
        ref1.checkMyBalance();
        ref2.checkMyBalance();

    }
}

 

📸 출력 결과

  • 위의 코드에서 출력 결과를 통해 두 개의 참조변수 ref1과 ref2가 하나의 인스턴스를 참조하고 있음을 확인할 수 있습니다.
잔액: 4300
잔액: 4300

 

참조변수의 매개변수 선언


  • 메소드는 매개변수를 통해 호출할 때 값을 전달할 수 있고 반환받을 수도 있습니다.
  • 이와 유사하게 메소드를 호출하면서 인스턴스의 참조값을 전달하는 것도 가능합니다.
  • 다음의 코드를 통해서 자세히 살펴봅시다.

 

💻 예시 코드

class BankAccount3{
    int balance = 0; //예금 잔액

    public int deposit(int amount){
        balance += amount;
        return balance;
    }
    public int withdraw(int amount){
        balance -= amount;
        return balance;
    }
    public int checkMyBalance(){
        System.out.println("잔액 : " + balance);
        return balance;
    }
}

public class PassRef {
   public static void main(String[] args){
       BankAccount3 ref = new BankAccount3();
       ref.deposit(3000);
       ref.withdraw(300);
       check(ref); //'참조 값'의 전달
   }

   public static void check(BankAccount3 acc){
       acc.checkMyBalance();
   }
}

 

📸 출력 결과

잔액 : 2700

 

👩🏻‍🏫 설명

  • 메소드 check의 매개변수로 BankAccount의 참조변수가 선언되었습니다.
  • 이 메소드는 인자로 매개변수의 참조 값을 전달받습니다.
  • 따라서 메소드 내에서는 전달된 참조 값의 인스턴스를 대상으로 메소드를 호출할 수 있습니다.

 

🤔 참조변수에 null 대입을 한다면?

  • 참조 변수에 null을 선언하면 참조하는 인스턴스와의 관계를 모두 끊습니다.
BankAccount ref = new BankAccount();
~
ref = null; //ref가 참조하는 인스턴스와의 관계를 끊음

 

생성자(Constructor)와 String 클래스의 소개


🤔 String 클래스란?

  • 문자열을 다루는 클래스입니다.
  •  문자열은 하나 이상의 문자의 모임을 의미하며 큰 따옴표( “ “)로 사용합니다.

ex) “abcdef”;

 

  • 문자열은 다음과 같이 참조 변수를 선언해서 참조할 수도 있습니다.
  • 참조변수 myName이 문자열 "아사비치즈스틱"을 가리키는 상황입니다.
String myName = "아사비치즈스틱"; //String형 참조변수의 문자열 참조

 

  • 이와 관련하여 다음의 예를 살펴봅시다.

💻 예시 코드

public class FirstStringIntro {
    public static void main(String[] args) {

        //문자열 선언과 동시에 참조변수로 참조한다.
        String str1 = "Happy";
        String str2 = "Birthday";
        System.out.println(str1 + " " + str2);

        //메소드에 문자열을 전달하는 상황
        printString(str1);
        printString(" ");
        printString(str2);
        printString("\\n");
        printString("End of program~ \\n");
    }

    //String 참조변수를 매개변수로 선언하여 문자열을 전달 받을 수 있다.
    public static void printString(String str){
        System.out.print(str);
    }

}

 

📸 출력결과

Happy Birthday
Happy Birthday
End of program~

 

👩🏻‍🏫 설명

  • 위의 예를 통해 다음의 두가지 사실을 알 수 있습니다.
  1. 문자열을 메소드의 인자로 전달할 수 있다.
  2. 매개변수로 String형 참조변수를 선언하여 문자열을 인자로 전달받을 수 있다.

 

❓각 인스턴스를 구분할 수 있는 상황이 필요하다면?

  • 앞서 예를 든 BankAccount클래스를 다시 살펴봅시다.
  • 평소 은행에서는 고객이 계좌를 개설할 때마다 아래의 코드의 인스턴스를 생성해야 합니다.

 

class BankAccount{
	int balance =0; //예금 잔액
	public int deposit(int amount) {
	  balnce += amount;
		return balance;	
 }
	public int withdraw(int amount) {
   ~
 }
	public int checkMyBalance() {
   ~
}

 

  • 그런데 문제는 인스턴스를 생성하면 누구의 계좌인지 구별할 수 있는 정보가 빠졌습니다.
  • 따라서 위의 클래스에는 계좌의 주인이 누구인지 구분할 수 있는 정보가 추가되어야 합니다.

1. 계좌번호 = String AccNumber

2. 주민번호 = String ssNumber

  • 이를 반영하여 BankAccount를 수정한 결과는 다음과 같습니다.

 

💻 예시 코드

class BankAccount4{
    String accNumber; //계좌번호
    String ssNumber; //주민번호
    int balance = 0; //예금 잔액

    /*
    초기화를 위한 메소드
    */
    public void initAccount(String acc, String ss, int bal){
        accNumber = acc;
        ssNumber = ss;
        balance = bal; //계좌 개설 시 예금액으로 초기화
    }

    public int deposit(int amount){
        balance += amount;
        return balance;
    }

    public int withdraw(int amount){
        balance -= amount;
        return balance;
    }

    public int checkMyBalance(){
        System.out.println("계좌번호: " + accNumber);
        System.out.println("주민번호: " + ssNumber);
        System.out.println("잔 액 : " + balance + '\\n');
        return balance;
    }
}

public class BankAccountUnilD {
    public static void main(String[]args){
        BankAccount4 yoon = new BankAccount4();// yoon의 계좌 생성
        yoon.initAccount("12-34-89","990990-9090990",10000); //초기화

        BankAccount4 park = new BankAccount4(); // park의 계좌 생성
        park.initAccount("33-55-04","77088-595907",10000); //초기화

        yoon.deposit(5000);
        park.deposit(3000);
        yoon.withdraw(2000);
        park.withdraw(2000);
        yoon.checkMyBalance();
        park.checkMyBalance();
    }

}

 

📸 출력 결과

계좌번호: 12-34-89
주민번호: 990990-9090990
잔 액 : 13000

계좌번호: 33-55-04
주민번호: 77088-595907
잔 액 : 11000

 

👩🏻‍🏫 설명

  • 위의 예의 클래스에는 다음의 메소드가 추가되었습니다.
public void initAccont(String acc, String ss, int bal) {
		accNumber = acc;
		ssNumber = ss;
		balance = bal; //계좌 개설 시 예금액으로 초기화

}

 

  • 이 메소드는 다음과 같은 부분에서 다른 메소드들과 성격상 구분됩니다.

1. 인스턴스의 초기화를 위한 메소드이다.

2. 때문에 인스턴스 생성 시 반드시 한번 호출해서 초기화를 진행한다.

  • 그러나 위와 같은 메소드를 정의하지 않고 “생성자”라는 것을 정의해서 인스턴스가 생성될 때마다 초기화를 진행할 수 있습니다.

 

생성자

  • 생성자는 인스턴스(객체) 생성과정에서 초기화를 위해, 자동으로 호출되는 일종의 메소드입니다.

 

생성자의 조건

1. 생성자의 이름은 해당 클래스의 이름과 동일합니다.

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

 

  • 위의 두 조건을 만족하면 자바 컴파일러(javac)에 의해 생성자로 인식됩니다.
  • 따라서 인스턴스를 생성할 때 자동으로 호출되어 인스턴스를 초기화합니다.
  • 인스턴스 초기화를 위해 정의한 메소드를 생성자로 바꾸어 봅시다.

 

🔎 변경할 코드

public BankAccount(String acc, String ss,int bal){
	accNumber = acc;
	ssNumber = ss;
	balance = bal;
}

 

  • 다음의 코드를 통해 살펴봅시다.

💻 예시 코드

class BankAccount5{
    String accNumber; //계좌번호
    String ssNumber; //주민번호
    int balance; //예금

    public BankAccount5(String accNumber, String ssNumber, int balance) {
        this.accNumber = accNumber;
        this.ssNumber = ssNumber;
        this.balance = balance;
    }
    public int deposit(int amount){
        balance += amount;
        return balance;
    }

    public int withdraw(int amount){
        balance -= amount;
        return balance;
    }

    public int checkMyBalance(){
        System.out.println("계좌번호: " + accNumber);
        System.out.println("주민번호: " + ssNumber);
        System.out.println("잔 액 : " + balance + '\\n');
        return balance;
    }
}

public class BankAccountConstructor {
    public static void main(String[]args){
        BankAccount5 yoon = new BankAccount5("12-34-89","990990-9090990",10000);// yoon의 계좌 생성

        BankAccount5 park = new BankAccount5("33-55-04","77088-595907",10000); // park의 계좌 생성

        yoon.deposit(5000);
        park.deposit(3000);
        yoon.withdraw(2000);
        park.withdraw(2000);
        yoon.checkMyBalance();
        park.checkMyBalance();
    }
}

 

📸 출력 결과

계좌번호: 12-34-89
주민번호: 990990-9090990
잔 액 : 13000

계좌번호: 33-55-04
주민번호: 77088-595907
잔 액 : 11000

 

  • 위의 예제에서 인스턴스의 생성 문장이 다음과 같이 바뀌었는 것을 확인할 수 있습니다.
  • 소괄호 안에 값을 전달하고 있는데 이 값들은 생성자가 호출될 때 생성자의 매개변수로 전달됩니다.
  • 위의 문장을 구성하면 인스턴스의 생성 마지막 단계에서 생성자가 호출되면서 값이 할당됩니다. 그리고 이 값들로 인스턴스 변수가 초기화 됩니다.
BankAccount yoon = new BankAccount("12-34-89","990990-909090",10000);

 

❓ 생성자가 생략된 클래스는?


디폴트 생성자

  • 생성자가 생략한 상태의 클래스를 정의하면 자바 컴파일러(javac)가 “디폴트 생성자”라는 것을 클래스 정의에 넣어줍니다.
class BankAcount{
	int balance;

	public BankAccont(){ //컴파일러에 의해 자동 상빕되는 "디폴트 생성"
		//empty
  }
	 public int deposit(int amount){...}
	 public int withdraw(int amount){...}
	 public int checkMyBalance() {...}
}
	

 

⚠️ 주의점

  • 컴파일러에 의해 디폴트 생성자가 자동으로 삽입되더라도 생성자는 직접 정의하는 것이 좋습니다.
  •  생성자가 필요없는 클래스는 잘 정의된 클래스가 아니기 때문입니다.(생성자를 작성하는 것이 더 좋은 코드입니다)

 

자바의 명명규칙


  • 자바 프로그램을 작성하면서 일반적으로 이름을 짓는 규칙들을 정리합니다.

 

클래스

  • 클래스의 이름을 규칙적으로 지을때 가장 보편적으로 CamelCase모델을 이용하여 이름을 사용합니다.

 

❓CamelCase란?

  • 낙타의 등처럼 이름이 비슷한 형태로 되어 있는 경우를 의미합니다.
  1. 클래스의 이름의 첫 문자는 대문자로 시작합니다.
  2. 둘 이상의 단어가 묶여 이름을 이룰때는 새로 시작하는 단어는 대문자로 작성합니다.

ex)  Circle + Point = CirclePoint

 

메소드와 변수의 규칙

  • 일반적으로 변형된 CamelCase 형태를 사용합니다.
  1. 메소드와 변수의 첫 문자는 소문자로 시작합니다.

ex)  Add + Your + Money = addYourMoney,    Your + age = yourAge

 

상수의 이름 규칙

  • 상수는 일반적으로 대문자로 표현합니다.
  • 단 둘 이상의 문자로 구성되어 있을 경우_(언더바)를 이용하여 연결하여 이름을 짓습니다.

ex)  final int COLOR = 7;

      final int COLOR_RAINBOW = 7;

 

📒 Reference (참고 자료)


  1. 윤성우의 열혈 자바

 

profile

제이제이

@아사비치즈스틱

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!