[자바 무료 강의] 접근 제어 지시자 - 캡슐화 - 코드라떼
Lesson List button
코스자바로 배우는 프로그래밍
hamburger button
강의접근 제어 지시자 - 캡슐화최종수정일 2021-11-21
아이콘약 5분

코드는 혼자 작성할 수도 있지만 현업에서는 여러 명이서 같이 일을 합니다. 여러 명이서 일을 할 때 코드 작성자의 의도를 파악해야 하는 경우가 있는데요. 접근 제어 지시자를 통해 자신이 만든 코드를 캡슐화할 수 있습니다.

추가 노트

1. 접근 제어 지시자


접근 제어 지시자를 이용하여 클래스, 변수, 메서드의 접근을 가능하게 하거나 하지 못하도록 할 수 있습니다.

  • 접근 - 클래스, 변수, 메서드의 접근을

  • 제어 - 제어 할 수 있는

  • 지시자 - 키워드

그렇다면 왜 클래스, 생성자, 변수, 메서드를 접근 가능하게 하거나 하지 못하도록 해야 할까요? 이 부분은 깊고 깊은 소프트웨어 설계 관점에서 생겼습니다.


캡슐화를 하는 이유

캡슐 안에 들어간 내용물을 보호하고 숨기기 위해서(정보은닉) 내부에서 사용하는 클래스를 노출하지 않거나 클래스 내부에서만 사용하는 메서드가 외부에 노출되지 않도록 숨기고 변수에 저장된 값이 외부에서 변하지 않도록 보호하기 위함입니다.


private 지시자

private 지시자는 생성자, 변수, 메서드에 선언할 수 있고, 기능은 클래스 내부에서만 접근할 수 있도록 합니다.

class Person {
    private String name;

    Person(String name) {
        this.name = name;
    }

    private void think() {
        System.out.printf("%s는 생각한다\n", name);
    }

    void eat() {
        think();
        System.out.println("그리고 밥을 먹는다");
    }
}

private String name 변수는 클래스 내부에서만 접근할 수 있습니다.

private void think() 메서드는 클래스 내부에서만 접근할 수 있습니다.

Person person = new Person(“록카”);
person.name = “roka”; // name 변수에 접근할 수 없다.

person.think(); // 호출 할 수 없다.

default

default는 접근 제어 지시자를 선언하지 않은 순수한 클래스, 생성자, 변수, 메서드를 말하며, default는 클래스는 같은 패키지 내에서만 import가 가능하고 생성자도 같은 패키지 내에서만 생성자를 통해 인스턴스를 생성할 수 있습니다.

그리고 변수, 메서드도 같은 패키지 내에서만 접근이 가능합니다.


public 지시자

public 지시자는 클래스, 생성자, 변수, 메서드에 선언할 수 있고 모든 곳에서 접근 가능한 가장 열려있는 접근제어 지시자입니다.

public class Person {
    public String name;

    public Person(String name) {
        this.name = name;
    }

    public void think() {
        System.out.printf("%s는 생각한다\n", name);
    }

    public void eat() {
        think();
        System.out.println("그리고 밥을 먹는다");
    }
}

public 지시자를 사용한다는 것은 누구나 사용해도 상관없을 만큼 안정화된 클래스, 생성자, 변수, 메서드에 선언합니다. public 지시자를 이용하는 것은 가급적 최소한으로 선언하는 것이 좋습니다.

이유는 현업에서는 여러 명이 하나의 프로젝트를 만들고 고쳐나가기 때문에 각각 범위를 정해서 코드를 작성하게 됩니다.

예시로, A라는 엔지니어가 Person 클래스를 만들고 B라는 엔지니어가 Job이라는 클래스를 만든다고 할 때

Person클래스와 Job클래스는 의존관계가 될 수도 있습니다.

B라는 엔지니어가 사용하지 말아야 할 Person 클래스의 변수나 메서드를 임의로 사용하는 경우가 발생하여 의도하지 않은 방향으로 갈 수 있습니다.

