Class와 Object를 구별하자(feat. 그놈의 붕어빵)

개요

Java 관련 단골 질문 중 하나는 바로 “Object 와 Class 차이”일 것입니다.
이 질문에 대해서 지식 전달자마다 다양하게 설명합니다.
제가 자바 국비지원 과정에서 강사님에게 들었던 설명은 아래와 같습니다.

Class 는 붕어빵 틀이고, Object는 붕어빵이다.
(본 문서의 썸내일이 바로 이 내용을 시각화 한 것입니다. 이에 대한 유래도 궁금하군요)

자바를 처음 접하던 당시에는 좋은 설명이라 생각하였지만,
시간이 지날수록 Class 와 Object 의 관계에 대해 위 설명으로는 부족하다 생각이 들었습니다.
그러던 중 한 책을 만나고 나서 나름의 정의와 설명을 할 수 있게 되었습니다.
이 문서에서는[객체지향의 사실과 오해]를 읽으며 얻은 지식을 바탕으로 Class와 Object를 구분하려합니다.

목표

🚀  Class와 Object에 대해서 이해합니다.
🚀 긴 글이 싫고, 요약만 보고 싶은 분은 마무리를 보시면 됩니다.

먼저 Type이라는 단어를 살펴보자.

Class와 Ojbect에 대한 이야기를 하기 전에 Type에 대해서 살펴보려합니다.
이 단어를 살펴보아야 Class와 Ojbect의 차이에 대해 이해하기 좋을 것이라 생각합니다.

네이버 어학사전에서 Type의 사전적 의미를 살펴보면 다음과 같습니다.

Type
1. 명사 형(태), 유형, 종류
2. 명사 비격식 (특정한 성격특징 등을 지닌) 사람, 타입
3. 동사 (타자기컴퓨터로) 타자 치다[입력하다]
4. 동사 전문 용어 유형[종류]을 알아내다, (유형별로) 분류하다
출처 : Naver Dictionary

Type의 사전적 의미를 정리해보면 비슷한 성질을 가진 실체를 분류한 것이라 볼 수 있겠습니다.
이 단어가 문장에서 어떻게 사용되는지 살펴보면 더욱 이해하기 편할 것 같습니다.

  • This type of work is uncharted territory for us. 
    : 이런 종류의 일은 우리에게 미지의 영역이다.
  • They stock every imaginable type of pasta. 
    : 그들은 생각할 수 있는 모든 종류의 파스타를 갖춰 놓고 있다.

즉, Type은 어떤 구체적인 실체를 말하기보다는 여러 실체로 부터 공통점을 발견하고 이를 통해 분류한 것이라 생각할 수 있습니다. 그리고 Type과 Classification은 같은 '분류'라는 뜻을 가집니다.

Class가 Classification의 줄임이라는 것으로 본다면, 결국 Class는 분류라고 말할 수 있습니다.

개념, 분류, 추상화

조영호님의 저서 [객체지향의 사실과 오해]에서는 어떤 대상을 분류하는 도구로 “개념”이라는 것을 제시합니다.
“개념”이란 세상의 존재하는 여러 실체를 어떤 공통점으로 묶기위한 틀이라 보면 될 것입니다.
이에 대해 책에서는 아래와 같이 세가지 관점으로 보이고 있습니다.

일반적으로 객체의 분류 장치로서 개념을 이야기할 때는 아래의 세 가지 관점을 함께 언급한다.
심볼(symbol)
: 개념을 가리키는 간략한 이름이나 명칭
내연(intension)
: 개념의 완전한 정의를 나타내며 내연의 의미를 이용해 객체가 개념에 속하는지 여부
를 확인할 수 있다.
외연(extension)
: 개념에 속하는 모든 객체의 집합(set)
참조 : 객체지향의 사실과 오해

위의 내용만 봐서는 무슨말인지 이해되지 않을 수 있을 것입니다.
예시를 들어 각 용어를 설명해보겠습니다.
아래와 같은 성격을 가진 어떤 물건이 있다고 해봅시다.

깍을 수 있다.
나무로 구성되어 있으며,길쭉하다.
안에는 검은 심이 있어 이를 통해 필기를 할 수 있다.

심볼

