KDT/Java

231228 Java

001cloudid 2023. 12. 28. 17:40
728x90

상속(inheritance)

상속이란 B 클래스가 A 클래스를 상속받으면 B클래스는 A 클래스의 멤버 변수와 메소드를 사용할 수 있다.

 

A클래스(상위 클래스)
  ↑
B 클래스(하위클래스)
: A 클래스가 B 클래스에게 상속한다. = B 클래스가 A 클래스를 상속받는다.

A클래스는 상위 클래스, 부모 클래스, super class, base class라고 표현하며,

B 클래스는 하위 클래스, 자식 클래스, subclass, derrived class라고 표현한다.

 

클래스 상속 문법

class B extends A {
}

A가 가지고 있는 속성이나 기능을 추가로 확장하여 B 클래스를 구현한다는 뜻이다.

일반적인 클래스 A에서 더 구체적인 클래스 B가 구현된다.

예를 들어 동물(상위 클래스), 사람(하위 클래스)라고 할 수 있다.

class Animal{
 ~~~
}
class Human extends Animal{
 ~~~
}

 

동물은 사람보다 일반적인 개념이다. 즉 사람은 동물의 특징과 기능을 기본으로 더 많거나 다른 특징과 기능을 가지고 있다.

상속 관계에서 상위 클래스가 하위 클래스보다 일반적인 개념이고,

하위 클래스는 상위 클래스보다 구체적인 클래스가 된다.

 

ex)

package inheritance;

 

public class Customer {

protected int ID;

protected String name;

protected String grade;

int bonusPoint; //보너스 포인트

double bounsRatio; //적립 비율

 

//protected 예약어로 선언한 변수를 외부에서 사용할 수 있도록 메소드 추가

public int getID() {

return ID;

}

 

public void setID(int iD) {

ID = iD;

}

 

public String getName() {

return name;

}

 

public void setName(String name) {

this.name = name;

}

 

public String getGrade() {

return grade;

}

 

public void setGrade(String grade) {

this.grade = grade;

}

 

//기본 생성자

public Customer() {

grade = "Silver"; //기본등급

bounsRatio = 0.01; //기본 적립비율

}

 

//보너스 포인트 적립, 지불 가격 계산 메소드

public int calcPrice(int price) {

bonusPoint += price * bounsRatio; //보너스 포인트 계산

return price;

}

 

//고객 정보를 반환하는 메소드

public String showCustomerInfo() {

return name + "님 등급은 " + grade + "이고, 보너스 포인트는 " + bonusPoint + "입니다.";

}

 

 

}

 

package inheritance;

 

public class VIPCustomer extends Customer {

private int agentID; //전문 상담원

double saleRatio; //할인율

 

public VIPCustomer() {

saleRatio = 0.1;

bounsRatio = 0.05;

grade = "VIP";

}

 

public int getAgentID() {

return agentID;

}

 

 

 

}

 

package inheritance;

 

public class CustomerTest1 {

 

public static void main(String[] args) {

Customer c1 = new Customer();

c1.setID(1);

c1.setName("고갱");

c1.bonusPoint = 100;

System.out.println(c1.showCustomerInfo());

 

VIPCustomer v1 = new VIPCustomer();

v1.setID(1000);

v1.setName("호갱");

v1.getAgentID();

v1.bonusPoint = 1000;

System.out.println(v1.showCustomerInfo());

 

}

 

}

고갱님 등급은 Silver이고, 보너스 포인트는 100입니다.

호갱님 등급은 VIP이고, 보너스 포인트는 1000입니다.

 

 

하위 클래스가 생성될 때는 상위 클래스의 생성자가 먼저 호출된다.

상속 관계에서 클래스의 생성 과정을 살펴보면 하위 클래스가 상위 클래스의 변수와 메소드를 이용할 수 있는 이유와

하위 클래스가 상위 클래스의 자료형으로 형 변환 할 수 있는 이유를 이해할 수 있다.

