글 작성자: beaniejoy

 Java에서 OOP개념에 들어가면 public, private, ... 등을 많이 볼 수 있다. 이들은 접근한정자(Access Modifier)라고 부른다. 정확한 정의는 아니지만 본인이 생각하기에 말 그대로 객체를 생성할 때나 클래스 자체를 사용하고 싶을 때 해당 클래스 내부의 정보들을 이용하는데 있어 제한할 수 있는 기능을 가지고 있다. 이번 시간에는 이런 접근한정자(한정자도 포함해서)들에 대해서 공부한 내용을 정리해보고자 한다.


Notice.java / package java_20191122.aa

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
 
// public class가 아니라 아무것도 없는 default라면
// 같은 패키지 내에서만 사용가능, 다른 곳에서는 접근 불가
public class Notice {
    
    // class가 default라면 그 안의 모든 내용들은 default or private만 가능
    public int number;
    protected String title;
    int hit;
    private String regdate;
    
    public void n(){
        
    }
    
    // 선언을 아래에 해도 적용되는 것은 class 전체에 해당
    // 위치가 중요하지 않다.
    // 가독성을 위해 원래하던대로!
    private int temp;
 
    public static void main(String[] args) {
        
        // 같은 class 내에서는 다 가능
        Notice n = new Notice();
        n.number = 10;
        n.title = "title";
        n.hit = 100;
        n.regdate = "2019-11-22";
    }
}
 

 

 같은 클래스 안에서는 public, protected, private, default 저부다 사용 가능하다.

 

 같은 클래스 내에서는 모든 접근한정자를 자유롭게 사용할 수 있다.

 

 

NoticeDemo.java / package java_20191122.aa

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 
public class NoticeDemo {
 
    public static void main(String[] args) {
        Notice n = new Notice();
        n.number = 10;
        n.title = "title";
        n.hit = 100;
 
        // 같은 패키지 내에서도 private 접근 불가
        // private variable이기에 불가능
        // n.regdate = "2019-11-22";
    }
}
 

 

 NoticeDemo 클래스는 위의 Notice 클래스와 같은 패키지 안에 있는 클래스다.

같은 패키지 안에서는 public, protected, default는 접근 가능하지만 private은 접근 불가능하다.

private은 같은 Class안에서만 접근이 가능하기에 그 이외의 다른 클래스에서는 접근 불가능하다는 것을 기억하자.

 

 

NoticeDemo2.java / package java_20191122.bb

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
 
// Notice class가 public이기에 가능
// 서로 다른 package의 class를 사용하기 위해서는 반드시 import 해야한다.
 
public class NoticeDemo2 extends Notice {
    // 중요!
    public static void main(String[] args) {
        // 서로 다른 패키지에서 class를 사용하려면
        // import package 해야한다.
        Notice n = new Notice();
        n.number = 10;
 
        // public variable을 제외하고 나머지는 싹다 안된다.
        // n.title = "title"; => 직접 Notice로 protected를 접근X
        // n.hit = 100;
        // n.regdate = "2019-11-22";
 
        // 다른 패키지의 Notice class를 상속받음
        // public인 number와 protected인 title 접근 가능
        // protected 접근 가능하다.
        NoticeDemo2 nc = new NoticeDemo2();
        nc.number = 10;
        nc.title = "title";
        // 상속을 받은 NoticeDemo2를 통해 protected 접근은 가능
 
        System.exit(0);
    }
}
 

 

 위의 두 클래스는 aa 패키지에 속해 있는 것들이었다. 지금 NoticeDemo2 클래스는 위의 두 개의 클래스와 다른 패키지에 속해 있는데 여기에는 어떤 한정자가 접근 가능한지 보고자 한다.

 

 public은 어디에서나 자유롭게 접근 가능하기에 다른 패키지에서도 접근 가능하고 private은 가장 폐쇄적이기에 다른 패키지에서는 접근 불가능하다. default는 같은 패키지 안에서만 접근 가능하기에 다른 패키지에서는 사용 불가능하다.

 

 다른 패키지에서 중요하게 봐야할 접근 한정자는 protected다. protected는 같은 패키지에서는 접근 가능하다는 점에서 default와 유사하다. 하지만 결정적인 차이점은 protected는 다른 패키지에 있더라도 이것을 상속받은 클래스 객체를 통해서 접근 가능하다는 것이다.

 

 상속받은 클래스 객체를 통해 protected 한정자를 받아서 사용가능하지만 꼭 상속받은 클래스의 객체여야 한다는 점을 유의해야한다. NoticeDemo2 클래스를 보면 다른 패키지에 있는 Notice 클래스의 protected 맴버변수 title을 바로 접근했을 때는 에러가 발생한다. 하지만 NoticeDemo2가 Notice를 상속받았기 때문에 NoticeDemo2의 객체를 만들어 title에 접근하는 것은 가능하다.

 

 ≫ 정리하자면

 

· public

패키지, 클래스 상관없이 자유롭게 사용 가능. 범위가 제일 넓다.

 

· private

같은 Class 안에서만 사용 가능. 범위가 제일 좁다.

 

· protected

같은 패키지 안에서만 사용가능

그리고 이것을 상속받은 Class의 객체는 다른 패키지더라도 사용 가능

 

· default