대부분 위 속성을 읽고나서 “연필”을 떠올렸을 것입니다. 또한 위 조건에 만족하면 우리는 그것을 “연필”이라 부를 수 있을 것입니다."연필"이라는 단어는 심볼입니다. 즉, 연필은 위 속성으로 분류된 물건들에 대한 이름인 것입니다. 우리의 인지능력은 한계가 있기 때문에 세상의 모든 것을 개별적인 것으로 받아드릴 수 없습니다. 최대한 특징을 묶어서 하나의 객체로 생각할 수밖에 없는 것이죠. 이렇게 우리는 세상을 개념이라는 창을 통해서 바라보고 있습니다. 연필, 사과, 컵, 자동차 등 이러한 단어들은 우리가 세상을 파악하고 위해서 만들어진 것들입니다.

내연

내연은 객체의 속성입니다. 위에서 적어둔 연필에 대한 속성이 내연인 것입니다.
세상에 존재하는 것은 모두 내연을 가집니다.

네 개 혹은 그 이상의 바퀴를 가지있다.
사람이나 물건을 싣고 오래 이동할 수 있다.

위와 같은 내연을 가진 물건이 있다고 합시다. 이를 보고 우리는 자동차라는 이름(심볼)을 붙였습니다.
자동차에 대한 정의에 위 문구가 적당하냐보다 이런 정의를 가지고 분류한다는 것에 초점을 맞춰봅시다.
이때 내연은 제가 정의한 자동차의 속성인 것이고, 이 내연을 통해서 세상의 수많은 실체 중 어느 것이 자동차인지 분류를 할 수 있을 것 입니다.

외연

외연은 내연을 통해서 분류된 실체들의 집합입니다. 제가 위에서 자동차에 대한 내연을 정의 해보았습니다. 이것으로 분류된 실체들은 다음과 같은 것입니다.

1톤 트럭, 전기 자동차, 경유 자동차, 휘발유 자동차, BMW, 화물 트럭 ...

외연이란 이처럼 내연을 통해서 분류된 객체의 집합이라 할 수 있겠습니다.
정리하자면 심볼은 이름, 내연은 속성, 외연은 내연으로 분류한 실체의 집합이라 할 수 있겠습니다.

Class와 Object의 차이점에 대해서 이야기하는 문서인데 심볼, 내연, 외연 같은 소리를 하나 생각하실 겁니다.
거의 다 도착하였습니다.
이제야 우리는 Class와 Object에 대해 이야기를 이야기 할 수 있게 되었습니다.
이미 Class와 Object가 무엇인지 눈치채신 분도 있을 것입니다.

Class와 Ojbect의 관계

지금까지 우리는 Type이란 단어의 사전적 의미를 보며 Class가 결국 분류의 의미를 가진 다는 것을 알아봤습니다.
또한 분류는 "개념"이라는 도구를 사용하여 이뤄지는 것이라 알아보았습니다.
이는 심볼, 내연, 외연으로 구성된 다는 것도 살펴보았습니다.
그럼 지금까지 살펴본 내용을 통해서 Class와 Ojbect의 관계에 대해서 살펴보겠습니다.

객체지향의 사실과 오해에서는 다음과 같이 객체를 정의하고 있습니다.

개념을 이용하면 객체를 여러 그룹으로 분류(classification)할 수 있다.
(중략)
이처럼 객체에 어떤 개념을 적용하는 것이 가능해서 개념 그룹의 일원이 될 때 객체를 그 개념의
인스턴스(instance)라고 한다. 따라서 객체를 다음과 같이 정의할 수도 있다.
객체란 특정한 개념을 적용할 수 있는 구체적인 사물을 의미한다. 개념이 객체에 적용됐을 때 객체를 개
념의 인스턴스라고 한다.
(중략)
객체지향의 세계에서 가장 널리 알려진 유명인사가 클래스(class)라는 사실을 감안한다
면 분류(classification)라는 개념이 얼마나 중요한지 실감할 수 있을 것이다

이를 바탕으로 제 나름대로 Class와 Ojbect를 정리 해볼 수 있을 것 같습니다.

Class : 세상의 존재하는 객체(실체 혹은 개체)의 분류. 그 기준이 정의되어 있는 것.
Object : 특정 분류, 혹은 개념을 적용할 수 있는 실체.
Instance : Object에 Class가 적용된 상태. 즉, 어떤 객체에 분류를 적용한 것.