package inheritance;

 

public class Customer {

protected int ID;

protected String name;

protected String grade;

int bonusPoint; //보너스 포인트

double bounsRatio; //적립 비율

 

//protected 예약어로 선언한 변수를 외부에서 사용할 수 있도록 메소드 추가

public int getID() {

return ID;

}

 

public void setID(int iD) {

ID = iD;

}

 

public String getName() {

return name;

}

 

public void setName(String name) {

this.name = name;

}

 

public String getGrade() {

return grade;

}

 

public void setGrade(String grade) {

this.grade = grade;

}

 

//기본 생성자

public Customer() {

grade = "Silver"; //기본등급

bounsRatio = 0.01; //기본 적립비율

System.out.println("Customer()생성자 호출");

}

 

//보너스 포인트 적립, 지불 가격 계산 메소드

public int calcPrice(int price) {

bonusPoint += price * bounsRatio; //보너스 포인트 계산

return price;

}

 

//고객 정보를 반환하는 메소드

public String showCustomerInfo() {

return name + "님 등급은 " + grade + "이고, 보너스 포인트는 " + bonusPoint + "입니다.";

}

 

 

}

 

package inheritance;

 

public class VIPCustomer extends Customer {

private int agentID; //전문 상담원

double saleRatio; //할인율

 

public VIPCustomer() {

saleRatio = 0.1;

bounsRatio = 0.05;

grade = "VIP";

System.out.println("VIPCustomer()생성자 호출");

}

 

public int getAgentID() {

return agentID;

}

 

 

 

}

 

package inheritance;

 

public class CustomerTest1 {

 

public static void main(String[] args) {

Customer c1 = new Customer();

c1.setID(1);

c1.setName("고갱");

c1.bonusPoint = 100;

System.out.println(c1.showCustomerInfo());

 

VIPCustomer v1 = new VIPCustomer();

v1.setID(1000);

v1.setName("호갱");

v1.getAgentID();

v1.bonusPoint = 1000;

System.out.println(v1.showCustomerInfo());

 

}

 

}

 

Customer()생성자 호출

고갱님 등급은 Silver이고, 보너스 포인트는 100입니다.

Customer()생성자 호출

VIPCustomer()생성자 호출

호갱님 등급은 VIP이고, 보너스 포인트는 1000입니다.

 

상위 클래스를 상속 받은 하위 클래스가 생성될 때는 반드시 상위 클래스의 생성자가 먼저 호출된다.

그리고 상위 클래스 생성자가 호출될 때 상위 클래스의 멤버 변수가 메모리에 생성되는 것이다.

 

super 부모를 부르는 예약어

super 예약어는 하위 클래스에서 상위 클래스로 접근할 때 사용한다.

하위 클래스는 상위 클래스의 주소(참조값)을 알고 있다.

이 참조값을 가지고 있는 예약어가 super이다.

this가 자기 자신의 참조 값을 가지고 있는 것과 같다고 생각하면 된다.

또한 super는 상위 클래스의 생성자를 호출하는데 사용한다.

super는 상위 클래스 생성자 호출, 매개변수가 있는 생성자 호출, 상위 클래스의 멤버 변수나 메소드를 참조할 수 있다.

 

상위 클래스 생성자 호출

package inheritance;

 

public class VIPCustomer extends Customer {

private int agentID; //전문 상담원

double saleRatio; //할인율

 

public VIPCustomer() {

super(); //컴파일러가 자동으로 추가하는 코드. 상위 클래스의 Customer()가 호출된다.

saleRatio = 0.1;

bounsRatio = 0.05;

grade = "VIP";

System.out.println("VIPCustomer()생성자 호출");

}

 

public int getAgentID() {

return agentID;

}

 

 

 

}

 

