Java

접근 제어자

자유와 규제

프로그래밍 도구의 기본적인 목표는 생각하는 것을 자유롭게 표현할 수 있도록 하는 것이다. 하지만 자유만으로는 부족하다. 프로그래밍은 작은 것에서 거대한 것, 단순한 것에서 복잡한 것, 단독 작업에서 협업으로 나아가게 된다. 이러한 변화를 수용하기 위해서는 다양한 규제가 필요해지게 된다. 우리 수업을 통해서 지금까지 경험한 대표적인 규제 중의 하나는 데이터 타입을 들 수 있겠다. 어떤 변수가 있을 때 그 변수에 어떤 데이터 타입이 들어있는지, 또 어떤 메소드가 어떤 데이터 타입의 데이터를 리턴하는지를 명시함으로써 사용하는 입장에서는 안심하고 변수와 메소드를 사용할 수 있게 된다. 물론 도구 설계자의 취향이나, 도구의 목적에 따라서 이러한 규제는 채택 되기도 하고, 배제 되기도 한다. 여기에 정답은 없다.

지금부터 배울 추상 클래스, final, 접근 제어자, 인터페이스 등은 바로 이 규제에 해당하는 것이다. 사려 깊은 규제라면 그것이 목적해야 하는 바는 분명해야 한다. 자유에 질서를 부여함으로서 자유를 촉진하는 것이다. 이번 시간에는 규제 중의 하나인 접근 제어자에 대해서 알아보자.

접근 제어자

접근 제어자는 클래스의 맴버(변수와 메소드)들의 접근 권한을 지정한다. 이게 무엇을 의미하는지는 아래의 코드를 보자.

package org.opentutorials.javatutorials.accessmodifier;
class A {
    public String y(){
		return "public void y()";
	}
	private String z(){
		return "public void z()";
	}
	public String x(){
		return z();
	}
}
public class AccessDemo1 {
	public static void main(String[] args) {
		A a = new A();
		System.out.println(a.y());
		// 아래 코드는 오류가 발생한다.
		//System.out.println(a.z());
		System.out.println(a.x());
	}
}

아래 코드는 실행된다.

System.out.println(a.y());

하지만 아래의 코드는 오류를 발생시킨다.

System.out.println(a.z());

오류의 내용은 아래와 같다.

Exception in thread "main" java.lang.Error: Unresolved compilation problem: 
    The method z() from the type A is not visible
	at org.opentutorials.javatutorials.accessmodifier.AccessDemo1.main(AccessDemo1.java:15)

즉 메소드 z에 접근 할 수 없다는 의미다. 메소드 z의 본체를 보자.

private String z(){
	return "public void z()";
}

메소드가 키워드 private으로 시작되고 있다. private은 클래스(A) 밖에서는 접근 할 수 없다는 의미다. 바로 이 private의 자리에 오는 것들을 접근 제어자(access modifier)라고 한다. 그럼 사용할 수 없는 메소드를 왜 정의하고 있는 것일까? 내부적으로 사용하기 위해서다. 다음 코드를 보자.

System.out.println(a.x());

메소드 x의 본체는 아래와 같다.

public String x(){
	return z();
}

접근 제어자가 public이기 때문에 호출 할 수 있다. 그리고 메소드의 내용을 보면 내부적으로 메소드 z를 호출하고 있다. 메소드 z는 정상적으로 호출된다. 왜냐하면 메소드 x와 메소드 z는 같은 클래스의 소속이기 때문이다. 따라서 메소드 x에서 z를 호출 할 수 있는 것이다.

접근 제어자를 사용하는 이유

접근 제어자는 매우 중요한 개념이다. 하지만 그 중요함은 기본적으로는 이해의 영역이지만 근본적으로는 공감의 영역이다. 규모있는 에플리케이션을 만드는 과정에서 경험하게 되는 수 많은 막장들로 인한 깊은 절망감을 경험해보지 않았다면 접근 제어자와 같은 개념들은 관념적인 것으로 치부되기 쉽다. 에플리케이션이 커진다는 것은 다른 말로 망가질 확률이 커진다는 의미와 같다. 특히 로직이 망가지는 첫번째 용의자는 사용자다. 즉 객체를 사용하는 입장에서 객체 내부적으로 사용하는 변수나 메소드에 접근함으로서 개발자가 의도하지 못한 오동작을 일으키게 되는 것이다.

 

