자바 상속 문법과 형변환 | 자바 입문강좌 26

자바 상속 문법과 형변환

이번 포스팅에서는 자바 상속 문법에 대하여 정리하겠습니다.

우선 상속이란 base 클래스를 확장 extends 하는 것이라고 했습니다. 부모 클래스, 자식 클래스라는 단어도 사용하는데요. 부모 자식이라는 단어에 선입견이 있을 수 있기 때문에 좀 조심해서 써야하고요. base 클래스와 sub 클래스가 좀더 중립적인 용어입니다.

여기서는 base 와 sub 클래스를 사용해서 설명합니다.

설명을 위한 소스 코드는 아래와 같습니다. 하나씩 알아보도록 하겠습니다.

package com.kay;

public class Main {

    public static void main(String[] args) {
	// write your code here
        System.out.println("\n-------- creating base base ---------");
        baseClass myDCs = new baseClass();
        myDCs.showData();

        baseClass myCs = new baseClass(101, "base Class");
        myCs.showData();

        System.out.println("\n-------- sub extends base ---------");

        subClass mySb = new subClass(201, "sub Class-1",
                "this is sub Class");

        mySb.showData();
        mySb.showProtected();

        System.out.println("\n-------- casting to base --------");
//        base class 로 형변환
        baseClass base1 = new subClass(301, "sub Class cast",
                "casting example");
        base1.showData();

        System.out.println("\n-------- casting to sub explilcit --------");
//        접근이 안됨
//        base1.showProtected();

//        명시적 캐스팅(형변환)
        subClass sub1 = (subClass) base1;
        sub1.showProtected();

    }
}

class baseClass{
    private int id;
    private String name;
    protected String text1;

    public baseClass(){
        id = 100;
        name = "null";
        System.out.println("[0- default base Class Created...]");
    }
    public baseClass(int id, String name) {
        this.id = id;
        this.name = name;
        this.text1 = "protected one";
        System.out.println("[1- base Class Created...]");
    }
    public void showData(){
        System.out.println("*id = " + id);
        System.out.println("*name = " + name);
    }
}

class subClass extends baseClass{
    private String description;

    public subClass(){
        super();
        description = "no contents";
    }
    public subClass(int id, String name, String description) {
        super(id, name);
        this.description = description;
        System.out.println("[2- sub Class Created...]");
    }
    public void showData(){
        super.showData();
        System.out.println("#description = " + this.description);
    }
    public void showProtected() {
        System.out.println("#super.text1 = " + super.text1);
    }

//    super의 private 에 접근 불가
//    public void tryPrivate(){
//        System.out.println("id = " + id);
//    }

}
-------- creating base base ---------
[0- default base Class Created...]
*id = 100
*name = null
[1- base Class Created...]
*id = 101
*name = base Class

-------- sub extends base ---------
[1- base Class Created...]
[2- sub Class Created...]
*id = 201
*name = sub Class-1
#description = this is sub Class
#super.text1 = protected one

-------- casting to base --------
[1- base Class Created...]
[2- sub Class Created...]
*id = 301
*name = sub Class cast
#description = casting example

-------- casting to sub explilcit --------
#super.text1 = protected one

base 클래스의 생성

base 클래스는 일반형 클래스입니다. 여러개의 sub 클래스로 확장을 위한 클래스이기 때문에 최소한의 기능만 갖도록 설계합니다. 군더더기가 없을 수록 좋습니다. 이게 심화된 것이 abstract (추상화) 클래스 입니다. 기능을 구현할 필요조차 없는데요.

Java 의 API는 abstract 계층과 implementation 계층을 분리해서 만드는 방식을 사용합니다. 자바가 100%의 객체지향을 추구한다는 말은 Java API 를 살펴보면 알 수 있습니다.

아래의 클래스는 어디에서나 사용할 수 있는 틀을 만들어 본 것 입니다. 클래스를 만들 때 특정한 의미와 관계를 가져야 한다고 생각하는데 그럴 필요는 없습니다. OOP 도 결국 하나의 문법이자 알고리즘에 지나지 않습니다. OOP는 연결관계를 전체부터 세부사항까지 파악하는게 중요합니다.

class baseClass{
    private int id;
    private String name;
    protected String text1;

    public baseClass(){
        id = 100;
        name = "null";
        System.out.println("[0- default base Class Created...]");
    }
    public baseClass(int id, String name) {
        this.id = id;
        this.name = name;
        this.text1 = "protected one";
        System.out.println("[1- base Class Created...]");
    }
    public void showData(){
        System.out.println("*id = " + id);
        System.out.println("*name = " + name);
    }
}

sub 클래스의 생성

sub 클래스는 base 클래스의 기능을 확장 extends 한 클래스입니다.

class subClass extends baseClass{
    private String description;

    public subClass(){
        super();
        description = "no contents";
    }
    public subClass(int id, String name, String description) {
        super(id, name);
        this.description = description;
        System.out.println("[2- sub Class Created...]");
    }
    public void showData(){
        super.showData();
        System.out.println("#description = " + this.description);
    }
    public void showProtected() {
        System.out.println("#super.text1 = " + super.text1);
    }

//    super의 private 에 접근 불가
//    public void tryPrivate(){
//        System.out.println("id = " + id);
//    }

}

