본문 바로가기
Java

Java | Hiding

by Sseul.dev 2025. 10. 4.

목차

  1. Hiding이란 무엇인가
  2. 오버라이딩 vs Hiding 핵심 차이
  3. static 메서드 Hiding
  4. 변수 Hiding
  5. 실전 예제와 함정

1. Hiding이란 무엇인가?

핵심 개념

Hiding = static 메서드나 변수를 자식 클래스에서 "가리는" 것

오버라이딩과 달리, 실제 객체 타입이 아닌 참조 변수 타입을 따라갑니다.


일반 원칙 vs Hiding

java
// 일반 메서드 (오버라이딩)
Parent p = new Child();
p.normalMethod();  // Child의 메서드 실행 (다형성)

// static 메서드 (Hiding)
Parent p = new Child();
p.staticMethod();  // Parent의 메서드 실행 (Hiding!)

2. 오버라이딩 vs Hiding 핵심 차이

비교표

구분 오버라이딩(Overriding) 하이딩(Hiding)
대상 인스턴스 메서드 static 메서드/변수
실행 기준 실제 객체 타입 참조 변수 타입
다형성 적용 O 적용 X
런타임 결정 Yes (동적 바인딩) No (컴파일 타임)

시각적 이해

[오버라이딩 - 인스턴스 메서드]
Parent p = new Child();
p.method() → "실제 객체가 뭐지?" → Child → Child.method() 실행

[Hiding - static 메서드]
Parent p = new Child();
p.staticMethod() → "변수 타입이 뭐지?" → Parent → Parent.staticMethod() 실행

3. static 메서드 Hiding

기본 예제

java
class P {
    public static void print() {
        System.out.print("Parent");
    }
}

class C extends P {
    public static void print() {  // Hiding 발생!
        System.out.print("Child");
    }
}

public class Main {
    public static void main(String[] args) {
        P myFam = new C();
        myFam.print();  // "Parent" 출력!
        
        // 비교: 직접 호출
        P.print();  // "Parent"
        C.print();  // "Child"
    }
}

왜 Parent가 출력되나?

myFam의 타입 체크
    ↓
P 타입이네?
    ↓
P의 static print() 호출
    ↓
"Parent" 출력

※ new C()는 무시됨!

4. 변수 Hiding

멤버 변수도 Hiding 됩니다

java
class Parent {
    public String name = "Parent";
    public static String type = "ParentType";
}

class Child extends Parent {
    public String name = "Child";  // 인스턴스 변수 Hiding
    public static String type = "ChildType";  // static 변수 Hiding
}

public class Main {
    public static void main(String[] args) {
        Parent p = new Child();
        Child c = new Child();
        
        // 인스턴스 변수
        System.out.println(p.name);  // "Parent" (변수 타입 따라감)
        System.out.println(c.name);  // "Child"
        
        // static 변수
        System.out.println(p.type);  // "ParentType"
        System.out.println(c.type);  // "ChildType"
    }
}

변수 접근 규칙

변수는 항상 참조 타입을 따라갑니다 (메서드와 다름!)


5. 실전 예제와 함정

실무 예제: 로깅 시스템

java
class BaseLogger {
    protected String logLevel = "INFO";
    
    public static void configure() {
        System.out.println("기본 로거 설정");
    }
    
    public void log(String msg) {
        System.out.println("[" + logLevel + "] " + msg);
    }
}

class CustomLogger extends BaseLogger {
    protected String logLevel = "DEBUG";  // 변수 Hiding
    
    public static void configure() {  // static 메서드 Hiding
        System.out.println("커스텀 로거 설정");
    }
    
    @Override
    public void log(String msg) {  // 일반 메서드 오버라이딩
        System.out.println("[커스텀-" + logLevel + "] " + msg);
    }
}

public class LogTest {
    public static void main(String[] args) {
        BaseLogger logger1 = new CustomLogger();
        CustomLogger logger2 = new CustomLogger();
        
        // static 메서드 (Hiding)
        logger1.configure();  // "기본 로거 설정" (타입 따라감)
        logger2.configure();  // "커스텀 로거 설정"
        
        // 인스턴스 메서드 (오버라이딩)
        logger1.log("테스트");  // "[커스텀-DEBUG] 테스트" (실제 객체)
        logger2.log("테스트");  // "[커스텀-DEBUG] 테스트"
        
        // 변수 접근 (Hiding)
        System.out.println(logger1.logLevel);  // "INFO" (타입 따라감)
        System.out.println(logger2.logLevel);  // "DEBUG"
    }
}

자주 하는 실수

java
class Animal {
    public static void makeSound() {
        System.out.println("동물 소리");
    }
}

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

// 잘못된 다형성 기대
Animal[] animals = {new Dog(), new Cat()};
for(Animal a : animals) {
    a.makeSound();  // 모두 "동물 소리" 출력! (의도와 다름)
}

// 해결: static 대신 인스턴스 메서드 사용

정리 : ) 업캐스팅 시 동작 규칙

java
Parent p = new Child();

 

요소 실행되는 것 이유
생성자 Parent() → Child() 부모부터 순서대로
인스턴스 메서드 Child의 메서드 오버라이딩 (다형성)
static 메서드 Parent의 메서드 Hiding (타입 따라감)
인스턴스 변수 Parent의 변수 타입 따라감
static 변수 Parent의 변수 타입 따라감

암기할 것

오버라이딩 = 실제 객체를 봄 (런타임)
Hiding = 변수 타입을 봄 (컴파일타임)

인스턴스 메서드 → 오버라이딩 → 실제 객체
static 메서드/모든 변수 → Hiding → 참조 타입

⚠️ 실무 권장사항

1. static 메서드는 클래스명으로 호출

 
java
   Parent.staticMethod();  // 권장
   p.staticMethod();      // 비권장 (혼란 유발)

 

2. 다형성이 필요하면 static 사용 금지

 
java
   // Bad
   static void process() { }
   
   // Good  
   void process() { }  // 인스턴스 메서드로 변경

 

3. 변수는 private으로 선언

 
java
   private String name;  // Hiding 방지

 

⚠️ 핵심은 static은 타입을 따라간다는 것!