본문 바로가기

TIL

객체지향 이해하기 -1 (배경 지식)

클래스와 객체

클래스란 무엇일까, 제가 이걸 처음 감을잡은건 "이건 절대 존재하는 어떤 것이 아니다" 라고생각을 했습니다.

정말 다양한 설명들이 있고 강의가 있지만 제가 스스로 이해(받아드린) 말은 저것이었습니다. 

물론 틀릴 수 도 있고 명확한 설명이 아닐 수 있지만,

제 나름의 근거를 설명 드리자면.

우선 객체는 무엇일까요?

학습한 강의를 보면

"실제로 존재하는 어떤 것" 이라고 설명이 되어있습니다. 그럼 저는 한가지 질문을 더 던져보고싶습니다.

"실제로 어디에 존재하나요?" 저는 이게 컴퓨터 세계안에 존재한다고 이해했습니다. 

코드로 예시를 살펴볼까요. 

하나의 클래스를 만들었습니다.

pubilc class Person {...}

하나의 객체도 만들어 볼까요.

new Person();

 

자 우린 여기서 잘 생각해 봐야한다고 생각합니다. 

저 new 키워드를 이용해 만든 객체는 컴퓨터 메모리 안에 "실제로 존재" 하게 됩니다.

Person이라는 정보가 생겨난 것이고 그것은 실제 다른 것들과 상호작용 하며 걸을수도 핸드폰을 집을 수도, 게임이라면 몬스터를 잡을 수도있습니다.

그럼 class로 만든 person은? 저것은 그저 객체가 어떤식으로 구성이 되어있는지 무엇과 상호작용하는지 설명되어있는 것뿐이지 실제로 클래스가 다른 클래스와 상호 작용하지 않습니다.

 

조금 더 쉽게 예시를 들어보면,

라면을 먹으려 해봅시다.

public class Ramen{...}

이건  우리가 먹을 수 있는 라면인가요? 

아니요 그렇지 않습니다. 이건 그저 라면이 어떻게 구성되어있는지 나타낸 성분표라고 이해하시면 됩니다.

그럼 우리가 먹을 수 있는 라면 은 무엇인가요?

Ramen sinRamen = new Ramen();

우리가 먹을 수 있는 신라면이 만들어졌습니다. 

저 new 키워드를 통해 만든 라면이 실제로 메모리에 들어가있는 데이터이고 우린 저 라면을 먹을 수 있습니다.

 

그럼 이런 클래스는어떻게 구성이 되어있을까요.

class 클래스 {

		// 1. 속성
		
		// 2. 생성자
		
		// 3. 기능
}

우리는 클래스의 속성 생성자 기능을 정의 해 주어야합니다.

속성 : 그 클래스가 가지고있는 특징입니다.

생성자 : 클래스를 어떻게 선언하고 사용해야 할지 나타냅니다.

기능 : 메서드로 표현하며 , 클래스가 할 수 있는 모든 기능을 구현 할 수있다.

 

이번에도 ramen 성분표를 한번 만들어 봅시다.

public class Ramen {
	// 1. 속성
    String noodle;
    String soup;
    String garnish;
    
}

어떤가요 무엇인지 이해가 가시나요? 속성은 말 그대로 그 클래스가 가지고 있는 특징을 나타낸다고 볼 수 있습니다.

public class Ramen {
	// 기본 생성자 Ramen(){} 
    
    Ramen (String nodle , String suop ,String garnish) {
    	this.nodle = nodle;
        this.suop = soup;
        this.garnish = garnish;
    }
}

 

ramen sinRamen = new Ramen("쫄깃한 맛있는 면" , "약간 매운맛의 스프" , "버섯이 들어간 건더기");

객체를 생성하면서 변수로 받은 값을 생성자를 통해 전달하여 속성들의 데이터를 할당 해주는 것을 확인 할 수 있습니다.

생성자는 반환 자료형이없고, 클래스와 이름이 똑같으며 여러개가 존재 할 수 있다는 특징이 있습니다.

여러개가 존재 할 수 있다, 무슨 말일까요?

확인 해봅시다

public class Ramen {
	// 기본 생성자 Ramen(){} 
    
    
    Ramen (String nodle , String suop) {
    	this.nodle = nodle;
        this.suop = soup;
    }
    