사이드 이펙트도 발생할 수 있습니다. (아직은 이해가 안 되실 겁니다)


protected 지시자

protected 지시자는 이후의 강의에서 배웁니다.


2. 접근제어 지시자 정리


접근 지시자

설명

사용할 수 있는 곳

public

모든 곳에서 접근 가능합니다. inner 클래스에서도 접근 가능

클래스, 생성자, 변수, 메서드

protected

일반적으론 같은 패키지가 아닌 다른 패키지 내에서 접근 불가합니다. 다만 다른 패키지라고 하더라도 상속으로는 접근 가능합니다.

생성자, 변수, 메서드

default

같은 패키지가 아닌 다른 패키지 내에서 접근 불가합니다.

클래스, 생성자, 변수, 메서드

private

클래스 내부에서만 접근 가능합니다.

inner 클래스, 생성자, 변수, 메서드

3. [실습해보기]


실습 코드에 이미 코드가 작성되어 있습니다.

하나씩 주석을 풀어 실행해봅시다.


1. default 생성자에 접근해보기

코드 작성(Main.java)

codelatte.defaultpkg.Coffee coffee = new codelatte.defaultpkg.Coffee("Coffee");

출력

codelatte/Main.java:9: error: Coffee is not public in codelatte.defaultpkg; cannot be accessed from outside package codelatte.defaultpkg.Coffee coffee = new codelatte.defaultpkg.Coffee("Coffee");

생성자가 default로 선언되어 있기 때문에 다른 패키지에 속해있는 Main.java에서는 Coffee 생성자를 선언할 수 없습니다.


2. private 변수에 접근해보기

코드 변경(Main.java)

codelatte.privatepkg.Coffee coffee = new codelatte.privatepkg.Coffee(Coffee");
System.out.println(coffee.name);

출력

codelatte/Main.java:15: error: name has private access in Coffee System.out.println(coffee.name); 1 error

privatepkg의 Coffee의 name 변수는 private 접근 제어 지시자가 선언되어 있으므로 직접 접근할 수 없습니다.


3. public 접근 제어 지시자로 접근해보기

코드 변경(Main.java)

codelatte.publicpkg.Coffee coffee = new codelatte.publicpkg.Coffee(Coffee");
System.out.println(coffee.name);

출력

Coffee

publicpkg의 Coffee의 name 변수는 public 접근 제어 지시자가 선언되어 있으므로 직접 접근할 수 있습니다.

도전자 질문
아이콘(2022-11-03 21:25 작성됨)
4:39
public 지시자 설명에서 질문입니다.

person.eat();
eat() 자체는 
public 지시자가 앞에 있어서
호출이 가능한 것은 이해가 됩니다.

다만 궁금한 것은
eat()를 호출하게 되면
think()를 호출하게 됩니다.

그런데,
think()는 
default 접근 제어 지시자가 있는 거라
과연
패키지가 다른 Main.java에서
think() 메세드를 
호출이 가능한지 의문이 들었습니다.

또다시 곰곰이 생각해보니
eat() 메서드는
클래스 내부의 think()를
호출하기 때문에
외부에서의 접근이 아니므로
가능하게 되는 건가요???
(올바르게 생각했는지 검토 부탁드립니다)


그렇다면
person.think();
를 하게되면 호출이 안 되지 않나요?

끝까지 읽어주셔서 감사드립니다.
아이콘코드라떼(2023-04-08 15:53 작성됨)
안녕하세요. 코드라떼입니다 :)

말씀하신대로 eat() 메서드에서 think() 메서드 호출은 외부에서 호출하는 것이 아니므로 상관없습니다.
그리고 외부에서 person.think() 메서드를 호출할 수는 없습니다.

외부에서 eat() 메서드를 호출하고 eat() 메서드가 think() 메서드를 호출한다면, 어떻게 생각해보면 결론적으로 외부의 호출로 인해 think() 메서드가 호출되는 것이 아닌가 헷갈릴 수 있지만 단순히 외부에서 명시적으로 호출되는 메서드에 대한 접근 가능 여부만 판단합니다.

감사합니다 :)
아이콘bng4535(2022-01-01 14:06 작성됨)
혹시 제가 임의로 package를 만들고 그 안에 java 파일을 만들고 컴파일을 하려고 하는데, 가장 처음 컴파일 했던 Main.java이 계속 컴파일이 됩니다. 임의로 컴파일 할 파일을 변경할 수 있을까요?
아이콘코드라떼(2022-01-01 14:32 작성됨)
안녕하세요. 코드라떼입니다 :)

