Post

Java 문법 (10) - 상속

Java 문법 (10) - 상속




상속 관계


상속은 객체 지향 프로그래밍의 핵심 요소 중 하나로, 기존 클래스의 필드와 메서드를 새로운 클래스에서 재사용하게 해줍니다. 이름 그대로 기존 클래스의 속성과 기능을 그대로 물려받는 것이고, exdends 키워드를 사용하며 대상은 하나만 선택 가능합니다.

전기차와 가솔린차는 자동차의 더 구체적인 개념이고, 반대로 자동차는 둘을 포함하는 추상적인 개념입니다. 또한, 자동차의 이동, 문을 열기, 시동걸기 등 공통 기능이 있기 때문에 이런 경우 상속관계를 사용하는 것이 효과적입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// Car.java
package extends1.ex2;  
  
public class Car {  
    public void move(){  
        System.out.println("차를 이동합니다.");  
    }  
}

// ElectricCar.java
package extends1.ex2;  
  
public class ElectricCar extends Car {  
    public void charge(){  
        System.out.println("충전합니다.");  
    }  
}

// GasCar.java
package extends1.ex2;  
  
public class GasCar extends Car{  
    public void fillUp(){  
        System.out.println("기름을 주유합니다.");  
    }  
}

// CarMain.java
package extends1.ex2;  
public class CarMain {  
    public static void main(String[] args) {  
        ElectricCar electricCar = new ElectricCar();  
        electricCar.move(); // 상속을 받았기 때문에 Car의 move 함수를 사용 가능  
        electricCar.charge();  
  
        GasCar gasCar = new GasCar();  
        gasCar.move(); // 상속을 받았기 때문에 Car의 move 함수를 사용 가능  
        gasCar.fillUp();  
    }  
}

new ElectricCar()를 호출하면 ElectricCar 뿐만 아니라 상속관계에 있는 Car까지 포함해서 인스턴스를 생성합니다. 참조값은 하나이지만 그 안에 Car, ElectricCar 두가지 클래스 정보가 공존합니다. 메모리에서는 부모와 자식이 모두 생성되고 공간도 구분됩니다. 메서드를 호출할 대는 호출하는 변수의 타입을 기준으로 선택하는데, 타입이 ElectricCar라면 먼저 ElectricCar 내부에서 찾고 없으면 부모인 Car로 올라가서 찾아서 호출합니다.




오버라이딩


부모에게서 상속받은 기능을 자식이 재정의 하는 것을 메서드 오버라이딩이라고 합니다. 위의 기존 예시에서 ElectricCar의 move를 메서드 이름은 같지만 새로운 기능으로 사용하고 싶다면 오버라이딩을 하면 됩니다. 기존 Car의 move는 “차를 이동합니다.” 라는 기능이고, 이를 “전기차를 빠르게 이동합니다.”로 재정의 하는 예제입니다.

1
2
3
4
5
6
7
8
9
10
11
12
package extends1.overriding;  
  
public class ElectricCar extends Car {  
    @Override  
    public void move() {  
        System.out.println("전기차를 빠르게 이동합니다.");  
    }  
  
    public void charge(){  
        System.out.println("충전합니다.");  
    }  
}




super 부모 참조

부모와 자식의 필드명이 같거나, 메서드가 오버라이딩 되어 있으면, 자식에서 부모의 필드나 메서드를 호출할 수 없습니다. 이때 super 키워드를 사용하면 부모를 참조할 수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// Parent.java
package extends1.access.super1;  
  
public class Parent {  
    public String value = "parent";  
  
    public void hello(){  
        System.out.println("Parent.hello");  
    }  
}

// Child.java
package extends1.access.super1;  
  
public class Child extends Parent{  
    public String value = "child";  
  
    @Override  
    public void hello(){  
        System.out.println("Child.hgello");  
    }  
  
    public void call(){  
        System.out.println("this value = " + this.value); // this 생략 가능  
        System.out.println("super value = " + super.value); // 부모의 value  
        this.hello();    // this 생략 가능
        super.hello();   // 부모의 hello() 호출
    }  
}




super - 생성자


자바는 상속관계를 사용하면 자식 클래스의 생성자에서 부모 클래스의 생성자를 반드시 호출해야 합니다. 또한 호출할 때 자식 클래스의 생성자 첫줄에 반드시 super(…)를 호출해야 합니다. (기본생성자는 생략 가능). 첫 줄에 super()가 있기 때문에, 항상 가장 위에 있는 부모의 생성자부터 자식의 생성자 순서로 실행이됩니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package extends1.access.super2;  
  
public class ClassA {  
    public ClassA(){  
        System.out.println("ClassA 생성자");  
    }  
}

package extends1.access.super2;  
  
public class ClassB extends ClassA {  
    public ClassB(int a){  
        super(); // 기본 생성자 생략 가능  
        System.out.println("ClassB 생성자 a = " + a);  
    }  
  
    public ClassB(int a, int b){  
        super(); // 기본 생성자 생략 가능  
        System.out.println("ClassB 생성자 a = " + a + " b = " + b);  
    }  
}

package extends1.access.super2;  
  
public class ClassC extends ClassB {  
    public ClassC(){  
        super(10, 20);  
        System.out.println("ClassC 생성자");  
    }  
}

package extends1.access.super2;  
  
public class SuperMain2 {  
    public static void main(String[] args) {  
        ClassC c = new ClassC();  
    }  
}