상속(Inheritance)
기존 클래스를 재사용하여 새로운 클래스를 작성하는 것.
적은 양의 코드로 새로운 클래스를 작성할 수 있고 코드를 공통적으로 관리할 수 있기 때문에 코드의 추가 및 변경이 용이
코드의 재사용성을 높이고 코드의 중복을 제거하여 프로그램의 생산성과 유지보수에 크게 기여
접근 제어자가 private을 갖는 필드나 메소드는 상속이 불가하고, 패키지가 다를 경우 접근제어자 default인 경우도 상속이 불가하다.
java에서 클래스를 통한 다중 상속은 허용되지 않지만 인터페이스를 통한 다중 상속이 지원되므로 클래스가 단순성을 유지하고 충돌을 피하면서 여러 소스의 동작을 상속할 수 있다.
구현하는 방법
새로 작성하고 하는 클래스의 이름 뒤에 상속받고자 하는 클래스의 이름을 키워드 ‘extends’를 써주기 만 하면 된다.
class Animal {} //조상 클래스, 부모 클래스
class Dog extends Animal { // 자손 클래스, 자식 클래스
//...
}
IS-A 관계
상속은 IS-A 관계에서 사용하는 것이 가장 효율적이다.
‘사람은 동물이다.’ , ‘소는 동물이다.’, ‘새는 동물이다’ 처럼 A는 B이다가 되는 관계에서 사용하면 좋다.
this와 super
this : 인스턴스 자신을 가리키는 참조 변수
this() : 같은 클래스의 다른 생성자를 호출할 때 사용
super : 부모, 자식 클래스의 변수/메서드 이름이 똑같을 때 구분을 위해 사용. 부모 클래스의 클래스 멤버 앞에 붙여준다.
super() : 자식 생성자 안에서 부모 클래스의 생성자를 호출할 때 사용
다형성
다형성(Polymorphism)
- 한 객체가 여러 가지 타입을 가질 수 있는 것
- 부모클래스 타입의 참조 변수로 자식 클래스 인스턴스 참조
- instanceof : 실제 참조하고 있는 인스턴스의 타입 확인, 상속관계가 없으면 문법 오류 발생
class Person {}
class student extends Person{}
Person p1 = new Student();
//Student s1 = new Person(); 이건 안됨
System.out.println(p1 instanceof Person); //true
장점
- 코드 재사용성(Reuse): 다형성을 통해 코드의 재사용성이 향상. 동일한 코드를 여러 클래스에서 활용할 수 있어, 개발자는 중복을 줄이고 생산성을 높일 수 있다.
- 유연성(Flexibility): 다형성은 객체의 형식을 추상화하고 동일한 인터페이스 사용을 가능케 한다. 이로 인해 객체 간 결합도가 낮아지고, 코드의 유연성과 확장성이 증가.
- 코드 가독성(Readability): 다형성을 통해 동일한 이름의 메서드나 연산자가 다양한 동작을 수행할 수 있어 코드의 가독성이 향상 된다. 이는 개발자가 코드를 더 쉽게 이해하고 유지보수할 수 있게 한다.
단점
- 복잡성(Complexity): 다형성 사용 시 코드의 복잡도가 증가할 수 있다. 여러 클래스에서 동일한 이름의 메서드나 연산자를 사용하므로, 코드의 동작을 파악하기 어려울 수 있다.
- 오버헤드(Overhead): 다형성은 런타임에 메서드나 연산자의 동작을 결정하기 위한 추가 연산이 필요할 수 있어, 일부 성능 저하가 발생할 수 있다.
- 디버깅 난이도(Difficulty of debugging): 다형성으로 인해 코드의 실행 경로가 다양해져 디버깅이 복잡해질 수 있다. 이에 대응하기 위해 특정 디버깅 도구와 기술을 습득해야 하며, 이는 추가적인 학습 비용을 발생시킬 수 있다.
업 캐스팅
업캐스팅은 자식 클래스가 부모 클래스 타입으로 캐스팅 되는 것
업캐스팅은 캐스팅 연산자 괄호를 생략할 수 있다.
단, 부모 클래스로 캐스팅 된다는 것은 멤버의 갯수 감소를 의미한다. 이는 곧 자식 클래스에서만 있는 속성과 메서드는 실행하지 못한다는 뜻이다.
업캐스팅을 하고 메소드를 실행할 때, 만일 자식 클래스에서 오버라이딩한 메서드가 있을 경우, 부모 클래스의 메서드가 아닌 오버라이딩 된 메서드가 실행되게 된다.
❗ 주의할점
- 업캐스팅하면 멤버 갯수가 제한되어 자식 클래스에만 있는 멤버는 사용할 수 없게 된다.
- 업케스팅 했지만 오버라이딩 된 메서드는 자식 클래스의 메서드로 실행이 된다.
다운 캐스팅
부모 클래스가 자식 클래스 타입으로 캐스팅 되는 것
캐스팅 연산자 괄호를 생략할 수 없다.
다운 캐스팅의 목적은 업 캐스팅한 객체를 다시 자식 클래스 타입의 객체로 되돌리는데 목적을 둔다.
❗ 주의할점
- 무부분별한 다운캐스팅은 컴파일 시점에는 오류가 발생하지 않아도 런타임 오류를 발생시킬 가능성 있다. 다운 캐스팅을 다룰때는 다운 캐스팅 할 객체가 오리지날 부모 객체인지, 업캐스팅된 부모 객체인지 항상 주의해야 한다.
- istanceof 연산자를 통해 이 문제를 해결할 수 있다.
오버로딩과 오버라이딩
오버로딩
동일한 클래스의 여러 메소드가 동일한 이름이지만 매개변수가 다른(다른 유형, 갯수 또는 둘 다) 경우를 말한다. 오버로딩을 사용하면 클래스에 이름은 같지만 인수 목록이 다른 메서드가 두 개 이상 있을 수 있으므로 코드 가독성과 유연성이 향상 된다.
public class MathUtils {
public int add(int a, int b) {
return a + b;
}
public double add(double a, double b) {
return a + b;
}
}
💡Point
메소드의 이름은 동일해야 하지만 매개변수 목록(매개변수 수 또는 유형)은 달라야 함.
반환 유형은 다를 수 있지만 오버로딩을 위한 메서드 시그니처에는 영향을 미치지 않는다.
비슷한 기능을 수행하지만 입력이 다른 메서드를 만드는 데 자주 사용.
오버 라이딩
하위 클래스가 상위 클래스에 이미 정의된 메소드에 대해 재정의 하는 경우를 말한다. 재정의된 메서드에는 상위 클래스의 메서드와 동일한 이름, 반환 유형 및 매개변수가 있어야 한다.
class Animal {
public void makeSound() {
System.out.println("Animal sound");
}
}
class Dog extends Animal {
@Override
public void makeSound() {
System.out.println("Bark");
}
}
💡Point
자식 클래스의 메서드는 부모 클래스의 메서드와 동일한 시그니처를 가져야 한다.
@Override 주석은 일반적으로 메서드가 재정의되고 있음을 나타내어 코드 가독성을 높이고 실수를 방지하는 데 사용
재정의 메서드의 액세스 한정자는 상위 클래스의 액세스 한정자보다 더 제한적이어서는 안 된다. 예를 들어, 상위 메소드가 'protected'인 경우 재정의 메소드는 'private'일 수 없다.
재정의 메서드는 다른 구현을 가질 수 있지만 기능 측면에서 호환성을 유지해야 한다.
정리
오버라이드(Override)는 상속 관계에서 상위클래스의 메서드를 하위클래스에서 재정의 하는 것이며, 오버로드(Overload)는 같은 클래스 내에서 메서드 이름은 같지만 매개 변수가 다른 여러 메서드를 정의하는 것입니다.
오버라이드는 상위 클래스에서 이미 정의된 메서드와 동일한 이름, 매개변수, 반환 유형을 가진 메서드를 하위 클래스에서 다시 정의하는 것을 의미합니다. 이로써 하위 클래스에서 상위 클래스의 메서드 동작을 변경하거나 확장할 수 있습니다. 상속관계 클래스에서 사용되며 static, final로 선언한 메서드는 오버라이딩이 불가능합니다.
오버로드는 같은 메서드 이름을 가지지만 매개변수의 종류, 개수 또는 유형이 다른 여러 메서드를 같은 클래스 내에서 정의하는 것을 말합니다. 이렇게 하면 동일한 메서드 이름을 사용하면서 다양한 매개변수 조합에 대해 다른 동작을 할 수 있습니다. 이는 프로그램의 유연성을 높이고 결과적으로 코드를 깔끔하게 하는 효과가 있습니다.
'TIL' 카테고리의 다른 글
| 241113 TIL CPU와 레지스터 (6) | 2024.11.13 |
|---|---|
| 241112 TIL 컨텍스트 스위칭 (2) | 2024.11.12 |
| 241108 TIL static과 final (3) | 2024.11.09 |
| 241107 TIL 운영체제 파일 시스템 (2) | 2024.11.07 |
| 241106 TIL 운영체제 Thread (6) | 2024.11.06 |