본문 바로가기
  • 코딩, 허쌤이 떠먹여 줄게
BackEnd/Java

# 8장. 객체지향 핵심 개념

by 허쌤 2026. 1. 1.

8장. 객체지향 핵심 개념

객체지향 프로그래밍의 4대 핵심 개념

객체지향 프로그래밍(OOP)의 핵심은 다음 4가지 개념으로 구성됩니다:

  1. 캡슐화 (Encapsulation): 데이터와 메서드를 하나로 묶어 관리
  2. 상속 (Inheritance): 기존 클래스를 확장하여 새로운 클래스 생성
  3. 다형성 (Polymorphism): 하나의 인터페이스로 여러 형태 구현
  4. 추상화 (Abstraction): 복잡한 것을 단순하게 표현

캡슐화 (Encapsulation)

캡슐화란?

캡슐화는 데이터와 그 데이터를 처리하는 메서드를 하나의 클래스로 묶는 것입니다. 외부에서 데이터에 직접 접근하지 못하도록 하고, 메서드를 통해서만 접근할 수 있게 합니다.

캡슐화의 목적

  1. 데이터 보호: 외부에서 데이터를 직접 변경하는 것을 방지
  2. 데이터 검증: setter 메서드에서 유효성 검사 가능
  3. 유지보수 용이: 필드 변경 시 getter/setter만 수정하면 됨
  4. 정보 은닉: 내부 구현을 숨기고 외부 인터페이스만 제공

캡슐화 구현 방법

1. private 필드 사용

public class Student {
    // private 필드: 외부에서 직접 접근 불가
    private String name;
    private int age;
    private double gpa;
}

2. Getter와 Setter 메서드 제공

public class Student {
    private String name;
    private int age;
    private double gpa;

    // Getter: 필드 값을 읽는 메서드
    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    // Setter: 필드 값을 설정하는 메서드 (유효성 검사 포함)
    public void setName(String name) {
        if (name != null && !name.trim().isEmpty()) {
            this.name = name;
        }
    }

    public void setAge(int age) {
        if (age >= 0 && age <= 150) {
            this.age = age;
        }
    }

    public void setGpa(double gpa) {
        if (gpa >= 0.0 && gpa <= 4.5) {
            this.gpa = gpa;
        }
    }
}

캡슐화 예제

public class BankAccount {
    private String accountNumber;
    private double balance;

    public BankAccount(String accountNumber, double initialBalance) {
        this.accountNumber = accountNumber;
        if (initialBalance >= 0) {
            this.balance = initialBalance;
        } else {
            this.balance = 0;
        }
    }

    // Getter
    public double getBalance() {
        return balance;
    }

    // 입금 (유효성 검사 포함)
    public void deposit(double amount) {
        if (amount > 0) {
            balance += amount;
        }
    }

    // 출금 (유효성 검사 포함)
    public boolean withdraw(double amount) {
        if (amount > 0 && amount <= balance) {
            balance -= amount;
            return true;
        }
        return false;
    }
}

상속 (Inheritance)

상속이란?

상속은 기존 클래스의 속성과 메서드를 새로운 클래스가 물려받는 것입니다. 코드 재사용을 극대화하고, 계층 구조를 만들 수 있습니다.

상속의 장점

  1. 코드 재사용: 기존 클래스의 코드를 재사용
  2. 유지보수 용이: 부모 클래스 수정 시 자식 클래스에 자동 반영
  3. 계층 구조: 클래스 간 관계를 명확히 표현
  4. 확장성: 기존 기능을 확장하여 새로운 클래스 생성

상속 문법

class 자식클래스 extends 부모클래스 {
    // 자식 클래스만의 추가 필드와 메서드
}

상속 예제

// 부모 클래스 (상위 클래스)
public class Animal {
    String name;
    int age;

    public void eat() {
        System.out.println(name + "이(가) 먹습니다.");
    }

    public void sleep() {
        System.out.println(name + "이(가) 잡니다.");
    }
}

// 자식 클래스 (하위 클래스)
public class Dog extends Animal {
    String breed;  // 자식 클래스만의 추가 필드

    public void bark() {  // 자식 클래스만의 추가 메서드
        System.out.println(name + "이(가) 짖습니다.");
    }
}

// 사용
Dog dog = new Dog();
dog.name = "멍멍이";
dog.age = 3;
dog.breed = "골든리트리버";
dog.eat();    // 부모 클래스의 메서드 사용
dog.bark();   // 자식 클래스의 메서드 사용

super 키워드

super는 부모 클래스를 가리키는 참조 변수입니다.

super로 부모 클래스의 생성자 호출

public class Animal {
    String name;
    int age;

