자바에서의 상속은 객체 지향 프로그래밍의 핵심 개념 중 하나로, 코드의 재사용과 확장성을 증가시키는데 중요한 역할을 합니다. 이 글에서는 상속의 정의, 중요성, 부모 클래스와 자식 클래스에 대해 알아보고, 예시 코드를 통해 실제 활용법을 알아보겠습니다.
상속의 개념
자바 프로그래밍에서 상속은 객체 지향 프로그래밍(OOP)의 핵심 개념 중 하나로, 코드 재사용성을 높이고 프로그램 구조를 더 간결하게 만들어주는 도구입니다. 상속은 클래스 간의 관계를 정의하고, 부모 클래스로부터 속성과 메서드를 물려받는 프로세스입니다. 이를 통해 새로운 클래스를 만들 때 기존 클래스의 기능을 확장하거나 수정할 수 있습니다.
상속의 정의와 중요성
상속의 정의
상속은 하위 클래스(자식 클래스)가 상위 클래스(부모 클래스)의 속성과 메서드를 상속받아 사용할 수 있는 프로그래밍 개념입니다. 부모 클래스에서 정의한 속성과 메서드를 자식 클래스에서 중복 작성하지 않고 활용할 수 있게 해 줍니다. 이것은 코드의 재사용성을 증가시키고 유지 보수를 용이하게 만듭니다.
▶ 상속의 중요성
- 코드 재사용성: 상속을 통해 부모 클래스의 기능을 자식 클래스에서 그대로 활용할 수 있으므로 중복 코드를 줄일 수 있습니다.
- 확장성: 새로운 기능을 추가하려면 기존 클래스를 수정하는 대신 새로운 자식 클래스를 만들어서 확장할 수 있습니다.
- 구조화된 프로그래밍: 객체 지향 프로그래밍에서는 상속을 통해 객체 간의 계층 구조를 만들어 코드를 더 이해하기 쉽게 만듭니다.
부모 클래스와 자식 클래스 개념
부모 클래스(또는 슈퍼 클래스)는 상속의 기반을 형성하는 클래스입니다. 자식 클래스(또는 서브 클래스)는 부모 클래스에서 상속받은 속성과 메서드를 포함하면서 자체적인 기능을 추가하거나 변경할 수 있습니다. 자식 클래스는 부모 클래스의 모든 특성을 상속받지만, 추가로 자신만의 고유한 특성을 가질 수 있습니다.
아래의 예시 코드를 통해 상속의 개념을 이해해보겠습니다. 예시 코드에서는 "동물"을 나타내는 부모 클래스와 "고양이"를 나타내는 자식 클래스를 활용합니다.
// 부모 클래스: 동물
class Animal {
String name;
Animal(String name) {
this.name = name;
}
void speak() {
System.out.println(name + "가 소리를 내다.");
}
}
// 자식 클래스: 고양이
class Cat extends Animal {
Cat(String name) {
super(name);
}
// 부모 클래스의 speak 메서드를 오버라이딩
@Override
void speak() {
System.out.println(name + "가 야옹~ 야옹~ 소리를 내다.");
}
void scratch() {
System.out.println(name + "가 할퀴다.");
}
}
- 위의 코드에서 Cat 클래스는 Animal 클래스를 상속받습니다.
- Cat 클래스는 speak 메서드를 부모 클래스에서 상속받았지만, 자신만의 scratch 메서드를 추가했습니다.
→ 이렇게 상속을 활용하면 Cat 객체는 부모 클래스인 Animal의 모든 속성과 speak 메서드를 사용하면서, 자신만의 메서드인 scratch를 가질 수 있습니다.
자바에서의 상속 구현
자바에서의 상속은 코드의 재사용성을 증가시키고 프로그램의 확장성을 높이는데 중요한 역할을 합니다. extends 키워드를 사용한 상속의 구현 방법과 부모 클래스와 자식 클래스 사이의 관계에 대해 알아보겠습니다.
extends 키워드를 사용한 상속
자바에서는 extends 키워드를 사용하여 부모 클래스의 기능을 자식 클래스에게 상속할 수 있습니다.
// 부모 클래스
class Animal {
String name;
Animal(String name) {
this.name = name;
}
void speak() {
System.out.println(name + "가 소리를 내다.");
}
}
// 자식 클래스
class Dog extends Animal {
Dog(String name) {
super(name);
}
// 부모 클래스의 speak 메서드를 오버라이딩
@Override
void speak() {
System.out.println(name + "가 멍멍! 소리를 내다.");
}
void wagTail() {
System.out.println(name + "가 꼬리를 흔든다.");
}
}
- 위의 코드에서 Dog 클래스는 Animal 클래스를 상속받습니다.
- extends 키워드를 사용하여 Dog 클래스가 Animal 클래스를 확장한다고 선언합니다.
- Dog 클래스는 Animal 클래스의 속성과 speak 메서드를 상속받으면서, 자체적으로 wagTail 메서드를 추가했습니다.
부모 클래스와 자식 클래스의 관계
상속을 통해 부모 클래스와 자식 클래스 간에는 특별한 관계가 형성됩니다. 이 관계는 다음과 같은 특징을 가집니다.
부모 클래스와 자식 클래스의 관계의 특징
1. 자식 클래스는 부모 클래스의 모든 멤버(필드와 메서드)를 상속받습니다.
2. 자식 클래스는 부모 클래스를 확장하거나 변경할 수 있습니다.
3. 자식 클래스는 부모 클래스의 생성자를 호출할 때 super 키워드를 사용합니다.
▷ 상속을 통해 클래스 간에 이러한 관계가 형성되므로, 코드의 재사용성이 높아지고 프로그램이 구조화되어 유지보수가 용이해집니다.
메서드 재사용과 확장
메서드 재사용은 중복 코드를 줄이고 유지보수를 용이하게 하며, 확장은 새로운 기능을 추가하거나 기존 기능을 수정하는 데 사용됩니다.
부모 클래스의 메서드 재사용
자바에서는 부모 클래스의 메서드를 자식 클래스에서 그대로 재사용할 수 있습니다.
// 부모 클래스
class Animal {
String name;
Animal(String name) {
this.name = name;
}
void speak() {
System.out.println(name + "가 소리를 내다.");
}
}
// 자식 클래스
class Dog extends Animal {
Dog(String name) {
super(name);
}
}
- 위의 코드에서 Dog 클래스는 Animal 클래스를 상속받고, super(name)를 사용하여 부모 클래스의 생성자를 호출합니다.
- Dog 클래스는 부모 클래스인 Animal의 speak 메서드를 그대로 상속받아 사용할 수 있습니다.
자식 클래스에서 메서드 추가와 수정
자식 클래스는 부모 클래스에서 상속받은 메서드를 그대로 사용하면서, 필요에 따라 자체적인 메서드를 추가하거나 부모 클래스의 메서드를 수정할 수 있습니다. 아래의 예시 코드를 통해 이를 설명합니다.
// 자식 클래스
class Dog extends Animal {
Dog(String name) {
super(name);
}
// 부모 클래스의 speak 메서드를 오버라이딩
@Override
void speak() {
System.out.println(name + "가 멍멍! 소리를 내다.");
}
void wagTail() {
System.out.println(name + "가 꼬리를 흔든다.");
}
}
- 위의 코드에서 Dog 클래스는 부모 클래스인 Animal의 speak 메서드를 오버라이딩하여 자신만의 구현을 제공합니다.
- 또한, wagTail 메서드를 추가하여 부모 클래스에는 없는 새로운 기능을 제공합니다.
→ 메서드 재사용과 확장을 통해 코드를 더 간결하게 유지하면서 새로운 기능을 추가하거나 수정할 수 있으므로, 객체 지향 프로그래밍에서의 상속은 매우 유용한 개념입니다.
super 키워드
super 키워드의 사용법
super 키워드는 주로 자식 클래스에서 부모 클래스의 멤버(필드 또는 메서드)에 접근하거나 부모 클래스의 생성자를 호출할 때 사용됩니다. 이것은 상속 관계에서 현재 클래스가 아닌 부모 클래스의 멤버에 접근하거나 호출할 수 있게 해주는 중요한 역할을 합니다.
1. 부모 클래스의 메서드 호출
super 키워드를 사용하여 부모 클래스의 메서드를 호출할 수 있습니다.
class Animal {
void speak() {
System.out.println("동물이 소리를 내다.");
}
}
class Dog extends Animal {
void speak() {
super.speak(); // 부모 클래스의 speak 메서드 호출
System.out.println("강아지가 멍멍! 소리를 내다.");
}
}
:: Dog 클래스에서 super.speak()를 호출하면, 부모 클래스인 Animal의 speak 메서드를 실행합니다.
2. 부모 클래스의 생성자 호출
super 키워드를 사용하여 부모 클래스의 생성자를 호출할 수 있습니다. 부모 클래스의 생성자를 호출할 때 super 키워드를 사용하는 경우, 자식 클래스의 생성자에서 반드시 첫 번째 줄에 호출되어야 합니다. 이것은 자식 클래스가 초기화되기 전에 부모 클래스의 초기화가 완료되어야 함을 보장합니다.
class Animal {
String name;
Animal(String name) {
this.name = name;
}
}
class Dog extends Animal {
Dog(String name) {
super(name); // 부모 클래스의 생성자 호출
}
}
:: Dog 클래스의 생성자에서 super(name)를 호출하여 부모 클래스인 Animal의 생성자를 호출합니다.
super 키워드는 상속을 통해 클래스 간의 관계를 더욱 유연하게 만들어주는 중요한 요소 중 하나입니다. 이를 활용하여 부모 클래스의 멤버에 접근하고 생성자를 호출함으로써 코드의 재사용성과 확장성을 향상시킬 수 있습니다.
메서드 오버라이딩 (Method Overriding)
자바 메서드 오버라이딩은 부모 클래스에서 정의한 메서드를 자식 클래스에서 재정의하여 사용하는 기술입니다.
1. 메서드 오버라이딩의 개념
메서드 오버라이딩은 상속 관계에서 부모 클래스의 메서드를 자식 클래스에서 다시 정의(재정의)하는 것을 의미합니다. 이때, 자식 클래스에서 정의한 메서드는 부모 클래스의 동일한 이름, 반환 타입 및 매개변수를 가져야 합니다. 오버라이딩을 통해 자식 클래스는 부모 클래스의 메서드를 자신의 필요에 맞게 수정하거나 확장할 수 있습니다.
2. @Override 어노테이션의 활용
자바에서는 @Override 어노테이션을 사용하여 메서드 오버라이딩을 명시적으로 표시할 수 있습니다. 이 어노테이션은 컴파일러에게 해당 메서드가 오버라이딩된 것임을 알려줍니다. 이것은 오타나 잘못된 시그니처로 인한 오버라이딩 오류를 방지하는데 도움을 줍니다.
예시 코드: 메서드 오버라이딩
class Animal {
void speak() {
System.out.println("동물이 소리를 내다.");
}
}
class Dog extends Animal {
// 메서드 오버라이딩
@Override
void speak() {
System.out.println("강아지가 멍멍! 소리를 내다.");
}
}
- 위의 코드에서 Dog 클래스는 Animal 클래스의 speak 메서드를 오버라이딩합니다.
- @Override 어노테이션을 사용하여 컴파일러에게 오버라이딩이 되었음을 알립니다.
3. 메서드 오버라이딩의 중요성
메서드 오버라이딩은 다형성(polymorphism)을 구현하는데 중요한 역할을 합니다. 다형성은 객체 지향 프로그래밍의 핵심 개념 중 하나로, 같은 이름의 메서드를 다양한 하위 클래스에서 다르게 구현함으로써 유연하고 확장 가능한 코드를 작성할 수 있게 합니다.
메서드 오버라이딩을 통해 부모 클래스와 자식 클래스 간에 연결을 형성하고, 자식 클래스가 부모 클래스의 기능을 적절하게 확장하거나 수정함으로써 객체 지향 프로그래밍의 강력한 특성을 활용할 수 있습니다.
자바 다중 상속과 인터페이스
다중 상속의 개념
다중 상속은 하나의 클래스가 여러 개의 클래스로부터 상속받는 개념을 의미합니다. 이는 하나의 클래스가 여러 부모 클래스로부터 특성을 물려받을 수 있다는 것을 의미합니다. 다중 상속은 코드의 재사용성을 높이고 다양한 특성을 하나의 클래스에서 결합할 수 있는 장점을 가지고 있습니다.
자바에서의 다중 상속
자바에서는 클래스 다중 상속을 지원하지 않습니다. 이는 클래스 다중 상속이 다양한 충돌과 문제를 야기할 수 있기 때문입니다. 예를 들어, 두 개의 부모 클래스에서 동일한 메서드나 필드가 있는 경우, 어떤 부모 클래스의 메서드를 사용해야 할지 모호해집니다. 따라서 자바에서는 클래스 다중 상속을 허용하지 않고, 대신 인터페이스를 통한 다중 상속 방식을 제공합니다.
인터페이스의 활용
인터페이스는 클래스가 특정 메서드를 구현하도록 강제하는 역할을 합니다. 자바에서는 클래스가 여러 개의 인터페이스를 구현하여 다중 상속과 유사한 효과를 얻을 수 있습니다.
예시 코드: 인터페이스를 통한 다중 상속
// 인터페이스 정의
interface Flyable {
void fly();
}
interface Swimmable {
void swim();
}
// 클래스가 인터페이스 구현
class Bird implements Flyable {
public void fly() {
System.out.println("새가 날다.");
}
}
class Fish implements Swimmable {
public void swim() {
System.out.println("물고기가 헤엄치다.");
}
}
class Duck implements Flyable, Swimmable {
public void fly() {
System.out.println("오리가 날다.");
}
public void swim() {
System.out.println("오리가 헤엄치다.");
}
}
- 위의 코드에서 Bird 클래스는 Flyable 인터페이스를 구현하고, Fish 클래스는 Swimmable 인터페이스를 구현합니다.
- Duck 클래스는 Flyable과 Swimmable 인터페이스를 동시에 구현하여 다중 상속과 유사한 기능을 제공합니다.
다중 상속과 인터페이스를 활용하면 코드의 재사용성을 높이고 다양한 특성을 조합하여 유연한 클래스를 설계할 수 있습니다. 특히 자바에서는 인터페이스를 통한 다중 상속 방식을 제공하여 다중 상속의 잠재적인 충돌을 피하면서도 다양한 특성을 클래스에 추가할 수 있습니다.
추상 클래스와 추상 메서드
추상 클래스와 추상 메서드는 객체 지향 프로그래밍에서 중요한 개념 중 하나로, 클래스의 설계와 구조를 정의하는 데 사용됩니다.
1. 추상 클래스와 추상 메서드의 정의
추상 클래스는 일반 클래스와 비슷하게 멤버 변수와 일반 메서드를 가질 수 있지만, 추상 메서드를 가질 수도 있습니다. 추상 메서드는 메서드의 선언만 있고 구현이 없는 메서드를 의미합니다. 추상 클래스는 객체를 직접 생성할 수 없으며, 추상 메서드를 하나 이상 가지는 클래스는 반드시 추상 클래스여야 합니다.
2. 추상 클래스의 상속과 구현
추상 클래스는 다른 클래스에게 공통된 메서드와 속성을 상속하고, 자식 클래스에서 반드시 추상 메서드를 구현하도록 강제할 수 있습니다. 이를 통해 다형성을 구현하고, 클래스 간에 일관된 인터페이스를 유지할 수 있습니다.
예시 코드: 추상 클래스와 추상 메서드
// 추상 클래스 정의
abstract class Shape {
int x, y;
Shape(int x, int y) {
this.x = x;
this.y = y;
}
// 추상 메서드 선언
abstract double calculateArea();
}
// Circle 클래스는 Shape 클래스를 상속하고 추상 메서드를 구현
class Circle extends Shape {
int radius;
Circle(int x, int y, int radius) {
super(x, y);
this.radius = radius;
}
// 추상 메서드 구현
double calculateArea() {
return Math.PI * radius * radius;
}
}
// Rectangle 클래스는 Shape 클래스를 상속하고 추상 메서드를 구현
class Rectangle extends Shape {
int width, height;
Rectangle(int x, int y, int width, int height) {
super(x, y);
this.width = width;
this.height = height;
}
// 추상 메서드 구현
double calculateArea() {
return width * height;
}
}
- 위의 코드에서 Shape 클래스는 추상 클래스로 선언되었으며, calculateArea라는 추상 메서드를 가지고 있습니다.
- Circle 클래스와 Rectangle 클래스는 Shape 클래스를 상속하고, 추상 메서드 calculateArea를 구현합니다.
3. 추상 클래스와 추상 메서드의 활용
추상 클래스와 추상 메서드를 활용하면 공통된 메서드를 추상 클래스에서 정의하고, 다양한 자식 클래스에서 이를 구현함으로써 코드의 재사용성을 높일 수 있습니다. 이러한 설계 패턴을 통해 다형성과 일관성을 유지하는데 도움을 줍니다.
상속의 장점과 주의점
자바 상속의 장점
1. 코드 재사용성
상속을 통해 부모 클래스의 속성과 메서드를 자식 클래스에서 그대로 사용할 수 있으므로 중복 코드를 줄일 수 있습니다. 이로 인해 코드의 유지보수가 쉬워지고 생산성이 향상됩니다.
2. 다형성 구현
상속을 통해 여러 클래스가 같은 부모 클래스를 공유할 수 있으며, 이를 통해 다형성을 구현할 수 있습니다. 다형성은 객체 지향 프로그래밍의 강력한 특성 중 하나로, 하나의 인터페이스를 통해 다양한 객체를 다룰 수 있게 합니다.
3. 구조화된 코드
상속은 코드를 더 구조화하고 추상화할 수 있게 합니다. 관련된 클래스들을 부모 클래스와 자식 클래스로 나누어 구조화함으로써 코드의 가독성을 향상시킵니다.
상속을 사용할 때 고려해야 할 주의사항
- 클래스 간 결합도: 높은 상속 계층 구조를 가질수록 클래스 간의 결합도가 높아집니다. 이는 코드 변경이 어려워질 수 있으므로 상속 구조를 신중하게 설계해야 합니다.
- 메서드 오버라이딩: 자식 클래스에서 부모 클래스의 메서드를 오버라이딩할 때, 의도치 않은 동작이 발생하지 않도록 주의해야 합니다.
- 다이아몬드 상속 문제: 자바와 같은 언어에서 다중 상속을 지원하지 않는 경우, 다이아몬드 상속 문제가 발생할 수 있습니다. 이를 해결하기 위해 인터페이스와 같은 다른 설계 패턴을 고려해야 합니다.
자바에서 상속은 객체 지향 프로그래밍의 핵심이며, 코드 재사용성과 확장성을 높이는 강력한 도구입니다. 상속을 올바르게 이해하고 활용하면 프로그램의 효율성을 높일 수 있으며, 코드의 유지 보수도 쉽게 수행할 수 있습니다.
'# Coding > Java' 카테고리의 다른 글
자바 인터페이스 추상클래스 (0) | 2023.09.29 |
---|---|
자바 내부클래스 익명클래스 (1) | 2023.09.25 |
자바 생성자 소멸자 this 키워드 (0) | 2023.09.23 |
자바 객체와 메모리 (0) | 2023.09.22 |
자바 메서드 (0) | 2023.09.20 |