이런 문제로부터 객체의 로직을 보호하기 위해서는 맴버에 따라서 외부의 접근을 허용하거나 차단해야 할 필요가 생긴다. 마치 은행이 누구나 접근 할 수 있는 창구와 관계자외에는 출입이 엄격하게 통제되는 금고를 구분하고 있는 이유와 같다.

접근 제어자를 사용하는 또 다른 이유는 사용자에게 객체를 조작 할 수 있는 수단만을 제공함으로서 결과적으로 객체의 사용에 집중 할 수 있도록 돕기 위함이다.

그럼 우리의 계산기를 좀 더 견고하고 사용하기 좋은 에플리케이션으로 만들어보자.

package org.opentutorials.javatutorials.accessmodifier;

class Calculator{
    private int left, right;
    
    public void setOprands(int left, int right){
        this.left = left;
        this.right = right;
    }
    private int _sum(){
        return this.left+this.right;
    }
    public void sumDecoPlus(){
        System.out.println("++++"+_sum()+"++++");
    }
    public void sumDecoMinus(){
    	System.out.println("----"+_sum()+"----");
    }
}
 
public class CalculatorDemo {
    public static void main(String[] args) {        
        Calculator c1 = new Calculator();
        c1.setOprands(10, 20);
        c1.sumDecoPlus();
        c1.sumDecoMinus();
    }
}

기존 코드와의 차이점은 아래와 같다.

실행 결과는 아래와 같다.

++++30++++
----30----

우선 인스턴스 필드인 left와 right가 private으로 지정되었다.

int left, right;

이 두개의 변수는 객체 외부에서 호출될 필요가 없다. 따라서 외부로부터 이 변수를 숨기기 위해서 접근 제어자로 private을 지정했다.

또한 메소드 _sum이 추가 되었는데 실제 계산은 이 메소드가 내부적으로 처리하고, 계산된 결과를 외부에 출력해주는 메소드는 sumDecoPlus, sumDecoMinus에서 처리한다.

이상과 같은 조치를 통해서 사용자가 접근하면 안되거나 접근 할 필요가 없는 맴버에 대한 접근을 규제할 수 있게 되었다. 어떤 맴버에 대한 접근을 허용할 것인가를 작업자의 판단에 달렸다.

세밀한 제어

접근 제어자는 public과 private외에도 두가지가 더 있다. protected과 default가 그것이다. protected는 상속 관계에 있다면 서로 다른 패키지에 있는 클래스의 접근도 허용한다. default는 접근 제어 지시자가 없는 경우를 의미하는데, 접근 제어자가 없는 메소드는 같은 패키지에 있고 상속 관계에 있는 메소드에 대해서만 접근을 허용한다. 아래 그림은 접근 제어자 별로 접근의 허용범위를 그림으로 나타낸 것이다. 안쪽에 있을수록 접근 통제가 삼엄하고, 밖에 있을수록 접근이 허용된다.  (출처)

 

  public protected default private
같은 패키지, 같은 클래스 허용 허용 허용 허용
같은 패키지, 상속 관계 허용 허용 허용 불용
같은 패키지, 상속 관계 아님 허용 허용 허용 불용
다른 패키지, 상속 관계 허용 허용 불용 불용
다른 패키지, 상속 관계 아님 허용 불용 불용 불용

위의 표는 매우 중요하다. 하지만 이걸 억지로 외우려하면 뇌를 혹사시키는 것이 된다. 필지가 제안하는 방법은 필자처럼 직접 코드를 작성해서 경우의 수를 완성해보는 것이다. 그리고 그 결과에 따라서 표를 작성해보면 좋을 것 같다. 무엇보다 애매한 것들에 대해서 직접 확인해보는 습관을 정착시키는 것도 좋은 일이다.

위의 관계는 필드(변수)에도 적용되기 때문에 변수를 위한 예제는 따로 언급하지 않겠다. 또한 클래스 맴버(static)에게도 적용된다. 궁금하면 직접 예제를 만들어보자.

클래스의 접근 제어자

