| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 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 |
- 게시판 만들기
- 게시판 리뷰 만들기
- Interface
- 개발자취업부트캠프
- View
- 클래스 상속
- 국비지원교육
- #javaStudy
- 메가바이트스쿨
- 패스트캠퍼스
- github
- group study
- MVC 패턴
- MVC
- MegabyteSchool
- spring boot
- 내일배움카드
- Entity
- crud
- Spring
- Algorism study
- AWS
- #패스트캠퍼스 #국비지원교육 #메가바이트스쿨 #MegabyteSchool #개발자취업부트캠프 #내일배움카드
- Java
- tomcat
- GIT
- 클래스 class
- Sts
- side project
- array
- Today
- Total
tuter77
Java : 상속(4) method overriding, 가상메서드, 다형성 본문
● 메서드 재정의하기 (overring)
▷ 하위 클래스에서 메서드 재정의 하기
- 오버라이딩 : 상위 클래스에 정의된 메서드의 구현 내용이 하위클래스에서 구현할 내용과 맞지 않는 경우, 하위 클래스에서 동일한 이름의 메서드를 재정의 할 수 있다.
- VIPCustomer 클래스의 calcPrice()는 할인율이 적용되지 않아 재정의하여 구현해야한다.
@Overrige
public int calcPrice(int price){
public int calcPrice(int price) {
bonusPoint += price * bonusRatio;
price -= (int)(price *salesRatio);
return price;
}
위의 예시를 작성할 때 마우스 우클릭 > Source > Overring 에서 상위 클래스의 변수를 재정의하면된다.
▷ @Override 애노테이션
- 애노테이션 : 컴파일러에게 특별한 정보를 제공해주는 역할을 한다.
@Override 재정의된 메서드라는 정보 제공 (선언부가 기존의 메서드와 다른경우 에러가 난다.)
@FunctionalInterface 함수형 인터페이스라는 정보 제공
@Deprecated 이후 버전에서 사용되지 않을 수 있는 변수, 메서드에 사용된다.
@SuppressWarnings 특정 경고가 나타나지 않도록 한다. 예를 들면 @SuppressWarnings("deprecation")는 @Deprecated 가 나타나지 않도록 한다.
▷ 형 변환과 오버라이딩 메서드 호출
Customer vc = new VIPCustomer(12345, "testName");
vc.calcPrice(1000); //가상함수와 형변환 - 가상 메서드.
/*
* vc 라는 변수의 타입은 Customer지만 인스턴스는 VIPCustomer이며,
* calcPrice는 VIPCustomer에서 override된 메서드.
* 원래 vs.하면 Customer의 메서드만 나오는데 calcPrice는 어떨까?
*/
System.out.println(price); //인스턴스의 calcPrice로 나온다.
자바에서는 항상 인스턴스의 메서드가 호출된다.
이는 가상 메서드의 원리이다.
● 가상함수( 가상 메서드)
▷ 가상메서드에 들어가기전 함수 호출 살펴보기 (메서드는 함수의 일종)
프로그램 안의 코드.a() 함수내에 변수, 인스트럭션(명령어) 들이 있다.a가 나중에 컴파일이 되고 a() 함수가 호출이 된다.
static 변수와 integer 상수도 있다.
이는 하나의 코드영역과 데이터영역(상수, static)으로 가게되는데, 코드영역으로 함수(Instructor set)가 가게된다.
(코드 영역은 logic만 갖고 있다.)
함수안의 다양한 기능자체는 동일하다(더하는것) > 다만 변수가 다른건데, 변수의 경우 지역변수는 Stack에, 인스턴스는 Heap에 메모리가 잡히게 된다.
기능이라는 부분은 인스턴스마다 다르지않다는 것.
함수의 이름은 주소로 변환되어있고 오버라이딩이 같은 이름으로 가능한 이유는, 더미 파라미터를 붙여서 이름(주소)을 조금씩 바꾼다.
정리하면, 함수를 호출하는 건 인스턴스마다 따로 생기는것이 아니다.
- 메서드(함수)의 이름은 주소값을 나타낸다.
- 메서드는 명령어의 set이고 프로그램이 로드되면, 메서드 영역(코드 영역)에 명령어 set이 위치한다.- 해당 메서드가 호출되면 명령어 set이 있는 주소를 찾아 명령어가 실행되는데, 이때 메서드에서 사용하는 변수들은 스택메모리에 위치하게 된다.- 따라서 다른 인스턴스라도 같은 메서드의 코드는 같으므로 같은 메서드가 호출된다.- 인스턴스가 생성되면 변수는 힙메모리에 따로 생성되지만, 메서드 명령어 set은 처음 한번만 로드된다.
예시)
public class TestMethod{
int num;
void aaa(){
System.out.println("aaa() 호출");
}
public static void main(String[] args){
TestMethod a1 = new TestMethod();
a1.aaa();
TestMethod a2 = new TestMethod();
a2.aaa();
}
}
<힙 메모리>
| a1의 num |
| a2의 num |
↓
<스택메모리> → <메서드 영역>
| aaa() 메서드 영역 | |
| a1 | → aaa() 호출 |
| a2 | → aaa() 호출 |
| args |
▷ 가상 메서드.
- 가상 메서드 테이블에서 해당 메서드에 대한 address를 갖고 있다.
- 재정의된 경우는 재정의 메서드의 주소를 가리킴
● 다형성.(polymorphism)
- 하나의 코드가 여러 자료형으로 구현되어 실행되는 것으로 같은 코드에서 여러 다른 실행 결과가 나온다.
- 정보은닉, 상속과 더불어 객체지향 프로그래밍의 가장 큰 특징 중 하나이며, 잘 활용하면 유연하고 확장성있고, 유지보수가 편리한 프로그램을 만들 수 있다.
예시)
위의 예제에서 보면, 먼저 AnimalTest 클래스를 만들고, 위에 Animal이라는 상위클래스를 만들었다.
이후, Animal클래스 고유의 메서드(move)를 만들고 이 클래스를 상속받는 Human, Tiger, Eagle 클래스를 각각 만든다.
이어 각 하위클래스 3가지에 공통적으로 적용되는 move() 메소드를 오버라이딩해서 각 하위클래스의 형태에 맞게 바꿔준다.(각 하위클래스의 고유의 메서드도 하나씩 만들어줬다.(flying 등))
Test클래스에서 Animal(상위클래스) 타입의 각 하위클래스에 속한 인스턴스들을 생성해주고, 맨 아래 moveAnimal이라는 메서드를 만들었다.
이 메서드는 매개변수를 Animal 타입의 animal들로 받고 생성된 매개변수가 move() 메서드를 실행할 수 있게 한다.
이 moveAnimal 메서드는 AnimalTest 클래스의 메서드라서 AnimalTest 생성자로 test 객체를 만들어주고, 이 객체를 통해 각 인스턴스들animal(hAnimal, eAnimal 등의 매개변수가 있는)이 불려오도록 한다.
출력해보면, moveAnimal 한줄의 코드지만, 어떤 animal 자료가 불려오느냐에 따라 move 구현(implementation)이 달라진다.

