📂 목차
📚 본문
Inheritance
is-a
관계, kind-of
에서 사용.
- 부모가 자식을 참조 가능
- 필드는 참조변수 타입을 기준
- 메소드 오버라이딩 시 자식 것 사용
모든 class 는 Object 의 상속
정적 바인딩과 동적 바인딩
정적 바인딩(early binding, compile-time)
컴파일 시점에 어떤 멤버/메서드를 사용할지 결정하는 것을 정적 바인딩이라고 한다.
다음이 정적 바인딩에 해당:
- 필드 접근(멤버 변수) → 참조 변수의 타입을 따름
static
메서드(오버라이딩 X, 메서드 숨김/hiding) → 참조 변수의 타입을 따름private
메서드,final
메서드(재정의 불가) → 호출 지점에서 이미 고정- 오버로딩(이름 같고 매개변수 시그니처 다른 메서드) → 인자와 참조의 정적 타입으로 선택
super.someMethod()
호출 → 상위 클래스 구현으로 고정
동적 바인딩(late binding, runtime)
런타임 시점에 어떤 멤버/메서드를 사용할지 결정하는 것을 동적 바인딩이라고 한다.
- 런타임에 실제 객체의 타입을 보고 어떤 인스턴스 메서드를 호출할지 결정
- 기본적으로 오버라이딩 가능한 인스턴스 메서드는 모두 동적 바인딩 대상
핵심 규칙 요약
“필드/
static
/private
/final
/super
/오버로딩” → 정적
“그 외 인스턴스 메서드(오버라이딩)” → 동적
Constructor 관점
A 클래스가 B 클래스를 상속한다고 쳤을때, 상속 받는 A 클래스는 어떻든 간에 B 클래스의 Constructor 를 실행시켜야 한다.
B 가 아무 생성자가 없더라도 인자가 없는 Constructor 를 컴파일러가 자동으로 생성해주는 이유도 그 때문이다.
밑의 예시를 보자.
class Parent {
public String name = "부모";
}
class Child extends Parent {
public String name = "자식";
}
Parent 는 아무런 생성자가 없지만 자동으로 빈 생성자가 생성될 것이다. Child 도 마찬가지로 빈 생성자가 생성되지만, 그 비어져 있는 생성자에 super()
라는 부모의 생성자가 생략된 것이다.
따라서 부모의 생성자가 먼저 실행이 되고, 그 실행된 것을 토대로 Child
가 한 번 더 수정을 해준다고 보면 되겠다.
만약 Parent 에 인자가 있는 생성자를 직접 명시했다면, 비어져 있는 생성자(default constructor) 가 자동 생성이 되지 않으므로 이때 Child 는 부모의 생성자
super()
를 이용하여 초기화 해주어야 한다.
이는 이 전 강의에서도 무조건super
가 있어야 한다고 했었다.
Field 관점
class Parent {
public String name = "부모";
}
class Child extends Parent {
public String name = "자식";
}
Parent pc = new Child();
System.out.println(pc.name)
위 코드를 출력해보면 pc.name 은 자식이 아니라 부모가 출력됨을 볼 수 있다.
실제로 pc 라는 변수는 Parent 필드와 Child 필드 둘 다 가지고 있다. 하지만 자바는 특정 변수를 볼 때 이 변수의 선언된 클래스 명을 우선으로 따라간다. 즉, Parent pc
이기 때문에 멤버 변수로는 Parent
것이 따라가게 된다.
이는 컴파일 시점에 결정되는 것이며, 필드는 정적 바인딩이 되는 것이기에 참조변수 타입을 따르는게 맞다.
Method 관점
위와 비슷한 예시로 다음을 또 보자.
class Parent {
public String name = "부모";
public void print() {
System.out.println("부모: 안녕하세요");
}
}
class Child extends Parent {
public String name = "자식";
public void print() {
System.out.println("자식: 안녕하세요");
}
}
class Main {
public static void main(String[] args) {
Parent pc = new Child();
pc.print();
}
}
위는 자식의 메서드가 실행되는 것을 볼 수 있다.
이는 메서드가 동적 바인딩이 되기 때문이다.
상속 주의점
class Parent {
Parent() { print(); } // 위험: 오버라이딩 가능 메서드 호출
void print(){ System.out.println("Parent"); }
}
class Child extends Parent {
int x = 42;
Child() {}
@Override void print(){ System.out.println(x); }
}
new Child(); // 출력: 0 (x가 아직 기본값 0일 때 Child.print()가 불림)
상속 요약
- 필드: 참조 타입(정적)
static
/private
/final
/super
/ 오버로딩: 정적- 오버라이딩된 인스턴스 메서드: 동적
- 생성자 내부에서 오버라이딩 메서드 호출 지양
Polymorphism
범용 메소드 이름을 정의하여 형태에 따라 각각 적절한 변환 방식을 정의해두어 타입 간의 변환이 자유성을 가지는 성질을 말한다.
정적/컴파일에서의 다형성
주로 오버로딩이 해당되며, 같은 이름을 가진 메서드가 매개변수 유형이나 개수에 따라 다르게 정의되어 컴파일러가 호출 시점에서 어떤 메서드인지 결정하게 된다.
class Calculator {
int add(int a, int b) { return a + b; }
double add(double a, double b) { return a + b; }
}
동적/런타임에서의 다형성
오버 라이딩 기반으로 부모 클래스를 참조 타입으로 사용하더라도, 실제 객체가 자식이라면 자식 클래스의 메서드가 호출됨.
class Animal {
void speak() { System.out.println("Animal speaks"); }
}
class Dog extends Animal {
@Override
void speak() { System.out.println("Dog barks"); }
}
Animal a = new Dog();
a.speak(); // "Dog barks"
위 다형성 외에도 제너릭, 인터페이스 기반 등의 다양한 형태의 다형성이 존재함
Servlet
java 에서 서블릿은 자바 기반의 웹 어플리케이션에서 동적 웹페이지를 생성하고 클라이언트의 요청을 처리하는 서버 컴포넌트이다.
주로 HTTP 요청을 받고, 동적인 응답을 반환하는 애다.
javax.servlet
javax.servlet.http
등을 보면 좋을 것이다.