Java

[인프런] 접근 제어자

sejin2 2024. 5. 22. 17:54

접근제어자

자바는 public, private 같은 접근 제어자를 제공한다. 접근 제어자를 사용하면 해당 클래스 외부에서 특정 필드나 메서드에 접근하는 것을 허용하거나 제한할 수 있다. 

package access;

public class Speaker {
    int volume;

    Speaker(int volume) {
        this.volume = volume;
    }

    void volumeUp() {
        if(volume >= 100) {
            System.out.println("음량을 증가할 수 없습니다. 최대 음량입니다.");
        } else {
            volume += 10;
            System.out.println("음량을 10 증가합니다.");
        }
    }

    void volumeDown() {
        volume -= 10;
        System.out.println("volumeDown 호출");
    }

    void showVolume() {
        System.out.println("현재 음량 : " + volume);
    }
}

생성자를 통해 초기 음량 값을 지정할 수 있다. volumeUp ( ) 메서드는 음량을 한 번에 10씩 증가시키고, 100을 넘게 되면 더 이상 음량이 증가하지 않는다.

public class SpeakerMain {
    public static void main(String[] args) {
        Speaker speaker = new Speaker(90);
        speaker.showVolume();

        speaker.volumeUp();;
        speaker.showVolume();

        speaker.volumeUp();
        speaker.showVolume();
    }
}

public class SpeakerMain {
    public static void main(String[] args) {
        Speaker speaker = new Speaker(90);
        speaker.showVolume();

        speaker.volumeUp();;
        speaker.showVolume();

        speaker.volumeUp();
        speaker.showVolume();

        // 필드에 직접 접근
        System.out.println("volume 필드 직접 접근 수정");
        speaker.volume = 200;
        speaker.showVolume();
    }
}

위에 코드 처럼 Speaker의 메서드와 필드에도 직접 접근이 가능하다. 
volumUp ( ) 메서드에서 음량이 100을 넘지 못하도록 해놓았지만 소용이 없다. 현재 Speaker를 사용하는 입장에서 volume 필드에 직접 접근해서 원하는 값을 설정할 수 있기 때문이다. 
그러므로 volume 필드를 Speaker 클래스 외부 접근을 막을 수 있는 방법이 필요하다. 

private int volume;

voulme 필드 앞에 private을 붙여주면, 해당 클래스 안에서만 volume필드에 접근할 수 있게 된다. 
다른 곳에서는 접근할 수 없다. 
private 접근 제어자는 모든 외부 호출을 막는다. 따라서 private이 붙은 경우 해당 클래스 내부에서만 호출할 수 있다.

기존에 작성한 코드를 실행해보면 voulme필드에 private을 붙여주었기 때문에, 아래와 같은 컴파일 오류가 발생한다. 

접근 제어자 종류

자바는 4가지 종류의 접근 제어자를 제공한다.

  • private : 모든 외부 호출을 막는다.
  • default (package private ) : 같은 패키지 안에서 호출은 허용한다. ( 아무것도 적지 않으면 default )
  • protected : 같은 패키지 안에서 호출은 허용한다. 패키지가 달라도 상속 관계의 호출은 허용한다.
  • public : 모든 외부 호출을 허용한다. 

순서대로 private이 가장 많이 차단하고, public이 가장 많이 허용한다.
private -> default -> protected -> public

package-private
접근 제어자를 명시하지 않으면 같은 패키지 안에서 호출을 허용하는 default 접근 제어자가 적용된다.
default라는 용어는 해당 접근 제어자가 기본값으로 사용되기 때문에 붙여진 이름이지만, 실제로는 package-private이 더 정확한 표현이다. 왜냐하면 해당 접근 제어자를 사용하는 멤버는 동일한 패키지 내의 다른 클래스에서만 접근이 가능하기 때문이다. 

접근 제어자 사용 위치
접근 제어자는 필드와 메서드, 생성자에 사용한다.
추가로 클래스 레벨이도 일부 접근 제어자를 사용할 수 있다. 

