ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Java]STEP1 - 12) 자바의 다형성, 클래스 타입 변환, 필드와 매개변수의 다형성, 강제 타입 변환(Casting), 추상클래스와 추상메소드
    개발 공부/Java 2020. 9. 24. 20:07

     

    본 게시글은 도서 "이것이 자바다" 동영상 강의를 듣고 기록하는 TIL(Today I Learned) 입니다.
    모든 저작권은 출판사 한빛미디어와 신용권님께 있음을 알립니다.👍

     

     

    이번 게시글에서는 자바의 다형성의 개념과 클래스의 타입 변환(자동, 강제)을 알아봅니다.

    또한 필드와 매개변수는 어떻게 다형성을 형성할 수 있는지 알아봅니다.

    마지막으로 추상 클래스와 추상 메소드란 무엇인가를 알아보겠습니다.

     

     

    1. 자바의 다형성과 자동 타입 변환


    다형성 같은 타입이지만 실행 결과가 다양한 객체를 이용할 수 있는 성질을 말한다.

    즉, 하나의 타입에 여러 객체를 대입함으로써 다양한 기능을 이용할 수 있도록 해주는 것을 말한다.

     

    다형성을 위해서 자바에서는 부모 타입에 모든 자식 객체가 대입 될 수 있도록 해주는데, 이것을 자동 타입 변환이라고 한다.

    // 부모 클래스
    class Animal {
    }

    // 자식 클래스
    class Cat extends Animal {
    }

    위와 같이 Animal이라는 부모 클래스와 이를 상속받는 Cat이라는 자식 클래스가 있을 때,

    Cat cat = new Cat();
    Animal animal = cat;

    이것과 같이 선언하게 되면 자동 타입 변환이 일어났다고 볼 수 있다.
    Animal이라는 부모 타입 객체인 animal에 Cat 타입 객체인 cat이 대입되었기 때문이다.

    이처럼 모든 자식 객체는 부모 객체로 타입이 변환 될 수 있다.
    이때 cat과 animal은 타입만 Cat과 Animal로 다를 뿐, 동일한 Cat 객체를 참조하고 있다. (주소값이 동일하다.)

     

    자동 타입 변환은 바로 위의 부모가 아니더라도 상속 계층에서 상위 타입이라면 일어날 수 있다.

    부모 타입으로 자동 타입 변환된 이후에는 부모 클래스에 선언된 필드와 메소드만 접근이 가능하다.

    그런데, 자식 클래스에서 메소드를 오버라이딩 하였다면, 자식 클래스의 메소드가 대신 호출된다.

    // 부모 클래스
    class Parent {
        void method1() { }
        void method2() { }
    }

    // 자식 클래스
    class Child extends Parent {
        void method2() { } // 메소드 오버라이딩
        void method3() { }
    }

    // 실행
    class ChildExample {
        public static void main(String[] args) {
            Child child = new Child();
            Parent parent = child; // 자동 타입 변환

            parent.method1();
            parent.method2();
            parent.method3(); // 호출 불가
        }
    }

    위와 같이 Parent 부모 클래스, Child 자식 클래스가 선언되어 있고
    Parent parent = child; 의 형태로 자동 타입 변환이 일어나 있다면

    parent.method2();는 오버라이딩 된 Child 자식 클래스의 method2() 가 실행될 것이다.
    parent.method3();은 이미 Parent 타입으로 변환이 되었으므로 실행이 불가능 하다.

     


     

    2. 필드와 매개변수의 다형성


    2-1) 필드의 다형성

    자동 타입 변환이 왜 필요한가?

    -> 그것은 다형성을 구현하는 기술적 방법이기 때문이다.

    -> 주로 필드의 값을 다양화함으로써 실행 결과가 다르게 나오도록 구현한다.

    -> 필드의 타입은 변함이 없지만, 실행 도중 어떤 객체를 필드로 저장하느냐에 따라 실행 결과가 달라진다.

     

    class Car {
        Tire frontLeftTire = new Tire();
        Tire frontRightTire = new Tire();
        Tire backLeftTire = new Tire();
        Tire backRightTire = new Tire();

        void run() { }
    }

    현재 Car 클래스는 4개의 Tire 필드를 가진다.
    만약 4개의 Tire 중 frontRightTire에 문제가 발생한다면 다른 객체인 HankookTire로 교체할 수 있다.

    Car myCar = new Car();
    myCar.frontRightTire = new HankookTire();
    myCar.run();

    HankookTire 클래스는 Tire 클래스의 자식 객체이다.
    따라서 Tire 타입인 frontRightTire에 HankookTire 객체를 대입할 수 있다.
    이것을 우리는 자동 타입 변환이라고 부르고, 이는 필드의 다형성을 가능하게 한다.

    즉, 자동 타입 변환을 통해 필드의 다형성이 가능해지고
    필드의 다형성이 가능해지기 때문에 필드에 저장되는 객체에 따라 실행 결과가 달라진다.
    필드에 저장되는 객체가 발전하면 발전할 수록 프로그램 전체의 성능도 발전할 수 있게 되는 것이다.

     

     

    2-2) 매개변수의 다형성

    자동 타입 변환은 필드의 값을 대입할 때에도 발생하지만, 주로 메소드를 호출할 때 많이 발생한다.

     

    // 부모 클래스
    class Vehicle {
        public void run() {
            System.out.println("차량이 달립니다.");
        }
    }

    // 자식 클래스
    class Bus extends Vehicle {
        @Override
        public void run() {
            System.out.println("버스가 달립니다.");
        }
    }

    부모 클래스인 Vehicle을 상속받는 자식 클래스 Bus가 있다고 가정하자.
    그리고 Bus 클래스에서는 run() 메소드가 오버라이딩 되었다고 가정하자.

    class Driver {
        void drive(Vehicle vehicle) {
            vehicle.run();
        }
    }

    Driver 클래스에서 drive 메소드의 매개변수에는 Vehicle 타입의 vehicle 객체가 들어간다.
    그리고 Vehicle 클래스에 선언되어있는 run() 메소드를 호출한다.

    그런데 만약! drive(Vehicle vehicle) 에서 Vehicle 타입이 아니라 Bus 타입의 객체가 매개변수로 들어가면 어떻게 될까?

    이것도 앞서 설명했던 개념들과 똑같다.
    Bus 클래스는 Vehicle 클래스를 상속하고 있는 자식 클래스이기 때문에, 아무 문제 없이 자동 타입 변환이 된다.
    하지만 바로 아래에서 실행되는 run() 메소드는, Bus 자식 클래스에서 오버라이딩 되었기 때문에
    "차량이 달립니다." 가 아니라 "버스가 달립니다." 라고 출력될 것이다.

    이것이 바로 매개변수의 다형성이다.
    매개변수의 다형성은 매개변수로 여러 객체가 들어올 수 있게 해줌으로써 실행 결과를 다양하게 만든다.

     

     

    2-3) 강제 타입 변환(Casting)

    강제 타입 변환(Casting)이란 자동 타입 변환과는 반대로 부모 타입 객체를 자식 타입 객체로 변환하는 것을 말한다.

     

    하지만 아주 큰 조건이 있다.

    바로 자식 타입이 부모 타입으로 자동 변환한 후,

    다시 자식 타입으로 변환할 때만 강제 타입 변환을 사용할 수 있다는 것이다.

     

    쉽게 말하면, 복원의 느낌이다.

    자식이 부모로 자동 변환하고 -> 다시 자식으로 복원할 때만 사용가능하다는 의미이다.

    위의 Vehicle과 Bus의 예로 살펴본다.

    Vehicle vehicle = new Bus();

    현재 Bus 객체는 Vehicle로 자동 타입 변환 된 상태이다.
    만약 이를 다시 Bus 타입으로 강제 타입 변환 하고 싶다면

    Bus bus = (Bus) vehicle; 와 같이 선언하면 된다.

     

    강제 타입 변환을 하는 이유는 다음과 같다.

     

    자식 객체가 부모 객체 타입으로 자동 타입 변환을 하게 되면,

    부모 객체에 존재하지 않는 추가적인 필드나 메소드를 자식 객체가 가지고 있다고 해도,

    이미 해당 자식 객체는 부모 객체 타입으로 변환 되었기 때문에 해당 필드와 메소드를 사용할 수 없다.

     

    따라서 원래 자식 객체에만 추가적으로 선언한 필드와 메소드를 사용하기 위해서는

    자동 타입 변환으로 인해서 부모 객체 타입으로 변환된 자식 객체를 강제 타입 변환을 통해서

    원래 자식 객체 타입으로 복원해야 한다.

     


     

    3. 추상 클래스와 추상 메소드


    추상(abstract) : 실체 간에 공통되는 특성을 추출한 것

    예) 새, 곤충, 물고기 등의 실체에서 공통되는 특성을 추출하면 동물이라는 공통점이 있다.

     

     

    추상 클래스: 객체를 직접 생성할 수 있는 클래스인 실체 클래스들의 공통적인 특성을 추출해서 선언한 클래스

     

    한마디로 추상 클래스는 일종의 규격이라고 보면 된다.

    모든 실재하는 물건들이 설계도라는 규격에 맞춰서 제작되듯이,

    실체 클래스는 추상 클래스라는 설계도에 맞춰서 제작된다고 생각하면 된다.

     

    추상 클래스는 실체 클래스의 공통되는 필드와 메소드를 추출하여 만들었기 때문에,

    객체를 직접 생성할 수 없고 상속만 가능하다. 즉 new 연산자를 사용하여 인스턴스를 만들 수 없고 extends 뒤에만 올 수 있다.

     

     

    추상 클래스의 용도

    1. 실체 클래스들의 공통된 필드와 메소드의 이름을 통일할 목적
    2. 실체 클래스를 작성할 때 시간을 절약

     

    추상 클래스의 선언

    public abstract class Phone {
     ....
    }

     

    추상 메소드: 추상 클래스에서만 선언할 수 있고, 메소드의 선언부만 있고 실행 내용인 중괄호가 없는 메소드를 말한다.

     

    public abstract class Animal {
        public abstract void sound();
    }

    추상 클래스인 Animal 안에
    추상 메소드인 sound()를 선언하였다.

    sound()는 나중에 Animal을 상속할 실체 클래스에서 더 구체적으로 오버라이딩 된다.
    Animal에서는 실체 클래스들이 꼭 가져야하는 메소드인 sound()를 미리 설계만 해놓은 것이다.

     

     

     

     

    본 게시글은 여기서 마치겠습니다.

    읽어주셔서 감사하고, 혹시나 틀린 부분이나 보완해야할 부분이 있다면 댓글에 남겨주세요~!

    댓글

Designed by Tistory.