이것이 다형성이 구현된 형태이다.
정리하면, 다형성은 동일한 타입처럼 쓰이지만 실질적인 Implement가 다르게 나오는 것을 의미한다.
이와같이 상속을 하게되면 상위클래스 하나의 타입으로 하위클래스들을 핸들링 할 수 있다.(좋은면이 있지만, dependency 측면에서는 좋지않다. 때문에 꼭 필요한 경우를 따져서 신중하게 상속을 설계해야한다.)
반면, animal 매개변수로 각 하위클래스 고유의 메서드를 불러올 수 는 없는데 불러오려면 다운캐스팅을 해야한다.
이렇게 핸들링 할 수있는것의 장점은 각 하위클래스에서 공통적으로 사용되는 메서드의 경우 상위클래스에 선언하면된다.
추가적으로 생성되는 다른 Class(animal)도 상속해서 똑같이 사용하면된다.(코드 재사용성)
만약 리스트에 동물클래스들을 추가하고 싶으면, 위 처럼 ArrayList의 타입을 Animal로 지정하고 생성자로 animalList를 생성한다.
list에 animalList.add()로 각 인스턴스를 매개변수로 받아주면 된다.
바로 아래 for문은 aniamlList를 돌면서 각 인스턴스(aniaml)move를 호출해주는 구문이다.

