[Java] 접근 제어자(access modifier) - public, protected, ( default ), private

접근 제어자(access modifier)

 

 


 

 

멤버 또는 클래스를 외부에서 접근하지 못하도록 제한하는 역할을 한다.

 

접근 제어자가 지정되어 있지 않다면, 접근 제어자가 default이다.

default임을 알리기 위해 실제로 default를 붙이지 않는다.

 

접근 제어자가 사용될수 있는 곳은 클래스, 멤버변수, 메서드, 생성자 입니다.

 

 private  같은 클래스 내에서만 접근 가능하다.
 default  같은 패키지 내에서만 접근 가능하다. < -- 비추합니다.
 protected  같은 패키지 내에서, 그리고 다른 패키지의 자손클래스에서 접근이 가능하다.
 public  접근 제한이 전혀 없다.

 

 

 대상 사용가능한 접근 제어자 
 클래스   public, (default)
 메서드   public, protected, (default), private
 멤버변수
 지역변수   없음

 

 

 

 


 

 

접근 제어자를 이용한 캡슐화

 

접근 제어자를 사용하는 이유는 무엇인가!?

클래스의 내부에 선언된 데이터를 보호하기 위해서 입니다.

 

비밀번호와 같은 데이터를 외부에서 함부로 변경하지 못하도록 하기 위해서는 외부로부터의 접근을 제한하는 것이 필요하다.

이것을 데이터 감추기(data hiding)이라고 하며, 객체지향개념의 캡슐화(encapsulation)에 해당하는 내용이다.

 

또 다른 이유는 클래스 내에서만 사용되는, 내부 작업을 위해 임시로 사용되는 멤버변수나 부분작업을 처리하기 위한 메서드 등의 멤버들을 클래스 내부에 감추기 위해서이다.

외부에서 접근할 필요가 없는 멤버들을 private으로 지정하여 외부에 노출시키지 않음으로써 복잡성을 줄일 수 있다.

 

1. 외부로부터 데이터를 보호하기 위해

2. 외부에는 불필요한, 내부적으로만 사용되는, 부분을 감추기 위해

 

 

 


public class Test
{
    public static void main(String[] args) 
    {
        Time t = new Time(12, 35, 30);
        System.out.println(t);
        t.setHour(t.getHour() +1);
        System.out.println(t);
    }    
}

class Time
{
    private int hour;
    private int minute;
    private int second;
    
    Time(int hour, int minute, int second)
    {
        setHour(hour);
        setMinute(minute);
        setSecond(second);
    }
    
    public int getHour(){ return hour;}
    public void setHour(int hour)
    {
        if (hour < 0 || hour > 23) return ;    // 0~23의 값을 갖는 hour
        this.hour = hour;
    }
    public int getMinute(){ return minute;}
    public void setMinute(int minute){
        if(minute <0 || minute >59) return; // 0~59의 값을 갖는 minute
        this.minute = minute;
    }
    public int getSecond(){ return second;}
    public void setSecond(int second){
        if(second <0 || second > 59) return; // 0~59의 값을 갖는 second
        this.second = second;
    }
    
    public String toString()    //이건 오버라이딩인가?? 음.. ㅎ
    {
        return hour + ":" + minute +":" + second;
    }
}



 

 

 

* 아래 내용은 많이 중요합니다.

 

생성자 접근 제어자

 

생성자에 접근 제어자를 사용한다면 인스턴스의 생성 제한 할 수 있다.

 

생성자의 접근 제어자를 private으로 지정하면, 외부에서 생성자에 접근할 수 없으므로 인스턴스를 생성할 수 없게 된다. 그래도 클래스 내부에서는 인스턴스의 생성이 가능하다.

 

 

 


class Singleton
{
    private static Singleton s = new Singleton();    //getInstance()에서 사용될 수 있도록 인스턴스가 미리 생성되어야 하므로 static이어야 한다.
    private Singleton()
    {
    }
    
    //인스턴스를 생성하지 않고도 호출할 수 있어야 하므로 static이어야 한다.
    public static Singleton getInstance()
    {
        return s;
    }
}

 

이렇게 생성자를 통해 직접 인스턴스를 생성하지 못하게 하고, public 메서드를 통해 인스턴스에 접근하게 함으로써 사용할 수 있는 인스턴스의 개수를 제한할 수 있다.

 

생성자가 private인 클래스는 다른 클래스의 조상이 될 수 없다.

 

 

자손 클래스의 인스턴스를 생성할 때 조상클래스의 생성자를 호출해야만 하는데, 생성자의 접근 제어자가 private이므로 자손클래스에서 호출하는 것이 불가능 하기 때문이다.

 

 

Tip.

그래서 클래스 앞에 final을 더 추가하여 상속할 수 없는 클래스라는것을 알리는 것이 좋다.

 

 

Math클래스는 몇 개의 상수와 static메서드만으로 구성되어 있기 때문에 인스턴스를 생성할 필요가 없다. 그래서 외부로부터의 불필요한 접근을 막기 위해 다음과 같이 생성자의 접근 제어자를 private으로 지정한다.

 


public final class Math{
         private Math(){}
}

 


public class Test
{
    public static void main(String[] args) 
    {
//        Singleton s = new Singleton();    //Singleton()은 private이므로 접근할 수 없어요.
        Singleton s = Singleton.getInstance();
    }    
}

class Singleton
{
    private static Singleton s = new Singleton();    //getInstance()에서 사용될 수 있도록 인스턴스가 미리 생성되어야 하므로 static이어야 한다.
    private Singleton()
    {
    }
    
    //인스턴스를 생성하지 않고도 호출할 수 있어야 하므로 static이어야 한다.
    public static Singleton getInstance()
    {
        if(s == null)
        {
            s = new Singleton();
        }    return s;
    }
}

 

 

 

 

 

정리.

 대상 사용가능한 제어자 
 클래스 public, (default), final, abstract 
 메서드  모든 접근 제어자, final, abstract, static
 멤버변수  모든 접근 제어자, final, static
 지역변수  final


 

주의사항

 

 1. 메서드에 static과 abstract를 함께 사용할 수 없다.
 static메서드는 몸통이 있는 메서드에만 사용할 수 있기 때문이다.

 

 2. 클래스에 abstract와 final을 동시에 사용할 수 없다.
 클래스에 사용되는 final은 클래스를 확장할 수 없다는 의미이고,
 abstract는 상속을 통해서 완성되어야 한다는 의미이므로 서로 모순이 된다.

 

 

 

 

 

 

 

 

 

 

 

 3. abstract메서드의 접근 제어자가 private일 수 없다.
 abstract메서드는 자손클래스에서 구현해주어야 하는데 접근 제어자가 private이면,
 자손클래스에서 접근 할 수 없기 때문이다.

 

 

 

 

 

 4. 메서드에 private과 final을 같이 사용할 필요는 없다.
 접근 제어자가 private인 메서드는 오버라이딩될 수 없기 때문이다. 이 둘 주 하나만 사용해도 의미가 충분하다.

 

 


 

참고 서적

Java의 정석

http://book.naver.com/bookdb/book_detail.nhn?bid=4473030