    public Animal(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

public class Dog extends Animal {
    String breed;

    public Dog(String name, int age, String breed) {
        super(name, age);  // 부모 클래스의 생성자 호출
        this.breed = breed;
    }
}

super로 부모 클래스의 메서드 호출

public class Animal {
    public void makeSound() {
        System.out.println("동물이 소리를 냅니다.");
    }
}

public class Dog extends Animal {
    @Override
    public void makeSound() {
        super.makeSound();  // 부모 클래스의 메서드 호출
        System.out.println("멍멍!");
    }
}

메서드 오버라이딩 (Method Overriding)

자식 클래스에서 부모 클래스의 메서드를 재정의하는 것입니다.

public class Animal {
    public void makeSound() {
        System.out.println("동물이 소리를 냅니다.");
    }
}

public class Dog extends Animal {
    @Override  // 어노테이션 (선택사항이지만 권장)
    public void makeSound() {
        System.out.println("멍멍!");
    }
}

public class Cat extends Animal {
    @Override
    public void makeSound() {
        System.out.println("야옹!");
    }
}

상속의 제한사항

  • Java는 단일 상속만 지원 (하나의 부모 클래스만 상속 가능)
  • private 필드와 메서드는 상속되지 않음
  • 생성자는 상속되지 않음

다형성 (Polymorphism)

다형성이란?

다형성은 하나의 인터페이스나 부모 클래스를 통해 여러 형태의 객체를 다룰 수 있는 것입니다. "하나의 이름으로 여러 형태를 표현"한다는 의미입니다.

다형성의 종류

1. 컴파일 타임 다형성 (오버로딩)

public class Calculator {
    public int add(int a, int b) {
        return a + b;
    }

    public double add(double a, double b) {
        return a + b;
    }
}

2. 런타임 다형성 (오버라이딩)

Animal animal1 = new Dog();
Animal animal2 = new Cat();

animal1.makeSound();  // "멍멍!"
animal2.makeSound();  // "야옹!"

업캐스팅 (Upcasting)

자식 클래스 객체를 부모 클래스 타입으로 참조하는 것입니다.

Animal animal = new Dog();  // 업캐스팅
animal.makeSound();  // Dog의 makeSound() 호출

다운캐스팅 (Downcasting)

부모 클래스 타입을 자식 클래스 타입으로 변환하는 것입니다.

Animal animal = new Dog();
Dog dog = (Dog) animal;  // 다운캐스팅
dog.bark();  // Dog만의 메서드 호출

instanceof 연산자

객체가 특정 클래스의 인스턴스인지 확인합니다.

Animal animal = new Dog();

if (animal instanceof Dog) {
    Dog dog = (Dog) animal;
    dog.bark();
}

다형성 예제

public class Animal {
    public void makeSound() {
        System.out.println("동물이 소리를 냅니다.");
    }
}

public class Dog extends Animal {
    @Override
    public void makeSound() {
        System.out.println("멍멍!");
    }

    public void bark() {
        System.out.println("왈왈!");
    }
}

public class Cat extends Animal {
    @Override
    public void makeSound() {
        System.out.println("야옹!");
    }
}

// 사용
Animal[] animals = {
    new Dog(),
    new Cat(),
    new Dog()
};

for (Animal animal : animals) {
    animal.makeSound();  // 각 객체의 오버라이딩된 메서드 호출
}

추상 클래스 (Abstract Class)

추상 클래스란?

추상 클래스는 완전하지 않은 클래스로, 하나 이상의 추상 메서드를 포함하는 클래스입니다. 직접 객체를 생성할 수 없고, 상속을 통해 사용됩니다.

추상 클래스의 특징

  1. abstract 키워드 사용: abstract class 클래스명
  2. 객체 생성 불가: new로 직접 생성 불가
  3. 추상 메서드 포함 가능: 구현이 없는 메서드
  4. 일반 메서드도 포함 가능: 구현된 메서드도 포함 가능
  5. 상속 필수: 자식 클래스에서 추상 메서드를 구현해야 함

추상 클래스 정의

public abstract class Animal {
    String name;
    int age;

    // 일반 메서드
    public void eat() {
        System.out.println(name + "이(가) 먹습니다.");
    }

    // 추상 메서드 (구현 없음)
    public abstract void makeSound();
}

추상 클래스 상속

public class Dog extends Animal {
    @Override
    public void makeSound() {
        System.out.println("멍멍!");
    }
}

public class Cat extends Animal {
    @Override
    public void makeSound() {
        System.out.println("야옹!");
    }
}

추상 클래스 예제

public abstract class Shape {
    String color;

    public Shape(String color) {
        this.color = color;
    }

    // 일반 메서드
    public String getColor() {
        return color;
    }

    // 추상 메서드: 넓이 계산
    public abstract double calculateArea();

    // 추상 메서드: 둘레 계산
    public abstract double calculatePerimeter();
}

public class Circle extends Shape {
    double radius;

    public Circle(String color, double radius) {
        super(color);
        this.radius = radius;
    }

    @Override
    public double calculateArea() {
        return Math.PI * radius * radius;
    }

    @Override
    public double calculatePerimeter() {
        return 2 * Math.PI * radius;
    }
}

public class Rectangle extends Shape {
    double width;
    double height;

    public Rectangle(String color, double width, double height) {
        super(color);
        this.width = width;
        this.height = height;
    }

    @Override
    public double calculateArea() {
        return width * height;
    }

    @Override
    public double calculatePerimeter() {
        return 2 * (width + height);
    }
}

인터페이스 (Interface)

인터페이스란?

인터페이스는 클래스가 구현해야 하는 메서드들의 목록을 정의한 것입니다. "무엇을 해야 하는지"는 정의하지만 "어떻게 하는지"는 정의하지 않습니다.

인터페이스의 특징

  1. interface 키워드 사용: interface 인터페이스명
  2. 객체 생성 불가: 직접 객체 생성 불가
  3. 모든 메서드는 추상 메서드: Java 8 이전에는 모든 메서드가 추상 메서드
  4. 다중 구현 가능: 여러 인터페이스를 구현 가능
  5. 상수만 포함 가능: 필드는 모두 public static final

인터페이스 정의

public interface Flyable {
    // 추상 메서드 (abstract 키워드 생략 가능)
    void fly();

    // 상수
    int MAX_SPEED = 100;
}

public interface Swimmable {
    void swim();
}

인터페이스 구현

public class Duck implements Flyable, Swimmable {
    @Override
    public void fly() {
        System.out.println("오리가 날아갑니다.");
    }

    @Override
    public void swim() {
        System.out.println("오리가 수영합니다.");
    }
}

인터페이스 vs 추상 클래스

구분 인터페이스 추상 클래스
키워드 interface abstract class
상속/구현 implements extends
다중 상속 가능 (여러 인터페이스 구현) 불가능 (단일 상속)
필드 상수만 가능 일반 필드 가능
메서드 추상 메서드만 (Java 8 이전) 추상/일반 메서드 모두 가능
생성자 없음 있음
사용 목적 "무엇을" 정의 "무엇을" + "어떻게" 일부 정의

인터페이스 예제

// 인터페이스 정의
public interface Drawable {
    void draw();
}

public interface Resizable {
    void resize(double factor);
}

// 클래스가 여러 인터페이스 구현
public class Circle implements Drawable, Resizable {
    double radius;

    public Circle(double radius) {
        this.radius = radius;
    }

    @Override
    public void draw() {
        System.out.println("원을 그립니다. 반지름: " + radius);
    }

    @Override
    public void resize(double factor) {
        radius *= factor;
        System.out.println("크기 조정 후 반지름: " + radius);
    }
}

Java 8의 인터페이스 개선

Java 8부터 인터페이스에 default 메서드static 메서드를 포함할 수 있습니다.

public interface Animal {
    // 추상 메서드
    void makeSound();

    // default 메서드 (구현 포함)
    default void eat() {
        System.out.println("동물이 먹습니다.");
    }

    // static 메서드
    static void info() {
        System.out.println("동물 인터페이스입니다.");
    }
}

객체지향 핵심 개념 종합 예제

예제: 도형 관리 시스템

// 추상 클래스
public abstract class Shape {
    String color;

    public Shape(String color) {
        this.color = color;
    }

    public abstract double calculateArea();
    public abstract void draw();
}

// 인터페이스
public interface Resizable {
    void resize(double factor);
}

// 클래스 구현
public class Circle extends Shape implements Resizable {
    double radius;

    public Circle(String color, double radius) {
        super(color);
        this.radius = radius;
    }

    @Override
    public double calculateArea() {
        return Math.PI * radius * radius;
    }

    @Override
    public void draw() {
        System.out.println(color + " 원을 그립니다.");
    }

    @Override
    public void resize(double factor) {
        radius *= factor;
    }
}

// 다형성 활용
Shape[] shapes = {
    new Circle("빨강", 5.0),
    new Rectangle("파랑", 4.0, 6.0)
};

for (Shape shape : shapes) {
    shape.draw();
    System.out.println("넓이: " + shape.calculateArea());
}

연습 문제

  1. 캡슐화

    • Person 클래스를 만들고, 이름과 나이를 private 필드로 선언한 후 getter/setter를 작성하세요.
  2. 상속

    • Vehicle 클래스를 부모로 하고, CarMotorcycle 클래스를 자식으로 만들어 상속을 구현하세요.
  3. 다형성

    • 여러 동물 클래스를 만들고, 부모 클래스 타입의 배열에 저장한 후 각각의 makeSound() 메서드를 호출하세요.
  4. 추상 클래스

    • Animal 추상 클래스를 만들고, makeSound() 추상 메서드를 정의한 후 자식 클래스에서 구현하세요.
  5. 인터페이스

    • Flyable 인터페이스를 만들고, BirdAirplane 클래스에서 구현하세요.
  6. 종합 예제

    • 도형 클래스들을 추상 클래스와 인터페이스를 사용하여 구현하고, 다형성을 활용하세요.

다음 장 예고

다음 장에서는 예외 처리(Exception Handling)를 통해 프로그램의 오류를 효과적으로 관리하는 방법을 학습합니다.

'BackEnd > Java' 카테고리의 다른 글

10장. 예외 처리  (0) 2026.01.02
9장. 컬렉션 프레임워크  (0) 2026.01.02
7장. 객체지향 프로그래밍(OOP) 기초  (0) 2026.01.01
6장. 메서드(Method)  (0) 2025.12.31
5장. 배열과 문자열  (0) 2025.12.30