하위 클래스 생성자만 호출했는데 상위 클래스 생성자가 호출되는 이유는 하위 클래스 생성자에서 super()를 자동으로 호출하기 때문이다. super()를 호출하면 상위 클래스의 디폴트 생성자가 호출된다.

 

super 예약어로 매개변수가 있는 생성자 호출

Customer 클래스를 생성할 때 고객 ID와 이름을 반드시 지정해야한다면 새로운 생성자를 만들어서 매개변수로 값을 전달 받아야한다. 즉 디폴트 생성자가 아닌 매개변수가 있는 생성자를 직접 구현해야한다.

package inheritance;

 

public class Customer {

protected int ID;

protected String name;

protected String grade;

int bonusPoint; //보너스 포인트

double bounsRatio; //적립 비율

 

//protected 예약어로 선언한 변수를 외부에서 사용할 수 있도록 메소드 추가

public int getID() {

return ID;

}

 

public void setID(int iD) {

ID = iD;

}

 

public String getName() {

return name;

}

 

public void setName(String name) {

this.name = name;

}

 

public String getGrade() {

return grade;

}

 

public void setGrade(String grade) {

this.grade = grade;

}

 

// //기본 생성자

// public Customer() {

// grade = "Silver"; //기본등급

// bounsRatio = 0.01; //기본 적립비율

// System.out.println("Customer()생성자 호출");

// }

 

public Customer(int ID, String name) {

this.ID = ID;

this.name = name;

grade = "Silver";

bounsRatio = 0.01;

System.out.println("Customer(int ID, String name) 생성자 호출");

}

 

//보너스 포인트 적립, 지불 가격 계산 메소드

public int calcPrice(int price) {

bonusPoint += price * bounsRatio; //보너스 포인트 계산

return price;

}

 

//고객 정보를 반환하는 메소드

public String showCustomerInfo() {

return name + "님 등급은 " + grade + "이고, 보너스 포인트는 " + bonusPoint + "입니다.";

}

 

 

}

디폴트 생성자를 주석처리하고 새로운 생성자를 작성하면 Customer 클래스를 상속받는 VIPCustomer 클래스에서 오류가 발생한다. 묵시적으로 호출될 디폴트 생성자 Customer()가 정의되지 않았기 때문에, 반드시 명시적으로 다른 생성자를 호출해야 한다는 뜻이다

Customer클래스를 새로 생성할 때 고객 ID와 고객 이름을 반드시 지정하여 생성하기로 했다면 VIPCustomer 클래스를 생성할 때도 이 값이 필요하다. 기존 VIPCustomer 클래스의 디폴트 생성자를 주석 처리한 후 필요한 매개변수를 포함하는 생성자를 작성

package inheritance;

 

public class VIPCustomer extends Customer {

private int agentID; //전문 상담원

double saleRatio; //할인율

 

// public VIPCustomer() {

// super(); //컴파일러가 자동으로 추가하는 코드. 상위 클래스의 Customer()가 호출된다.

// saleRatio = 0.1;

// bounsRatio = 0.05;

// grade = "VIP";

// System.out.println("VIPCustomer()생성자 호출");

// }

 

public VIPCustomer(int ID, String name, int agentID) {

super(ID, name);

saleRatio = 0.1;

bounsRatio = 0.05;

grade = "VIP";

this.agentID = agentID;

System.out.println("VIPCustomer(int ID, String name, int agentID) 생성자 호출");

}

 

public int getAgentID() {

return agentID;

}

 

 

 

}

 

super(ID, name);

== 

public Customer(int ID, String name) {

this.ID = ID;

this.name = name;

grade = "Silver";

bounsRatio = 0.01;

System.out.println("Customer(int ID, String name) 생성자 호출");

}

 

super()를 통해 Customer(int ID, String name) 상위클래스 생성자를 호출하고 코드 순서대로 멤버 변수가 초기화된다.

상위 클래스 생성자 호출이 끝나면 VIPCustomer 하위 클래스 생성자의 내부 코드 수행이 마무리된다.

