-
자바 클래스, 상속, 다형성언어/Java 2023. 7. 7. 23:41728x90반응형SMALL
오늘은 자바 프로그래밍에서 꼭 알고 있어야 하는 클래스와 관련된 문법들을 정리해보면서, 이런 문법들이 왜 나왔고 또 활용하는 방법은 무엇인지 알아보려고 합니다.
클래스 상속
- 새로운 클래스를 구현할 때 이미 존재하는 클래스의 메소드나 멤버변수를 모두 사용할 경우 해당 클래스를 상속 받아 기능을 확장하여 클래스를 정의할 수 있습니다.
- 이미 구현된 클래스보다 좀 더 구체적인 클래스를 구현해야 할 경우 클래스 상속을 사용합니다.
상속하는 클래스는 주로 상위 클래스, 부모 클래스, base class, super class라고 불립니다.
상속받는 클래스는 주로 하위 클래스, 자식 클래스, derived class, subclass라고 불립니다.
사용 방법
Class Child extends Parent { ... }
- 상속받는 클래스(Child)를 먼저 쓰고, 상속 하는 클래스(Parent)를 extends 키워드 다음 써줍니다.
- 자바는 단일 상속만 지원합니다.
상속을 구현하는 대표적인 경우
- 상위 클래스는 하위 클래스보다 일반적인 개념을 가짐
- 하위 클래스는 상위 클래스보다 더 구체적인 개념을 가짐
- 하위 클래스는 상위 클래스의 속성과 기능을 좀 더 확장한다는 의미입니다.
예) 동물 -> 사람 (상속하는 클래스 -> 상속받는 클래스)로 동물은 예를 들어 숨쉰다. 움직인다. 라는 기능을 가지고 있다면, 사람은 동물의 기능들을 모두 수행하기도 하고 더 확장하여 생각한다. 걷는다. 와 같은 기능으로 확장될 수 있습니다.
접근 제어자
- private : 상위 클래스에서 private 으로 선언된 멤버 변수는 하위 클래스에서 접근할 수 없습니다.
- protected : 외부 클래스에서는 접근할 수 없지만, 하위 클래스에서는 접근할 수 있습니다.
- public : 어디서든 접근 가능합니다.
하위 클래스 생성 과정
- 하위 클래스를 생성하면 상위 클래스가 먼저 생성됩니다.
new <하위 클래스>();
를 호출하면 상위 클래스의 생성자가 먼저 호출됩니다.- 클래스가 상속을 받을 경우 하위 클래스의 생성자는 반드시 상위 클래스의 생성자를 호출합니다.
super 키워드
- 하위 클래스에서 사용할 수 있는 상위 클래스의 참조 값입니다.
super()
는 상위 클래스의 기본 생성자를 호출합니다.- 하위 클래스에서 생성자를 선언할 때
super()
를 호출하지 않았다면 자동으로super()
가 호출됩니다. (상위 클래스의 기본 생성자가 존재해야 합니다.) - super는 상위 크래스 인스턴스의 참조 값을 가지므로 super를 이용하여 상위 클래스의 메서드나 멤버 변수에 접근할 수 있습니다.
상속에서 인스턴스 메모리 상태
항상 상위 클래스의 인스턴스가 먼저 생성되고 다음 하위 클래스의 인스턴스가 생성됩니다.
형 변환 (업캐스팅)
- 상위 클래스 변수로 선언하고 하위 클래스 인스턴스를 생성한 경우
<상위 클래스> instance = new <하위 클래스>();
- 하위 클래스 변수를 상위 클래스 변수에 대입 하는 경우
public void do(<상위 클래스> ins){ ... } ... { <하위 클래스> instance = new <하위 클래스>(); do(instance); }
- 하위 클래스는 상위 클래스의 타입을 내포하고 있으므로 상위 클래스로의 묵시적 형 변환이 가능합니다.
- 상속 관계에 있는 모든 하위 클래스들은 상위 클래스로의 형 변환(업캐스팅)이 가능합니다.
형 변환과 메모리
<상위 클래스> instance = new <하위 클래스>();
상위 클래스 변수에 하위 클래스 인스턴스를 생성했을 경우, 하위 클래스의 생성자에 의해 하위 클래스의 멤버 변수와 메소드는 메모리에 생성되어 있지만, 변수의 타입이 상위 클래스이므로 상위 클래스의 변수나 메서드만 접근 가능합니다.
메서드 재정의(overriding)
- 오버라이딩 : 상위 클래스에서 정의했던 메서드를 하위 클래스에서 재정의하여 상위 클래스와 다르게 사용하는 경우를 말합니다.
@Override
어노테이션을 통해 재정의된 메서드라는 정보를 컴파일러에게 제공해줍니다.
형 변환 이후 오버라이딩 메서드 호출
- 자바에서는 항상 인스턴스의 메서드를 호출하게 됩니다. (가상 메서드의 원리로)
- 자바의 모든 메서드는 가상 메서드 입니다.
class Parent { ... void doSomething() { System.out.println("parent call"); } } class Child extends Parent { ... void doSomething() { System.out.println("child call"); } } { ... Parent temp = new Child(); temp.doSomething(); // child call 출력 }
-> 상위 클래스 타입의 변수로 선언된 하위 클래스 인스턴스에서 하위 클래스에서 오버라이딩한 메서드를 호출할 경우 하위 클래스의 메서드 구현 내용으로 호출됩니다.
메서드 호출과 실행
- 메서드의 이름은 주소값을 나타냅니다.
- 메서드는 명령어의 집합이고 프로그램이 로드되면 메서드 영역에 명령어 집합이 위치하게 됩니다.
- 해당 메서드가 호출되면 명령어 집합이 있는 주소를 찾아 명령어가 실행됩니다.
- 메서드 호출 시 사용하는 멤버 변수는 스택 메모리에 위치하게 됩니다.
- 다른 인스턴스라도 같은 메서드가 호출되면 같은 주소값의 메서드를 호출하게 됩니다. (하위 클래스에서 재정의하지 않을 경우)
- 인스턴스가 생성되면 힙 메모리에 따로 생성되지만, 메모리 명령어 집합은 한 번만 로드 됩니다.
가상 메서드 원리
- 가상 메서드 테이블에서 해당 메서드에 대한 주소값을 가지고 있습니다.
- 재정의된 경우는 재정의 된 메서드의 주소를 가리킵니다.
자식 클래스에서 func1을 재정의하고 새로운 메서드 func3를 추가했을 때의 예시입니다.
자식 클래스의 가상 메서드 테이블에서 재정의된 func1은 부모 클래스의 func1과 다른 주소값을 가리키고 있는 것을 볼 수 있습니다.
자식 클래스 인스턴스에서 func1을 호출할 경우 가상 메서드 테이블의 func1의 주소값을 통해 자식 클래스의 func1을 호출하게 됩니다.
자식 클래스 인스턴스에서 func2를 호출할 경우 가상 메서드 테이블의 func2의 주소값을 통해 부모 클래스의 func2를 호출하게 됩니다.
다형성
- 같은 코드를 통해 다른 실행 결과가 나오는 것입니다.
- 객체지향 프로그래밍의 가장 큰 특징 중 하나입니다.
- 다형성을 잘 활용하면 유연하고 확장성 있고, 유지보수가 편리한 프로그램을 만들 수 있습니다.
public A(){ do(){ System.out.println("A do"); } } public B() extends A{ do(){ System.out.println("B do"); } } public C() extends A{ do(){ System.out.println("C do"); } } { ... A a = new A(); A b = new B(); A c = new C(); a.do(); // A do 출력 b.do(); // B do 출력 c.do(); // C do 출력 }
각 인스턴스에서 같은 메서드를 실행하더라도 다른 실행결과를 보이고 있습니다.
다형성을 사용하는 이유
- 이처럼 상속과 메서드 재정의를 활용하여 확장성 있는 프로그래밍이 가능하게 됩니다.
- 상위 클래스에서 공통적으로 사용할 메서드를 제공하고 하위 클래스에서 이를 구체적으로 각 클래스에 맞게 재정의하여 사용합니다.
- 여러 클래스를 하나의 타입으로 핸들링 할 수 있다는 것이 큰 장점입니다.
상속을 사용하는 경우
IS-A 관계
- 일반적인 개념과 구체적인 개념의 관계입니다.
- 과일과 사과의 관계입니다.
- 상속은 클래스간의 결합도가 높은 설계입니다.
- 상위 클래스의 수정은 하위 클래스에 영향을 미칠 수 있습니다.
- 계층 구조가 복잡해지거나 계층이 높으면 좋지 않습니다.
HAS-A 관계
- 클래스가 다른 클래스를 포함하는 관계입니다.
- 자동차가 바퀴를 포함하는 것과 같은 관계입니다.
- 상속하지 않습니다.
다운 캐스팅
- 업캐스팅된 클래스를 다시 원래의 타입으로 형 변환하는 것을 말합니다.
- 하위 클래스로의 형 변환은 명시적으로 해줘야 합니다.
Parent temp1 = new Child(); // 묵시적 Child temp2 = (Child)temp1; // 명시적
instanceof
원래 인스턴의 형을 확인할 수 있습니다.
Animal animal = something; if(animal instanceof monkey){ System.out.println("monkey"); } else if(animal instanceof cat){ System.out.println("cat"); } else if(animal instanceof dog){ System.out.println("dog"); } ...
마무리
오늘은 자바에서 사용되는 클래스, 상속이라는 개념과 다형성에 대해 알아볼 수 있었습니다.
상속이란 일반적인 개념을 가진 클래스에서 공통적으로 사용할 멤버 변수나 메소드를 상속시켜줌으로써 각각의 구체적인 클래스들이 동일한 코드를 반복하지 않아도 되도록 해줍니다. 또한, 상위 메서드를 하위 클래스에서 재정의해주는 오버라이딩이 가능합니다. 이는 객체지향 프로그래밍의 특징 중 하나인 다형성으로, 여러 하위 클래스들이 같은 메서드를 통해 다른 실행 결과를 보여주기도 하고, 상위 클래스를 통해 하위 클래스들을 모두 핸들링할 수도 있도록 해줍니다. 이러한 점을 잘 활용한다면 유연하고 확장성 있는 코드를 작성할 수 있습니다.
이후 포스팅에서는 추상 클래스와 인터페이스에 대해 알아보도록 하겠습니다.
반응형LIST'언어 > Java' 카테고리의 다른 글
자바 내부 클래스, 람다식, 함수형 프로그래밍, 함수형 인터페이스 (2) 2023.07.13 자바 자료구조, 제네릭, 컬렉션 (0) 2023.07.11 자바 Object, Class (5) 2023.07.10 자바 추상 클래스, 인터페이스 (0) 2023.07.08 자바를 시작해보자 (0) 2023.06.26