안녕하세요, 여행벌입니다.
오늘은 static 선언을 이용한 클래스 변수, 클래스 메소드의 정의 방법 및 특징에 대해서 알아보겠습니다.
클래스 변수 (static 변수)
지난 포스팅부터 계속 등장하던 '인스턴스 변수'는 인스턴스가 생성되었을 때, 생성된 인스턴스 안에 존재하는 변수입니다. 그러나 '클래스 변수'는 인스턴스의 생성과 상관없이 존재하는 변수입니다.
"클래스 변수는 클래스를 정의할 때 생성되는 변수입니다.
따라서, 클래스 변수는 선언된 클래스의 모든 인스턴스가 공유하게 됩니다."
같은 의미로 클래스 변수는 인스턴스 내에 존재하는 변수가 아니라 '어떠한 인스턴스에도 속하지 않는 상태로 클래스 정의시 메모리 공간에 딱 하나만 존재하게 되는 변수' 라고도 표현할 수 있습니다.
클래스 변수도 저번 포스팅에서 다루었던 '접근 수준 지시자'의 규칙을 그대로 적용받기 때문에 public으로 선언되면 어디서든 접근이 가능하고 아래와 같이 default 로 선언되면 같은 패키지 내에서만 접근이 가능합니다. 그럼, 클래스 변수의 특징을 예제를 통해서 익혀보도록 하겠습니다.
package Hello;
class Example{
static int n = 0;
public void printN() {
System.out.println("현재 n : " + n);
}
}
public class test{
public static void main(String args[]) {
Example ex1 = new Example();
ex1.n++;
ex1.printN();
Example.n++;
ex1.printN();
}
}
클래스 변수 n과 n의 값을 출력해주는 메소드를 가지고 있는 클래스 Example을 만들고, 인스턴스를 생성해 n의 값을 1 증가시켜주고 출력을 진행했습니다. 그 후, Example.n++; 명령어를 수행하고 다시 한 번 메소드를 통해 n의 값을 출력했습니다. 결과는 다음과 같습니다.
결과는 다음과 같습니다.
"Example.n 과 같이 클래스 변수는 클래스의 이름을 통해서도 접근이 가능한 것을 알 수 있습니다."
package Hello;
class Example{
static int n = 0;
public void printN() {
System.out.println("현재 n : " + n);
}
}
public class test{
public static void main(String args[]) {
Example ex1 = new Example();
ex1.n++;
ex1.printN();
Example.n++;
ex1.printN();
Example ex2 = new Example();
ex2.printN();
}
}
이번에는 인스턴스를 하나 더 생성하고 클래스 변수의 특징을 알아보겠습니다. ex2 라는 인스턴스를 하나 더 만든 후, n의 값을 출력해보았습니다.
다른 인스턴스인 ex2 에서 n 의 값을 출력해도 ex1의 n의 값과 동일한 것을 확인할 수 있습니다.
"클래스 변수는 모든 인스턴스가 공유하는 변수인 것을 확인할 수 있습니다."
따라서 자연스럽게 우리는 클래스 변수가 인스턴스의 생성과 상관이 없는 것을 알 수 있습니다. 그럼, 클래스 변수는 언제 메모리에 할당되고 초기화가 될까요??
다음 예제를 확인해보겠습니다.
package Hello;
class Example{
static int n = 0;
public void printN() {
System.out.println("현재 n : " + n);
}
}
public class test{
public static void main(String args[]) {
Example.n++;
Example ex1 = new Example();
ex1.printN();
}
}
이번에는 인스턴스 생성하기 전에 클래스 명을 이용해 클래스 변수에 접근했습니다. 결과는 다음과 같습니다.
인스턴스를 생성하기도 전에 클래스 변수에 접근해 1을 증가시키는 코드가 제대로 작동한 것을 확인할 수 있습니다. 즉, 클래스 변수는 인스턴스 생성 이전에 메모리 공간에 존재하는 것을 확인할 수 있습니다.
"클래스 변수는 클래스가 정의되는 순간 메모리 공간에 할당되고 초기화됩니다."
그럼 클래스 변수는 언제 사용하면 좋을까요?? 모든 인스턴스가 참조해야하는 값이지만, 인스턴스가 각각 지녀야할 필요는 없을 때 클래스 변수를 이용하면 됩니다. 예를 들어, 환율과 관련된 클래스를 정의할 때, 모든 인스턴스가 각각 현재 환율을 저장하고 있을 필요는 없습니다. 따라서, 환율을 static으로 선언해 클래스 변수로 만들어 놓는다면 메모리를 아낄 수 있습니다.
클래스 메소드 (static 메소드)
클래스 메소드는 클래스 변수와 마찬가지로 메소드에 static 선언이 들어간 것을 의미합니다. 또, 동일하게 인스턴스 생성 이전부터 접근이 가능하고 어느 인스턴스에 속하지 않습니다.
package Hello;
class Example{
static int n = 0;
public void printN() {
System.out.println("현재 n : " + n);
}
public static void staticPrintN() {
System.out.println("현재 n : " + n);
}
}
public class test{
public static void main(String args[]) {
Example.n++;
Example.staticPrintN();
}
}
클래스 변수와 마찬가지로 인스턴스 생성과 관계없이 클래스 명으로 접근할 수 있고, 결과는 아래와 같습니다.
그럼 클래스 메소드는 어떤 경우에 사용하면 좋을까요?? 다음과 같은 경우에는 클래스 메소드로 정의하는 것이 더 좋습니다.
외부에 기능을 제공하기 위한 메소드
인스턴스 변수의 값을 참조하거나 수정하지 않는 메소드 / 인스턴스 메소드를 호출하지 않는 메소드
하나씩 왜 클래스 메소드로 사용하면 좋은지 생각해보겠습니다.
먼저, 오로지 기능을 제공하기 위한 메소드는 인스턴스 생성이 따로 필요없이 우리는 메소드(기능)만 이용하면 됩니다. 따라서, 클래스 메소드로 선언하는 것이 더 현명합니다. 우리가 자주 사용하면 Math 클래스는 기능 제공을 위한 목적으로 만들어진 클래스입니다. 따라서, 메소드와 변수들이 모두 Static으로 선언되어있습니다.
package Hello;
import java.lang.Math.*;
public class test{
public static void main(String args[]) {
System.out.println(Math.PI); // Math클래스의 PI static 변수
Syttem.out.println(Math.abs(-1)); // Math클래스의 abs static 메소드
}
}
그 다음으로, 클래스 메소드는 인스턴스 변수의 값을 참조하거나 수정하지 않아야 되고 인스턴스 메소드를 호출하면 안된다고 했습니다. 그 이유는 간단합니다. 클래스 메소드는 인스턴스 생성과 상관 없이 참조할 수 있습니다. 하지만, 인스턴스 변수는 인스턴스 생성 시 선언되는 변수이므로 클래스 메소드에서 인스턴스 변수를 참조하거나 수정하면 에러가 날 수 밖에 없습니다. 마찬가지로 인스턴스 메소드도 인스턴스 생성 전까지 선언되지 않으므로 참조할 수 없습니다.
Static 초기화 블록
위에서 클래스 변수는 모든 인스턴스가 공유해야하는 상황에서 유용하게 사용할 수 있다고 했습니다. 그럼, 클래스 변수는 어떻게 초기화를 해야될까요?? 생성자를 이용해서 초기화를 하면 인스턴스 생성 시 초기화가 진행되므로, 적절하지 않습니다. 따라서 자바에서는 "Static 초기화 블록" 을 지원해줍니다.
class example{
static String date;
static {
LocalDate today = LocalDate.now();
date = today.toString();
}
}
다음과 같이 static 초기화 블록을 사용하면 클래스 변수를 선언과 동시에 초기화 할 수 있고, 클래스 로딩 시 단 한 번 실행됩니다.
'Computer Language > JAVA' 카테고리의 다른 글
[JAVA] #13 자바 String 클래스 특징 및 메소드 정리(1) (0) | 2020.05.28 |
---|---|
[JAVA] #12 자바 메소드 오버로딩(Method Overloading) (0) | 2020.05.28 |
[JAVA] #10 자바 접근 수준 지시자(public, protected, private, default) (0) | 2020.05.26 |
[JAVA] #9 자바 클래스 생성자(Constructor) (0) | 2020.05.26 |
[JAVA] #8 자바 클래스, 메소드란 무엇인가 (1) | 2020.05.25 |