[Java] 클래스와 인스턴스

6 분 소요

클래스와 인스턴스 관련 개념을 알아보자 :raising_hand:

목차

1. 개념익히기

2. 인스턴스 생성과정 분석




:pencil2: 들어가기 전에!

자바는 객체지향 프로그래밍(OOP, Object-Oriented Programming)이 가능한 객체 지향 언어이다.

  • 객체 지향 프로그래밍이란, 프로그래밍에서 필요한 모든 데이터를 객체(Object)로 취급하여, 각 객체들간의 관계를 서술하는 방식으로 프로그래밍하는 기법을 말한다. 해당 프로그래밍 기법을 기반으로 위의 워딩들을 이해할 수 있다.
  • 따라서 앞으로 나올 단어들도 OOP의 관점에서 이해하면 된다.

:point_right: 용어정리

1. 클래스(Class): 객체(Object)를 만들 수 있는 ‘틀’

  • 1.1. 필드(Field) : 클래스 내에서 정의한 객체의 속성/상태(state)
  • 1.2. 메서드(Method) : 클래스 내에서 정의한 객체의 행위(behavior)
  • 1.3. 생성자(Constructor) : 클래스로부터 만들어진 인스턴스 변수를 초기화하기 위한 메서드
  • 1.4. this 참조변수 : Constructor의 매개변수명과 Instance 변수명이 같을 경우 구별을 위해 사용하는 참조 변수

2. 인스턴스(Instance) : ‘틀’(Class)로부터 만들어낸, 메모리 상에 존재하는 실제 객체(Object)

  • 2.1. new 키워드 : 인스턴스를 만들 때, ‘생성자’를 호출하기 위해 사용하는 키워드


개념 익히기

0. 클래스(class)

클래스는 객체의 속성을 표현하는 field행위를 표현하는 method로 구성된다. 또한 생성된 인스턴스의 필드를 초기화 하는 특별한 메서드인 constructor를 가진다.

:point_right: 포켓몬을 예로 들어보자.

class Pocketmon{
	  // 필드(field) : 모든 포켓몬이 가지는 속성
	  String name;		// 몬스터 이름
	  int hp; 			// 체력
	  int level = 1; 	// 레벨
	  
	  // 메서드(method) : 모든 포켓몬이 가능한 행위
	  void attack() {  
	      System.out.println(name + "가 공격을 한다.");  
	  }  
	  void eat() {  
	      System.out.println(name + "가 밥을 먹는다.");  
	  }  
	  void exercise() {  
	      System.out.println(name + "가 운동을 먹는다.");  
	  }  
  
	  // 생성자(constructor) : 객체 생성, 인스턴스 변수 초기화
	  Pocketmon() {}
	  Pocketmon(String name, int hp) {  
		  this.name = name;  
		  this.hp = hp;  
	  }
}

포켓몬은 여러 몬스터들의 상위개념이다. 피카츄,파이리, 또가스, 피존 등 여러 몬스터가 포켓몬이라는 추상적인 개념의 하위개념에 속한다.

  • 이것을 OOP적 관점에서 보면, 포켓몬이라는 추상적인 클래스피카츄, 파이리 등의 실제 인스턴스를 만들어 낼 수 있다는 것을 의미한다.
    • 피카츄파이리는 서로 다른 개체이지만, 포켓몬이라는 상위개념에 포함되는 개념이라는 것은 동일하다.
    • 따라서 포켓몬이라는 하나의 클래스로 여러 몬스터 객체(인스턴스)를 만들 수 있는 것이다.

  • 여기서 주목할 점은 몬스터들의 속성(field)과 행위(behavior)이다.
    • 모든 포켓몬은 모두 이름, 체력, 레벨이라는 속성을 공통적으로 가지고 있다.
    • 또한 공격하기, 밥먹기,운동하기라는 행위가 가능한 것도 동일하다.
    • 따라서 이와 같은 속성과 행위를 해당 클래스의 필드와 메서드로 갖는 것이다.


1. 필드(field) : 객체의 속성들

클래스에서 필드(field)란 클래스에 포함된 변수(variable)을 의미한다. 필드의 선언 위치에 따라 다음과 같이 구분된다.

1.1. 클래스 변수(static variable)

  • 클래스 영역에 위치한 변수 중 static 키워드를 가지는 변수
  • 모든 인스턴스가 공유하는 변수
  • 인스턴스 생성 없이 사용가능
  • this 참조변수 사용불가

1.2. 인스턴스 변수(instance variable)

  • 클래스 영역에 위치한 변수 중 static 키워드를 가지지 않은 변수
  • 인스턴스마다 가져야할 변수
  • 인스턴스 생성 후에 사용가능

