학습 목표
- 자바 상속의 특징
- super 키워드
- 메소드 오버라이딩
- 다이나믹 메소드 디스패치 (Dynamic Method Dispatch)
- 추상 클래스
- final 키워드
- Object 클래스
1. 자바 상속의 특징
자바에서 상속이란 무엇인가?
- 현실 세계에서 부모가 자식에게 재산을 '상속'한다고 하는 것처럼 객체 지향 프로그램에서도 부모가 자식에게 부모의 클래스나 메소드를 자식의 클래스에게 물려주는 경우를 상속이라고 한다.
자바 상속의 특징
- 공통된 특징을 가지는 클래스에서 코드 중복을 줄여준다.
- 부모 클래스의 멤버를 재사용하면서 자식 클래스는 간결해질 수 있다.
- 클래스간의 계층적 분리를 도와주어 분류, 관리 상의 이점이 있다.
- 부모 클래스는 Super Class이고 자식 클래스는 Sub Class이다.
- 다중 상속을 지원하지 않는다. 즉, extends뒤에는 하나의 부모 클래스만 올 수 있다.
- 상속 횟수에 제한이 없다.
- 자바의 최상위 클래스는 'Object' 라는 클래스이다. 즉, 자바의 모든 클래스는 'Object'클래스의 자손이다.
상속 구현 방법
<자식 클래스의 부모 클래스 상속 방법>
class 자식 클래스 extends 부모클래스 {
}
<부모 클래스>
public class TV {
멤버 변수 1;
멤버 변수 2;
메소드1;
}
<자식 클래스>
public class LG extends TV {
String tvType;
}
2. Super 키워드
자바에서 자식 객체를 생성할 경우 부모 객체가 먼저 생성된 후 자식 객체가 생성된다.
super 키워드란?
- 상속관계에서 자식 클래스가 부모 클래스의 멤버 변수나 메소드를 참조하기 위해 사용된다.
- 자식 클래스에 부모 객체의 생성자를 임의로 지정하지 않았을 경우 자식 객체 생성시 컴파일러가 자동으로 'super()' 메소드를 통해 부모의 기본 생성자를 호출한다.
- 만약 부모 클래스에 기본 생성자가 없고 매개 변수가 있는 생성자만 있다면 자식 생성자의 첫 줄에 반드시 부모 생성자 호출을 위한 super() 메소드를 명시적으로 작성해두어야 한다. 그렇지 않을 경우 컴파일 에러가 발생한다.
3. 메소드 오버라이딩
메소드 오버라이딩이란?
- 자식 클래스에서 부모 클래스를 상속 받은 후, 부모 클래스에 정의되어 있는 메소드를 재정의하여 사용하는 것이다.
- 부모 클래스 내의 특정 메소드는 자식 클래스에서 그대로 사용하기에 적합하지 않을 수 있기 때문에 보통 오버라이딩을 거쳐 부모 메소드를 사용하는 경우가 많다.
- 메소드가 오버라이딩 되면 자식 객체에서 메소드가 호출될 경우 부모 객체의 메소드는 숨겨지고, 오버라이딩된 자식 메소드가 호출된다.
오버라이딩 규칙(@override 어노테이션 사용)
- 오버라이딩된 자식 클래스의 메소드는 부모의 메소드와 '메소드 이름, 매개 변수 조합, 리턴 타입'이 동일해야 한다.
- 접근 제한을 축소하여 오버라이딩 할 수 없다. 단, 반대는 가능하다.
(부모 메소드가 public인데 자식 메소드가 private일 수는 없다는 의미)
- 새로운 예외를 throw할 수 없다.
4. 다이나믹 메소드 디스패치(Dynamic method dispatch)
메소드 디스패치란?
- 자바는 런타임 시 객체를 생성하고 컴파일 시 생성할 객체 타입에 대한 정보만 보유한다.
- 메소드 디스패치란 어떤 메소드를 호출할지 결정하여 실제로 실행시키는 과정이다.
- 그 과정은 static(정적)/dynamic(동적) 두가지가 있다.
정적 디스패치(static dispatch)
- 컴파일 시점에서 컴파일러가 특정 메소드를 호출할 것이라고 명확하게 알고 있는 경우
- 컴파일 타임에 컴파일러, 사용자, 바이트코드 모두 어떤 메소드가 실행될 지 아는 것이다.
<코드예시>
<person 클래스>
public class Person{
private int age;
public void print() {
System.out.println("Hello");
}
public void print(String greeting) {
System.out.println(greeting);
}
public void printJob(){
}
}
<main 클래스>
public class Main {
public static void Main(String[] args) {
Person P = new Person();
p.print();
p.print("hi");
}
}
<출력결과>
Hello
Hi
- 보통 오버라이딩한 메소드가 없을 경우, 상속받은 자식 클래스의 메소드가 아닐 경우에 대한 설명이지 않을까 개인적인 생각이다.
- 함수를 오버라이딩하여 사용했을 경우에도 인자의 타입이나 리턴타입 등에 따라 어떤 메소드를 호출할 지 알 수 있는 경우
동적 디스패치(dynamic dispatch)
- dynamic은 runtime의 동의어로 사용되며 dispatch는 어떤 메소드를 호출할지 결정하는 것이므로 런타임시에 호출할 메소드를 결정할 경우를 의미한다.
- 컴파일러는 어떤 메소드를 호출할 지 모른다.
- 인터페이스나 추상 클래스에 정의된 추상 메소드를 호출하는 경우
<Tv 클래스>
public class Tv {
public void view() {
System.out.println("티비를 보여줌");
}
}
<Tv를 상속한 samsung 클래스>
public class Samsung extends Tv {
@Override
public void view() {
System.out.println("OLED 티비를 보여줌");
}
}
public class Main {
public static void main(String[] args) {
Tv tv = new Tv(); // Tv 참조 Tv 객체
Tv samsungTv = new Samsung(); // Tv 참조, 삼성 객체
tv.view(); //참조와 객체가 동일
samsungTv.view();// 참조와 객체가 다름 (상속) => 다이나믹 메소드 디스패치
}
}
=> 컴파일 시에는 참조 타입만 확인하고 런타임시 JVM(Java Virtual Machine)이 객체 타입을 파악하여 메소드를 실행시켜준다.
5. 추상 클래스
추상 클래스란?
- 먼저 사전적 의미로 추상(abstract)은 실체 간의 공통되는 특성을 추출한 것을 말한다.
- 이를 객체 지향 프로그래밍에 접목해보면, 객체를 직접 생성할 수 있는 클래스를 실체 클래스라고 했을 때, 이 클래스들의 공통적인 특성(즉, 필드와 메소드)을 추출해 선언한 클래스를 추상 클래스라고 할 수 있다.
- 원론적으로는 하나 이상의 추상 메소드를 포함하는 클래스를 가리켜 추상 클래스라고 한다.
- 추상 클래스와 실체 클래스는 '상속 관계'를 갖는다.
- 추상 클래스가 부모, 실체 클래스가 자식 관계로 구현된다.
- 따라서 실체 클래스는 추상 클래스의 모든 특성을 물려받고 추가적인 특성을 가질 수 있다.
*특성 : 필드, 메소드
추상 클래스의 선언
클래스 선언에 abstract를 붙인다.
public abstract class 클래스 {
//필드
//생성자
//메소드
}
추상 클래스의 특징
- 일반 클래스처럼 필드, 생성자, 메소드를 선언할 수는 있지만 객체를 직접 생성해서 사용할 수는 없다. 따라서 new연산자를 통해 인스턴스 또한 생성하지 못한다.
- 그러나 자식 객체가 생성될 때 'super()' 메소드를 호출하여 추상 클래스 객체를 생성하므로 추상 클래스 또한 반드시 생성자가 있어야 한다.
- 추상 클래스를 상속받는 모든 클래스에서는 추상 메소드를 반드시 재정의해야 한다.
- 추상 클래스는 새로운 실체 클래스를 만들기 위한 부모 클래스로만 사용된다. 즉, extends 뒤에만 올 수 있다.
추상 클래스의 용도
1. 실체 클래스들의 공통된 필드와 메소드의 이름을 통일하고자
- 실체 클래스를 설계하는 사람들이 여러 명일 경우 실체 클래스마다 결국엔 공통된 역할을 하는 필드와 메소드가 여러번 선언되고 각기 다른 이름을 갖게 된다.
- 이러한 상황에서 실체 클래스의 부모 클래스인 추상 클래스에서 공통된 필드와 메소드를 선언함으로써 각각의 실체 클래스에서는 추상 클래스의 필드 메소드를 상속받아 사용할 수 있다.
=> 코드에 통일성을 부여한다.
2. 실체 클래스를 작성할 시간을 절약하고자
- 추상 클래스에 실체 클래스에서 사용될 필드와 메소드를 미리 만들어두고 실체 클래스마다 다른 점만 구현한다면 코드 작성 시간을 절약할 수 있게 된다.
3. 추상 메소드가 포함된 클래스를 상속받는 자식 클래스가 반드시 추상 메소드를 구현하도록 하기 위해
- 일반 메소드를 상속받은 자식 클래스는 해당 클래스 내의 메소드를 구현할 수도, 안 할 수도 있다.
- 그러나 추상 메소드가 포함된 추상 클래스를 상속받은 모든 자식 클래스는 추상 메소드를 구현해야만 인스턴스를 생성할 수 있으므로 반드시 구현하게 하고자 할 때 추상 클래스를 사용할 수 있다.
추상 메소드
- 자식 클래스에서 반드시 오버라이딩 해야만 사용할 수 있는 메소드를 의미한다.
- 선언부만이 존재하며 구현부는 작성되어 있지 않다.
- 자식 클래스에서 작성되어 있지 않은 구현부를 오버라이딩하여 사용한다.
- 추상 메소드의 선언
abstract 반환타입 메소드이름();
6. final 키워드
- 클래스, 필드, 메소드를 수정할 수 없고 최종 상태임을 선언하고자 할 때 붙여준다.
- 클래스, 필드, 메소드에 붙었을 때 각각의 해석이 조금씩 다르다.
- 'final + 클래스' : 해당 클래스는 최종적인 클래스이므로 더이상 자식 클래스를 만들 수 없고 상속할 수 없다.
- 'final + 메소드' : 해당 메소드는 최종적인 메소드이므로 오버라이딩 할 수 없다.
- 'final + 필드(멤버변수)' : 해당 필드는 초기값 설정 후 더이상 값을 변경할 수 없다.
7. object 클래스
- 자바에서 가장 기본적인 동작을 수행하는 클래스들의 집합인 java.lang 패키지 내에서 가장 많이 사용되는 클래스
- 모든 자바 클래스의 최고 조상 클래스
- 자바의 모든 클래스는 object클래스의 모든 메소드를 바로 사용할 수 있다.
- 필드(멤버변수)를 가지지 않고 11개의 메소드로만 구성되어 있다.
object 클래스 내의 11가지 메소드