본문 바로가기
프로그래밍언어/Java

06-6 패키지와 접근 제한자

by 스꼬맹이브로 2021. 2. 23.
728x90
반응형
SMALL

프로젝트를 개발하다 보면 적게는 수십 개, 많게는 수백 개의 클래스를 작성해야 한다.

이 대 클래스를 체계적으로 관리하지않으면 클래스 간의 관계가 뒤엉켜서 복잡하고 난해한 프로그램이 되어 결국 유지 보수가 어려워 진다. 때문에 자바에서는 패키지(package)를 사용하여 클래스를 체계적으로 관리한다.

 

패키지의 물리적인 형태는 파일 시스템의 폴더이지만, 폴더 기능만 하는 것이 아니라 클래스의 일부분으로 클래스를 유일하게 만들어주는 식별자 역할을 한다.

즉, 클래스 이름이 동일하더라도 패키지가 다르면 다른 클래스로 인식한다.

클래스의 전체 이름은 '패키지 이름+클래스 이름'인데 패키지가 상, 하위로 구분되어 있다면 도트(.)를 사용하여 '상위패키지.하위패키지.클래스'로 표현한다.

 

예를 들어, 다음과 같은 패키지가 구성되어 있다고 가정해보자.

A클래스의 전체 이름은 com.mycompany.A이고 B클래스의 전체 이름은 com.yourcompany.B가 된다.

 

<패키지 선언>

패키지 선언 : 클래스를 작성할 때 해당 클래스가 어떤 패키지에 속할 것인지를 선언하는 것

//선언 방법
package 상위패키지.하위패키지;

public class ClassName{...}

예를 들어 Car 클래스가 com.mycompany 패키지에 속해야 한다면 다음과 같이 작성한다.

//Car 클래스 선언
package com.mycompany;

public class Car{...}

크래스만 따로 복사해서 다른 곳으로 이동하면 클래스는 사용할 수 없기 때문에 패키지는 클래스의 일부이다.

 

패키지 이름은 개발자가 임의대로 지어주면 되지만, 지켜야 할 몇 가지 규칙이 존재한다.

  1. 숫자로 시작해서는 안 되고 _,$를 제외한 특수 문자를 사용해서는 안된다.
  2. java로 시작하는 패키지는 자바 표준 API에서만 사용하므로 사용해서는 안된다.
  3. 모두 소문자로 작성하는 것이 관례이다.

*참고*

여러 개발 회사가 함께 참여하는 대규모 프로젝트나 다른 회사의 패키지를 이용해서 개발할 경우 패키지 이름이 중복될 수 있으므로 흔히 회사의 도메인 이름으로 패키지를 생성하여 사용한다.

 

▶import문

사용하고자 하는 클래스 또는 인터페이스가 다른 패키지에 소속되어 있다면, import문으로 해당 패키지의 클래스 또는 인터페이스를 가져와 사용할 것임을 컴파일러에게 알려줘야한다.

//import문 작성 방법
import 상위패키지.하위패키지.클래스이름;

//패키지 안의 모든 클래스를 import하는 방법
import 상위패키지.하위패키지.*;

import문은 패키지 선언과 클래스 선언 사이에 작성하며, 개수에 제한이 없고 얼마든지 추가 가능하다.

 

<접근 제한자>

접근제한자(Access Modifier) : 접근을 제한하기 위해 사용

 * 여기서의 접근은 클래스 및 인터페이스 그리고 이들이 가지고 있는 멤버의 접근을 말한다.

 

[접근제한자 종류와 의미]

  • public 접근 제한자 : 외부 클래스가 자유롭게 사용할 수 있음
  • protected 접근 제한자 : 같은 패키지 또는 자식 클래스에서 사용할 수 있음
  • default 접근 제한자 : 같은 패키지에 소속된 클래스에서만 사용할 수 있음
  • private 접근 제한자 : 외부에서 사용할 수 없음

 

<클래스의 접근 제한>

클래스를 선언할 때 해당 클래스를 같은 패키지 내에서만 사용할 것인지, 아니면 다른 패키지에서도 사용할 수 있도록 할 것인지 결정해야 한다. 클래스는 public, default 접근 제한을 가질 수 있다.

//default 접근 제한
class 클래스 {...}

//public 접근 제한
public class 클래스 {...}

▶ default 접근 제한

클래스를 선언할 public을 생략했다면 클래스는 default 접근 제한을 가짐

→ 같은 패키지에서는 아무런 제한 없이 사용할 수 있지만 다른 패키지에서는 사용할 수 없음.

 

▶public 접근 제한

클래스를 선언할 때 public 접근 제한자를 붙였다면 클래스는 public 접근 제한을 가짐

같은 패키지뿐만 아니라 다른 패키지에서도 아무런 제한 없이 사용 가능

인터넷으로 배포되는 라이브러리 클래스는 모두 public 접근 제한을 가지고 있음

 

<생성자의 접근 제한>

객체를 생성하기 위해서는 new 연산자로 생성자를 호출하는데, 어디에서나 호출할 수 있는 것은 아니다.

생성자가 어떤 접근 제한을 갖느냐에 따라 호출 가능 여부가 결정되며, public, protected, default, private 접근 제한을 가질 수 있다.

public class ClassName{
  //public 접근 제한
  public ClassName(...){...}
  
