[Java] 상속과 캡슐화

Nakjoo·2022년 12월 29일
0

[SEB_BE_43]

목록 보기
11/29

1. 상속

상속이란 기존의 클래스에 기능을 추가하거나 재정의하여 새로운 클래스를 정의하는 것을 의미한다.
이러한 상속은 캡슐화, 추상화와 더불어 객체 지향 프로그래밍을 구성하는 중요한 특징 중 하나이다.

상속을 이용하면 기존의 정의되어 있던 클래스의 모든 필드와 메소드를 물려받아, 새로운 클래스를 생성할 수 있다.
이때 기존에 정의되어 있던 클래스를 부모 클래스(parent class) 또는 상위 클래스(super class)라고도 한다.
그리고 상속을 통해 새롭게 작성되는 클래스를 자식 클래스(child class) 또는 하위 클래스(sub class)라고도 한다.

상속의 장점으로는

  1. 기존에 작성된 클래스를 재활용할 수 있다.
  2. 자식 클래스 설계시 중복되는 멤버를 미리 부모 클래스에 작성해 놓으면, 자식 클래스에서는 해당 멤버를 작성하지 않아도 된다.
  3. 클래스 간의 계층적 관계를 구성함으로써 다형성의 문법적 토대를 마련한다.

자바에서 상속을 구현하는 방법은 extends 키워드를 사용하며, 클래스명 다음에 extends 상위 클래스명을 사용해 정의한다.

위의 예제처럼 Parent 클래스를 Child 클래스가 extends 키워드로 상속받아, Parent 클래스의 test() 메서드를 사용하는 것을 볼 수 있다.

참고로 자바의 객체 지향 프로그래밍에서는 단일 상속(single inheritance)만을 허용한다. 다른 말로, 다중 상속은 허용되지 않는다.

1.1. 포함 관계

포함은 상속처럼 클래스를 재사용할 수 있는 방법으로, 클래스의 멤버로 다른 클래스 타입의 참조변수를 선언하는 것을 의미한다.

그렇다면 클래스 간의 관계를 설정하는 데 있어서 상속관계를 맺어줄 것인지 포함관계를 맺어줄 것인지 어떤 기준으로 판별할 수 있을까?

가장 쉬운 방법은 클래스 간의 관계가 ~은 ~이다(IS-A) 관계인지 ~은 ~을 가지고 있다(HAS-A) 관계인지 문장을 만들어 생각해보는 것이다.

예시로 Employee 클래스와 Address 클래스가 있다고 할 때, Employee는 Address이다. 라는 문장은 성립하지 않는 반면, Employee는 Address를 가지고 있다. 는 어색하지 않은 올바른 문장임을 알 수 있다. 따라서 이 경우에는 상속보다 포함관계가 적합하다.

반면 Car 클래스와 SportCar 라는 클래스가 있다고 할 때, SportCar는 Car를 가지고 있다. 라는 문장보다 SportCar는 Car이다. 라는 문장이 훨씬 더 자연스럽다. 따라서 이 경우는 Car를 상위 클래스로 하는 상속관계를 맺어주는 것이 적합하다고 할 수 있다.

1.2. 메서드 오버라이딩

메서드 오버라이딩(Method Overriding)상위 클래스로부터 상속받은 메서드와 동일한 이름의 메서드를 재정의하는 것을 의미한다.

위 예시에서, Person 클래스에 eat() 메서드가 정의되어 있으며, Minsu, Suji 클래스에서 eat() 메서드를 재정의함으로서 Person 클래스의 eat() 메서드를 오버라이딩하고 있다.

따라서 Minsu, Suji의 인스턴스를 통해 eat() 메서드를 호출하면 Personeat()이 아닌, Minsu, Sujieat()이 호출된다.

상위 클래스의 메서드를 오버라이딩하려면 다음의 세 가지 조건을 반드시 만족시켜야 한다.

1. 메서드의 선언부(메서드 이름, 매개변수, 반환타입)이 상위클래스의 그것과 완전히 일치해야 한다.
2. 접근 제어자의 버무이가 상위 클래스의 메서드보다 같거나 넓어야 한다.
3. 예외는 상위 클래스의 메서드보다 많이 선언할 수 있다.

1.3. super 와 super()

앞서 배운 thisthis()의 차이처럼 supersuper()의 차이도 비슷하다. super상위 클래스의 객체, super()상위 클래스의 생성자를 호출하는 것을 의미한다.

가장 중요한 사실은 모든 생성자의 첫 줄에는 반드시 this() 또는 super()가 선언되어야 한다는 것이다.

만약 super()가 없는 경우에는 컴파일러가 생성자의 첫 줄에 자동으로 super()를 삽입한다.

이때 상위클래스에 기본생성자가 없으면 에러가 발생한다.

1.4. Object 클래스

