백엔드 개발 공부 일지
JAVA Basic - 상속 본문
● 상속이란?
상속은 객체 지향 프로그램에 이써 유지보수성과 연관이 깊은 개념이다. B클래스를 생성할때의 기존에 있던 A클래스의 멤버변수나 메서드를 사용해야 할 경우 새로 클래스를 생성하지 않고 A클래스를 상속받음으로써 멤버변수와 메서드를 공유하여 사용할 수 있다.
이경우, A클래스는 상위클래스, B클래스는 하위클래스에 해당한다.
Class B extends A { }
아래의 예시는 Customer라는 상위클래스를 VIPCustomer라는 하위클래스가 상속을 받는 예제이다.
(VIP 고객은 일반 고객과 다르게 상담원 ID와 할인률이 적용되는 경우)
보통 상위클래스에서의 멤버변수는 하위클래스만 사용할 수 있도록 protected로 선언한다. public일시 하위클래스외의 클래스가 사용이 가능하며 private일시 하위클래스마저도 사용이 불가능하다.
즉, protected는 상속된 하위 클래스를 제외한 나머지 외부 클래스에서 private과 동일한 역할을 한다.
package inheritance;
public class Customer {
protected int customerID;
protected String customerName;
protected String customerGrade;
int bonusPoint;
double bonusRatio;
public Customer() {
customerGrade = "SILVER";
bonusRatio = 0.01;
}
public int calcPrice(int price) {
bonusPoint += price * bonusRatio;
return price;
}
public String showCustomerInfo() {
return customerName + " 님의 등급은 " + customerGrade + " 이며, 보너스 포인트는 " + bonusPoint + " 입니다.";
}
}
package inheritance;
public class VIPCustomer extends Customer {
private int agentID;
double saleRatio;
public VIPCustomer() {
customerGrade = "VIP";
bonusRatio = 0.05;
saleRatio = 0.1;
}
public int getAgentID() {
return agentID;
}
}
● 상속에서 클래스 생성과 형 변환
하위 클래스가 생성될 떄는 상위 클래스의 생성자가 먼저 호출된다.
즉, 클래스의 멤버변수들은 생성될 때 힙메모리에 저장되므로 상위클래스의 멤버변수가 먼저 메모리에 저장된 후, 하위클래스의 멤버변수가 힙메모리에 저장된다.
(private으로 선언하여도 상위클래스에서 생성이 안되는것은 아니고, 생성은되나 하위클래스에서 접근만 되지 않는것)
◆ 부모를 부르는 예약어 super()
super 예약어는 하위 클래스에서 상위 클래스로 접근할 때 사용된다.
(this는 자기 자신의 참조 값을 가지고 있는것 과 같이 super는 상위클래스의 생성자를 호출하는데 사용한다.)
1) 상위 클래스 생성자 호출하기
하위클래스의 디폴트 생상자는 바이트 코드로 변환되기 전에 다음과 같이 코드가 자동으로 변경된다.
public VIPCustomer(){
super(); // 컴파일러가 자동으로 추가하는 코드, 상위클래스의 Customer()가 호출됨
cutomerGrade = "VIP";
bonusRatio = 0.05;
saleRatio = 0.1;
System.out.println("VIPCustomer() 생성자 호출");
}
만일, 디폴트 생성자가 존재 하지않고(CustomerID를 반드시 지정해야 하는경우)는 하위클래스의 생성자에 매개변수로 상위 클래스 멤버변수를 받고 super에 매개변수를 추가하여 상위클래스의 생성자(디폴트가 아닌)를 호출한다.
public VIPCustomer(int customerID, String customerName, int agentID){
super(customerID, customerName); // 상위 클래스 생성자 호출
cutomerGrade = "VIP";
bonusRatio = 0.05;
saleRatio = 0.1;
this.agentID = agentID;
System.out.println("VIPCustomer() 생성자 호출");
}
2) 상위의 멤버 변수나 메서드를 참조하는 super
상위 클래스에서 선언한 멤버 변수나 메서드를 하위 클래스에서 참조할 떄도 super를 사용한다.
다음 문장을 살펴 보자.
public String ShowVIPInfo() {
return super.showCustomerInfo() + "담당 상담원 아이디는" + agentID + "입니다.";
}
showCustomerinfo() 메서드는 상위 클래스(Customer)에서 작성된 메서드이며 이를 사용하기 위해서 예제와 같이 super 예약어를 사용하면 편리하다.
만일 상위 메서드에 추가하고 싶으면 추후 배우는 오버라이딩 기법을 사용하면 된다.
◆ 상위 클래스로 묵시적 클래스 형 변환
상속을 공부하면서 매우 중요한 관계가 클래스 간의 형 변환이다.
위의 예시에서 Customer(상위클래스), VIPCustoemr(하위클래스)를 비교하여 보면 상위클래스가 하위클래스보다 일반적인 개념이고 기능적으로는 하위클래스가 훨씬 많다. (상위클래스에 계속 기능을 추가하므로)
여기서 VIPCustomer는 Customer형이면서 VIPCustomer형이기도 하다. 그리고, VIPCustoemr클래스로 인스턴스를 생성할 떄 이 인스턴스의 자료형을 Customer형으로 클래스 형 변환하여 선언할 수 있다.
Custoemr vc = new VIPCustomer();
하지만, 그역은 성립하지 않는다.. 즉 Customer는 VIPCustomer형으로 형 변환은 불가능하다.
이러한 형변환은 오버라이딩과 "다형성"에서 자세히 다뤄진다.
● 메서드 오버라이딩
public int calcPrice(int price) {
bonusPoint += price * bonusRatio;
return price;
}
여기서, VIP고객에게도 보너스와 추가로 할인율까지 적용하여서 VIPCustomer에서 메소드를 만들어야 하지만 이경우 보너스를 적용하는 내용은 공통된 부분이다.
이 경우 상위클래스의 calPrice() 메서드를 오버라이딩 하여 재정이 할 수 있다.
@Override
public int calcPrice(int price) {
bonusPoint += price * bonusRatio;
return price - (int)(price * saleRatio);
return price;
}
에노테이션(Annotation) ??
에노테이션은 영어로 주석을 의미한다. 자바에서 제공하는 애노테이션은 컴파일러에게 특정한 정보를 제공해주는 역할을 한다. (만약 메서드의 선언부가 다르다면 컴파일 오류를 발생시켜 프로그래머의 실수를 막아준다.
주로사용하는 애너테이션은 다음과 같다.
@Override : 재정의된 메서드
@FunctionalInterface : 함수형 인터페이스
@Deprecated : 이후 버전에 사용되지 않을 수 있는 변수, 메서드에 사용됨
@SuperessWarnings : 특정 경고가 나타나지 않도록 함
Q. 다음과 같은 코드에서는 어떤 클래스의 메서드가 실행될까??
Customer vc = new VIPCustomer("10030", "나몰라", 2000);
vc.calcPrice(10000);
이는, 묵시적 형변환에 의해 VIPCustoemr가 Customer형으로 변환된 형태이다.
보통, 멤버변수와 메서드는 선언한 클래스형에 따라 호출된다.
그러나, 상속에서 상위 클래스와 하위 클래스에 같은 이름의 메서드가 존재할 경우(= 재 정의된 경우) 호출되는 메서드는 인스턴스에 따라 결정된다.

기존에 알던 개념이랑 혼동되 보이나 다음의 가상 메서드를 보면 이해가 쉽다.
◆ 가상 메서드
우리는 클래스의 존재하는 멤버변수와 메서드중 멤버변수는 힙메모리에 저장되는 것을 안다.
그럼 메서드는??
메서드는 어떤 인스턴스에도 똑같은 명령을 수행한다. 즉, 메모리를 여기저기 할당할 필요가 없으므로 메서드 영역(코드 영역) 에 따로 명력집합이 저장된다. 이말은 인스턴스가 달라도 다 동일한 메서드를 호출하게 된다.
일반적으로 프로그램에서 메서드를 호출한다는 것은 그 메서드의 명령 집합이 있는 메모리의 위치를 참조하여 명령을 실행한다.
그런데, 가상 메서드는 '가상메서드 테이블'이 따로 만들어져 각 메서드의 이름과 실제 메모리 주소가 짝을 이루고 있습니다.
정리하면,
1. 재정의 되지 않는 다른 클래스의 동일한 명 메소드는 같은 메서드 주소 값을 가지고 있다.
2. 하지만, 메서드가 하위클래스에서 재정의 되었다면 다른 메서드 주소값을 가지게된다.
3. 여기서, 1의 경우 가상 메서드는 같은 주소의 메서드와 짝을 이루고 2의 경우 다른 주소의 메서드와 짝을 이룩고 있다.
자바의 모든 메서드는 가상 메서드이다.
● 다형성
package polymorphism;
class Animal {
public void move() {
System.out.println("동물이 움직입니다.");
}
}
class Human extends Animal {
public void move() {
System.out.println("사람이 두 발로 걷습니다");
}
}
class Tiger extends Animal {
public void move() {
System.out.println("호랑이가 네 발로 걷습니다");
}
}
class Eagle extends Animal {
public void move() {
System.out.println("독수리가 납니다");
}
}
public class AnimalTest1 {
public static void main(String[] args) {
Human human1 = new Human();
human1.move();
Tiger tiger1 = new Tiger();
tiger1.move();
System.out.println();
AnimalTest1 aTest = new AnimalTest1();
aTest.moveAnimal(new Human());
aTest.moveAnimal(new Tiger());
aTest.moveAnimal(new Eagle());
}
public void moveAnimal(Animal animal) {
animal.move();
}
}
사람이 두 발로 걷습니다
호랑이가 네 발로 걷습니다
사람이 두 발로 걷습니다
호랑이가 네 발로 걷습니다
독수리가 납니다
● 다운 캐스팅과 instance of
앞에서는 상위클래스로 형 변환이 묵시적으로 이루어지는 과정을 알아 보았다.
이제는 다시 하위클래스로 형 변환이 되는 과정을 살펴보자.
앞에서 처럼 Animal ani = new Human();으로 묵시적인 형변환이 이루어 졌을 때, ani라는 인스턴스는 Animal클래스에서 선언한 멤버 변수와 메서드만 사용할 수 있다.
만일, Human클래스의 메서드와 멤버변수를 사용하기 위해서는 원래 자료형으로의 다운캐스팅이 필요로하다.
instanceof 예약어
우리는 다운캐스팅을 위해 instaceof예약어가 필요로하다.
"다운 캐스팅은 원래의 인스턴스 자료형으로 돌아가는 것이므로 객체의 인스턴스를 확인하는 예약어이다."
다음과 같은 코드로 다운캐스팅 수행이 가능하다.
Animal hAnimal = new Human( );
if(hAnimal instanceof Human) {
Human human = (Human)hAnimal;
}
'Java 입문' 카테고리의 다른 글
JAVA Basic - 인터페이스 (0) | 2022.12.08 |
---|---|
JAVA Basic - 추상 클래스 (0) | 2022.12.08 |
JAVA Basic - 배열 (0) | 2022.11.28 |
JAVA Basic - CLASS와 객체 2 (0) | 2022.11.26 |
JAVA Basic - CLASS와 객체 1 (0) | 2022.11.25 |