26/06/24 TIL (Today I Learned)

Java 객체지향 심화 - 상속, 다형성, 인터페이스, 제너릭


📚 오늘 배운 내용 요약

주제핵심 내용
상속(Inheritance)기존 클래스의 기능을 물려받아 확장
오버라이딩(Override)부모 메서드를 재정의
동적 바인딩실제 객체 기준으로 메서드 호출
업캐스팅자식 객체를 부모 타입으로 참조
다운캐스팅부모 타입을 자식 타입으로 변환
추상 클래스공통 기능 정의 및 구현 강제
인터페이스다중 구현을 위한 계약
Wrapper Class기본형을 객체 형태로 사용
Generic타입을 일반화하여 재사용성 향상

1) 상속과 오버라이딩

학습 내용설명
extends부모 클래스를 상속
super()부모 생성자 호출
오버라이딩부모 메서드를 재정의
toString()객체 출력 형식 변경
동적 바인딩실제 객체 기준 메서드 실행
정적 바인딩변수 타입 기준 필드 접근
public class Example01 {

    public static void main(String[] args) {

        Developer dev = new Developer("Tom", "Java");

        BackendDeveloper backend =
                new BackendDeveloper("Jane", "Spring");

        dev.work();
        backend.work();
    }
}

class BackendDeveloper extends Developer {

    String version = "2.0";

    BackendDeveloper(String name, String skill) {
        super(name, skill);
    }

    @Override
    void work() {
        System.out.println(name + "이 백엔드 개발을 수행합니다.");
    }
}

class Developer {

    String version = "1.0";
    String name;
    String skill;

    Developer(String name, String skill) {
        this.name = name;
        this.skill = skill;
    }

    void work() {
        System.out.println(name + "이 개발을 수행합니다.");
    }
}
  • BackendDeveloper가 Developer 상속
  • 부모 생성자는 super()로 호출
  • work() 메서드를 재정의하여 기능 확장
  • 같은 메서드 호출이지만 실제 객체 타입에 따라 다르게 실행
느낀 점내용
상속은 확장기존 기능을 재사용하면서 기능 추가 가능
오버라이딩 중요다형성의 핵심
동적 바인딩 이해변수 타입보다 실제 객체 타입이 중요

2) 접근 범위와 상속

학습 내용설명
protected상속 관계에서 접근 가능
private해당 클래스 내부만 접근 가능
super부모 메서드 호출
오버라이딩 제한접근 범위를 더 좁게 변경 불가
class Engineer {

    protected String secret = "SECRET";

    void work() {
        System.out.println("작업 수행");
    }
}

class SoftwareEngineer extends Engineer {

    @Override
    public void work() {

        super.work();

        System.out.println("추가 작업 수행");
    }
}
  • protected 필드는 자식 클래스 접근 가능
  • super를 통해 부모 기능 재사용
  • 오버라이딩 시 접근 범위를 줄일 수 없음
느낀 점내용
protected 활용 중요상속 구조에서 자주 사용
부모 기능 재사용 가능super 활용
접근제어 설계 필요무조건 public 사용 지양

3) 업캐스팅과 다운캐스팅

학습 내용설명
업캐스팅자식 객체 → 부모 타입
다운캐스팅부모 타입 → 자식 타입
instanceof타입 확인
패턴 매칭다운캐스팅 간소화
Animal animal = new Dog();

animal.eat();

if(animal instanceof Dog dog){
    dog.eat();
}
  • 업캐스팅은 자동 수행
  • 다운캐스팅은 명시적으로 수행
  • instanceof로 안전성 확보
느낀 점내용
업캐스팅 활용도 높음다형성 구현 가능
다운캐스팅 위험성 존재타입 확인 필수
instanceof 중요런타임 오류 예방

4) 추상 클래스

학습 내용설명
abstract class객체 생성 불가
추상 메서드구현 강제
공통 기능 정의코드 중복 감소
abstract class Fruit {

    abstract int getPrice();

    void info() {
        System.out.println("과일 정보");
    }
}

class Apple extends Fruit {