지금까지는 클래스 맴버에 대한 접근 제어자를 살펴봤다. 이번에 살펴볼 것은 클래스의 접근 제어자다. 클래스도 접근 제어자가 있다. 클래스의 접근 제어자는 총 2개로 public과 default이다. default는 접근 제어자를 붙이지 않은 경우 default가 된다. 클래스의 접근 제어자는 패키지와 관련된 개념이다. 즉 접근 제어자가 public인 클래스는 다른 패키지의 클래스에서도 사용할 수 있고, default인 경우는 같은 패키지에서만 사용 가능하다.

두개의 클래스를 만들자. 각각의 클래스의 접근 지시자는 이름에 이미 암시되어 있다.

package org.opentutorials.javatutorials.accessmodifier.inner;
public class PublicClass {}
package org.opentutorials.javatutorials.accessmodifier.inner;
class DefaultClass {}

위의 클래스들과 같은 패키지에서 이 클래스들을 사용해보자. 문제 없다.

package org.opentutorials.javatutorials.accessmodifier.inner;
public class ClassAccessModifierInnerPackage {
    PublicClass publicClass = new PublicClass();
	DefaultClass defaultClass = new DefaultClass();
}

이번에는 다른 패키지에 있는 클래스에서 사용해보자.

package org.opentutorials.javatutorials.accessmodifier.outter;
import org.opentutorials.javatutorials.accessmodifier.inner.*;
public class ClassAccessModifierOuterPackage {
    PublicClass publicClass = new PublicClass();
	//DefaultClass defaultClass = new DefaultClass();
}

주석으로 처리한 부분은 오류가 발생한다. DefaultClass의 접근 제어자가 default이기 때문이다.

한가지 중요한 제약 사항이 있다. public 클래스가 포함된 소소코드는 public 클래스의 클래스 명과 소스코드의 파일명이 같아야 한다. 코드를 보자. 이 코드의 이름은 PublicNameDemo.java이다.

package org.opentutorials.javatutorials.accessmodifier.inner;
//public class PublicName {}
public class PublicNameDemo {}

주석처리된 부분은 오류가 발생한다. 퍼블릭 클래스의 이름과 소스코드의 이름이 일치하지 않기 때문이다. 그 말은 하나의 소스 코드에는 하나의 public 클래스가 존재 할 수 있다는 의미다.

수업을 마치며

접근 제어자는 그것이 무엇인지, 또 어떤 접근 제어자가 있는지 정도만 일단 알아두자. 그리고 당분간은 public과 private만 구분해서 사용만해도 더 안전하고 결고한 에플리케이션을 만들 수 있을 것이다. 다시 한번 강조 하지만 각박하게 외우지 말자. 느긋하게 이해하자. 충분한 이해는 암기의 양을 비약적으로 줄여준다.

댓글

