본문 바로가기

Programming 언어/JAVA

10. 메서드 재정의(overring), 다형성, 다운 캐스팅 및 instanceof

1. 메서드 재정의 하기(overring)

하위 클래스에서 메서드 재정의 하기(오버라이딩)

상위 클래스에서 정의된 메서드의 구현 내용이 하위 클래스에서 구현할 내용과 맞지 않는 경우 하위 클래스에서 동일한 이름의 메서드를 재정의 할 수 있음(오버라이딩시 반환값, 메서드 이름, 매개 변수 타입 및 개수 모두 같아야함)

ex) VIPCustomer 클래스의 calcPrice()는 할인율이 적용되지 않는다 가정하고 재정의한다면

(vscode를 사용한다면 오른쪽 키 -> 소스 작업으로 쉽게 만들 수 있다)

위는 소스 작업으로 오버라이딩 코드를 구현한 것이고 이를 구체화한다면

이렇게 오버라이딩하면 된다.

근데 @Override 가 뭘까??

// 애노테이션 //

@Override 이게 애노테이션

1. 애노테이션은 원래 주석이라는 의미

2. 컴파일러에게 특별한 정보를 제공해주는 역할

추가적으로

이렇게 코드를 작성하면 vc.calcPrice는 상위 클래스인 Customer의 calcPrice일까, VIPCustomer의 calcPrice일까

-> 이럴때는 인스턴스 생성자의 calcPrice가 불려진다!!! (new VIPCustomer) 

즉, vc 변수의 타입은 Customer이지만 인스턴스 타입은 VIPCustomer이며 자바에서는 항상 인스턴스 메소드가 호출 된다. -> 가상메서드 원리(자바에서 모든 메서드는 가상 메서드)

2. 메서드는 어떻게 호출되고 실행 되는가?

1. 메서드(함수)의 이름은 주소값을 나타냄

2. 메서드는 명령어의 set이고 프로그램이 로드되면 메서드 영역(코드 영역)에 명령어 set이 위치

3. 해당 메서드가 호출되면 명령어 set이 있는 주소를 찾아 명령어가 실행

4. 이때 메서드에서 사용하는 변수들은 스택 메모리에 위치

5. 따라서 다른 인스턴스라도 같은 메서드의 코드는 같으므로 같은 메서드 호출

6. 인스턴스가 생성되면 변수는 힙 메모리에 따로 생성되지만, 메서드 명령어 set은 처음 한 번만 로드

변수의 영역

지역 변수 -> 스택, 인스턴스 변수 -> 힙 메모리

이러한 변수의 영역이 따로 생긴다.

3. 가상 메서드의 원리

1. 가상 메서드 테이블에서 해당 메서드에 대한 address를 가지고 있음

2. 재정의된 경우는 재정의된 메서드의 주소를 가리킴(재정의시 재정의 주소로 호출)

쉽게 생각해서 만약 클래스 내에서 사용하는 메서드들이 같다면 -> 같은 주소에 있는 메서드들을 사용하는 것

-> 달라지는건 변수의 영역이 달라진다!!!!!

4. 다형성과 다형성을 사용하는 이유

다형성이란?

하나의 코드가 여러 자료형으로 구현되어 실행되는 것(하나가 다양한 형태를 가짐)

1. 같은 코드에서 여러 다른 실행 결과가 나옴

2. 정보은닉, 상속과 더불어 객체지향 프로그래밍의 가장 큰 특징 중 하나

3. 다형성을 잘 활용하면 유연하고 확장성있고, 유지보수 편리한 프로그램을 만들 수 있다.

Animal animal 자리에는 하위 클래스들을 넣을 수 있다.

위 코드를 출력하면

여러 클래스 타입을 Animal 이라는 하나의 타입으로 모두 핸들링이 가능함 -> 이게 바로 다형성이다.

(단, Animal에 없는 메서드를 가져올 수 없다.)

공통적으로 사용할 수 있는 메서드를 그냥 상위 클래스에 선언해라!

만약 ArrayList<Animal> -> Animal 타입으로 지정한다면

이렇게 넣어주면된다.

결과는 이러하다~~~

다형성을 사용하는 이유?

1. 상속과 메서드 재정의를 활용하여 확장성 있는 프로그램을 만들 수 있다.

2. 그렇지 않는 경우 많은 if - else - if 문이 구현되고 코드의 유지보수가 어렵다.

3. 상위 클래스에서는 공통적인 부분 제공하고 하위 클래스에서는 각 클래스에 맞는 기능 구현

4. 여러 클래스를 하나의 타입(상위 클래스)으로 핸들링 할 수 있음

5. 다운 캐스팅과 instanceof

다운 캐스팅

업캐스팅된 클래스를 다시 원래의 타입으로 형 변환(원래 인스턴스로 돌아오는 것)

-> 하위 클래스로의 형 변환은 명시적으로 해야함

Customer vc = new VIPCustomer(); -> 묵시적

VIPCustomer vCustomer = (VIPCustomer)vc; -> 명시적

이렇게 다른 인스턴스 형 생성자를 사용하여 인스턴스를 생성한 놈은 기존과 다른 형 변환이 불가하다.

instanceof 키워드

왼쪽이 원래 오른쪽 인스턴스였는지 확인하는 키워드

맞으면 true 리턴함