    Ramen (String nodle , String suop ,String garnish) {
    	this.nodle = nodle;
        this.suop = soup;
        this.garnish = garnish;
    }
}
ramen sinRamen = new Ramen("쫄깃한 맛있는 면" , "약간 매운맛의 스프" , "버섯이 들어간 건더기");
ramen ansungRamen = new Ramen("탱탱한 면" , "부드러운 국물이 예술인 스프");

어떤가요 신라면과 다르게 안성탕면은 가니시를 선언 해주지 않았습니다.

생성자는 이런식으로 속성을 선택해서 할당 해 줄 수있습니다.

 

마지막으로 기능 부분을 확인해보도록 하겠습니다.

우리가 흔히 작성하는 매서드가 기능이라고 생각해도 좋고, 우리가 생각하는 모든 기능을 구현 할 수 있다.

단 그 객체에 맞는 기능을 작성해야 우리가 객체지향 관점에서 좋은 코드를 작성했다고 생각 해볼 수 있을거같다.

public class Ramen {

	void becomeDelicious() {
    	// ..맛있어 지는중..
    }

}

어떤가 라면이 맛있어지는 기능을 가지고있다. 

그럼 이건 어떨까

public class Ramen {

	void eat(){
    	// 맛있게 먹는중..
    }

}

라면이 맛있게 먹는다? 이게 라면의 기능인가? 하게되는 생각을 해봐야 한다. 지금은 쉬운 예제이지만 개발을 하다 우리가 도매인에 대한 이해도가 낮을때 이런 애매한 상황이 나올 수 있다고 생각한다.

그럴때마다 우리는 의사결정을 잘 해봐야 좋은 코드를 만들 수 있을거같다.

 

JVM 메모리 영역

Java에는 크게 3가지의 메모리 구조로 나누워진다. 이전 포스팅에서 JVM에대해 간단히 서술한적 있는데, 그 구조중에 데이터를 보관하고 저장하는 공간을 메모리 영역이라 한다. 

위 사진 처럼3가지 공간이 존재하며, 각각 Method Area, Stack ,Heap 이라고 불린다.

Method Area : 프로그램 시작 시 데이터가 모두 저장 되며 클래스의 정보가 올라가는 곳, 

클래스의 메서드 정보 static 변수 등이 저장. 모든 객체가 공유 가능한 공유 공간입니다. 

 

Stack : 선입 후출 구조이며 먼저 들어온것이 가장 나중에 나가는 구조. 메서드가 호출될때마다 새로운 스택프레임이 쌓인다.

 

Heap : new 키워드를 사용해 생성된 객체가 실제로 저장되는 곳, 데이터의 주소는 stack에 저장.

https://cscircles.cemc.uwaterloo.ca/java_visualize/

 

Java Visualizer

Write your Java code here: args: +command-line argument stdin (also visualizes consumption of StdIn) x <!-- Execute code using Python 2.7 Python 3.3 , --> <!-- these two make sense, but are not implemented yet hide frames of exited functions show frames of

cscircles.cemc.uwaterloo.ca

해당 사이트에서 실제 데이터가 어떤식으로 쌓이는지 눈으로 확인 할 수 있다.

Frames 부분이 Stack Area Objects가 Heap Area이다.

이 부분을 학습 하다 문득 궁금해진것이 있는데, 사이트에 들어가 동작을 해보면 method area에서 메서드는 종료시 빠져나가는 것을 확인 할 수 있지만 변수들을 끝까지 남아있는 것을 확인 할 수 있다. 

 

그럼 만약 저 변수가 100개200개가 된다면 어떤 문제가 생기지 않을까?? 구글링 좀 해보니 가비지 컬랙터 라는애가 그걸 처리해준다는데.

튜텨님에게 여쭤보니 한번 학습해보고 TIL작성 해보는것도 좋겠다 말씀 주셔서 주말동안 가비지컬랙터에 대해 조금 공부하고 작성해보고자 합니다.

 

래퍼클래스

기본자료형을 객체로 감싸는 클래스,

기본 자료형 (Primitive Type) 래퍼 클래스 (Wrapper Class)
byte Byte
short Short
int Integer
long Long
float Float
double Double
char Character
boolean Boolean

 

래퍼 클래스는 왜 사용할까? 

