자바의 제어자에는 접근 제어자와 기타 제어자가 있고, 이번 포스팅에서는 자주 쓰이는 기타 제어자인 static, final, abstract에 대해 중점적으로 알아보려고 한다.
제어자의 정의와 접근 제어자에 관해서는 다음 포스팅을 참고하면 된다.
https://nueahx7674.tistory.com/49
static
static 은 '클래스의' 또는 '공통적인'의 의미를 가지고 있다. 인스턴스 변수는 하나의 클래스로 부터 생성되었더라도 각기 다른 값을 유지하지만, 클래스변수(static 멤버 변수)는 하나의 변수를 모든 인스턴스가 공유하여 인스턴스에 관계 없이 같은 값을 갖는다.
static이 붙은 멤버변수와 메서드, 그리고 초기화 블럭은 인스턴스가 아닌 클래스에 관계된것이기 때문에 인스턴스를 생성하지 않고도 사용할 수 있는 특징이 있다.
예시와 함께 static 변수를 살펴보겠다.
class HouseLee {
String lastname = "이";
}
public class Sample {
public static void main(String[] args) {
HouseLee lee1 = new HouseLee();
HouseLee lee2 = new HouseLee();
}
}
이씨 집안을 나타내는 HouseLee 클래스이다. 위와 같은 클래스를 만들고 객체를 생성하면 객체마다 객체변수 lastname을 저장하기 위한 메모리가 별도로 할당된다. 하지만 가만히 생각해 보면 HouseLee 클래스의 lastname은 어떤 객체이던지 동일한 값인 "이" 이어야 할 것이다. 이렇게 항상 값이 변하지 않는 경우라면 static 사용시 메모리의 이점을 얻을 수 있다.
class HouseLee {
static String lastname = "이";
}
public class Sample {
public static void main(String[] args) {
HouseLee lee1 = new HouseLee();
HouseLee lee2 = new HouseLee();
}
}
위와 같이 lastname 변수에 static 키워드를 붙이면 자바는 메모리 할당을 딱 한번만 하게 되어 메모리 사용에 이점이 있다.
그리고 메모리 사용 이외에도 static을 사용하는 또다른 이유는 공유이다. static 으로 설정하면 같은 곳의 메모리 주소만을 바라보기 때문에 static 변수의 값을 공유하게 되는 것이다.
class Counter {
static int count = 0;
Counter() {
count++; // count는 더이상 객체변수가 아니므로 this를 제거하는 것이 좋다.
System.out.println(count); // this 제거
}
}
public class Sample {
public static void main(String[] args) {
Counter c1 = new Counter();
Counter c2 = new Counter();
}
}
이 코드를 실행하면 결과값은 1 2 의 순서로 출력된다. count값이 공유되어 순서대로 증가한 것이다.
그리고 함수 앞에 static 제어자를 붙이면 static 메서드가 된다.
class Counter {
static int count = 0;
Counter() {
count++;
System.out.println(count);
}
public static int getCount() {
return count;
}
}
public class Sample {
public static void main(String[] args) {
Counter c1 = new Counter();
Counter c2 = new Counter();
System.out.println(Counter.getCount()); // 스태틱 메서드는 클래스를 이용하여 호출
}
}
메서드 앞에 static 키워드를 붙이면 Counter.getCount() 와 같이 객체 생성없이 클래스를 통해 메서드를 직접 호출할 수 있다. 보통 스태틱 메서드는 유틸리티성 메서드를 작성할 때 많이 사용된다. 예를 들어 "오늘의 날짜 구하기", "숫자에 콤마 추가하기" 등의 메서드를 작성할 때에는 클래스 메서드를 사용하는 것이 유리하다. 이 때 스태틱 메서드 안에서는 객체변수 접근이 불가능 하다.
static 멤버의 제약 조건
- static 메서드는 오직 static 멤버만 접근할 수 있다.
static 메서드는 객체가 생성되지 않은 상황에서도 사용이 가능하므로 객체에 속한 인스턴스 메소드, 인스턴스 변수 등을 사용할 수 없다. - static 메서드에서는 this 키워드를 사용할 수 없다.
this는 호출 당시 실행 중인 객체를 가리키는 레퍼런스이다. 따라서 객체가 생성되지 않은 상황에서도 클래스 이름을 이용하여 호출이 가능한 static 메서드는 this를 사용할 수 없다.
static vs non-static
- non-static 멤버
- 멤버는 객체마다 별도로 존재하며, 인스턴스 멤버 라고 부른다.
- 객체 생성 시에 멤버가 생성되어 사용할 수 있는 상태가 되며, 객체가 사라지면 멤버도 사라진다.
- 멤버는 객체 내에 각각의 공간을 유지하여, 공유되지 않는다.
- static 멤버
- 멤버는 클래스당 하나가 생성된다. 멤버는 객체 내부가 아닌 별도의 공간에 생성된다.
- 클래스 로딩 시에 멤버가 생성된다.
객체가 생기기 전에 이미 생성되므로, 객체를 생성하지 않고도 사용할 수 있다. 멤버는 프로그램이 종료될 때 사라진다. - 동일한 클래스의 모든 객체들에 의해 공유된다.
JVM과 Static
자바에서 main 메서드는 static이다. 그 이유는 JVM이 인스턴스가 없는 클래스의 main()을 호출해야하기 때문이다. JVM이 main 메서드를 호출하는 과정은 다음과 같다.
- 코드를 실행하면 컴파일러가 .java 코드를 .class(byte code)로 변환한다.
- 클래스 로더가 .class파일을 메모리 영역(Runtime Data Area)에 로드한다.
- Runtime Data Area 중 Meathod Area(= Class area = Static area)라고 불리는 영역에 Class Variable이 저장되는데, static 변수 또한 여기에 포함된다.
- JVM은 Meathod Area에 로드된 main()을 실행한다.
final
final 은 '마지막의' 또는 '변경될 수 없는'의 의미를 가지고 있으며 거의 모든 대상에 사용 될 수 있다. 변수나 메서드 또는 클래스가 '변경 불가능'하도록 만드는 것이다.
abstract
abstract는 '미완성'의 의미를 가지고 있어, 메소드의 선언부만 작성하고 실제 수행내용은 구현하지 않은 추상메소드를 선언하는데 사용한다. 클래스, 메소드에 붙을 수 있다.
abstract class AbstractTest { //추상클래스(추상메서드를 포함한 클래스)
abstract void move(); //추상메서드(구현부가 없는 메서드)
}
제어자의 조합
- 메서드에 static과 abstract를 함께 사용할 수 없다.
- 클래스에 abstract와 final을 동시에 사용할 수 없다.
- abstract메서드의 접근 제어자가 private일 수 없다.
- 메서드에 private와 final을 같이 사용할 필요는 없다.
'Computer Science > Java' 카테고리의 다른 글
String, StringBuilder, StringBuffer의 차이 (0) | 2023.04.10 |
---|---|
동일성과 동등성 (0) | 2023.04.10 |
원시 타입과 참조 타입 (1) | 2023.04.10 |
접근 제어자 (1) | 2023.04.10 |
자바 컬렉션 프레임워크 - List, Set, Map (0) | 2023.03.30 |