붕어빵 틀과 붕어빵이라는 개념으로 바라보기엔 역시 Class와 Object에 대해서 설명하기는 부족했습니다.
이 붕어빵과 붕어빵 틀의 관계는 생성자와 생산물의 관계로 볼 수 있습니다.

Class는 Object의 생산자다.
Object는 Class의 생산물이다.

이렇게 뭔가 순환적으로 서로를 서술할 뿐이었습니다.

하지만 본 문서에서 정리한 내용을 보면 Class와 Object는 분류와 그 분류에 속하는 객체의 관계로 정의됩니다.

Class는 현상과 현실을 개념화하여 해석한 것입니다. 같은 현상과 문제라도 어떻게 분류하고 정의하냐에 따라 다른 결과가 나옵니다. Class는 결국 현실을 단순화하여 정보와 행위의 단위로 구분한 것이라 할 수 있습니다.
객체는 분류를 만나기 전까지는 고정된 정의를 가지지 않습니다. 즉, 객체는 어떤 관점이나 개념을 적용하여 분류하기 나름이라는 의미도 될 수 있을 것입니다.
연필을 우리가 연필로 이름 붙이고 필기라는 행위를 부여할 수 있지만, 누군가는 다른 이름을 붙이고 다른 용도로 사용할 수 있을 것입니다. 그러면 아예 분류가 바뀌게 되는거죠. 더 이상 그것은 연필이 아닐 겁니다.

여담으로 Object와 Intance의 관계는 알아볼 수록 혼란스러운 부분이 있습니다.
Object는 분류되기 전이고 Instance는 분류된 후라는 것인데, 개념적으로든, 코드로 보든 그 둘의 차이를 크게 느낄 수 없었습니다. 또한 인터넷에서 Object와 Instance의 구분에 대해서 찾아 볼 수록 혼란스러움이 커지기만 할 뿐이었습니다. 이는 100명이 정의할 때마다 100가지 정의가 나오는 것 같았습니다. 다들 미묘한 차이가 있다며 설명해나가다 결국 둘이 같은 것처럼 이야기할 뿐이었습니다...

Object와 Instance에 구분에 대해서 명확히 설명해주실 수 있는 분이 있다면 댓글로 남겨주세요.
감사한 마음으로 참고하겠습니다.

이제 Class와 Ojbect에 대한 이야기를 java 코드를 살펴보도록 하겠습니다.

public class 강아지 {
	private final String 이름;
	private final String 견종;
	private final int 나이;
	private final String 감정;
	
	public 강아지(String 이름, String 견종, int 나이, String 감정) {
	    this.이름 = 이름;
	    this.견종 = 견종;
	    this.나이 = 나이;
	    this.감정 = 감정;
	}
	public void 꼬리치기(){
      System.out.printf("%s가 꼬리를 칩니다. %n",this.이름);
  }

  public void 감정표현(){
      System.out.printf("%s가 감정을 표현합니다. %s로 보입니다.%n", this.이름, this.감정);
  }

  public void 왈왈(){
      System.out.printf("%s가 마구 짖습니다. 와르르르르왈왈와와라와라랑라아라랄ㄹ ㄹㄹㄹ!!!", this.이름, this.감정);
  }

}

저는 위의 Class(분류)를 통해서 객체(강아지)들을 생성할 것입니다.
제가 분류하여 묶을 동물은 감정표현이 가능해야 하고, 꼬리도 칠 줄 알아야하며, “왈왈왈” 하고 짖을 수 있어야 합니다.
해당 특징으로 강아지를 나누는게 맞느냐 할 수 있겠지만, 너무 깊게 생각하시지 않으면 좋겠습니다.
여기서 중요한 것은 행위로 분류한다는 것입니다.

[객체지향의 사실과 오해]에서 여러 번 강조하듯 분류를 할 때 중요한 기준은 행위입니다. 이름, 견종, 나이, 감정 등의 데이터보다 꼬리를 치거나, 왈왈 짖거나 하는 행동이 어떤 개체를 분류하는 것이 더 바람직할 것입니다. 극단적으로 예를 들자면 이름이라는 속성은 사람도 갖고, 강아지도 갖고, 호랑이도 갖습니다. 그렇다고 호랑이랑 인간이 같은 부류에 들어가는 것은 적절치 않겠죠.

이제 분류를 통해서 각 객체를 만들어 보겠습니다.