강의에서 설명한 내용은 기본 자료형은 객체처럼 속성,기능을 가질 수 없지만 객체는 기능을 제공 할 수있다. 

Integer num = 123; // 래퍼클래스
String str = num.toString(); // ✅ 편리한 기능

int a = 100; // 그냥 데이터 100
String str = a.toString(); // ❌ 변환 불가

근데 나에겐 이게 그렇게까지 강력한 기능인가? 라는 생각이 들었다..

그래서 gpt와 학습을 조금 해봤는데

래퍼 클래스의 본질은 “값을 객체 세계(Object World)로 끌어오기” 라는 답변을 받았다. 

 

Primitive 세계 int, double, boolean → 계산 빠름, 메모리 작음
Object 세계 Object 기반 → 컬렉션, 제네릭, null, 다형성 가능

제내릭, null ,다형성등 데이터를 객체로써 다룰 수 있기때문에 필요한 것이라 할 수있겠다.

 

오토박싱 , 언박싱

래퍼클래스와 기본형으로 형변환은 아주 자주 일어난다.

Java에서는 이런 형변환 과정을 자동으로 지원해준다. 

 

오토박싱 - 기본형=> 래퍼형으로 변환 하는 과정

Integer num3 = 10; // ✅ 오토박싱

// 내부 처리 과정
// Integer num = Integer.valueOf(10);

 

언박싱 - 래퍼형 => 기본형으로 변환 하는 과정

Integer num3 = 10; 
int num = num3;   // ✅ 오토 언박싱

// 내부 과정
// int num = num3.intValue();

 

간단한 것이지만 오토박싱을 잘못사용하면 아주 간단하게 프로그램을 고장나게 할 수 있습니다. 

Integer sum = 0;

for (int i = 0; i < 10_000_000; i++) {
    sum += i;
}

그냥 보기에 정말 간단한 더하기 코드같지만 보면 sum을 래퍼클래스로 선언했고, 반복문 안에서 기본형인 int i 가 계속해서더해지고 있습니다.

그럼 내부적으로 어떤 일이 발생하냐면

sum = Integer.valueOf(sum.intValue() + i);

이런 코드가 계속 동작을 하는겁니다 Integer 라는 객체를 1000만개를 만들어 버리는거고 그러면 프로그램이 오류가 발생하거나 성능이 저하 될 것입니다. 이런 점의 유의하여 코딩을 해야할거같습니다. 

 

Static

모든 객체가 함께 사용하는 변수나 메서드를 만들 때 사용,

객체를 만들지 않아도 클래스 이름만으로 바로 사용할 수 있다.

모든 객체가 같은 값을 공유하고 처음 한번만 생성되며 method area에 저장됩니다.

class Person {
		// ✅ static 변수
		static int population = 0; 
		
		// ✅ static 메서드
		static void printPopulation() { 
				System.out.println("현재 인구 수: " + population);
		}
}
System.out.println("static 변수: " + Person.population);
System.out.println("static 메서드: " + Person.printPopulation);

static으로 선언된 데이터는 객체생성없이 접근이 가능하다. 이런 변수나 매서드를 클래스 맴버 클래서 매서드라고 부릅니다.

그럼 그 반대로 객체를 생성해야 접근 할 수 있는 속성과 매서드를 인스턴스 변수 인스턴스 매서드라고 부릅니다.

 

static은 꼭 필요할때만 만들어서 사용해야 한다. 만약 name을 static으로 선언해버리면 모든 객체가 다똑같은name을 가지게 될것입니다. 또한 너무 많이 남용하면 메모리또한 낭비됩니다. 

final

변수의 변경이 불가능하게 만든다. 

클래스는 상속을 불가능 하게 만든다

메서드는 오버라이딩이 불가능 하게 만들어줍니다.

즉 상수를 만드는건데 자바에서 상수는 대문자로 표현하는것이 관례이며 절대 변경되서는 안되기 때문에 static final 키워드를 사용한다.

'TIL' 카테고리의 다른 글

싱글톤 패턴(Singleton Pattern)이란?  (1) 2026.01.13
Garbage Collection(GC) 이란?  (0) 2026.01.12
Hello Java!  (1) 2026.01.08
git revert ,rebase, amend, Squash  (0) 2026.01.07
트러블슈팅 (git protect branch from merge.)  (0) 2026.01.07