댓글 본문
  1. nextLevel
  2. coster97
    재미따
  3. wwwqiqi
    똑같은 접근제어자들만 사용해서 새삼 다른 접근제어자들의 존재들을 새겨보는 강의였습니다. 완료
  4. Alan Turing
    09/13
  5. 너굴
    public = 모두 허용
    protected = 상속 받으면 부모 클래스만 허용
    default = 같은 패키지만 허용
    private = 같은 클래스만 허용

    위로 갈수록 아래 허용범위를 포함
  6. PassionOfStudy
    복습 4일차!
  7. 김은희
    20220615 완료
  8. 치키티타
    220613
  9. PassionOfStudy
    접근 제어자!
  10. 자바잡아
    22.05.03 접근제어자 실습 완료, 추후 복습 예정
  11. 20220427
  12. 모찌말랑카우
    22.02.17 완료
  13. aesop0207
    220208 Tue.
  14. 민둥빈둥
    22.02.08
  15. 행달
    22.02.06 완료!
  16. 드림보이
    2021.12.15. 접근 제어자 파트 수강완료
  17. syh712
    2021-12-09
    1. 접근 제어자
    public
    private - 같은 클래스 안에서만 접근 가능.

    2. 접근 제어자를 사용하는 이유
    객체의 로직을 보호하기 위해서는 맴버에 따라서 외부의 접근을 허용하거나 차단해야 할 필요.
    마치 은행이 누구나 접근 할 수 있는 창구와 관계자외에는 출입이 엄격하게 통제되는 금고를 구분하고 있는 이유와 같다.


    3. 세밀한 제어

    public protected default private
    같은 패키지, 같은 클래스 허용 허용 허용 허용
    같은 패키지, 상속 관계 허용 허용 허용 불용
    같은 패키지, 상속 관계 아님 허용 허용 허용 불용
    다른 패키지, 상속 관계 허용 허용 불용 불용
    다른 패키지, 상속 관계 아님 허용 불용 불용 불용


    4. 클래스의 접근 제어자
    접근 제어자가 public인 클래스는 다른 패키지의 클래스에서도 사용할 수 있고, default인 경우는 같은 패키지에서만 사용 가능하다.
    한가지 중요한 제약 사항이 있다. public 클래스가 포함된 소소코드는 public 클래스의 클래스 명과 소스코드의 파일명이 같아야 한다.

    **다시 한번 강조 하지만 각박하게 외우지 말자. 느긋하게 이해하자. 충분한 이해는 암기의 양을 비약적으로 줄여준다.
  18. 네제가해냈습니다
    211118
  19. IaaS
    2021.11.02 수강 완료
  20. H4PPY
    1101
  21. 미NI언
    10.15 완료
  22. 베이스박
    210826 학습완료. 감사합니다.
  23. super1Nova
    210825
  24. 이땅콩
    드디어 public, private, default, protected에 대해서 배웠네요.
    JAVA1 수업을 할 때부터 뭔지 참 궁금했는데 속 시원하게 해결됐네요!
  25. Eunyoung Eunice Kang
    2021.8.16(월) 완료
  26. 악어수장
    2021-5-13
  27. 악어수장
    2021-05-07 완료
  28. 하연주
    210209 완료
  29. 석동현
    안녕하세요
    세밀한제어 밑에 설명부붙 링크가 바뀌었는지, 이상한 페이지가 나옵니다
    http://www.noesispoint.com......htm
    확인부탁드려용 ㅎㅎ
  30. 김태현
    public
    - 아무데서나 불러다 쓸 수 있고

    protected
    같은 클래스 , 같은 패키지 사용
    // 상속해서 써야 한다.

    default
    같은 팩키지, 클래스 사용
    // 상속불가

    private
    // 같은 클래스 외에 사용금지
  31. EunSeok Kang
    어려웠지만 잘보고갑니다.
    20200812
  32. 김승민
    2020-04-21
    감사합니다~
  33. 퍼블릭은 전부가능 프로택티드는 다른패키지에서 상속되어졌을때까지 사용가능
    디폴트는 같은패키지에서 사용가능 프라이베이트는 같은 클래스에서 사용가능
  34. 대학생
    잘들었습니다. ~~ 책도 샀어용 정말감사하고 다른 것도 책으로 내주세요
  35. 허공
    감사합니다!
  36. PassionOfStudy
    191007(월) - (1)
    수강완료~
  37. 홍주호
    20190915 완료
  38. 다나가
    190904 - 수강완료~~
  39. doevery
    수강완료
  40. 소월
    // 서브클래스는 상속(extends)
  41. 6/17시작
    7월 3일 완료

    어렴풋이 이해했습니다. 2독할 때 다시 자세히 봐야겠네요 ㅎㅎ
  42. 랑그
    표를 만들어주셔서 이해에 도움이 좀 더 되네요 . 잘 들었습니다 .
  43. 라또마니
    접근 제어자 잘 들었습니다.
  44. j-graphy
    2019. 2. 21. 학습완료
  45. 호두
    고맙습니다
  46. 호두
    은행 비유는 정말 적절하네요
  47. 소스코드 == 파일
    하나의 파일에는 하나의 public 클래스만 정의해야한다는 뜻입니다
    대화보기
    • 모르겠다람쥐
      수업을 마치며 위쪽에 있는, 소스코드 이야기.. 뭔소린지 모르겠어요.
      public 클래스가 포함된 소스코드가 무슨말이죠??
    • Seong-Won Bae
      감사합니다.
    • 기수니
      정리가 싹 되었습니당
    버전 관리
    egoing
    현재 버전
    선택 버전
    graphittie 자세히 보기