어떤 방식으로 컴파일을 했는지에 따라 달라집니다. 에디터라면, 에디터에서 'Run' 버튼을 클릭하여 실행하면 일반적인 상황에선 프로젝트내에 있는 전체 파일을 컴파일 후 컴파일된 파일을 '자바 가상 머신'이 읽어서 실행됩니다.
좀 더 자세한 상황과 프로젝트 구조를 파악하기 위해 '도전하기'후 제공되는 오픈 채팅방에서 질문을 주시면 감사하겠습니다.

오픈 채팅방에서 스크린샷을 제공하여 질문하시면 좀 더 상세히 답변드릴 수 있습니다.

감사합니다.
이용약관|개인정보취급방침
알유티씨클래스|대표, 개인정보보호책임자 : 이병록
이메일 : cs@codelatte.io
사업자등록번호 : 824-06-01921
통신판매업신고 : 2021-성남분당C-0740
주소 : 경기도 성남시 분당구 대왕판교로645번길 12, 9층 24호
파일
파일파일
Root
파일

각 패키지에 있는 Coffee 클래스의 접근 제어 지시자들을 확인해보세요. Main.java에 있는 것을 주석을 하나씩 풀어봅시다.

Output
root$
Lesson List button
코스자바로 배우는 프로그래밍
hamburger button
강의접근 제어 지시자 - 캡슐화최종수정일 2021-11-21
아이콘약 5분

코드는 혼자 작성할 수도 있지만 현업에서는 여러 명이서 같이 일을 합니다. 여러 명이서 일을 할 때 코드 작성자의 의도를 파악해야 하는 경우가 있는데요. 접근 제어 지시자를 통해 자신이 만든 코드를 캡슐화할 수 있습니다.

추가 노트

1. 접근 제어 지시자


접근 제어 지시자를 이용하여 클래스, 변수, 메서드의 접근을 가능하게 하거나 하지 못하도록 할 수 있습니다.

  • 접근 - 클래스, 변수, 메서드의 접근을

  • 제어 - 제어 할 수 있는

  • 지시자 - 키워드

그렇다면 왜 클래스, 생성자, 변수, 메서드를 접근 가능하게 하거나 하지 못하도록 해야 할까요? 이 부분은 깊고 깊은 소프트웨어 설계 관점에서 생겼습니다.


캡슐화를 하는 이유

캡슐 안에 들어간 내용물을 보호하고 숨기기 위해서(정보은닉) 내부에서 사용하는 클래스를 노출하지 않거나 클래스 내부에서만 사용하는 메서드가 외부에 노출되지 않도록 숨기고 변수에 저장된 값이 외부에서 변하지 않도록 보호하기 위함입니다.


private 지시자

private 지시자는 생성자, 변수, 메서드에 선언할 수 있고, 기능은 클래스 내부에서만 접근할 수 있도록 합니다.

class Person {
    private String name;

    Person(String name) {
        this.name = name;
    }

    private void think() {
        System.out.printf("%s는 생각한다\n", name);
    }

    void eat() {
        think();
        System.out.println("그리고 밥을 먹는다");
    }
}

private String name 변수는 클래스 내부에서만 접근할 수 있습니다.