  //protected 접근 제한
  protected ClassName(...){...}
  
  //default 접근 제한
  default ClassName(...){...}
  
  //private 접근 제한
  private ClassName(...){...}
}

각 접근 제한의 의미는 다음과 같다.

  • public 접근 제한
    : 모든 패키지에서 아무런 제한 없이 생성자를 호출할 수 있도록 한다.
  • protected 접근 제한
    : default와 마찬가지로 같은 패키지에 속하는 클래스에서 생성자를 호출할 수 있도록 한다.
    차이점은 다른 패키지에 속한 클래스가 해당 클래스의 자식(child)클래스라면 생성자를 호출할 수 있다.
  • default 접근 제한
    : protected와 마찬가지로 같은 패키지에 속하는 클래스에서 생성자를 호출할 수 있도록 한다.
  • private 접근 제한
    : 동일한 패키지든 다른 패키지든 상관없이 생성자를 호출하지 못하도록 제한한다.

생성자를 선언하지 않을 시 자동으로 생성되는 기본 생성자는 클래스의 접근 제한과 동일하다.

 

<필드와 메소드의 접근 제한>

필드와 메소드를 선언할 때 해당 필드와 메소드를 ①클래스 내부에서만 사용할 것인지, ②패키지 내에서만 사용할 것인지, 아니면 ③다른 패키지에서도 사용할 수 있도록 할 것인지를 결정해야 한다.

이것은 필드와 메소드가 어떤 접근 제한을 갖느냐에 따라 결정된다.

 

필드와 메소드는 public, protected, default, private 접근 제한을 가질 수 있다.

//필드 선언
[public | protected | private] [static] 타입 필드;

//메소드 선언
[public | protected | private] [static] 리턴 타입 메소드(...) {...};
  • public 접근 제한 
    : 모든 패키지에서 아무런 제한 없이 필드와 메소드를 사용할 수 있도록 한다.
  • protected 접근 제한 
    : default와 마찬가지로 같은 패키지에 속하는 클래스에서 필드와 메소드를 사용할 수 있도록 한다.
    차이점은 다른 패키지에 속한 클래스가 해당 클래스의 자식(child)클래스라면 필드와 메소드를 사용할 수 있다.
  • default 접근 제한 
    : protected와 마찬가지로 같은 패키지에 속하는 클래스에서 필드와 메소드를 사용할 수 있으나 다른 패키지에서는 사용할 수 없도록 한다.
  • private 접근 제한
    : 동일한 패키지든 다른 패키지든 상관없이 필드와 메소드를 사용하지 못하도록 제한한다.

<Getter와 Setter 메소드>

일반적으로 객체 지향 프로그래밍에서는 객체의 필드를 객체 외부에서 직접적으로 접근하는 것을 막는데, 그 이유는 외부에서 마음대로 변경할 경우 객체의 무결성이 깨질 수 있기 때문이다.

(예를 들어, 자동차의 속력은 음수가 될 수 없는데 외부에서 음수로 변경 시 객체의 무결성이 깨짐)

 

이러한 문제점을 해결하기 위해 객체 지향 프로그래밍에서는 메소드를 통해서 필드를 변경하는 방법을 선호한다.

필드는 외부에서 접근할 수 없도록 막고 메소드는 공개해서 외부에서 메소드를 통해 필드에 접근하도록 유도한다.

그 이유는 메소드는 매개값을 검증해서 유효한 값만 객체의 필드로 저장할 수 있기 때문이다.

이러한 역할을 하는 메소드가 Setter이다.

 

예를 들어, 자동차의 속도를 setSpeed() 메소드로 변경할 경우 다음과 같이 검증 코드를 작성할 수 있다.

void setSpeed(double speed){
  //매개값이 음수일 경우 speed 필드에 0으로 저장하고, 메소드 실행 종료
  if(speed<0){
    this.speed = 0;
    return;
  } else {
    this.speed = speed;
  }
}

외부에서 객체의 데이터를 읽을 때도 메소드를 사용하는 것이 좋다.

왜냐하면 필드값을 직접 사용하면 부적절한 경우도 있기 때문이다. 이런 경우 메소드로 필드값을 가공한 후 외부로 전달한다. 이런 메소드가 Getter이다.

 

예를 들어, 자동차의 속도를 마일에서 km 단위로 환산해서 외부로 리턴해주는 getSpeed() 메소드를 다음과 같이 작성할 수 있다.

double getSpeed(){
  double km = speed*1.6;
  return km;
}

클래스를 선언할 때 가능하면 필드를 private로 선언해서 외부로부터 보호하고, 필드에 대한 Setter와 Getter 메소드를 작성해서 필드값을 안전하게 변경하고 사용하는 것이 좋다.

 

예를 들어 stop필드의 Getter와 Setter는 다음과 같이 작성할 수 있다.

private boolean stop;

//Getter
public boolean isStop(){
  return stop;
}

//Setter
public void setStop(boolean stop){
  this.stop = stop;
}

 

728x90
반응형
LIST

'프로그래밍언어 > Java' 카테고리의 다른 글

07-2 타입 변환과 다형성  (0) 2021.03.09
07-1 상속  (0) 2021.02.25
06-5 인스턴스 멤버와 정적 멤버  (0) 2021.02.17
06-4 메소드  (0) 2021.02.15
06-3. 생성자  (0) 2021.02.08