목차
- 클래스와 객체의 관계
- 인스턴스란 무엇인가?
- 생성자(Constructor)란?
- 오버로딩(Overloading) vs 오버라이딩(Overriding)
- 상속(Inheritance)과 생성자 호출 순서
- 실전 예제와 연습 문제
1. 클래스와 객체의 관계
클래스는 설계도다!
java
public class Handbag {
// 속성(필드)
String brandName;
int price;
String bagName;
boolean hasHandle;
// 행동(메서드)
void display() {
System.out.println(bagName + " by " + brandName);
}
}
시각적 이해
┌─────────────────────────────┐
│ CLASS (설계도) │
│ ┌─────────────────────┐ │
│ │ brandName: String │ │ ← 이것만으로는
│ │ price: int │ │ 아무것도 할 수 없음!
│ │ bagName: String │ │
│ │ hasHandle: boolean │ │
│ └─────────────────────┘ │
└─────────────────────────────┘
↓ new 키워드로 실체화
┌──────────┐ ┌──────────┐ ┌──────────┐
│ bag1 │ │ bag2 │ │ bag3 │
│ "에르메스" │ │ "샤넬" │ │ "구찌" │
│ 50000 │ │ 30000 │ │ 20000 │
└──────────┘ └──────────┘ └──────────┘
(객체1) (객체2) (객체3)
2. 인스턴스란 무엇인가?
핵심 개념
- 클래스: 붕어빵 틀 (메모리에 존재하지 않음)
- 인스턴스: 실제로 만들어진 붕어빵 (메모리에 존재)
- new 키워드: 붕어빵을 굽는 행위
java
public class Main {
public static void main(String[] args) {
// Dog 클래스의 인스턴스 생성
Dog myDog = new Dog(); // 첫 번째 강아지
Dog yourDog = new Dog(); // 두 번째 강아지
// 각각 독립적인 메모리 공간
myDog.name = "Buddy";
yourDog.name = "Max";
System.out.println(myDog.name); // Buddy
System.out.println(yourDog.name); // Max
}
}
메모리 구조
HEAP 메모리
┌─────────────────────────────────┐
│ myDog (주소: 0x100) │
│ ┌──────────────┐ │
│ │ name: "Buddy"│ │
│ │ age: 3 │ │
│ └──────────────┘ │
│ │
│ yourDog (주소: 0x200) │
│ ┌──────────────┐ │
│ │ name: "Max" │ │
│ │ age: 5 │ │
│ └──────────────┘ │
└─────────────────────────────────┘
3. 생성자(Constructor) 란 ?
생성자의 규칙
- 클래스 이름과 동일해야 함
- 반환 타입이 없음 (void도 쓰지 않음)
- 객체 생성 시 자동 호출
java
class Handbag {
String brandName;
int price;
// 기본 생성자
public Handbag() {
brandName = "No Brand";
price = 0;
}
// 매개변수가 있는 생성자 (오버로딩)
public Handbag(String brandName, int price) {
this.brandName = brandName; // this = 현재 객체
this.price = price;
}
}
this 키워드의 이해
java
public Handbag(String brandName, int price) {
this.brandName = brandName;
// ↑ 객체의 필드 ↑ 매개변수
this.price = price;
// ↑ 객체의 필드 ↑ 매개변수
}
this가 가리키는 것
Handbag bag1 = new Handbag("에르메스", 50000);
↓
this는 bag1을 가리킴
Handbag bag2 = new Handbag("샤넬", 30000);
↓
this는 bag2를 가리킴
4. 오버로딩 vs 오버라이딩
오버로딩 (Overloading) - "다양한 방법"
같은 이름, 다른 매개변수
java
class Calculator {
// 정수 2개 더하기
int add(int a, int b) {
return a + b;
}
// 정수 3개 더하기 (오버로딩)
int add(int a, int b, int c) {
return a + b + c;
}
// 실수 2개 더하기 (오버로딩)
double add(double a, double b) {
return a + b;
}
}
오버라이딩 (Overriding) - "재정의"
상속받은 메서드를 자식이 다시 정의
java
class Car {
void refuel() {
System.out.println("⛽ 주유소에서 기름 넣기");
}
}
class ElectricCar extends Car {
@Override
void refuel() {
System.out.println("🔌 충전소에서 전기 충전");
}
}
class HydrogenCar extends Car {
@Override
void refuel() {
System.out.println("💧 수소 충전소에서 수소 충전");
}
}
비교표
특징 | 오버로딩 | 오버라이딩 |
위치 | 같은 클래스 | 부모-자식 관계 |
메서드명 | 동일 | 동일 |
매개변수 | 반드시 달라야 함 | 반드시 같아야 함 |
반환타입 | 상관없음 | 같아야 함 |
접근제어자 | 상관없음 | 부모보다 좁으면 안됨 |
@Override | 사용 안함 | 권장 (명확성) |
5. 상속과 생성자 호출 순서
상속 계층 구조
java
class Vehicle {
Vehicle() {
System.out.println("1. Vehicle 생성자");
}
}
class Car extends Vehicle {
Car() {
System.out.println("2. Car 생성자");
}
}
class ElectricCar extends Car {
ElectricCar() {
System.out.println("3. ElectricCar 생성자");
}
}
// 실행
ElectricCar tesla = new ElectricCar();
// 출력:
// 1. Vehicle 생성자
// 2. Car 생성자
// 3. ElectricCar 생성자
생성자 호출 흐름도
[Vehicle]
↑
[Car] ← super() 자동 호출
↑
[ElectricCar] ← super() 자동 호출
↑
new 호출
super 키워드
java
class Car {
String model;
int year;
Car(String model, int year) {
this.model = model;
this.year = year;
}
}
class ElectricCar extends Car {
int batteryCapacity;
ElectricCar(String model, int year, int battery) {
super(model, year); // 부모 생성자 명시적 호출
this.batteryCapacity = battery;
}
}
6. 실전 예제
종합 예제: 은행 계좌 시스템
java
// 기본 계좌 클래스
class Account {
protected String accountNumber;
protected double balance;
public Account(String accountNumber) {
this.accountNumber = accountNumber;
this.balance = 0;
}
// 입금
public void deposit(double amount) {
balance += amount;
System.out.println("입금: " + amount);
}
// 출금
public void withdraw(double amount) {
if (balance >= amount) {
balance -= amount;
System.out.println("출금: " + amount);
} else {
System.out.println("잔액 부족!");
}
}
}
// 저축 계좌 (상속)
class SavingsAccount extends Account {
private double interestRate;
public SavingsAccount(String accountNumber, double rate) {
super(accountNumber); // 부모 생성자 호출
this.interestRate = rate;
}
// 이자 계산 (새로운 메서드)
public void addInterest() {
double interest = balance * interestRate;
balance += interest;
System.out.println("이자 추가: " + interest);
}
}
// 체크카드 계좌 (상속 + 오버라이딩)
class CheckingAccount extends Account {
private double overdraftLimit;
public CheckingAccount(String accountNumber, double limit) {
super(accountNumber);
this.overdraftLimit = limit;
}
@Override
public void withdraw(double amount) { // 오버라이딩
if (balance + overdraftLimit >= amount) {
balance -= amount;
System.out.println("출금(마이너스 통장): " + amount);
} else {
System.out.println("한도 초과!");
}
}
}
추가 학습 자료
Oracle 공식 문서
핵심 암기 사항 ✅
- 클래스 = 변수의 타입
- 생성자 = 클래스명과 동일
- this = 현재 객체 참조
- super = 부모 클래스 참조
- new = 인스턴스 생성
- extends = 상속 키워드
- @Override = 메서드 재정의 표시
연습 문제
java
// 문제: Animal 클래스를 상속받는 Cat 클래스를 만들고,
// makeSound() 메서드를 오버라이딩하세요.
class Animal {
String name;
void makeSound() {
System.out.println("동물이 소리를 냅니다");
}
}
// 여기에 Cat 클래스 작성
class Cat extends Animal {
@Override
void makeSound() {
System.out.println("야옹~");
}
// Cat만의 메서드
void scratch() {
System.out.println("할퀴기!");
}
}
'Java' 카테고리의 다른 글
Java | 메모리 구조 + static vs 인스턴스 종합 정리 (0) | 2025.10.04 |
---|---|
Java | Hiding (0) | 2025.10.04 |
Java | 정적 변수 vs 정적 메서드 (2) | 2025.10.04 |
Java | static vs 인스턴스 변수 차이점 (0) | 2025.10.04 |
Java | 업캐스팅과 다운캐스팅 (0) | 2025.10.02 |