package inheritance;

 

public class CustomerTest1 {

 

public static void main(String[] args) {

Customer c1 = new Customer(1, "고갱");

c1.bonusPoint = 100;

System.out.println(c1.showCustomerInfo());

 

VIPCustomer v1 = new VIPCustomer(100,"호갱",1000);

v1.bonusPoint = 1000;

System.out.println(v1.showCustomerInfo());

 

}

 

}

Customer(int ID, String name) 생성자 호출

고갱님 등급은 Silver이고, 보너스 포인트는 100입니다.

Customer(int ID, String name) 생성자 호출

VIPCustomer(int ID, String name, int agentID) 생성자 호출

호갱님 등급은 VIP이고, 보너스 포인트는 1000입니다.

 

상위 클래스의 멤버 변수나 메소드를 참조하는 super

상위 클래스에 선언한 멤버 변수나 메소드를 하위 클래스에서 참조할 때도 super를 사용한다.

this를 사용하면 자신의 멤버에 접근했던 것과 비슷하다.

package inheritance;

 

public class VIPCustomer extends Customer {

private int agentID; //전문 상담원

double saleRatio; //할인율

 

// public VIPCustomer() {

// super(); //컴파일러가 자동으로 추가하는 코드. 상위 클래스의 Customer()가 호출된다.

// saleRatio = 0.1;

// bounsRatio = 0.05;

// grade = "VIP";

// System.out.println("VIPCustomer()생성자 호출");

// }

 

public VIPCustomer(int ID, String name, int agentID) {

super(ID, name);

saleRatio = 0.1;

bounsRatio = 0.05;

grade = "VIP";

this.agentID = agentID;

System.out.println("VIPCustomer(int ID, String name, int agentID) 생성자 호출");

}

 

public int getAgentID() {

return agentID;

}

 

public String showVIPInfo() {

return super.showCustomerInfo() + "담당 상담원 아이디 " + agentID + "입니다.";

}

 

 

}

 

package inheritance;

 

public class CustomerTest1 {

 

public static void main(String[] args) {

Customer c1 = new Customer(1, "고갱");

c1.bonusPoint = 100;

System.out.println(c1.showCustomerInfo());

 

VIPCustomer v1 = new VIPCustomer(100,"호갱",1000);

v1.bonusPoint = 1000;

System.out.println(v1.showVIPInfo());

 

}

 

}

Customer(int ID, String name) 생성자 호출

고갱님 등급은 Silver이고, 보너스 포인트는 100입니다.

Customer(int ID, String name) 생성자 호출

VIPCustomer(int ID, String name, int agentID) 생성자 호출

호갱님 등급은 VIP이고, 보너스 포인트는 1000입니다.담당 상담원 아이디 1000입니다.

 

public String showVIPInfo() {

return super.showCustomerInfo() + "담당 상담원 아이디 " + agentID + "입니다.";

}

super 예약어는 상위 클래스의 참조 값을 가지고 있으므로 위와 같이 사용하면 고객 정보를 출력하는 showCustomerInfo() 메소드를 새로 구현하지 않고 상위 클래스의 구현 내용을 활용할 수 있다.

 

상위 클래스로 묵시적 클래스 형 변환

상위 클래스 A, 하위 클래스 B.(위의 예시에서 Customer, VIPCustomer)

A가 B보다 일반적인 개념이고, B가 A보다 더 기능이 많다.

이유는 상속받는 클래스는 상위 클래스 기능을 모두 사용할 수 있고 추가로 더 많은 기능을 구현하기 때문이다.

따라서 B는 B형이면서 동시에 A형이다.

즉, B 클래스로 인스턴스를 생성할 때 이 인스턴스 자료형으로 클래스형 변환하여 선언할 수 있다.

Customer vc = new VIPCustomer();

Customer : 선언된 클래스형(상위 클래스)
VIPCustomer(); : 생성된 인스턴스의 클래스형(하위클래스)

