
"변수는 오버라이딩되지 않는다"는 말은 변수를 참조할 때 참조 변수의 타입 기준으로 결정된다는 것이다.
- 메서드는 동적 바인딩(실행 시점 기준)
 - 변수는 정적 바인딩(컴파일 시점 기준)
 
- 즉 변수는 오버라이딩 되지 않는다 → 참조타입 기준,
 - 메서드는 오버라이딩 된다 → 실제 객체 기준
 - 메서드 안의 변수 → 선언된 클래스 기준 (예 - 그 메서드가 정의된 클래스의 name필드 사용)
 - this.name → this객체의 클래스 내 필드, 즉 메서드가 정의된 클래스에서의 this 기준
 - super.name → 부모 클래스의 name 기준, 자식 클래스에서 부모 필드 강제 접근
 
class Parent {
    String name = "Parent";
    void printName() {
        System.out.println("name: " + name);
    }
}
class Child extends Parent {
    String name = "Child";
    @Override
    void printName() {
        System.out.println("name: " + name);
    }
}
public class Main {
    public static void main(String[] args) {
        Child c = new Child();
        Parent p = new Child();
        System.out.println("c.name: " + c.name);  // "Child"
        System.out.println("p.name: " + p.name);  // "Parent"
        System.out.print("c.printName(): ");
        c.printName();  // name: Child
        System.out.print("p.printName(): ");
        p.printName();  // name: Child
    }
} 
실행결과
c.name: Child
p.name: Parent
c.printName(): name: Child
p.printName(): name: Child 
`c.name`은 `Child`타입 참조 변수이므로 자식 클래스의 변수를 참조한다. (결과: Child)
`p.name`은 `Parent` 타입 참조 변수이므로 부모 클래스의 변수를 참조한다. (결과: Parent)
`c.printName()`은 실제 객체가 `Child`이므로 자식의 메서드를 실행한다. (동적바인딩, 결과: Child)
`p.printName()`은 실제 객체가 `Child`이므로 자식의 메서드를 실행한다. (동적바이딩, 결과: Child)
Parent p = new Child();
- 메서드 호출: Child의 메서드가 호출됨 (오버라이딩, 동적 바인딩)
 - 변수 접근: Parent의 name이 사용됨 (정적 바인딩)
 
업캐스팅 + 다운캐스팅 + this.name + super.name
class Parent {
    String name = "Parent";
    void printName() {
        System.out.println("Parent.printName(): " + name);
    }
}
class Child extends Parent {
    String name = "Child";
    @Override
    void printName() {
        System.out.println("Child.printName()");
        System.out.println("this.name = " + this.name);
        System.out.println("super.name = " + super.name);
    }
}
public class Main {
    public static void main(String[] args) {
        Child c = new Child();
        Parent p = new Child();    // 업캐스팅
        System.out.println("▶ c.name: " + c.name); // "Child"
        System.out.println("▶ p.name: " + p.name); // "Parent" ← 변수는 참조타입 기준
        System.out.println("\n▶ c.printName():");
        c.printName();
        System.out.println("\n▶ p.printName():");
        p.printName();             // Child의 오버라이드 메서드가 호출됨
        System.out.println("\n▶ 다운캐스팅 후:");
        Child down = (Child) p;
        System.out.println("down.name: " + down.name); // "Child"
        down.printName(); // 여전히 Child의 printName() 호출됨
    }
} 
실행결과
▶ c.name: Child
▶ p.name: Parent
▶ c.printName():
Child.printName()
this.name = Child
super.name = Parent
▶ p.printName():
Child.printName()
this.name = Child
super.name = Parent
▶ 다운캐스팅 후:
down.name: Child
Child.printName()
this.name = Child
super.name = Parent`p.name` – 변수는 참조 타입 기준 (결과 : Parent)
`p.printName()` – 메서드는 동적 바인딩 (결과: Child.printName())  
this.name (in Child) – 자기 클래스의 변수 (결과: Child)
super.name (in Child) – 부모 클래스의 변수 (결과 : Parent)  
다운캐스팅 후 down.name – 자식 클래스의 변수 (결과 : Child)
 
 
super.printName() 호출
class Parent {
    void printName() {
        System.out.println("Parent.printName()");
    }
}
class Child extends Parent {
    @Override
    void printName() {
        System.out.println("Child.printName() 시작");
        // 현재 클래스의 printName
        System.out.println("this.printName():");
        this.printName2();
        // 부모 클래스의 printName
        System.out.println("super.printName():");
        super.printName();
        System.out.println("Child.printName() 끝");
    }
    void printName2() {
        System.out.println("Child.printName2()");
    }
}
public class Main {
    public static void main(String[] args) {
        Child c = new Child();
        c.printName();
    }
}출력 결과
Child.printName() 시작
this.printName():
Child.printName2()
super.printName():
Parent.printName()
Child.printName() 끝- this.printName2()는 현재 클래스의 메서드 호출
 - super.printName()은 부모 클래스의 메서드 강제 호출
 - 오버라이딩을 무시하고 부모 기능을 호출할 수 있을 때 사용
 
protected, private 변수 접근 차이
class Parent {
    public String pub = "public 변수";
    protected String pro = "protected 변수";
    private String pri = "private 변수";
    void show() {
        System.out.println("Parent.pub: " + pub);
        System.out.println("Parent.pro: " + pro);
        System.out.println("Parent.pri: " + pri); // 같은 클래스라 접근 가능
    }
}
class Child extends Parent {
    void accessTest() {
        System.out.println("Child.pub: " + pub);   // 접근 O
        System.out.println("Child.pro: " + pro);   // 접근 O (상속+같은 패키지)
        // System.out.println("Child.pri: " + pri); // ❌ private → 접근 불가
    }
}protected는 같은 패키지거나 상속된 자식 클래스 내부에서만 접근 가능하다.
 
'Java' 카테고리의 다른 글
| [Java] local variables referenced from a lambda expression must be final or effectively final 에러 해결법 (6) | 2025.08.18 | 
|---|---|
| [Java] (상속) 참조타입과 실제타입 중 무엇을 따라가는가? (5) | 2025.06.24 | 
| [Java] 자바에서 this, 생성자 호출시 this() (3) | 2025.06.22 | 
| [Java] JVM의 작동 원리 (5) | 2025.05.13 | 
| [Java] 자바의 예외 - Exception, RuntimeException 차이 (5) | 2025.04.22 |