무엇을 배우나?
- 패키지 분리로 코드 조직하기
- 상속(extends)과 메소드 오버라이딩
- protected 접근 제어자의 의미
- 호출 흐름과 콘솔 출력 확인
프로젝트 코드

src/
├─ idusw/jwa
│ ├─ Main.java
│ └─ Same.java
└─ idusw/other
└─ Other.java
핵심 코드

- 의도와 핵심 포인트
- 오버로딩(Overloading): sayHello()와 sayHello(String)처럼 같은 이름 + 다른 매개변수로 메서드를 나눠 호출 의도를 분명히 한다. 어떤 버전이 호출될지는 컴파일 타임에 결정된다.
- 오버라이딩(Overriding): 자식이 부모 메서드를 같은 시그니처로 재정의해 런타임 다형성을 얻는다. 안전을 위해 @Override 사용 권장.
- protected의 의미: 같은 패키지 또는 상속 관계에서만 접근을 허용해 외부 공개를 줄이면서 내부 확장용 API로 활용한다.
- 출력 설계: 두 메서드는 값을 반환하지 않고 콘솔에 출력(부작용)하므로 데모·로그용에 적합하다.
- sayHello()
- 고정 문구를 출력한다. 공개 범위가 넓어 어디서든 호출 가능하며, 자식에서 오버라이딩 대상이 된다.
- sayHello(String msg)
- 전달된 msg까지 함께 출력한다. 오버로딩 예시이며, protected로 제한해 같은 패키지/자식 클래스에서만 사용하도록 설계했다.
- 호출 흐름 요약
- 기본 사용: sayHello("...") → sayHello() 순으로 호출해 출력 차이를 확인.
- 자식 클래스: 오버라이딩한 sayHello() 내부에서 sayHello("...")를 호출해( protected 접근 허용 ) 부모 동작 + 자식 동작을 조합할 수 있다.

- 의도와 핵심 포인트
- 오버라이딩(Overriding): 부모의 sayHello()를 자식에서 재정의해 자식 고유 동작을 추가한다(런타임 다형성).
- protected 활용: 자식은 부모의 protected 메서드 (sayHello(String)) 에 접근할 수 있다.
현재 구현처럼 new Other().sayHello("...") 로도 접근 가능하지만, 불필요한 객체 생성을 피하려면
this.sayHello("...") 또는 부모 버전을 확실히 호출하려면 super.sayHello("...")가 더 명확하다. - 호출 의도 분리: 문자열 인자를 받는 버전을 상태 출력/로그 보강용으로 활용하고, 인자 없는 버전은 기본 흐름에 둔다.
- 출력 설계: 콘솔 출력(부작용) 기반 데모이므로 동작 순서를 시각적으로 확인하기 쉽다.
- public void sayHello() (자식 클래스의 오버라이딩 메서드)
- Other other = new Other(); : 동일 클래스의 새 인스턴스를 하나 만든다.
- other.sayHello("hahaha"); : 부모로부터 상속받은 protected sayHello(String)을 호출한다.
- System.out.println("Other's World"); : 자식 고유 메시지를 출력한다.
- 호출 흐름 요약
- 실행 시 출력 순서는 Same's World hahaha → Other's World.

-
- 엔트리 포인트: main에서 전체 실행 흐름을 주도해 오버로딩/오버라이딩 호출 순서를 눈으로 확인한다.
- 객체 생성과 메서드 호출: Same 인스턴스로 sayHello(String)(오버로딩) → sayHello() 순서로 호출해 컴파일 타임 선택(오버로딩) 을 보여준다.
- 다형성 데모: Other 인스턴스의 sayHello()는 오버라이딩된 자식 구현이 실행되고, 내부에서 부모의 protected sayHello(String)을 호출해 런타임 디스패치(다형성) 를 체감하게 한다.
- 출력/포맷: 인사 메시지는 printf로 \n 포함 출력, 나머지는 println 사용. 한 파일 내 포맷터를 섞어 쓰는 예를 보여주되, 실제 코드에선 형식을 일관시키는 게 좋다.
- 루프 연습: for문으로 1~5 카운팅을 출력해 기본 반복 제어 흐름을 확인한다.
- System.out.printf("Hello and welcome!\n");
→ 인사 한 줄 출력. - Same ref = new Same();
→ Same 객체 생성. - ref.sayHello( "have a good day" );
→ 오버로딩된 버전 실행 → Same's World have a good day. - ref.sayHello();
→ 기본 버전 실행 → Same's World. - Other other = new Other();
→ Other(자식) 객체 생성. - other.sayHello();
→ 오버라이딩된 자식 메서드 실행 → 내부에서 sayHello("hahaha") 호출 후 Other's World 출력한다.
→ 콘솔 순서: Same's World hahaha → Other's World. - for (int i = 1; i <= 5; i++) System.out.println("i = " + i);
→ i = 1 … i = 5까지 한 줄씩 출력한다.
실행 흐름 & 결과

Main.main →
① 인사 출력 →
② Same.sayHello("...") →
③ Same.sayHello() →
④ Other.sayHello()
└─ 내부에서 Same.sayHello("hahaha") 먼저 실행 →
└─ 이어서 "Other's World" 출력 →
⑤ for문 i=1..5
- 오버로딩: sayHello() vs sayHello(String) — 이름 같고 매개변수 다름, 컴파일 타임에 결정한다.
- 오버라이딩: Other.sayHello() — 부모 시그니처 그대로 재정의, 런타임에 자식 구현이 실행한다.
- protected 접근: 자식(Other)에서 부모(Same)의 sayHello(String) 호출 가능하다.
이때 new Other().sayHello("hahaha") 대신 this.sayHello("hahaha") 또는 super.sayHello("hahaha")로 써도 동작 의도가 더 선명해진다.
느낀 점
콘솔을 직접 찍어보니 오버로딩과 오버라이딩의 차이가 호출 시점(컴파일/런타임) 기준으로 확실해진다.
protected는 같은 패키지·상속 관계만 허용하는 절충형 공개라는 점이 체감되며 개념이 명확해진다.
this와 super를 골라 쓰는 연습을 하니 의도가 분명해지고 불필요한 객체 생성이 줄어든다.
출력 중심 예제는 흐름 파악에 도움이 되지만, 테스트를 위해 반환형 메서드로 리팩터링하는 습관이 필요할 것 같다.
'Java' 카테고리의 다른 글
| Spring 컨트롤러 및 컴포넌트 정리 (0) | 2026.04.08 |
|---|