Java/기초문법

[Java 기본 문법] 6. 접근제한자와 캡슐화

robinjoon98 2021. 8. 16. 01:02

2021.08.14 - [Java] - [Java 기본 문법] 5. 객체와 클래스

 

[Java 기본 문법] 5. 객체와 클래스

2021.08.14 - [Java] - [자바 기본 문법] 4. 참조타입 [자바 기본 문법] 4. 참조타입 2021.08.13 - [Java] - [Java 기본 문법] 1. 변수와 타입 2021.08.13 - [Java] - [Java 기본문법] 2. 연산자 2021.08.13 - [Ja..

blog.robinjoon.space

이전 포스팅에서 접근제한자 라는걸 언급했다. 이번 포스팅에선 접근제한자가 무었이고 왜 사용하는지 이것을 통해 캡슐화를 어떻게 하는지 알아보자.

접근제한자

접근제한자란, 클래스, 필드, 매서드에 어떤 객체가 접근이 가능한지 설정하는 키워드다. 접근제한자는 클래스에 사용될 때와 필드나 매서드에 사용될때 그 의미가 살짝 다르다. 각각의 경우별로 나눠서 설명해본다.

 

클래스의 접근제한자

클래스에 사용할 수 있는 접근 제한자는 public과 default가 있다. 

default 접근 제한자

클래스를 선언할 때 public 키워드를 사용하지 않았다면 default 접근제한을 가진다. 클래스가 default 접근제한을 가지면, 다른 패키지의 클래스에선 접근할 수 없고, 같은 패키지 내에선 접근 가능하다. 이는 그 클래스가 외부에 공개되지 않음을 의미한다. 즉, 다른 패키지내의 클래스들은 다른 패키지에 이 클래스가 존재하는지조차 알 수 없다.

public 접근제한자

클래스를 선언할 때 public 키워드를 사용했다면 그 클래스는 패키지와 상관없이 모든 클래스에서 접근할  수 있다. public 접근제한을 가진 클래스들은 공개 API가 되어 다른 패키지의 클래스에서 이 클래스를 필드변수로 가질 수도 있고, 매서드 내부에서 자유롭게 이 클래스의 객체를 만들어 사용할 수 있게된다.

이는, 필드의 수정이나 매서드의 수정이 발생할 시 클래스를 사용한 모든 클래스에서 변경을 발생시킬 여지가 생기기 때문에 확실히 다른 패키지에서 사용해야되는 클래스만 public 접근제한을 부여해야 한다. 

초심자가 이해하기 쉽게 말하면, 10개의 클래스에서 자신이 public으로 만든 클래스를 사용하는 중인데, 그 클래스의 매서드의 반환타입을 바꿔버리면, 10개의 클래스에서 자신이 만든 클래스를 사용한 수십 수백개의 매서드를 수정하고 테스트하는 대참사가 난다는 말이다. 즉, 한번 public으로 클래스를 만들면 클래스를 변경하기가 매우 어려워진다.

만일 개발할 클래스가 인터넷을 통해 배포되어, 라이브러리로 사용될 목적이라면 반드시 public 키워드를 사용해야 한다. 

생성자의 접근제한자

생성자에 부여할 수 있는 접근제한자는 public, protected, default, private 접근제한자가 있다.

public 접근제한자

생성자에 public 접근제한을 부여하면, 모든 패키지에서 이 생성자를 이용해 클래스의 객체를 생성할 수 있다. 만약, 생성자가 public 접근제한을 가진다면, 클래스도 public 접근제한을 가져야 한다. 클래스가 default 접근제한을 가진다면 생성자가 public 접근제한을 가져도, 다른 패키지에선 클래스의 존재를 모르므로 객체를 생성할 수 없다.

protected 접근제한자

생성자가 protected 접근제한을 가진다면, 외부 패키지에선 이 생성자를 호출할 수 없다. 단, 외부패키지의 클래스가 이 클래스의 자식클래스라면 protected 생성자를 호출할 수 있다. 자식클래스라는 개념은 다음 포스팅에서 알아볼 예정이니 지금은 넘어가자. 이 경우 클래스의 접근제한은 public 이어야 한다.

default 접근제한자

생성자가 default 접근제한자를 가지면, 외부 패키지에선 이 생성자를 호출할 수 없다. 하지만, 같은 패키지의 클래스들은 자유롭게 이 생성자를 호출 할 수 있다. 

private 접근제한자

생성자가 private 접근제한자를 가지면, 이 생성자는 이 클래스 내부에서만 호출할 수 있다. 즉, 모든 생성자가 private 접근제한을 가지면, 다른 클래스에선 생성자를 통해 이 클래스의 객체를 만들 수 없다. 생성자를 private로 하는 경우는 여러 생성자가 존재하고, 객체의 필드초기화를 private 생성자에 몰아놓고 다른 생성자 내부에서 이 생성자를 호출하기 위함인 경우와, 이 클래스의 객체가 오직 하나만 존재함을 보증하는 싱글톤을 구현하는 경우가 있다.

 

매서드와 필드의 접근제한자

매서드와 필드의 접근제한자도 생성자와 같이 4가지가 존재한다.

public 접근제한자

필드와 매서드에 public 접근제한을 부여하면, 모든 패키지에서 아무 제한없이 이 필드나 매서드를 사용할 수 있다. 이 경우 클래스의 접근제한자도 public이어야 한다. 클래스가 default 라면, 다른 패키지에서는 이 클래스를 사용할 수 없기 때문이다.

protected 접근제한자

필드나 매서드가 protected 접근제한을 가진다면, 외부 패키지에선 이 필드나 매서드를 사용할 수 없다. 단, 외부패키지의 클래스가 이 클래스의 자식클래스라면 protected 필드나 매서드를 사용할 수있다. 이 경우 클래스의 접근제한은 public 이어야 한다.

default 접근제한자

필드나 매서드가 default 접근제한자를 가지면, 외부 패키지에선 이 필드나 매서드를 사용할 수 없다. 하지만, 같은 패키지의 클래스들은 자유롭게 이 필드와 매서드를 사용할 수 있다.

private 접근제한자

필드나 매서드가 private 접근제한자를 가지면, 오직 이 클래스 내부에서만 사용할 수 있다.

 

캡슐화

접근제한자를 어떻게 사용해야 하나?

자바의 접근제한자는 캡슐화의 핵심이다. 지난 포스팅에서도 말했지만, 캡슐화는 내부데이터와 구현을 외부로부터 숨기고, 오로지 상호작용을 위한 최소한의 매서드만 외부에 공개하는 것을 의미한다. 

객체가 외부에 공개한 매서드(필드)는 함부로 수정할 수 없다. 어떤 객체에서 그 객체의 공개된 필드나 매서드를 사용했는지 알 수 없기 때문이다. 특히 상수가 아닌 필드의 접근제한을 private이 아닌 다른 접근제한을 부여하는 것은 절대 지양해야 한다. 객체의 필드는 근본적으로 다른 객체가 필요한 데이터가 아니다. 다른 객체가 필요한 데이터는 객체의 필드가 아닌 매서드의 반환값으로 제공해야 한다. 필드를 다른 객체가 접근할 수 있게 하는것은, 다른 사람의 생각을 알겠다고 말로 물어보는게 아닌, 뇌를 꺼내는 것과 같다.

정리하면, 객체의 필드는 아주 급하고 꼭 필요하며 방법이 그것밖에 없는경우가 아니면 private 접근제한을 부여하고, 매서드의 경우 각 매서드가 하고자 하는 역할에 맞게 접근지정자를 지정해 주어야 한다.

Getter와 Setter 매서드

객체의 필드에 값을 넣는 매서드setter 매서드라 하고, 필드를 조회하는 것getter 매서드 라고 한다. 이를 사용하는 이유는 위에서 이야기한 내용과 일맥상통한다. 사실 객체의 필드값을 그대로 가져오거나, 필드의 변경을 목적으로하는 매서드는 그다지 적합한게 아니다. 필드는 외부에서 알 필요가 없는 것이어야 하기 때문이다. 하지만 프로그래밍을 하다보면 언제나 이상과 현실(주로 시간이 된다)을 타협해야 한다.

어쨋든 객체의 필드에 값을 넣거나, 필드의 값을 직접 조회한다면 setter와 getter를 사용하는 것이 옳다.

setter를 사용하면 필드가 가져선 안되는 값을 가지지 않도록 검출할 수 있고, getter를 사용하면 객체내부의 필드를 적절히 가공해서 외부에 제공할 수 있기 때문이다. getter와 setter가 생성자처럼 특별한 매서드인 것은 아니다. 그냥 이런 역할을 하는 매서드를 getter와 setter라고 부르는 것이다.

일반적으로 getter와 setter를 만들 때 지키는 규칙이 있다.

  • 매서드의 이름은 set /get 으로 시작한다.
  • 그 뒤에 가져오고자 하는 필드의 이름을 첫글자를 대문자로 바꿔 붙인다. ex) name 필드를 가져오면 getName
  • 만일 필드가 boolean 타입일 경우 get 대신 is 를 쓴다.

경우에 따라서 getter나 setter중 하나만 만들어도 좋다. 가장 좋은것은 getter와 setter가 아예 없고, 다른 객체로부터 필드를 완전히 숨기는 것이다.

 

다음글

2021.08.17 - [Java] - [Java 기본 문법] 7. 상속과 다형성