Dev.Std
상속 (Inheritance) 본문
상속(Inheritance)이란?
상속(Inheritance)은 코드 재사용성을 높이고 클래스 간의 계층 구조를 구성하는 데 사용되는 객체 지향 프로그래밍에서 중요한 개념 중 하나다. 상속을 통해 기존 클래스의 기능을 확장하거나 수정하지 않고 새로운 클래스를 생성할 수 있다. 부모 클래스에서 자식 클래스에서 상속이 되면, 자식 클래스는 부모 클래스의 모든 멤버를 상속받는다.
public class Student {
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
public class UniversityStudent extends Student {
private String major;
public UniversityStudent(String name, int age, String major) {
super(name, age);
this.major = major;
}
public String getMajor() {
return major;
}
public void setMajor(String major) {
this.major = major;
}
}
public class Inheritance {
public static void main(String[] args) {
UniversityStudent uniStudent = new UniversityStudent("John", 20, "Computer Engineering");
System.out.println("Name: " + uniStudent.getName());
System.out.println("Age: " + uniStudent.getAge());
System.out.println("Major: " + uniStudent.getMajor());
}
}
Name: John
Age: 20
Major: Computer Engineering
위의 코드를 살펴보면 UniversityStudent 클래스가 extends 키워드를 사용하여 Student 클래스를 상속받고 있는 것을 볼 수 있다. 이처럼 extends 키워드를 사용하면 extends 앞에 나온 클래스가 뒤에 나온 클래스를 상속받겠다는 의미가 된다.
또 자식 클래스의 생성자에서는 반드시 부모 클래스의 생성자를 호출해야 하는데 이때 super 키워드를 사용하여 부모 클래스의 생성자를 호출할 수 있다. 부모 클래스의 생성자 호출은 자식 클래스 생성자의 가장 첫 줄에 위치해야 한다.
상속을 사용하는 이유
- 코드 재사용성
상속을 통해 부모 클래스의 속성과 메서드를 자식 클래스에서 재사용 가능하다. 이는 중복된 코드를 줄이고 개발 시간을 단축할 수 있다.
- 계층 구조 형성
상속을 사용하여 부모 클래스와 이를 상속받는 자식 클래스들 사이에 계층 구조를 형성하여 코드의 구조를 명확하게 만들어 준다. 이는 코드의 유지 보수에도 도움을 준다.
- 다형성 제공
부모 클래스 타입의 변수에 여러 종류의 자식 클래스를 할당하여 다양한 동작을 수행할 수 있다. 이는 코드의 유연성을 높여주고, 코드를 추상화하여 일반화할 수 있게 해 준다.
- 확장성
새로운 기능을 추가하거나 기존 기능을 변경 시, 기존 클래스를 확장하여 새로운 클래스를 만들 수 있다. 기존 코드를 변경하지 않고 새로운 기능을 추가할 수 있도록 한다.
- 추상화를 통한 모델링
추상 클래스를 이용하여 부모 클래스를 정의할 수 있다. 하위 클래스들의 공통적인 특성을 정의하고, 다형성을 제공하며, 안정성과 일관성을 유지하고, 확장성을 제공하는 등 다양한 장점이 존재한다.
IS-A 관계 & Has-A 관계
Is-A관계와 Has-A 관계는 객체 지향 프로그램에서 사용되는 중요한 개념 중 하나로, 객체들 간의 상속 관계를 설명하는 데 사용된다.
IS-A 관계
직원은 사람이다.
사각형은 도형이다.
새는 동물이다.
IS-A 관계는 한 클래스가 다른 클래스의 자식 클래스일 때 발생한다. "직원은 사람이다"라는 문장을 예로 들어보면 직원은 사람의 한 종류로 직원 클래스를 사람 클래스의 하위 클래스로 볼 수 있고, "직원 is a 사람"이 성립하기 때문에 IS-A 관계로 볼 수 있다.
Has-A 관계
컴퓨터는 키보드를 가지고 있다.
자동차는 엔진을 가지고 있다.
사람은 머리카락을 가지고 있다.
IS-A 관계에서는 클래스 간의 상속 관계를 설명했다면, Has-A 관계에서는 클래스 간의 포함 관계를 설명할 수 있다. "자동차는 엔진을 가지고 있다"라는 문장에서 "자동차 is a 엔진"은 성립하지 않지만 "자동차 has a 엔진"은 성립한다. 자동차가 엔진이진 않지만 자동차가 엔진을 포함하는 관계는 맞기 때문에 Has-A 관계이다.
메서드 오버라이딩(Method Overriding)
메서드 오버라이딩(Method Overriding)이란 메서드를 오버라이딩, 즉 덮어쓴다는 이야기다. 자식 클래스는 부모 클래스의 메서드를 재정의 할 수 있다. 이를 통해 자식 클래스는 부모 클래스의 동일한 이름 메서드를 자신의 필요에 맞게 구현할 수 있다.
public class Student {
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
// 동일한 코드
public void displayInfo() {
System.out.println("Name: " + name);
System.out.println("Age: " + age);
}
}
public class UniversityStudent extends Student {
private String major;
public UniversityStudent(String name, int age, String major) {
super(name, age);
this.major = major;
}
// 동일한 코드
@Override
public void displayInfo() {
super.displayInfo();
System.out.println("Major: " + major);
}
}
public class Inheritance {
public static void main(String[] args) {
UniversityStudent uniStudent = new UniversityStudent("John", 20, "Computer Engineering");
System.out.println("University Student Information:");
uniStudent.displayInfo();
}
}
University Student Information:
Name: John
Age: 20
Major: Computer Engineering
위 코드에서 Student 클래스의 displayInfo 메서드를 UniversityStudent 클래스의 displayInfo 메서드가 오버라이드 하고 있다.
다형성(Polymorphism)
다형성(Polymorphism)이란 하나의 객체가 여러 가지 타입을 가질 수 있는 것을 의미한다. 자바에서 부모 클래스 타입의 변수에 자식 클래스 객체를 할당할 수 있다. 이를 통해 다양한 형태의 객체를 하나의 변수로 다룰 수 있다.
public class GraduateStudent extends Student{
private String researchArea;
public GraduateStudent(String name, int age, String researchArea) {
super(name, age);
this.researchArea = researchArea;
}
@Override
public void displayInfo() {
super.displayInfo();
System.out.println("Research Area: " + researchArea);
}
}
public class Inheritance {
public static void main(String[] args) {
// Student 클래스 타입 변수에 자식 클래스 객체 할당
Student student1 = new UniversityStudent("John", 20,"Computer Engineering");
Student student2 = new GraduateStudent("Alice", 26, "Machine Learning");
displayStudentInfo(student1);
displayStudentInfo(student2);
}
public static void displayStudentInfo(Student student) {
student.displayInfo();
System.out.println();
}
}
Name: John
Age: 20
Major: Computer Engineering
Name: Alice
Age: 26
Research Area: Machine Learning
기존의 코드에 GraduateStudent 클래스를 추가하고 main 함수를 수정했다. 메인 함수를 포함하고 있는 Inheritance 클래스에 displaySudentInfo 메서드를 만들고 Student 객체를 매개 변수로 받아 각 인스턴스가 속한 클래스의 displayInfo를 호출하도록 하고 있다.
만약 다형성을 이용하지 않고 자식 클래스의 객체를 따로 선언해서 사용한다면 아래의 코드처럼 새로운 자식 클래스를 추가할 때마다 해당 자식 클래스에 대한 새로운 오버로딩된 메서드를 추가해주어야 하는 번거로움이 생길 것이다.
public class Inheritance {
public static void main(String[] args) {
UniversityStudent student1 = new UniversityStudent("John", 20,"Computer Engineering");
GraduateStudent student2 = new GraduateStudent("Alice", 26, "Machine Learning");
displayStudentInfo(student1);
displayStudentInfo(student2);
}
public static void displayStudentInfo(Student student) {
student.displayInfo();
System.out.println();
}
public static void displayStudentInfo(UniversityStudent universityStudent) {
universityStudent.displayInfo();
System.out.println();
}
public static void displayStudentInfo(GraduateStudent graduateStudent) {
graduateStudent.displayInfo();
System.out.println();
}
// 새로운 자식 클래스 생성될 때마다 메서드 추가...
}
instanceof 연산자
instanceof 연산자를 사용하면 참조 변수가 실제로 가리키고 있는 인스턴스의 타입을 확인할 수 있다.
public class Inheritance {
public static void main(String[] args) {
// Student 클래스 타입 변수에 자식 클래스 객체 할당
Student student1 = new UniversityStudent("John", 20,"Computer Engineering");
Student student2 = new GraduateStudent("Alice", 26, "Machine Learning");
System.out.println(student1 instanceof Object);
System.out.println(student1 instanceof Student);
System.out.println(student1 instanceof UniversityStudent);
System.out.println(student1 instanceof GraduateStudent);
System.out.println();
System.out.println(student2 instanceof Object);
System.out.println(student2 instanceof Student);
System.out.println(student2 instanceof UniversityStudent);
System.out.println(student2 instanceof GraduateStudent);
}
}
true
true
true
false
true
true
false
true
왼쪽의 참조 변수가 실제로 참조하고 있는 인스턴스 타입이 오른쪽에 전달된 클래스 타입이면 true를 반환, 아니면 false를 반환한다.
Object 클래스
자바에서 모든 클래스의 최상위 클래스는 Object 클래스가 된다. 즉 모든 클래스가 Object를 상속받고 있다. 따라서 자바에서 만드는 모든 객체는 Object 자료형으로 사용가능하다.
Object student = new Student(); Object UniversityStudent = new UniversityStudent();
'📂Language > Java' 카테고리의 다른 글
접근 제어자 (Access Modifier) (0) | 2024.04.07 |
---|---|
값에 의한 호출 & 객체(참조)에 의한 호출 (Call by value & Call by object(reference)) (0) | 2024.04.07 |
생성자 (Constructor) (0) | 2024.04.05 |
클래스 (Class) (0) | 2024.04.03 |