private void think() 메서드는 클래스 내부에서만 접근할 수 있습니다.

Person person = new Person(“록카”);
person.name = “roka”; // name 변수에 접근할 수 없다.

person.think(); // 호출 할 수 없다.

default

default는 접근 제어 지시자를 선언하지 않은 순수한 클래스, 생성자, 변수, 메서드를 말하며, default는 클래스는 같은 패키지 내에서만 import가 가능하고 생성자도 같은 패키지 내에서만 생성자를 통해 인스턴스를 생성할 수 있습니다.

그리고 변수, 메서드도 같은 패키지 내에서만 접근이 가능합니다.


public 지시자

public 지시자는 클래스, 생성자, 변수, 메서드에 선언할 수 있고 모든 곳에서 접근 가능한 가장 열려있는 접근제어 지시자입니다.

public class Person {
    public String name;

    public Person(String name) {
        this.name = name;
    }

    public void think() {
        System.out.printf("%s는 생각한다\n", name);
    }

    public void eat() {
        think();
        System.out.println("그리고 밥을 먹는다");
    }
}

public 지시자를 사용한다는 것은 누구나 사용해도 상관없을 만큼 안정화된 클래스, 생성자, 변수, 메서드에 선언합니다. public 지시자를 이용하는 것은 가급적 최소한으로 선언하는 것이 좋습니다.

이유는 현업에서는 여러 명이 하나의 프로젝트를 만들고 고쳐나가기 때문에 각각 범위를 정해서 코드를 작성하게 됩니다.

예시로, A라는 엔지니어가 Person 클래스를 만들고 B라는 엔지니어가 Job이라는 클래스를 만든다고 할 때

Person클래스와 Job클래스는 의존관계가 될 수도 있습니다.

B라는 엔지니어가 사용하지 말아야 할 Person 클래스의 변수나 메서드를 임의로 사용하는 경우가 발생하여 의도하지 않은 방향으로 갈 수 있습니다.

사이드 이펙트도 발생할 수 있습니다. (아직은 이해가 안 되실 겁니다)


protected 지시자

protected 지시자는 이후의 강의에서 배웁니다.


2. 접근제어 지시자 정리


접근 지시자

설명

사용할 수 있는 곳

public

모든 곳에서 접근 가능합니다. inner 클래스에서도 접근 가능

클래스, 생성자, 변수, 메서드

protected

일반적으론 같은 패키지가 아닌 다른 패키지 내에서 접근 불가합니다. 다만 다른 패키지라고 하더라도 상속으로는 접근 가능합니다.

생성자, 변수, 메서드

default

같은 패키지가 아닌 다른 패키지 내에서 접근 불가합니다.

클래스, 생성자, 변수, 메서드

private

클래스 내부에서만 접근 가능합니다.

inner 클래스, 생성자, 변수, 메서드

3. [실습해보기]


실습 코드에 이미 코드가 작성되어 있습니다.

하나씩 주석을 풀어 실행해봅시다.


1. default 생성자에 접근해보기

코드 작성(Main.java)

codelatte.defaultpkg.Coffee coffee = new codelatte.defaultpkg.Coffee("Coffee");

출력

codelatte/Main.java:9: error: Coffee is not public in codelatte.defaultpkg; cannot be accessed from outside package codelatte.defaultpkg.Coffee coffee = new codelatte.defaultpkg.Coffee("Coffee");

생성자가 default로 선언되어 있기 때문에 다른 패키지에 속해있는 Main.java에서는 Coffee 생성자를 선언할 수 없습니다.


2. private 변수에 접근해보기

코드 변경(Main.java)