같은 패키지 안에서만 사용 가능

 

  같은 Class 내 같은 package 다른 package (상속관계) 서로 다른 package
public 가능 가능 가능 가능
protected 가능 가능 가능 불가능
default 가능 가능 불가능 불가능
private 가능 불가능 불가능 불가능

static

 

 - static 맴버변수: 클래스 변수

 - static method: 클래스 메서드

 

1) instance variable / method: 각 객체가 생성될 때마다 각 객체의 고유한 변수(메서드)로 사용, 객체마다 고유값을 가진다.

  객체를 통해서 접근

2) class variable / method: 하나의 클래스에 있는 클래스변수(메서드)를 모든 객체들이 공유

  객체, 클래스를 통해서 접근가능하지만 클래스이름을 통해서 접근하는 것을 권장

 

StaticDemo.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package java_20191125;
// 중요
// static은 class의 객체를 생성하기 전에 생성
// 그래서 static method안에서 instance variable을 사용X
public class StaticDemo {
    static String name;
    int age;
 
    public void m1() {
        name = "Lee"// instance method 안에서는
        age = 10// 다 가능하다.
        m2();
        m4();
    }
 
    public void m2() {
        System.out.println("instance method m2()");
    }
 
    public static void m3() {
        // 객체가 생성되기도 전에 static이 생성이 되기 때문
        // this를 사용할 수 없음
        name = "Lee2"// static에서는 instance 호출 불가
        // age = 20; => instance variable 호출 불가
        // m2(); => instance method 호출 불가
        m4();
 
        // instance를 호출하고 싶으면 새로운 객체 생성
        StaticDemo sd = new StaticDemo();
        sd.age = 10;
        sd.m2();
    }
 
    public static void m4() {
        System.out.println("instance method m4()");
    }
 
}
 

 

 위의 코드를 예시로 들어보자. name은 static변수(class variable)이고 age는 객체변수(instance variable)이다다른 클래스에서 이 두개의 변수에 접근하고자 할 때 차이가 있다.

 

 ≫ 객체변수인 age는

     StaticDemo ex = new StaticDemo();

     ex.age = 10; (객체를 통해서만 접근)

 ≫ 클래스변수인 name은 

     StaticDemo.name = "BeanieJoy";

     (객체생성해서 객체이름으로도 접근가능하지만 클래스이름으로 접근하는 것을 권장)

 이런 식으로 접근해야 한다. 또한 static변수는 지정할 때마다 그 값을 모든 객체들이 공유하기에 만약 새로운 StaticDemo 객체인 ex2를 생성해서 name을 출력하면 "BeanieJoy"가 출력될 것이다.

 

 static 한정자가 나왔으니 static Initialization(Static 초기화)에 대해서 알아보자.

 

StaticInitializationDemo.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package java_20191126;
 
public class StaticInitializationDemo {
    int age; // instance variable
    static String title; // static variable
 
    // static initialization
    // 가장 먼저 호출이 된다.
    // 먼저 메모리에 올라온다. 그래야 main에서 사용
    // 딱 한번 호출, 초기화됨
    static {
        System.out.println("static block");
        title = "모기지론";
    }
 
    public StaticInitializationDemo(int age) {
        this.age = age; // instance variable 초기화
        System.out.println("constructor");
    }
 
    public static void main(String[] args) {
        System.out.println("main");
        new StaticInitializationDemo(10);
        new StaticInitializationDemo(20);
        new StaticInitializationDemo(30);
    }
}
 

 

 static 초기화는 말 그대로 static 변수(메서드)를 초기화하는 블럭을 의미한다. static 블럭안에 본인이 초기화하고 싶은 값을 static 변수에 할당하면 된다. (나중에 따로 다룰 예정)

 

 ≫ 특징

1) static 초기화는 단 한번만 작동한다. (객체를 계속 만들어도 가장 처음 단 한번만 실행됨)

2) static 한정자 변수, 메서드만 가능

3) 객체가 생성되기도 전에 가장 먼저 실행됨

StaticInitializationDemo.java 실행 결과

(static block이 가장먼저 출력)

 

 

final

 

 종단 변수라고도 부르며 final로 선언하고 초기화한 변수는 절대 변할 수 없는 상수값을 가지게 된다. final변수는 static처럼 단 한번 초기화하지만 static과 다르게 final 그 이후에도 값을 변경할 수 없는 고정값이 된다. 변수 뿐만 아니라 메서드나 클래스에도 사용가능한데 용도가 다르다. 

 

- final의 3가지 용도

1) 맴버변수 - 상수화(관례상 식별자는 대문자로만)

2) 메소드 - Overriding 금지

   (private 처리하는 방법도 있지만 Encapsulation을 위해 사용.)

3) 클래스 - 상속금지

 

 final을 사용할 때 보통 static과 같이 쓰는 것이 좋다. 그리고 final을 사용하는 변수의 식별자는 대문자만 사용하는 것이 좋다.


※ 정리

 

1) Class 접근한정자 : [public/ default] - [abstract/ final]

    private, protected는 inner class에서나 사용, 근데 별로 사용하지는 않는 것 같다.

 

2) 맴버변수: [public/ protected/ private] - [static/ (static)final]

 

3) 메서드: [public/default/protected/private] - [static/final/abstract/synchronized]

    (synchronized는 Thread 공부 때 자세히 알아보도록 하겠다.)