강아지 가을이 = new 강아지("가을이", "믹스", 3, "화남");
강아지 덕순이 = new 강아지("덕순이", "슈나우저", 18, "기쁨");
강아지 바우 = new 강아지("바우", "닥스훈트", 5, "배고픔");

가을이.꼬리치기();
덕순이.감정표현();
바우.왈왈();

//결과
가을이가 꼬리를 칩니다. 
덕순이가 감정을 표현합니다. 기쁨로 보입니다.
바우가 마구 짖습니다. 와르르르르왈왈와와라와라랑라아라랄ㄹ ㄹㄹㄹ!!!

“강아지”는 분류(Class)입니다.
그리고 분류에 의해서 생성된 각 객체는 이름, 견종, 나이, 감정이라는 데이터와 꼬리도 치고, 감정도 표현하고, 왈왈 짓는 등의 행위를 가지게 됩니다.

좀 더 자바스럽게(?!) 설명하자면 다음과 같이 해석할 수 있을 것입니다.

  • 강아지 라는 Class(분류)는 이런 저런 맴버변수(데이터)와 메소드(행위)로 정의되고 이는 java 코드로 작성됩니다.
  • 이 코드는 *.java 형태의 파일로 저장됩니다.
  • 작성된 코드 파일(.java)을 자바 컴파일러가 바이트코드로 변환합니다.
    이때 자바 컴파일러는
    .class 형태의 파일을 생성합니다.
  • 생성된 파일을 클래스 로더가 불러와 적절히 파싱하여 메소드영역에 저장합니다.
  • 인터프리터는 main 메소드를 시작점으로 코드를 쭉 읽어가며 다음의 문구를 만납니다.
강아지 가을이;
  • [가을이]라는 실별자는 [강아지] 타입으로 생성된 인스턴스의 주소만을 가질 수 있습니다.

가을이 = new 강아지("가을이", "믹스", 3, "화남");
  • new 키워드와 생성자 메소드를 통해서 [강아지] 타입의 객체를 생성합니다.
    이때 생성자 메소드의 매개변수에는 위와 같은 데이터가 들어갑니다.
  • 이렇게 생성된 객체의 주소를 [가을이]라는 식별자에 할당합니다.
가을이.왈왈();
  • [가을이]라는 식별자를 통해서 heap메모리에 있는 객체에 접근합니다.
    그리고 그 객체는 [강아지] Class에 정의된 왈왈이라는 메소드를 가지고 있습니다.
가을가 마구 짖습니다. 와르르르르왈왈와와라와라랑라아라랄ㄹ ㄹㄹㄹ!!!
  • 왈왈 메소드가 호출되면 위와 같이 콘솔에 메시지가 출력됩니다.

사실 코드가 실행되는 과정에 대해서 더 자세히 알려면 JVM의 내부동작을 자세히 알아야합니다.
아직 JVM에 대한 지식이 부족하여 제가 알고 있는 내용을 기반으로 대략적으로 설명하였습니다.
JVM에 대해선 이후에 더 공부하여 알아보려고 합니다.

마무리

약간 철학적인(?!?!) 이야기와 java 코드를 동원하여 Class와 Object에 대해서 알아보았습니다.
설명하다보니 생각보다 내용이 길어지고, 파고갈 수록 제가 감당하기 힘든 지식들도 있어서 이 문서를 작성하는데 애를 먹었습니다.
바쁜 분들을 위해서 요약을 해보겠습니다.

  • 개념적 비교
    Class는 분류이다. Class 행위와 이에 필요한 정보로 구성된다.
    Object는 그 분류를 적용하여 생성한 개별적인 실체들이다.
    Object는 개별적으로 자신만의 정보(인스턴스 변수의 값)를 가지며,
    Class에 정의된 행위(메소드)대로 동작한다.
  • 메모리의 비교
    Class의 정보는 ClassLoader에 의해서 메소드 영역에 적재된다.
    Object는 new 키워드와 생성자 메소드에 의해서 힙 영역에 적재된다.
    Ojbect는 Type(Class)의 정보를 바탕으로 메모리에 생성된다.
    각각의 Object는 힙메모리에서 주소를 가지게 되며, 변수는 이 주소로 Ojbect에 접근할 수 있다.
    Class에서 접근할 수 있는 것은 ststic 키워드가 붙은 데이터와 메소드이다.
    이는 어플리케이션 전체에서 공유된다.

좋은 웹페이지 즐겨찾기