💡 해당 글은 『자바의 신 3판』을 복습하며 도서의 내용과 본인의 주관적인 생각을 정리한 글입니다.
☁️ 내용정리
상속
자바에서는 다른 클래스에서 미리 만들어둔 기능을 특정 클래스에서 사용하거나, 특정 형식에 맞춰 클래스를 장석할 때, 상속이라는 개념을 사용한다.
상속은 super class
의 자원을 물려받아 사용할 수 있게 해주는 기술이다.
extends
키워드를 통해 class
, abstract class
를 확장할 수 있으며,implements
키워드를 통해 interface
를 구현할 수 있다.
extends를 통해 super클래스를 확장한 sub클래스의 생성자는 내부적으로 super클래스의 생성자를 호출하게 되어있다. 따라서 sub클래스가 heap에 올라가기 전 super클래스부터 올라가기 때문에 sub class는 super class로 타입 변환이 가능한 것이다.
Super sup = new Sub();
Sub sub = new Super(); // 이건 안됨
유의해야 할 점은 super클래스에서 기본생성자 없이 매개변수를 받는 생성자만 존재하는 경우,
sub클래스의 생성자에서 명시적으로 super클래스의 매개변수를 받는 생성자를 호출해줘야 한다는 것이다.
extends 키워드로 확장할 때는 유의해야할 점이 있다. 하나의 클래스만 extends할 수 있다는 점이다.
왜 하나의 클래스만 extends할 수 있게 했을까? 다이아몬드 상속문제를 검색하면 답이 나온다.
만약 다중상속이 허용된다고 가정했을 때, A 클래스를 B, C 클래스가 extends한 상황에서 D클래스가 B, C 클래스를 extends한 상황이다.
D 클래스에서 super.call();
을 호출하면 어떤 메서드를 호출해주어야 할까?
다중 상속은 클래스 간 정체성이 모호해질 수 있기 때문에 지원하지 않는다.
메서드 overriding
메서드 overriding
은 sub클래스에서 super클래스의 메서드명과 시그니처를 동일하게 선언하여 사용할 수 있는 개념이다.
class Super {
public void call() {
System.out.println("super");
}
}
class Sub extends Super {
@Override
public void call() {
System.out.println("sub");
}
}
public class Main {
public static void main(String ... args) {
Super sup = (Super) new Sub();
sup.call(); // sub
}
}
overriding 할 때 유의할 점은 super의 접근제한자 보다 약한 접근 권한을 지정하면 안된다는 것이다.
super의 메서드가 public이라면 sub의 메서드는 무조건 public이여야만 한다.
반대로 강한 접근 권한을 지정하는 것은 가능하다.
class Super {
protected void call() {
System.out.println("super");
}
}
class Sub extends Super {
@Override
public void call() {
System.out.println("sub");
}
}
private은 상속받지 못하니까 패스한다.
형 변환
super 클래스로 생성된 인스턴스는 sub 클래스로 type casting이 불가능하다.
sub 클래스로 생성된 인스턴스는 super 클래스로 type casting이 가능하다.
sub 클래스로 생성된 인스턴스를 super 클래스로 casting 후, 다시 sub 클래스로 casting이 가능하다.
public class Main {
public static void main(String ... args) {
Sub sub = (Sub) new Super(); // XXX throw ClassCastException
Super sup = new Sub();
Sub sub = (Sub) sup;
}
}
위에서 언급했듯이 sub클래스의 생서자는 super클래스의 생성자를 무조건 호출하기 때문이다.
다형성(Polymorphism)
다형성이란 다양한 형태를 가질 수 있는 특성이다.
class Super {
public void call() {
System.out.println("super");
}
}
class Sub extends Super {
@Override
public void call() {
System.out.println("sub");
}
}
public class Main {
public static void main(String ... args) {
Super sup = (Super) new Sub();
sup.call(); // sub
}
}
해당 코드에서 sup변수의 형태는 Super인데 실제로는 Sub의 메서드를 호출한다.
이렇게 런타임에서 어떤 메서드가 호출될지 결정되는 것을 런타임 다형성이라고 부르며 오버라이딩이 그 예시이다.
☁️ 내 생각
자바에서 다형성이 주는 이점
다형성이란 추상화된 타입으로 실제 메모리에 선언된 타입의 역할을 수행할 수 있게 해준다.
이는 의존성을 낮추는데 큰 역할을 한다. 의존성이 낮으면 유연한 변경에서 큰 이점을 얻을 수 있다.
의존성이란 A클래스가 B를 사용할 때, “A와 B는 의존성을 가진다.” 라고 할 수 있다.
interface Animal {
void crying();
}
class Cat implements Animal {
public void crying() {
System.out.println("야옹");
}
}
class CatController {
private final Cat cat;
public CatController() {
this.cat = new Cat();
}
public cry() {
cat.crying();
}
}
위의 코드에서 CatController는 Cat 클래스와 강하게 의존하고 있다.
하나의 CatController 인스턴스는 무조건 내부적으로 생성한 하나의 Cat 인스턴스를 생성하기 때문에 내가 원하는 Cat 인스턴스를 넣어줄 수 없을 뿐더러, 인터페이스의 이점도 가져가지 못한다.
내가 원하는 Cat인스턴스를 넣을 수 있게 변경해보겠다.
class CatController {
private final Cat cat;
public CatController(Cat cat) {
this.cat = cat;
}
public cry() {
cat.crying();
}
}
간단하게 생성자에서 Cat 인스턴스를 받음으로써 외부에서 원하는 Cat 인스턴스를 주입해줄 수 있게 되었다. 이렇게 CatController 와 Cat 의 의존성은 조금 약해지게 되었다.
하지만 아직 인터페이스의 이점은 사용하지 못했다.
인터페이스의 이점을 사용하지 않는다면, Animal을 구현하는 Dog, Horse, Eagle 등등의 클래스가 생겼을 때, 모든 클래스에 대한 컨트롤러를 생성해야 할 것이다. 아주 비효율적이다.
따라서 아래처럼 변경할 수 있다.
class AnimalController {
private final Animal animal;
public AnimalController (Animal animal) {
this.animal= animal;
}
public cry() {
animal.crying();
}
}
이제 하나의 컨트롤러 클래스애서 Animal 인터페이스를 확장하는 모든 클래스를 받을 수 있다.
AnimalController는 컴파일시점에는 어떤 인스턴스가 들어올지 모른다.
인스턴스 변수에 할당되는 인스턴스가 익명클래스일지도?
하지만 런타임 시점에는 Animal을 구현한 클래스의 crying 메서드를 호출하며 각 타입에 맞는 동작을 수행한다. 멋지다.
☁️ 질문
- 다형성이란 무엇인가?
- 다형성이란 하나의 클래스가 여러 타입의 변수에 할당될 수 있고, 메서드 호출 시 실제 저장되어 있는 인스턴스의 동작을 수행할 수 있는 매커니즘이다.
- 다형성의 이점은 무엇인가?
- 다형성은 의존성을 낮추는 데 큰 역할을 한다.
- 다형성을 통해 의존성을 낮추는 방법을 설명해 달라.
'JAVA > 자바의 신' 카테고리의 다른 글
12장. 모든 클래스의 부모 클래스는 Object에요 (0) | 2024.01.05 |
---|---|
11장. 매번 만들기 귀찮은데 누가 만들어 놓은 거 쓸 수 없나요? (0) | 2024.01.05 |
9장. 자바를 배우면 패키지와 접근 제어자는 꼭 알아야 해요 (0) | 2024.01.05 |
8장. 참조 자료형에 대해서 자세히 알아봅시다. (1) | 2024.01.05 |
7장. 여러 데이터를 하나에 넣을 수는 없을까요? (0) | 2024.01.04 |