codelatte.privatepkg.Coffee coffee = new codelatte.privatepkg.Coffee(Coffee");
System.out.println(coffee.name);

출력

codelatte/Main.java:15: error: name has private access in Coffee System.out.println(coffee.name); 1 error

privatepkg의 Coffee의 name 변수는 private 접근 제어 지시자가 선언되어 있으므로 직접 접근할 수 없습니다.


3. public 접근 제어 지시자로 접근해보기

코드 변경(Main.java)

codelatte.publicpkg.Coffee coffee = new codelatte.publicpkg.Coffee(Coffee");
System.out.println(coffee.name);

출력

Coffee

publicpkg의 Coffee의 name 변수는 public 접근 제어 지시자가 선언되어 있으므로 직접 접근할 수 있습니다.

도전자 질문
아이콘(2022-11-03 21:25 작성됨)
4:39
public 지시자 설명에서 질문입니다.

person.eat();
eat() 자체는 
public 지시자가 앞에 있어서
호출이 가능한 것은 이해가 됩니다.

다만 궁금한 것은
eat()를 호출하게 되면
think()를 호출하게 됩니다.

그런데,
think()는 
default 접근 제어 지시자가 있는 거라
과연
패키지가 다른 Main.java에서
think() 메세드를 
호출이 가능한지 의문이 들었습니다.

또다시 곰곰이 생각해보니
eat() 메서드는
클래스 내부의 think()를
호출하기 때문에
외부에서의 접근이 아니므로
가능하게 되는 건가요???
(올바르게 생각했는지 검토 부탁드립니다)


그렇다면
person.think();
를 하게되면 호출이 안 되지 않나요?

끝까지 읽어주셔서 감사드립니다.
아이콘코드라떼(2023-04-08 15:53 작성됨)
안녕하세요. 코드라떼입니다 :)

말씀하신대로 eat() 메서드에서 think() 메서드 호출은 외부에서 호출하는 것이 아니므로 상관없습니다.
그리고 외부에서 person.think() 메서드를 호출할 수는 없습니다.

외부에서 eat() 메서드를 호출하고 eat() 메서드가 think() 메서드를 호출한다면, 어떻게 생각해보면 결론적으로 외부의 호출로 인해 think() 메서드가 호출되는 것이 아닌가 헷갈릴 수 있지만 단순히 외부에서 명시적으로 호출되는 메서드에 대한 접근 가능 여부만 판단합니다.

감사합니다 :)
아이콘bng4535(2022-01-01 14:06 작성됨)
혹시 제가 임의로 package를 만들고 그 안에 java 파일을 만들고 컴파일을 하려고 하는데, 가장 처음 컴파일 했던 Main.java이 계속 컴파일이 됩니다. 임의로 컴파일 할 파일을 변경할 수 있을까요?
아이콘코드라떼(2022-01-01 14:32 작성됨)
안녕하세요. 코드라떼입니다 :)

어떤 방식으로 컴파일을 했는지에 따라 달라집니다. 에디터라면, 에디터에서 'Run' 버튼을 클릭하여 실행하면 일반적인 상황에선 프로젝트내에 있는 전체 파일을 컴파일 후 컴파일된 파일을 '자바 가상 머신'이 읽어서 실행됩니다.
좀 더 자세한 상황과 프로젝트 구조를 파악하기 위해 '도전하기'후 제공되는 오픈 채팅방에서 질문을 주시면 감사하겠습니다.

오픈 채팅방에서 스크린샷을 제공하여 질문하시면 좀 더 상세히 답변드릴 수 있습니다.

감사합니다.
이용약관|개인정보취급방침
알유티씨클래스|대표, 개인정보보호책임자 : 이병록
이메일 : cs@codelatte.io|운영시간 09:00 - 18:00(평일)
사업자등록번호 : 824-06-01921|통신판매업신고 : 2021-성남분당C-0740
주소 : 경기도 성남시 분당구 대왕판교로645번길 12, 9층 24호(경기창조혁신센터)
파일
파일파일
Root
파일

각 패키지에 있는 Coffee 클래스의 접근 제어 지시자들을 확인해보세요. Main.java에 있는 것을 주석을 하나씩 풀어봅시다.

Output
root$