1.3. 지역변수(local variable)

  • 특정 메서드 내에서만 사용되는 변수

:point_right: 다시 포켓몬으로 예로 들어보자.

class Pocketmon{
	static String townName;		// 클래스변수(마을이름)
	String name;				// 인스턴스변수(몬스터이름)	
	
	void eat(String food){// 매개변수도 지역변수
		String beverage = "맥쥬"; // 지역변수
	}
}
  • 모든 포켓몬은 한 마을에만 살고 있다고 가정한다.
    • 포켓몬 클래스에 마을이름(townName)이라는 변수가 있다면, 모든 인스턴스가 동일한 값을 가지게 된다.
    • 즉, 모든 인스턴스가 공유하므로 클래스 변수이다.
    • 해당 변수는 클래스가 메모리에 올라갈 때(프로그램이 실행될 때) 생성되어 method영역에 메모리를 할당받고 프로그램이 종료될 때 제거된다.

  • 몬스터의 이름(name) 은 몬스터마다 다르기 때문에 인스턴스마다 다른 값을 가지게 된다.
    • 따라서 인스턴스 변수이다.
    • 해당 변수는 new 키워드로 새로운 객체가 생성될 때마다 생성되어 heap영역에 메모리를 할당받고, 해당 객체가 더 이상 사용되지 않으면 Garbage Collector에 의해 메모리에서 제거된다.

  • 메서드의 매개변수(food)와 메서드 내부에서 선언된 변수(beverage)는 변수가 선언되는 시점부터 블럭이 종료되는 시점까지만 stack 영역에 존재한다.
    • 이러한 변수는 할당된 범위에서만 생존하는 지역변수이다.


변수 종류별 특징

종류 초기화여부 생성시기 소멸시기 저장메모리 사용방법
클래스 변수 O 클래스가 메모리에 올라갈 때 프로그램이 종료될 때 method 영역 클래스이름.변수이름
인스턴스 변수 O 인스턴스가 생성될 때 인스턴스가 소멸할 때 heap 영역 인스턴스이름.변수이름
지역 변수 X 블록 내에서 변수의 선언문이 실행될 때 블록을 벗어날 때 stack 영역 변수이름



2. 메서드(method)

메서드란 클래스 내에서 존재하는 함수다. 보통 다른 언어에는 함수가 별도로 존재하지만, 자바는 모든 메서드가 클래스 내에 존재하기 때문에 존재하는 모든 함수가 메서드이다.
메서드는 다음과 같이 구분된다.

2.1. 클래스 메서드(static method)

  • static 키워드를 가지는 메서드
  • 인스턴스 생성 없이 사용가능
    • 전달된 매개변수만으로 동작
  • 내부에서 인스턴스변수 사용 불가, 클래스변수만 사용가능

2.2. 인스턴스 메서드(instance method)

  • static 키워드를 가지지 않는 메서드
  • 인스턴스 생성 후에 사용가능
  • 내부에서 클래스변수, 인스턴스변수 모두 사용가능

:point_right: 다시 포켓몬으로 예로 들어보자.

class Pocketmon{
	static String townName;// 마을이름 (포켓못은 모두 한 마을에만 산다고 가정)
	String name; 
	int hp;  
	int level = 1;

	// 2.1 클래스 메서드 (클래스 변수만 사용가능)
	static void changeTownName(String newTownName){
		townName = newTownName;
	}
	
	// 2.2 인스턴스 메서드 (클래스 변수, 인스턴스 변수 모두 사용가능)
	void printInfo(){
		System.out.println(townName+"에 사는 "+name+"의 레벨은 "+level+"입니다.";
	}
}
  • 포켓몬은 모두 한 마을에 살고 있기 때문에, 포켓몬들의 townName값이 다를 순 없다. 하지만, 마을 이름 자체(changeTownName)가 변할 수는 있다.
  • 그럴 경우 클래스 메서드를 사용해서 클래스 변수의 값을 초기화할 수 있다.
  • 클러스 메서드는 클래스 변수와 마찬가지로 클래스가 메모리에 올라간 시점부터 사용가능하다.
  • 해당 시점은 인스턴스가 생성되기 전이므로, 클래스 메서드 내부에서 인스턴스 변수를 사용할 수 없다.

  • 인스턴스 메서드는 인스턴스 변수와 마찬가지로 객체가 생성된 이후 시점부터 사용가능하다.
  • 따라서 클래스 변수와 인스턴스 변수를 모두 사용할 수 있다.

:point_right: 테스트 코드

import org.junit.jupiter.api.*;  
public class MethodTest { 