※이러한 클래스형 변환을 업캐스팅(upcasting)이라고 한다.

 

하지만 상위 클래스가 하위 클래스의 다 가지고 있지 않기 때문에 반대는 불가능하다.

즉 모든 하위 클래스는 상위 클래스 자료형으로 형 변환이 가능하지만 그 역은 불가능하다.

 

Customer vc = new VIPCustomer();

클래스가 형 변환이 되었을 때는 선언한 클래스형에 기반하여 멤버 변수와 메소드에 접근할 수 있다.

vc 참조변수가 가리킬 수 있는 변수와 메소드는 Customer클래스의 멤버뿐이다.

 

※클래스의 상속 계층 구조가 여러 단계일 경우에도 묵시적으로 형변환이 된다.

         동물(Animal)
    ↑                        ↑
개(Dog)           영장류(Primate)
                             ↑                      
                        사람(Human)
Primate h1 = new Human();
Animal h2 = new Human();

 

메소드 오버라이딩

위의 예시에서 VIP 고객은 정가에서 10%를 할인 받을 수 있는데 calcPrice()메소드로는 구현하기 힘들다.

상위 클래스에 정의한 메소드가 하위 클래스에서 구현할 내용과 맞지 않을 때 하위 클래스에서 메소드를 재정의할 수 있다.

상위 클래스 메소드를 재정의하는 것을 메소드 오버라이딩(method overriding)이라고 한다.

오버라이딩을 하려면 반환형, 메소드 이름, 매개 변수 개수, 매개변수 자료형이 반드시 같아야한다.

그렇지 않으면 자바 컴파일러는 재정의한 메소드를 기존 메소드와 다른 메소드로 인식한다.

 

VIP 고객 클래스의 제품 가격 계산 메소드 재정의

package inheritance;

 

public class VIPCustomer extends Customer {

private int agentID; // 전문 상담원

double saleRatio; // 할인율

 

// public VIPCustomer() {

// super(); //컴파일러가 자동으로 추가하는 코드. 상위 클래스의 Customer()가 호출된다.

// saleRatio = 0.1;

// bounsRatio = 0.05;

// grade = "VIP";

// System.out.println("VIPCustomer()생성자 호출");

// }

 

@Override

public int calcPrice(int price) {

bonusPoint += price * bounsRatio; // 보너스 포인트 계산

return price - (int)(price*saleRatio);

}

 

public VIPCustomer(int ID, String name, int agentID) {

super(ID, name);

saleRatio = 0.1;

bounsRatio = 0.05;

grade = "VIP";

this.agentID = agentID;

System.out.println("VIPCustomer(int ID, String name, int agentID) 생성자 호출");

}

 

 

public int getAgentID() {

return agentID;

}

 

public String showVIPInfo() {

return super.showCustomerInfo() + "담당 상담원 아이디 " + agentID + "입니다.";

 

}

}

 

※애노테이션(Annotation)

영어로는 주석이라는 의미. @ 기호화 함께 사용하며 '@애노테이션 이름'으로 표현한다.

자바에서 제공하는 애노테이션은 컴파일러에게 특정한 정보를 제공해 주는 역할을 한다.

미리 정의되어 있는 애노테이션을 표준 애노테이션이라고 한다.

@Override : 재정의된 메소드라는 정보 제공

@FuctionalInterface : 함수형 인터페이스라는 정보 제공

@Deprecated : 이후 버전에서 사용되지 않을 수 있는 변수, 메소드에 사용

@SuppressWarnings : 특정 경고가 나타나지 않도록 함

 

 

 

 

 

 

 

 

 

 

 

 

 

 

728x90

'KDT > Java' 카테고리의 다른 글

240104 Java  (0) 2024.01.04
240103 Java  (0) 2024.01.03
231227 Java  (0) 2023.12.27
231221 Java  (0) 2023.12.21
231220 Java  (0) 2023.12.20