sub 클래스를 시작할 때 base 클래스의 모든 것을 가지고 있다고 생각하고 시작합니다. 보이지 않지만 base 클래스의 private 멤버들이 다 있는데요. base 에서 private 은 sub 클래스에서도 접근이 안됩니다. 직접 접근을 하려면 protected 를 걸어야 합니다. 기본적으로 base 클래스가 public 이어야 사용이 가능합니다.

그리고 상속받은 것들 중에 바꾸고 싶은 것들은 메소드 오버라이드를 합니다. override 란 base 에서 확장한 메소드를 밀어버리고 새로 깔아버리는 것 입니다. 아무래도 sub 에서는 기능적으로 추가되는 것들이 많기 때문에 오버라이드를 할 수 밖에 없습니다. 기존의 코드를 포함시키고 싶을 때 super 를 사용하면 base 의 public 과 protected 를 사용할 수 있습니다. base 의 private 은 sub 가 접근할 수 없다고 했습니다.

super 는 base 의 참조를 의미하고 this 는 현재 클래스의 참조를 의미합니다. 이는 어떤 대상이 아니라 인스턴스에 접근하는 해시키(메모리값)입니다.

C++은 메모리에 직접 주소를 읽어서 접근하지만 자바는 com.kay.subClass@1d81eb93 같은 해시키로 접근합니다. 값이 있어야 인스턴스의 메모리에 접근할 수 있다는 면은 같은데요. C++이 좀더 원시적(raw)이라면 자바가 좀 더 세련된 정도로 볼 수 있습니다.

자바를 공부하면서도 C++같은 메모리 개념을 알아야 되는데요. 다형성을 다루기 위해서는 메모리 모델을 머리속에 갖고 있는게 좋습니다.

형변환(Casting)

다형성을 다루기 위해서 들여다 봐야 할 부분입니다.

base 와 sub 의 형변환에서 base는 기본이고 sub 는 확장입니다. 즉 집합으로 따지면 base는 sub 의 부분집합입니다. 데이터형을 base 로 선택하면 부분집합적으로 sub의 인스턴스에 접근할 수 있습니다.

반대로 sub 데이터형에 base 인스턴스를 선언하는 것은 불가능합니다. sub 참조가 base 인스턴스에 없는 멤버변수들에 접근할 수 없기 때문입니다.

약간 헷갈릴 수 있지만 잘 생각해보면 base 참조가 안전할 수 밖에 없습니다.

아래는 sub 인스턴스를 base 참조에 할당하고 나중에 base 참조를 sub로 형변환까지 하는 모습입니다. 이때는 명시적으로 캐스팅을 해줘야합니다. 이 부분은 다형성에서 다루는 내용입니다.

처음에 base 클래스를 기본형으로 선언하면 나중에는 sub 클래스를 몇개를 만들더라도 적응할 수가 있다는 장점이 있습니다.

//        base class 로 형변환
        baseClass base1 = new subClass(301, "sub Class cast",
                "casting example");
        base1.showData();

        System.out.println("\n-------- casting to sub explilcit --------");
//        접근이 안됨
//        base1.showProtected();

//        명시적 캐스팅(형변환)
        subClass sub1 = (subClass) base1;
        sub1.showProtected();

요약

자바 상속 문법에 대하여 빠른 속도로 알아봤습니다.

상속이라는 말의 의미에 사로잡히지 말고 base 와 sub 간의 확장(extends) 문제로 생각하면 좀 더 이해하기 쉽습니다. 이 확장한다는 OOP 개념은 자바 뿐 아니라 파이썬 등 대부분 현대 언어 그리고 동적 언어들에서 채용하고 있기 때문에 자바의 상속을 잘 배워두면 개념적으로 쓸일이 많습니다.

C++ 이 객체지향프로그래밍의 정석이라고 하는 교재도 있습니다만, 그것도 맞는 이야기죠. 그런데 C++은 자바에 비해 상대적으로 어려워서 대중적으로 익숙하지 않습니다. MS도 C++ 다음에 C#과 닷넷프레임워크를 출시하면서 자바를 많이 모방했습니다.

프로그래밍 언어는 정통성도 중요하지만 너무 어려워서 대중성이 떨어지면 시장에서 밀려나고 결국 아무리 기술이 좋아도 빛을 보기 힘들게 되는데요. 지금은 과거에 비해 캐주얼한 개발자들을 많이 요구하는 사회입니다. 그 만큼 이 분야가 확대되고 있다는 뜻 입니다. 보고 있으면 계속 IT쪽에서 새로운 직업이 만들어 질 것입니다. 물론 그 기반은 코딩입니다.

기술을 좋아하는 사람들에겐 하드코어 코딩이 더 좋겠지만 꼭 그렇지 않아도 프로그래밍을 할 수 있습니다. 현재는 자바 정도가 대중성과 기술 그 중간 어디쯤 포지션을 가지고 있는 것 같습니다.

자바는 OOP를 제대로 알아둬야 쓸만합니다.

외부참고문서

Java extends Keyword (w3schools.com)

Java – Inheritance – Tutorialspoint

Inheritance 자바 상속 문법 오라클 (oracle.com)

Guide to Inheritance in Java | Baeldung

자바 상속 문법 생성자 , super 키워드, 클래스 형변환

자바 상속, protected 접근제어자

Leave a Comment