출력은 전과 같다.
▷ 다형성을 사용하는 이유
- 다른 클래스(동물)을 추가하거나, 상속과 메서드 재정의를 활용하여 확장성있는 프로그램을 만들 수 있다.
- 사용하지 않은 경우엔 많은 if-else if 문이 구현되고 코드의 유지보수가 어려워진다.- 상위클래스에서는 공통적인 부분을 제공하고 하위클래스에서는 각 클래스에 맞는 기능을 구현한다.- 여러 클래스를 하나의 타입(상위 클래스)으로 핸들링 할 수 있다.
▷ 다형성을 활용한 멤버십프로그램 확장.(실습)
/* 일반고객과 VIP고객 중간 멤버십 만들기
Gold 고객을 만들고 혜택은 다음과 같다.
1. 제품을 살 때 10프로 할인
2. 보너스 포인트는 2%적립.
*/
골드 고객 코드.
public class GoldCustomer extends Customer{
double salesRatio;
public GoldCustomer(int customerId, String customerName) {
super(customerId, customerName);
salesRatio = 0.1;
bonusRatio = 0.02;
customerGrage = "Gold";
}
@Override
public int calcPrice(int price) {
bonusPoint += price * bonusRatio;
return price - (int)(price *salesRatio);
}
}
각 등급에 따른 고객 인스턴스 생성 후 계산 테스트
import java.util.ArrayList;
public class CustomerTest {
public static void main(String[] args) {
ArrayList<Customer> customerList = new ArrayList<>();
Customer customerT = new Customer(10010, "Tomas");
Customer customerJ = new Customer(10020, "James");
Customer customerE = new GoldCustomer(10030, "Edward");
Customer customerP = new GoldCustomer(10040, "Percy");
Customer customerK = new VIPCustomer(10050, "Kim");
customerList.add(customerT);
customerList.add(customerJ);
customerList.add(customerE);
customerList.add(customerP);
customerList.add(customerK);
for(Customer customer : customerList) {
System.out.println(customer.showCustomerInfo());
}
int price = 10000;
for(Customer customer : customerList) {
int cost = customer.calcPrice(price);
System.out.println(customer.getCustomerName() + "님이 " + cost + "원을 지불하셨습니다.");
System.out.println(customer.getCustomerName() + "님의 현재 보너스 포인트는 " + customer.bonusPoint + "입니다.");
}
}
}
결과.

상속과 오버라이딩, 다형성 등의 개념에 대해 배웠는데 이러한 상속을 언제사용하는게 좋은지 알아보겠다.
▷IS-A 관계(is a relationship : inheritance)
- 일반적인 개념과 구체적인 개념과의 관계.
- 상위 클래스 : 하위클래스보다 일반적인 개념.(Employee)
- 하위 클래스 : 상위 클래스보다 구체적인 개념들이 더해진다.(Engineer,...)
- 상속은 클래스간의 결합도가 높은 설계이므로 상위클래스의 수정이 많은 하위 클래스에 영향을 미칠 수 있다.
- 계층 구조가 복잡하거나 hierarachy(계층의 길이)가 높으면 좋지않다.
▷HAS-A 관계(composition) - 클래스가 다른 클래스를 포함하는 관계(변수로 선언)- 코드 재사용의 가장 일반적인 방법.- Student 가 Subject 를 포함하지만 상속받지는 않는다.- Library를 구현할 때 ArrayList 생성하여 사용한다.- 상속하지 않는것. 이 경우가 훨씬 많다.
위 내용은 2023.01.04에 공부한 내용입니다.링크 : https://dudwls3278.tistory.com/35
'JavaStudy' 카테고리의 다른 글
| Java : 예외 처리 (0) | 2023.01.29 |
|---|---|
| Java : 다운 캐스팅, instanceOf (0) | 2023.01.29 |
| Java : 상속(3) super, 메모리, 업캐스팅 (0) | 2023.01.29 |
| Java : 상속(2) 및 복습. (0) | 2023.01.29 |
| Java : 상속, 배열(로테이션) (0) | 2023.01.29 |