자바의 상속에 대해 학습
1. 자바 상속의 특징
2. super 키워드
3. 메소드 오버라이딩
4. 다이나믹 메소드 디스패치 (Dynamic Method Dispatch)
5. 추상 클래스
6. final 키워드
7. Object 클래스
상속은 객체 지향 프로그래밍(OOP)의 중요한 개념 중 하나로, 자바에서도 매우 중요한 역할을 합니다. 상속을 통해 기존 클래스의 속성과 메소드를 새로운 클래스에서 재사용하고 확장할 수 있습니다.
상속을 사용하면 새로운 클래스(자식 클래스 도는 서브 클래스)가 기존 클래스(부모 클래스 또는 슈퍼 클래스)의 특성과 동작을 물려받을 수 있습니다.
자식 클래스는 부모 클래스의 모든 필드와 메소드를 상속받으며, 필요한 경우 이를 재정의(오버라이딩)하거나 새로운 특성과 동작을 추가할 수 있습니다.
1) 재사용성
2) 계층 구조
3) 확장성
4) 다형성
5) 접근 제어자
public: 모든 클래스에서 접근 가능
protected: 같은 패키지와 자식 클래스에서 접근 가능
default(접근제어자가 없을때): 같은 패키지에서 접근 가능
private: 동일 클래스 내에서만 접근 가능
6) 단일 상속
다이아몬드 문제 를 참고해주세요!
// 부모 클래스
class Animal {
String name;
void eat() {
System.out.println("Eating...");
}
void sleep() {
System.out.println("Sleeping...");
}
}
// 자식 클래스
class Dog extends Animal {
void bark() {
System.out.println("Barking...");
}
}
public class Main {
public static void main(String[] args) {
Dog myDog = new Dog();
myDog.name = "Buddy";
myDog.eat(); // 부모 클래스의 메소드 호출
myDog.sleep(); // 부모 클래스의 메소드 호출
myDog.bark(); // 자식 클래스의 메소드 호출
}
}
상속받은 메소드를 자식 클래스에서 재정의(오버라이딩)할 수 있습니다. 이를 통해 부모 클래스의 동작을 변경하거나 확장할 수 있습니다.
// 부모 클래스
class Animal {
void makeSound() {
System.out.println("Some generic animal sound");
}
}
// 자식 클래스
class Dog extends Animal {
@Override
void makeSound() {
System.out.println("Bark");
}
}
public class Main {
public static void main(String[] args) {
Animal myAnimal = new Animal();
myAnimal.makeSound(); // 출력: Some generic animal sound
Dog myDog = new Dog();
myDog.makeSound(); // 출력: Bark
}
}
@Override를 붙여 재정의 할 수 있습니다. 그래서 Animal의 makeSound와 Dog의 makeSound가 다르게 출력됩니다.
이처럼 상속(Inheritance)은 코드 재사용성을 높이고, 계츨 구조를 형성하며, 다형성을 지원하는 강력한 도구라고 할 수 있겠습니다.
super키워드는 자바에서 부모 클래스의 멤버(필드, 메소드, 생성자)에 접근할 때 사용되는 특별한 키워드 입니다. 이를 통해 자식 클래스는 부모 클래스의 필드와 메소드에 접근하거나 부모 클래스의 생성자를 호출할 수 있습니다.
부모 클래스의 메소드 호출
자식 클래스에서 부모 클래스의 메소드를 호출 할때,
super키워드를 사용합니다. 이를 통해 자식 클래스에서 재정의(오버라이딩)된 메소드를 호출할 수 있습니다.
부모 클래스의 필드 접근
자식 클래스에서 부모 클래스의 필드에 접근할 때
super키워드를 사용합니다.
부모 클래스의 생성자 호출
자식 클래스의 생성자에서 부모 클래스의 생성자를 호출할 때
super키워드를 사용합니다. 이는 부모 클래스의 초기화 작업을 수행하기 위해 필요합니다.
부모 클래스의 매개변수가 있는 생성자 호출
자식 클래스의 생성자에서 부모 클래스의 매개변수가 있는 생성자를 호출할때
super키워드를 사용할 수 있습니다.
class Parent {
// 부모 클래스의 필드
int value = 100;
// 부모 클래스의 기본 생성자
Parent() {
System.out.println("Parent Constructor");
}
// 부모 클래스의 매개변수가 있는 생성자
Parent(String message) {
System.out.println("Parent Constructor: " + message);
}
// 부모 클래스의 메소드
void display() {
System.out.println("Display from Parent");
}
}
class Child extends Parent {
// 자식 클래스의 필드
int value = 200;
// 자식 클래스의 기본 생성자
Child() {
super("Hello from Child"); // 부모 클래스의 매개변수가 있는 생성자 호출
System.out.println("Child Constructor");
}
// 자식 클래스의 메소드
@Override
void display() {
System.out.println("Display from Child");
}
// 자식 클래스의 메소드
void show() {
super.display(); // 부모 클래스의 display() 메소드 호출
this.display(); // 현재 클래스의 display() 메소드 호출
System.out.println("Value from Parent: " + super.value); // 부모 클래스의 value 필드
System.out.println("Value from Child: " + this.value); // 현재 클래스의 value 필드
}
}
public class Main {
public static void main(String[] args) {
Child child = new Child();
child.show();
}
}
Parent Constructor: Hello from Child
Child Constructor
Display from Parent
Display from Child
Value from Parent: 100
Value from Child: 200
super("Hello from Child")를 사용하여 부모 클래스의 매개변수가 있는 생성자를 호출했습니다.super.display()를 사용하여 부모 클래스의 display 메소드를 호출하고, this.display()를 사용하여 자식 클래스의 display 메소드를 호출했습니다.super.value를 사용하여 부모 클래스의 value 필드에 접근하고, this.value를 사용하여 자식 클래스의 value 필드에 접근했습니다.메소드 오버라이딩(Method Oberriding)은 자바에서 상속 관계에 있는 클래스들간에 부모 클래스의 메소드를 자식 클래스에서 재정의 하여 사용하는 기능입니다.
이는 다형성(Polymorphism)의 중요한 요소로, 부모 클래스의 기본 동작을 자식 클래스에서 변경할 때 사용됩니다.
동일한 메소드 이름
부모 클래스의 메소드와 동일한 이름을 가져야 합니다.
동일한 매개변수 목록
매개변수의 개수, 타입, 순서가 부모 클래스의 메소드와 동일해야 합니다.
동일한 반환 타입
반환 타입이 부모 클래스의 메소드와 동일해야 합니다. 자바 5 이후부터는 공변 반환 타입(Convariant Return Type)을 허용하여 자식 클래스에서 반환 타입을 부모 클래스의 반환 타입의 서브 클래스로 변경할 수 있습니다.
class Animal {
public Animal getInstance() {
return new Animal();
}
}
class Dog extends Animal {
@Override
public Dog getInstance() {
// 공변 반환 타입: Animal의 서브 타입인 Dog 반환
return new Dog();
}
}
public class Main {
public static void main(String[] args) {
Animal animal = new Animal();
Animal animalInstance = animal.getInstance();
// Animal 객체 반환
Dog dog = new Dog();
Dog dogInstance = dog.getInstance();
// Dog 객체 반환
Animal polyAnimal = new Dog();
Animal polyAnimalInstance = polyAnimal.getInstance();
// 다형성 사용 시 여전히 Dog 객체 반환
}
}
이렇게 원래라면 Animal을 반환해야하지만, Dog 타입을 반환할 수 있게 되었습니다. 타입 안정성, 가독성 향상, 다형성 지원 강화라는 장점이 있겠습니다.
요약하자면,
protected이면 자식 클래스에서는 protected 또는 public만 가능합니다.class Parent {
// 부모 클래스의 메소드
void display() {
System.out.println("Display from Parent");
}
}
class Child extends Parent {
// 자식 클래스에서 메소드 오버라이딩
@Override
void display() {
System.out.println("Display from Child");
}
}
public class Main {
public static void main(String[] args) {
Parent parent = new Parent();
parent.display();
// Output: Display from Parent
Child child = new Child();
child.display();
// Output: Display from Child
Parent parentRef = new Child();
parentRef.display();
// Output: Display from Child (다형성)
}
}
자식 클래스에서 오버라이딩하는 메소드는 부모클래스의 메소드가 던지는 예외보다 더 많은 예외를 던질 수 없습니다. 던지는 예외의 범위는 같거나 더 좁아야합니다.
class Parent {
void display() throws IOException {
System.out.println("Display from Parent");
}
}
class Child extends Parent {
@Override
void display() throws FileNotFoundException {
// 허용됨: 더 좁은 범위의 예외
System.out.println("Display from Child");
}
}
@Override 어노테이션을 사용하여 오버라이딩을 명시적으로 표시하고, 컴파일러의 체크를 받을 수 있습니다.다이나믹 메소드 디스패치(Dynamic Method Dispatch)는 객체 지향 프로그래밍에서 다형성을 구현하는 기술 중 하나입니다. 이는 컴파일 시점에는 어떤 메소드가 호출될지 결정되지 않고, 실행 시점에 객체의 실제 타입에 따라 메소드가 동적으로 호출되는 것을 의미합니다.
자바에서는 메소드 오버라이딩과 함께 다이나믹 메소드 디스패치를 통해 다형성을 구현합니다. 예를 들어, 부모 클래스의 참조 변수로 자식 클래스의 인스턴스를 참조할 때, 메소드 호출은 실제 객체의 타입에 따라 동적으로 결정됩니다.
class Animal {
void makeSound() {
System.out.println("Animal makes sound");
}
}
class Dog extends Animal {
@Override
void makeSound() {
System.out.println("Dog barks");
}
}
public class Main {
public static void main(String[] args) {
Animal animal = new Dog();
// 다형성: 부모 클래스의 참조 변수로 자식 클래스의 인스턴스를 참조
animal.makeSound();
// Output: Dog barks
// (실제 객체인 Dog의 makeSound 메소드가 호출됨)
}
}
위 예제에서 animal.makeSound() 호출 시, 컴파일 시점에는 Animal 클래스의 makeSound 메소드가 호출될 것으로 예상되지만, 실행 시점에는 실제 객체가 Dog 클래스의 인스턴스이므로 Dog 클래스의 makeSound 메소드가 호출됩니다.
이렇게 컴파일 시점에는 어떤 메소드가 호출될지 확정되지 않고, 실행 시점에 결정되는 것이 다이나믹 메소드 디스패치의 핵심입니다.
다형성
객체 지향 프로그래밍의 핵심인 다형성을 구현할 수 있습니다. 부모 클래스의 참조 변수로 여러 종류의 자식 클래스 인스턴스를 참조하여 각각의 메소드를 호출할 수 있습니다.
유연성
실행 시점에 메소드 호출이 결정되므로 프로그램의 동작을 동적으로 조절할 수 있습니다. 이는 프로그램의 유연성과 확장성을 향상시킵니다.
코드 재사용
메소드 오버라이딩을 통해 부모 클래스의 기능을 자식 클래스에서 재정의할 수 있습니다. 이는 코드의 재사용성을 높여줍니다.
자바에서는 다이나믹 메소드 디스패치를 가상 메소드 테이블(Virtual Method Table, VMT)을 통해 구현합니다. 각 클래스에는 해당 클래스의 메소드들에 대한 참조를 가지고 있는 VMT가 존재하며, 객체가 생성될 때마다 VMT가 생성됩니다. 메소드 호출 시에는 객체의 VMT를 참조하여 해당 메소드의 주소를 찾아서 호출하게 됩니다.
다이나믹 메소드 디스패치는 실행 시점에 메소드 호출이 결정되는 기술로, 다형성을 구현하는 중요한 요소입니다.
다형성을 통해 부모 클래스의 참조 변수로 여러 종류의 자식 클래스 인스턴스를 참조하여 다양한 메소드를 호출할 수 있습니다.
자바에서는 가상 메소드 테이블을 사용하여 다이나믹 메소드 디스패치를 구현합니다.
추상 클래스는 상속 관계에서 공통된 동작을 정의하고 확장하기 위한 용도로 사용됩니다.
예를 들어, 동물의 동물을 나타내는 추상 클래스에서는 추상 메소드로
움직이다,소리내다등의 행동을 정의할 수 있고, 실제 동물 종류(개, 고양이 등)를 나타내는 구체적인 클래스에서는 이러한 메소드를 구현할 수 있습니다.
추상 메소드 포함 가능
추상 클래스는 추상 메소드(Abstract Method)를 포함할 수 있습니다.
추상 메소드는 메소드의 시그니처(이름, 매개변수, 반환 타입)만을 정의하고 메소드의 본문(구현)은 포함하지 않습니다. 따라서 추상 메소드를 가지는 클래스는 반드시 추상 클래스여야 합니다.
일반 메소드 포함 가능
추상 클래스는 추상 메소드 뿐만 아니라 일반 메소드를 포함할 수도 있습니다. 일반 메소드는 메소드의 시그니처와 구현을 모두 포함합니다.
인스턴스 생성 불가능
추상 클래스는 직접적으로 인스턴스를 생성할 수 없습니다. 즉, 추상 클래스로부터 객체를 생성할 수 없으며, 추상 클래스를 상속받아서 추상메소드를 구현한 하위 클래스를 통해서만 인스턴스를 생성할 수 있습니다. 또한 추상메소드가 있다면, 반드시 구현부를 작성해야합니다.
상속을 통한 확장
추상 클래스는 다른 클래스에게 공통된 메소드나 속성을 상속하여 코드의 재사용성을 높일 수 있습니다. 하위 클래스에서는 추상 클래스의 추상 메소드를 구현하거나 재정의하여 사용할 수 있습니다.
원래 추상클래스는 추상메소드를 포함할때, 구현부가 없기때문에, 하위 클래스에서 구현한 뒤, 인스턴스를 생성할 수 있습니다만...
만약 추상클래스가 일반 메소드만 가지고 있다면, 하위 클래스에서 따로 구현할 필요 없이 바로 인스턴스를 생성해서 사용이 가능합니다.
구현의 유연성
추상 클래스의 하위 클래스는 원하는 메소드만 가져다 사용할 수 있지만, 인터페이스는 강제적으로 전부 구현해야합니다.
다중 상속
자바는 단일 상속만 지원하기 때문에, 하나의 클래스가 여러개의 인터페이스를 구현할 수 있습니다. 이를 통해 다중 상속의 장점을 일부 활용할 수 있습니다. 하지만 추상클래스는 여러개의 추상 클래스를 동시에 상속받을 수 없습니다.
관련성
추상 클래스는 주로 is-a 관계를 나타내는데 사용됩니다. 즉, 개(Dog)는 동물(Animal)의 일종이므로 추상 클래스로 구현할 수 있습니다.
반면 인터페이스는 can-do의 관계를 나타내는데 사용됩니다. 즉, 클래스가 특정 동작을 할 수 있는지 여부를 나타내는데 사용됩니다. 예를 들어날수있는(Flyable)또는 수행할 수 있는(Perfomable)등의 동작을 나타내는 인터페이스를 구현할 수 있습니다.
용도
추상 클래스는 클래스 간의 코드 재사용과 확장을 위해 사용됩니다.
반면 인터페이스는 클래스 간의 느슨한 결합(loose coupling)을 위해 사용됩니다. 인터페이스를 통해 다양한 구현체를 대체할 수 있으며, 이는 유연하고 확장 가능한 설계를 위한 중요한 도구 입니다.
final키워드는 자바에서 변수, 메소드, 클래스에 적용될 수 있습니다.
변수에 final 키워드를 사용하면 해당 변수는 상수(Constant)로 선언됩니다. 한 번 초기화된 이후에는 값을 변경할 수 없게됩니다.
final int MAX_SIZE = 10; // final 변수 선언과 동시에 초기화
final double PI; // final 변수 선언
PI = 3.14; // 생성자에서 final 변수 초기화
메소드에 final 키워드를 사용하면 해당 메소드는 하위 클래스에서 오버라이딩(재정의)할 수 없습니다. 즉, final 메소드는 부모 클래스에서 정의된 그대로의 동작을 보장하게 됩니다.
class Parent {
final void doSomething() { // final 메소드
// 메소드 구현
}
}
class Child extends Parent {
// 오버라이딩을 시도하면 컴파일 에러 발생
// void doSomething() {
// // 오버라이딩 불가
// }
}
클래스에 final 키워드를 사용하면 해당 클래스는 상속될 수 없게 됩니다. 즉, final 클래스는 다른 클래스에서 확장될 수 없습니다.
final class FinalClass {
// 클래스 내용
}
// FinalClass를 상속하려고 하면 컴파일 에러 발생
// class SubClass extends FinalClass {
// // 상속 불가
// }
final 키워드는 코드의 안정성과 확장성을 높이는데 사용됩니다. final 변수는 변하지 않는 값으로사용되며, final 메소드와 클래스는 의도적으로 오버라이딩이나, 상속을 제한하여 코드의 안정성을 확보합니다.
Object클래스는 자바에서 모든 클래스의 최상위 부모 클래스이며, 모든 클래스는Object클래스에서 상속을 받습니다. 따라서 자바에서 정의된 모든 클래스는Object클래스의 멤버들을 상속받아 사용할 수 있습니다.
equals(Object obj)
객체의 동등성을 확인하기 위해 사용됩니다. 두 객체가 동일한 값을 가지는지 비교하여 true 또는 false를 반환합니다.
기본적으로는 객체의 참조 값(identity)을 비교하지만, 클래스에서 이 메소드를오버라이딩 하여 동등성 비교를 사용자 정의할 수 있습니다.
hashCode()
객체의 해시 코드 값을 반환합니다. 이 메소드는 객체를 저장허거나 검색하는데 사용되는 해시 기반 컬렉션에서 객체를 식별하는 데 사용됩니다.
equals 메소드를 오버라이딩한 경우에는 hashCode 메소드도 함께 오버라이딩하여 일관성을 유지해야합니다.
toString()
객체의 문자열 표현을 반환합니다. 기본적으로는 객체의 클래스 이름과 해시 코드 값을 반환하지만, 클래스에서 이 메소드를 오버라이딩 하여 사용자 정의 문자열 표현을 제공할 수 있습니다.
getClass()
객체의 클래스를 나타내는 Class 객체를 반환합니다. Class 객체는 클래스에 대한 정보를 제공하며, 리플랙션(reflection)을 통해 클래스의 메타 데이터를 다룰 수 있게 해줍니다.
clone()
객체의 얕은 복사(Shallow Copy)를 생성하여 반환합니다. 이 메소드는 Cloneable 인터페이스를 구현한 클래스에서만 사용할 수 있으며, 클래스 에서 이 메소드를 오버라이딩 하여 깊은 복사(Deep Copy)를 수행할 수 있습니다.
finalize()
객체가 더 이상 사용되지 않을 때 가비지 컬렉터에 의해 호출되는 메소드입니다. 이 메소드는 자원의 해제나 정리 작업을 수행할 수 있습니다.
Object 클래스의 이러한 메소드들은 모든 자바 클래스에서 사용할 수 있으며, 필요에 따라 클래스에서 이러한 메소드를 오버라이딩하여 특정 동작을 정의할 수 있습니다.