📔 학습한 내용을 정리하기 위해 작성하는 게시글입니다.
제어자(modifier)란 클래스와 클래스 멤버의 선언 시 사용하여 부가적인 의미를 부여하는 키워드를 의미한다.
객체 지향에서 정보 은닉(data hiding)이란 사용자가 굳이 알 필요가 없는 정보는 사용자로부터 숨겨야 한다는 개념이다.
그렇게 함으로써 사용자는 언제나 최소한의 정보만으로 프로그램을 손쉽게 사용할 수 있게 된다.
자바에서는 이러한 정보 은닉을 위해 접근 제어자(access modifier)라는 기능을 제공하고 있다.
접근 지정자는 1) 클래스 자체 또는 2) 클래스의 내부 구성 요소(멤버와 생성자) 앞에 위치하며, 말 그대로 각 요소의 접근 범위를 지정하는 제어자이다.
접근 지정자를 붙이는 곳
- 클래스
: 해당 클래스를 import 할 수 있는지 여부를 결정한다.- 생성자
: 해당 생성자를 호출해서 객체를 생성할 수 있는지 여부를 결정한다.- 필드
: 해당 필드를 참조할 수 있는지 여부를 결정한다.- 메서드
: 해당 메서드를 호출할 수 있는지 여부를 결정한다.
클래스의 접근 지정자는
public
ordefault
2가지만 가능하다.
멤버 및 생성자에는 다음과 같은 네 가지의 접근 지정자를 사용할 수 있다.
class Test {
public int a;
protected int b;
int c; //default 접근 지정자 자동 설정
private int d;
public void abc() {}
protected void bcd() {}
void cde() {} //default 접근 지정자 자동 설정
private void def() {}
}
클래스에서는 public
, default
접근 지정자만 사용할 수 있다.
쉽게 말해, class 키워드 앞에 public
이 붙어 있거나 붙어 있지 않거나(default)이다.
클래스를
default
로 정의하면 다른 패키지에서 임포트가 불가능해 사용할 수 없다.
private
는 자신의 클래스 내부에서만 사용할 수 있다. (즉, 같은 멤버끼리만 사용 가능 / 외부 클래스에서 사용 불가능)default
는 같은 패키지 안의 모든 클래스에서 사용할 수 있다.protected
는 같은 패키지의 모든 클래스, 다른 패키지의 자식 클래스 안에서 사용할 수 있다.public
은 동일 패키지의 모든 클래스, 다른 패키지의 모든 클래스에서 사용할 수 있다.접근 범위는 public > protected > default > private 순이다.
다른 클래스의 필드를 사용하기 위해서는 객체를 먼저 생성한 후에 사용해야 한다.
static 제어자는 클래스의 멤버(필드, 메서드, 내부 클래스)에 사용하는 제어자이다. static은 클래스의
또는 공통적인
이라는 의미이다.
클래스 멤버를 다른 클래스 내에서 사용하기 위해서는 가장 먼저 클래스의 객체를 생성해야 한다. 객체 안에 있을 때 사용할 수 있는 상태가 되는 멤버를 인스턴스 멤버(instance member)라고 한다.
인스턴스 멤버는 멤버 앞에 static
이 붙어 있지 않는 멤버를 말한다. 반면,static
이 붙어 있는 멤버를 정적 멤버(static member)라고 한다.
클래스명.멤버명
만으로 바로 사용할 수 있다는 것이다.static
제어자를 변수에 사용하면 해당 변수를 클래스 변수로 만들어 주고, 메서드에 사용하면 해당 메서드를 클래스 메서드로 만들어 준다.
static
제어자를 사용할 수 있는 대상
1. 메서드
2. 필드
3. 초기화 블록
인스턴스 변수는 하나의 클래스로 부터 생성되었더라도 각기 다른 값을 유지하지만, 클래스변수(static 멤버 변수)는 인스턴스에 관계 없이 같은 값을 갖는다. 하나의 변수를 모든 인스턴스가 공유하기 때문이다.
class A {
int m = 3; //객체 생성 후 사용 가능
static int n = 5; //객체 생성 없이 사용 가능
}
이러한 인스턴스 필드와 정적 필드는 각 필드 메모리의 저장 위치가 다르다.
인스턴스 필드는 스택 영역에 데이터의 위칫값을, 힙 영역에 실제 데이터 값을 저장한다. 반면, 정적 필드는 힙 영역에 데이터의 위치값을, 클래스 영역(메서드 영역)에 실제 데이터 값을 저장한다.
이러한 이유로 정적 필드는 객체 간 공유 변수의 성질을 가진다.
class A {
int m = 3; //인스턴스 필드
static int n = 5; //정적 필드
}
public class StaticField_1 {
public static void main(String[] args) {
A a1 = new A();
A a2 = new A();
//인스턴스 필드
a1.m = 5;
a2.m = 6;
System.out.println(a1.m);
System.out.println(a2.m);
//정적 필드
a1.n = 7;
a1.n = 8;
System.out.println(a1.n);
System.out.println(a2.n);
A.n = 9;
System.out.println(a1.n);
System.out.println(a2.n);
}
}
인스턴스 메서드와 정적 메서드는 모두 메모리의 첫 번째 영역에 위치한다. (인스턴스 메서드는 인스턴스 메서드 영역, 정적 메ㅔ서드는 클래스 내부에 존재함)
class A {
static void bcd() {
System.out.println("static 메서드");
}
}
//정적 메서드 활용1(권장)
A.bcd();
//정적 메서드 활용2(권장X)
A a = new A();
a.bcd();
static 멤버 변수와 static 메서드
대상 | 의미 |
---|---|
static 멤버변수 | - 모든 인스턴스에 공통으로 사용되는 클래스 변수 - 인스턴스를 생성하지 않고도 사용 가능 - 클래스가 메모리에 로드될 때 생성 |
static 메서드 | - 인스턴스를 생성하지 않고도 호출 가능 - 인스턴스 멤버들을 직접 사용할 수 없음 |
정적 메서드 내에서는 정적 필드 또는 정적 메서드만 사용할 수 있다.
정적 멤버(정적 필드, 정적 메서드)는 객체 생성 없이 사용할 수 있는 반면, 인스턴스 멤버(인스턴스 필드, 인스턴스 메서드)는 반드시 객체를 생성한 후에 사용해야 한다.
만일 정적 메서드 내에 인스턴스 멤버를 사용하면 결국 정적 메서드도 객체를 생성해야 동작한다.
→ 정적 메서드 내부에는 객체 생성 없이 사용할 수 있는 요소인 정적 멤버만 올 수 있다.
- 정적 메서드 내부에서는 클래스 내부에서 자신의 객체를 가리키는
this
키워드를 사용할 수 없다.- 인스턴스 메서드 내에서는 인스턴스 멤버와 정적 멤버 모두 사용 가능
일반적으로 인스턴스 필드의 초기화는 객체가 만들어지는 시점에서 이루어진다. (생성자 내에서 초기화)
하지만 정적 필드는 객체 생성 이전에도 사용할 수 있어야 하므로 생성자에서는 정적 필드를 초기화할 수 없다.
자바에서는 정적 필드를 초기화하기 위한 문법인 정적 초기화 블록static{}
을 제공한다.
static {
//클래스가 메모리에 로딩될 떄 실행되는 내용
}
class A {
int a;
static int b;
static { //static 초기화 블록
b = 5;
System.out.println("클래스가 로딩될 때 static block 실행");
}
A() {
a = 3; //인스턴스 필드의 초기화 위치
}
}
자바 가상 머신은 실행 클래스명.main()
을 호출해 main()
메서드를 실행한다.
이를 가능하게 하는 것이 static
키워드이다.
만일 main()
메서드가 인스턴스 메서드라면 자바 가상 머신이 객체를 생성하고, 객체의 참조 변수를 이용해 main()
메서드를 호출해야 한다.
<Do it! 자바 완전 정복>
http://www.tcpschool.com/java/java_modifier_accessModifier
https://live-for-myself.tistory.com/92
https://kephilab.tistory.com/53
https://88240.tistory.com/447
https://gptjs409.github.io/java/2019/08/22/modifier.html
https://rorobong.tistory.com/125?category=905121