Object 클래스는 자바의 클래스 상속계층동서 최상위에 위치한 클래스이다. 따라서 자바의 모든 클래스는 Object 클래스로부터 확장된다는 명제는 항상 참이다.

아래는 Object 클래스의 대표적인 메서드 들이다.

메서드명반환 타입주요 내용
toString()String객체 정보를 문자열로 출력
hashCode()boolean등가 비교 연산(==)과 동일하게 스택 메모리값을 비교
wait()int객체의 위치정보 관련. Hashtable 또는 HashMap에서 동일 객체여부 판단
notify()void일시정지 중인 쓰레드 재동작

2. 캡슐화

캡슐화특정 객체 안에 관련된 속성과 기능을 하나의 캡슐로 만들어 데이터를 외부로부터 보호하는 것을 말한다.

이렇게 캡슐화를 해야하는 이유로 크게 두 가지 목적이 있다. 첫 번째는 데이터 보호의 목적이고, 두 번째로 내부적으로만 사용되는 데이터에 대한 불필요한 외부 노출을 방지하기 위함이다.

정리하면, 캡슐화의 가장 큰 장점은 정보 은닉(data hiding)에 있다고 할 수 있다.

즉, 외부로부터 객체의 속성과 기능이 변경되지 못하게 막고, 데이터가 변경되더라도 다른 객체에 영향을 주지 않기에 독립성을 확보할 수 있다.

더 나아가 유지보수와 코드 확장 시에도 오류의 범위를 최소화할 수 있어서 효과적으로 코드를 유지보수하기에 용이하다.

2.1. 패키지

패키지(package)특정한 목적을 공유하는 클래스와 인터페이스의 묶음을 의미한다.

패키지는 클래스들을 그룹 단위로 묶어 효과적으로 관리하기 위한 목적을 가지고 있다.

자바에서 패키지는 물리적인 하나의 디렉토리(directory)이고, 하나의 패키지에 속한 클래스나 인터페이스 파일은 모두 해당 패키지에 속해있다.

더 나아가, 이 디렉토리 하나는 계층구조를 가지고 있는데, 계층 구조 간 구분은 점(.)으로 표현된다.

마지막으로, 패키지가 있는 경우 소스 코드의 첫 번째 줄에 반드시 package 패키지명이 표시되어야 하고, 만약 패키지 선언이 없으면 이름 없는 패키지에 속하게 된다.

// 패키지를 생성했을 때
package practicepack.test; // 패키지 구문 포함. 패키지가 없다면 구문 필요 없음

public class PackageEX {

}

2.1.1. Import문

import문은 다른 패키지 내의 클래스를 사용하기 위해 사용하며, 일반적으로 패키지 구문과 클래스문 사이에 작성한다.

import 패키지명.클래스명; 또는 import 패키지명.*;

2.2. 접근 제어자

2.2.1. 제어자(Modifier)

자바 프로그래밍에서 제어자는 클래스, 필드, 메서드, 생성자 등에 부가적인 의미를 부여하는 키워드를 의미한다.

자바에서는 제어자를 크게 접근 제어자 기타 제어자로 구분할 수 있다.

구분종류
접근 제어자public, protected, (default), private
기타 제어자static, final, abstract, native, transient, synchronized 등

각 대상에 대해서 접근 제어자는 단 한번만 사용 가능하다.

2.2.2. 접근 제어자(Access Modifier)

자바의 접근 제어자는 4가지가 있다.

접근 제어자접근 제한 범위
private동일 클래스에서만 접근 가능
default동일 패키지 내에서만 접근 가능
protected동일 패키지 + 다른 패키지의 하위 클래스에서 접근 가능
public접근 제한 없음

위의 내용을 접근 제한 범위에 따라 표현하면,
public(접근 제한 없음) > protected(동일 패키지 + 하위 클래스) > default(동일 패키지) > private(동일 클래스) 순으로 정리할 수 있다.

2.3. getter와 setter 메서드

객체지향의 캡슐화의 목적을 달성하면서도 데이터의 변경이 필요한 경우는 어떻게 할까?

대표적으로 private 접근제어자가 포함되어 있는 객체의 변수의 데이터 갑을 추가하거나 수정하고 싶을 때를 생각해볼 수 있겠다.

이런 경우 getter와 setter 메서드를 사용하면 된다.

예제 처럼 setter 메서드는 외부에서 메서드에 접근하여 조건에 맞을 경우 데이터의 값을 변경 가능하게 해주고 일반적으로 메서드명에 set-을 붙여서 정의한다.

한편 getter 메서드는 이렇게 설정한 변수 값을 읽어오는 데 사용하는 메서드이다. 마찬가지로 get-을 메서드명 앞에 붙여 사용한다.

이렇게 setter와 getter 메서드를 활용하면 데이터를 효과적으로 보호하면서도 의도하는 값으로 값을 변경하여 캡슐화를 보다 효과적을 달성할 수 있다.

0개의 댓글