    @Override
    int getPrice() {
        return 1000;
    }
}
  • Fruit는 직접 생성 불가
  • 하위 클래스가 반드시 구현
  • 공통 기능은 부모에서 제공
느낀 점내용
설계 강제 가능구현 규칙 제공
코드 중복 감소공통 기능 관리
다형성과 궁합 좋음부모 타입 활용 가능

5) 인터페이스

학습 내용설명
interface구현 계약
implements인터페이스 구현
다중 구현여러 인터페이스 구현 가능
다형성인터페이스 타입 활용
interface Playable {
    void play();
}

interface Streamable {
    void stream();
}

class SmartTV implements Playable, Streamable {

    @Override
    public void play() {
        System.out.println("재생");
    }

    @Override
    public void stream() {
        System.out.println("스트리밍");
    }
}
  • 인터페이스는 기능 명세 제공
  • 클래스는 여러 인터페이스 구현 가능
  • 다중 상속 문제 해결
느낀 점내용
느슨한 결합 가능유지보수 유리
다형성 극대화인터페이스 기반 설계
실무 활용도 매우 높음Spring에서도 자주 사용

6) Wrapper Class

학습 내용설명
Wrapper기본형을 객체로 변환
Boxing기본형 → 객체
Unboxing객체 → 기본형
Auto Boxing자동 변환
List<Integer> scoreList =
        new ArrayList<>();

Integer value = 100;

int number = value;
  • Generic에는 기본형 사용 불가
  • Wrapper 클래스 사용 필요
  • 자동 Boxing/Unboxing 지원
느낀 점내용
Generic 사용 시 필수Integer 자주 사용
내부 동작 이해 필요성능 영향 가능
기본형과 객체형 구분 중요메모리 사용 차이 존재

7) Generic

학습 내용설명
Generic타입을 일반화
타입 안정성컴파일 시 오류 확인
재사용성다양한 타입 지원
Generic Method메서드 단위 타입 선언
class Storage<T> {

    private T data;

    public void setData(T data) {
        this.data = data;
    }

    public T getData() {
        return data;
    }

    public <K> K echo(K value) {
        return value;
    }
}
  • T는 클래스 전체에서 사용
  • 자료형을 외부에서 결정
  • String, Integer 등 다양한 타입 활용 가능
느낀 점내용
코드 재사용성 증가타입별 클래스 생성 불필요
컴파일 단계 검증 가능안정성 향상
컬렉션 프레임워크 핵심List, Map 모두 Generic 사용

🚨 직면한 문제 : Generic 이해 부족

문제 상황

수업 중 다음 코드가 이해되지 않았다.

Box<String> box1 = new Box<>();

Box<Integer> box2 = new Box<>();

특히 T가 무엇인지, 왜 String이나 Integer를 넣을 수 있는지 혼란스러웠다.


해결 과정

Generic이 없는 경우

class StringBox {

    private String value;
}
class IntegerBox {

    private Integer value;
}

타입마다 클래스를 새로 만들어야 한다.


Generic 사용

class Box<T> {

    private T value;
}

사용 시

Box<String> textBox = new Box<>();

Box<Integer> numberBox = new Box<>();

컴파일러가 자동으로 타입을 결정한다.


최종적으로 이해한 내용

구분의미
TType
EElement
KKey
VValue
?Wildcard

Generic의 장점

장점설명
타입 안정성컴파일 시 오류 확인
캐스팅 감소형변환 불필요
재사용성여러 타입 지원
가독성 향상의도 명확

오늘 배운 점

Generic은 "여러 타입을 받는다"가 아니라

"클래스나 메서드를 정의할 때 타입을 나중에 결정하도록 미루는 기술"

이라는 것을 이해하게 되었다.

특히 List, List, Map<String,Integer> 같은 컬렉션들이 모두 Generic을 기반으로 동작한다는 점을 알게 되었고, 앞으로 Spring과 Java 컬렉션을 사용할 때 Generic 문법을 훨씬 자연스럽게 읽을 수 있을 것 같다.

profile
예 마 함 가보입시더

0개의 댓글