접근 제어자의 핵심속성과 기능을 외부로부터 숨기는 것이다.
- private 은 나의 클래스 안으로 속성과 기능을 숨길 때 사용, 외부 클래스에서 해당 기능을 호출할 수 없다.
- default는 나의 패키지 안으로 속성과 기능을 숨길 때 사용, 외부 패키지에서 해당 기능을 호출할 수 없다.
- protected는 상속 관계로 속성과 기능을 숨길 때 사용, 상속 관계가 아닌 곳에서 해당 기능을 호출할 수 없다.
- public은 기능을 숨기지 않고 어디서든 호출할 수 있게 공개한다. 

접근 제어자 사용 -  필드, 메서드

public class AccessData {

    public int publicField;
    int defaultField;
    private int privateField;

    public void publicMethod() {
        System.out.println("publicMethod 호출 : " + publicField);
    }

    void defaultMethod() {
        System.out.println("defaultMethod 호출 : " + defaultField);
    }
    
    private void privateMethod() {
        System.out.println("privateMethod 호출 : " + privateField);
    }
    
    public void innerAccess() {
        System.out.println("내부 호출");
        publicField = 100;
        defaultField = 200;
        privateField = 300;
        publicMethod();
        defaultMethod();
        privateMethod();
    }
}

해당 클래스 내부에서는 모두 필드와 메서드 모두 접근이 가능하다. 

public class AccessInnerMain {
    public static void main(String[] args) {
        AccessData data = new AccessData();
        // public 호출 가능
        data.publicField = 1;
        data.publicMethod();

        //같은 패키지 default 호출 가능
        data.defaultField = 2;
        data.defaultMethod();

        // private 호출 불가
        data.privateField = 3;
        
        data.innerAccess();
    }
}

패키지가 다를 경우 default 호출 불가 ! 

public class AccessOuterMain {
    public static void main(String[] args) {
        AccessData data = new AccessData();
        // public 호출 가능
        data.publicField = 1;
        data.publicMethod();

        // 다른 패키지 default 호출 불가
        // data.defaultField = 2;
        // data.defaultMethod();

        // private 호출 불가
        // data.privateField = 3;
        // data.privateMethod();

        data.innerAccess();
    }
}

AccessData.innerAccess( ) 메서드는 public 이므로 외부에서 호출이 가능하다.
외부에서 호출이 되었지만 해당 메서드 안에서는 자신의 private 필드와 메서드에 접근할 수 있다. 

생성자도 접근 제어자 관점에서 메서드와 같다. 

접근 제어자 사용 - 클래스 레벨

  • 클래스 레벨의 접근 제어자는 public, default만 사용할 수 있다.
    • private, protected는 사용할 수 없다. 
  • public 클래스는 반드시 파일명과 이름이 같아야 한다.
    • 하나의 자바 파일에 public 클래스는 하나만 등장할 수 있다.
    • 하나의 자바 파일에 default 접근 제어자를 사용하는 클래스는 무한정 만들 수 있다. 
package access.a;

public class PublicClass {
    public static void main(String[] args) {
        PublicClass publicClass = new PublicClass();
        DefaultClass1 class1 = new DefaultClass1();
        DefaultClass2 class2 = new DefaultClass2();
    }
}

class DefaultClass1 {

}

class DefaultClass2 {

}

패키지 위치는 package access.a이로, 패키지 위치를 꼭 맞추어야 한다.
PublicClass라는 이름의 클래스를 pubic 접근 제어자로 만든다. 파일명과 이 클래스의 이름이 반드시 같아야 한다. 
DefaultClass1, DefaultClass2는 default 접근제어자로, 같은 패키지 내부에서만 접근할 수 있다.
PublicClass는 public 접근 제어로 어디서든 사용할 수 있고, DefaultClass1, DefaultClass2와는 같은 패키지에 있으므로 사용할 수 있다. 

 

 

공부 내용: [인프런] 김영한의 실전 자바 - 기본편

'Java' 카테고리의 다른 글

[인프런] 자바 메모리 구조  (0) 2024.05.25
[인프런] 캡슐화  (0) 2024.05.22
[인프런] 패키지  (0) 2024.05.22
[인프런] 생성자, this  (0) 2024.05.21
[인프런] 객체 지향 프로그래밍  (0) 2024.05.21