    @Test  
	void classMethodTest(){  
        Pocketmon pikachu = new Pocketmon("피카츄",10);  
	    Pocketmon longstone = new Pocketmon("롱스톤",30);  
		pikachu.printInfo();  
		longstone.printInfo();  
  
	    pikachu.townName = "태초마을";	//pikachu 인스턴스로 클래스변수 초기화 
 
	    longstone.printInfo();  		//longstone 인스턴스로 클래스변수 값 확인
	}  
}
null에 사는 피카츄의 레벨은 1입니다.
null에 사는 롱스톤의 레벨은 1입니다.

태초마을에 사는 롱스톤의 레벨은 1입니다.



3. 생성자(Constructor)

생성자는 인스턴스 변수를 초기화하는 특수한 메서드이다.

  • 생성자는 클래스 이름과 같아야 한다.
  • 반환값이 없지만 반환타입을 void로 선언하지 않는다.
  • 초기화를 위한 데이터를 인수로 전달받을 수 있다
  • 객체 초기화 방법이 여러 개일 경우 여러 개의 생성자를 가질 수 있다.
    • 메소드 오버로딩 가능
  • 생성자가 정의되지 않은 경우, 자바 컴파일러가 클래스에 default 생성자를 자동으로 추가한다.
    • 하지만 생성자가 하나라도 정의된 경우, default 생성자 자동추가 안된다.


생성자 선언

// 반환타입 명시 안함
Pocketmon(){}
Pocketmon(String name){
	this.name = name;
}
Pocketmon(String name, int hp){
	this.name = name;
	this.hp = hp;
}

생성자를 호출할 때는 new 키워드를 사용한다.

생성자 호출

	public  static  void  main(String[]  args) {
	
	// new 키워드를 사용하여 생성자 호출
	Pocketmon pikachu = new Pocketmon();
	Pocketmon ggobugi = new Pocketmon("꼬부기",10);

}



인스턴스 생성과정 분석

예제코드 원본

Pocketmon이라는 클래스의 인스턴스를 생성하는 간단한 코드를 작성해보았다.

  • new 연산자로 Pocketmon 클래스의 인스턴스를 생성한다.
  • String name에 초기화할 값으로 “pikachu”를 int hp에 초기화할 값으로 10을 할당하여 생성자를 호출한다. (인스턴스 변수 초기화)
  • 만들어진 인스턴스의 heap영역 레퍼런스 값을 pikachu라는 이름의 변수에 삽입한다.
/*
class Pocketmon {  
    String name;      
    int hp;   
    Pocketmon(String name, int hp) {  
      	  this.name = name;  
 	  this.hp = hp;  
    }
 */
public static void main(String[] args) {
	Pocketmon pikachu = new Pocketmon("pikachu",10);
}


바이트코드

바이트코드로 인스턴스의 생성과정을 살펴보았다.

Compiled from "Test.java"
  public static void main(java.lang.String[]);
    Code:
       0: new           #7                  // class javabasic/week5/Pocketmon
       3: dup
       4: ldc           #9 (상수 풀의 인덱스)                  // String Pikachu
       6: bipush        10
       8: invokespecial #11                 // Method javabasic/week5/Pocketmon."<init>":(Ljava/lang/String;I)V
      11: astore_1
      12: return


1. new : Pocketmon 클래스의 인스턴스를 생성


  • Pocketmon 클래스에 대한 새로운 인스턴스가 heap에 생성
  • 해당 heap으로의 참조(@100)가 오퍼랜드 스택(operand stack)에 push된다.

2. dup : 앞에서 생성한 인스턴스의 참조자를 복사(duplicate)


  • 생성자를 호출하면 해당 객체의 참조자가 스택에서 제거된다.
  • 따라서 new 키워드를 사용해 객체를 생성한 뒤
  • 생성자를 호출하기 전에 dup 명령어를 사용해 참조자(@100)를 복사한다.

3. ldc : 리터럴형태로 “Pikachu” 문자열 생성


  • 런타임 상수풀(run-time constant pool)에 push
  • 오퍼랜드 스택(operand stack)에도 String 참조값 push

4. bipush 10 : 생성자에 전달할 인자(10)를 스택에 추가




5. invokespecial <init> (Ljava/lang/String;I)V : String과 int를 매개변수로 가지는 생성자 호출


  • 매개변수 값으로 인스턴스 변수를 초기화
  • Pocketmon(), int 10, @500, @100를 오퍼랜드 스택에서 pop시켜, 인스턴스 변수를 초기화한다.



6. astore_1 : 지역변수에 오퍼랜드 스택에 있는 참조값을 넣는다


  • 지역변수 pikachu에 초기화가 완료된 인스턴스의 참조값(@100)을 넣는다.



7. 작업완료된 상태




:orange_book: References

태그:

카테고리:

업데이트:

댓글남기기