자바 백엔드 입문 2편. 클래스·객체·필드·메서드·생성자·캡슐화를 붕어빵 틀 비유로 풀고, 왜 이게 Spring Bean 이해의 출발점이 되는지까지 한 흐름으로 정리한 입문자용 학습 노트.
이 글은 자바 백엔드 입문 시리즈 59편 중 2편이에요. 1편에서 자바·JVM·JDK·JRE 네 이름을 정리했다면, 2편에서는 자바의 진짜 기본기 — 클래스와 객체를 잡습니다. 여기를 단단히 잡고 가야 5편부터 본격적으로 다룰 Spring Bean이 "왜 그렇게 설계됐는지" 가 보이거든요.
클래스·객체가 어렵게 들리는 이유
처음 객체지향 책을 펴면 "클래스로 인스턴스를 찍어낸다" 같은 표현이 거듭 나옵니다. 단어는 다 한국어인데 머리에 그림이 안 그려져요. 두 가지가 원인이에요.
첫째, "클래스"와 "객체"가 비슷한 듯 다른 단어거든요. 클래스는 설계도, 객체는 실제 물건 — 책마다 비유는 다른데 머리에 한 번에 안 박힙니다.
둘째, "왜 객체지향 같은 걸 굳이?" 가 안 보입니다. 함수만 쓰면 안 되나? 이 질문은 5편 IoC 컨테이너에서 한 번에 풀려요. 일단 이번 글에서는 클래스 = 설계도, 객체 = 그 설계도로 만든 실물 한 줄만 머리에 박아두시면 충분합니다.
이 글에서는 두 단어를 붕어빵 틀과 붕어빵 비유로 풀어 갑니다. 끝까지 따라오시면 자바 코드가 "왜 new Player() 처럼 생긴 게 자꾸 나오는지" 가 한 번에 풀려요.
클래스 = 붕어빵 틀, 객체 = 그 틀로 찍어낸 붕어빵
클래스(Class) 는 "이런 모양·이런 능력을 가진 무언가를 만들겠다" 는 설계도예요. 자바 코드로는 이렇게 생겼습니다.
public class Player {
String name;
int hp;
void attack() {
System.out.println(name + " 공격!");
}
}
이건 틀이에요. 아직 실체가 없어요. 실제로 게임을 돌리려면 이 틀로 캐릭터를 "하나 찍어내야" 합니다.
Player alice = new Player(); // 1번 캐릭터 찍어냄
Player bob = new Player(); // 2번 캐릭터 찍어냄
alice.name = "Alice";
alice.hp = 100;
bob.name = "Bob";
bob.hp = 80;
alice.attack(); // "Alice 공격!"
bob.attack(); // "Bob 공격!"
new Player() 가 바로 "붕어빵 틀에 반죽 부어 한 개 찍어내는" 행위예요. 이렇게 찍어낸 결과물(alice, bob) 을 객체(Object) 또는 인스턴스(Instance) 라고 불러요. 두 단어는 거의 같은 뜻이라 헷갈리지 마세요 — 객체와 인스턴스는 99% 같이 써도 됩니다.
여기서 헷갈리기 쉬운 함정 하나 — "클래스를 객체" 라고 부르는 자료가 가끔 있어요. 정확히는 클래스로 찍어낸 결과물이 객체예요. 클래스는 객체가 아닙니다. 시험에 "클래스와 객체는 같은 말이다" 가 보기로 나오면 X.
한 줄 정리 — 클래스(Player) = 붕어빵 틀, 객체(alice·bob) = 그 틀로 찍어낸 붕어빵 한 개씩. new 키워드 = 반죽 부어 찍어내는 행위.
필드·메서드·생성자 — 클래스 안의 세 부품
클래스 안에는 세 가지 부품이 들어가요. 처음엔 다 비슷해 보이는데 역할이 명확해요.
1. 필드(Field) — 그 객체가 가진 정보
String name; int hp; 같은 줄이 필드예요. "이 캐릭터는 이름과 체력을 가진다" 라는 데이터 슬롯이에요. 다른 언어에서는 속성(property)·멤버 변수·인스턴스 변수로 부르기도 합니다.
2. 메서드(Method) — 그 객체가 할 수 있는 동작
void attack() {...} 같은 줄이 메서드예요. "이 캐릭터가 할 수 있는 행동" 이에요. 다른 언어의 함수와 비슷한데, 한 가지 결정적으로 다른 점이 있어요 — 메서드는 항상 특정 객체에 묶여서 실행돼요. alice.attack() 처럼 "누가 이 행동을 하는가" 가 항상 명확해야 호출이 됩니다.
3. 생성자(Constructor) — 객체를 처음 만들 때 한 번만 실행되는 초기화 코드
매번 alice.name = "Alice"; alice.hp = 100; 같이 두 줄로 초기화하는 게 번거롭잖아요. 그래서 생성자라는 특수한 메서드를 박아둡니다.
public class Player {
String name;
int hp;
public Player(String name, int hp) { // 생성자
this.name = name;
this.hp = hp;
}
void attack() { ... }
}
Player alice = new Player("Alice", 100); // 한 줄로 끝
생성자는 클래스 이름과 똑같은 이름을 가지고, new 호출 시 자동으로 한 번 실행돼요. "객체가 태어나는 순간에 한 번 호출되는 초기화 메서드" 라는 뉘앙스예요.
this.name = name; 의 this 는 "지금 만들어지고 있는 이 객체 자신" 을 가리켜요. 메서드 매개변수 이름과 필드 이름이 같을 때 둘을 구분하기 위해 박는 키워드. this 가 빠지면 자바 컴파일러가 "name = name" 으로 해석해서 필드가 아니라 매개변수에 자기 자신을 할당하는 황당한 결과가 나와요.
캡슐화 — private과 getter/setter
여기서 자바 객체지향의 핵심 개념 하나가 등장해요. 캡슐화(Encapsulation). 한 줄로 풀면 "객체의 내부를 함부로 못 만지게 보호하고, 공식 통로로만 접근하게 한다" 는 원칙이에요.
회사 비유로 풀어볼게요. "직원의 월급 정보" 를 누구나 직접 손대게 두면 안 되잖아요. 인사팀이 정해진 절차로만 변경해야 해요. 자바 클래스도 똑같이 다룹니다.
public class Player {
private String name; // private = 외부에서 직접 못 만짐
private int hp;
public Player(String name, int hp) {
this.name = name;
this.hp = hp;
}
// getter — 외부에서 hp 값을 읽을 수 있는 공식 통로
public int getHp() {
return hp;
}
// setter — 외부에서 hp 값을 바꿀 수 있는 공식 통로 (검증 가능)
public void setHp(int hp) {
if (hp < 0) hp = 0; // 음수 방지
this.hp = hp;
}
}
private— "이 필드는 클래스 안에서만 접근 가능, 외부에서 직접 못 만짐"public— "외부 어디서나 접근 가능"- getter —
getHp()같이 "필드 값을 읽기 위한 공식 메서드" - setter —
setHp()같이 "필드 값을 쓰기 위한 공식 메서드, 검증 로직을 끼워 넣을 수 있음"
여기서 시험 함정 하나 있어요. 자바 신입 면접에서 "왜 필드를 그냥 public으로 안 하고 private + getter/setter로 박나요?" 가 자주 나와요. 답은 검증 로직을 끼워 넣을 수 있고, 나중에 내부 구현을 바꿔도 외부 코드가 안 깨지기 때문이에요. 위 예제에서 setHp(-50) 호출이 들어와도 음수가 안 들어가도록 막을 수 있는 게 setter의 힘이에요.
한 줄 정리 — 캡슐화 = private 필드 + public getter/setter. 외부는 메서드로만 만지게 해서 "객체의 내부 상태 보호".
왜 객체와 클래스가 Spring 이해의 출발점인가
5편부터 본격적으로 다룰 Spring을 미리 짧게 미리보기 할게요. Spring의 핵심은 Bean이에요. Bean이 뭐냐 — "Spring 컨테이너가 대신 만들어 주는 객체" 예요.
@Component
public class PlayerService {
public void attack() { ... }
}
@Component 가 박혀 있으면 Spring이 "이 클래스로 객체를 한 개 찍어내서 컨테이너에 보관해 둘게" 라고 처리해요. 우리가 직접 new PlayerService() 를 안 해도 Spring이 시작 시점에 알아서 한 번 찍어내고, 필요한 곳에 자동으로 끼워 넣어줍니다.
이게 5편에서 풀 IoC(Inversion of Control) 의 핵심이에요. "객체 생성을 내가 직접 하지 않고 컨테이너에 맡긴다". 그 그림이 머리에 박히려면 클래스로 객체를 찍어낸다는 기본 그림이 먼저 박혀 있어야 합니다. 그래서 2편을 객체와 클래스에 통째로 쓴 거예요.
클래스(2편) → 인터페이스·다형성(3편) → 어노테이션(4편) → Spring Bean(8편) → IoC 컨테이너(11편) — 이 흐름으로 자바 객체지향이 Spring DI에 어떻게 연결되는지 한 줄로 풀려요.
시험 직전 한 번 더 — 클래스·객체 입문자가 매번 헷갈리는 것
- 클래스 = 설계도(붕어빵 틀), 객체 = 그 설계도로 찍어낸 실물(붕어빵)
new키워드 = "클래스로 객체 한 개 찍어내는" 행위- 객체 = 인스턴스 (99% 같은 말, 책마다 다른 단어 쓸 뿐)
- 클래스는 객체가 아님 — "클래스가 객체다" 라는 보기는 X
- 클래스의 세 부품 = 필드(데이터) · 메서드(동작) · 생성자(초기화)
- 생성자 이름 = 클래스 이름과 동일,
new시 자동 1회 실행 this= "지금 만들어지고 있는 이 객체 자신"- 캡슐화 =
private필드 +publicgetter/setter private= 클래스 안에서만 접근,public= 외부 어디서나- getter/setter 박는 이유 = 검증 로직 + 내부 구현 변경 시 외부 코드 보호
- IDE(IntelliJ·Eclipse)는 getter/setter 자동 생성 단축키가 있어요
- 자바 메서드는 항상 특정 객체에 묶여서 실행 (
alice.attack()) static키워드 박으면 객체 없이 클래스 자체로 호출 (다음 시간에)- 자바 신입 면접 단골 — "필드를 왜 private + getter/setter로 박나요?"
- 답 = 검증 끼워 넣기 + 내부 구현 자유롭게 바꿀 수 있음
- 클래스 이름 = PascalCase (
Player), 메서드·필드 이름 = camelCase (getName) - Spring Bean = "Spring 컨테이너가 대신 만들어 주는 객체"
@Component= "이 클래스로 객체 하나 찍어내 컨테이너에 보관해 줘"- 클래스·객체 그림이 안 박히면 Spring IoC 컨테이너 이해가 무너짐
시리즈 다른 편 (앞뒤 글 모음)
이전 글:
다음 글: