static 키워드클래스를 정의할 때 static이라는 키워드와 함께 변수 혹은 메소드를 정의할 수 있다. static은 클래스에 고정되어 있다는 의미이다. static키워드가 붙은 변수와 메소드를 정적멤버 혹은 클래스멤버라고 한다. 정적 멤버의 특징은 다음과 같다.
클래스명.멤버병으로 사용한다.언급했다시피 정적멤버는 객체 생성없이 사용하며 모든 객체가 공유하므로 효율적인 것 같지만, 무분별한 사용은 프로그램의 성능을 저하시킨다. 정적멤버는 한번 로딩되면 프로그램이 종료될 때까지 메모리에 남아있기 때문이다.
정적멤버의 특징을 다음 예제를 통해 이해해보자.
// Sample클래스는 정적변수 정적메소드를 포함한다.
public class Sample {
static int x;
static void test1() {
System.out.println("정적 메소드 사용");
System.out.println("정적 변수 x의 값: " + x);
}
static void test2(int value) {
System.out.println(value);
}
}
public class StaticApp {
public static void main(String[] args) {
// Sample객체를 생성하지 않고도 해당 클래스의 변수와 메소드를 이용할 수 있다.
Sample.x = 10;
Sample.test1();
System.out.println();
// Sample객체 두 개를 생성 한 뒤 sample2객체의 정적변수x에 20을 대입했다.
Sample sample1 = new Sample();
Sample sample2 = new Sample();
sample2.x = 20;
// 정적멤버는 모든 객체가 공유하기 때문에 sample1.x와 sample2.x는 같은 값을 가진다.
sample1.test2(sample1.x); // 20 출력
sample2.test2(sample2.x); // 20 출력
}
}
출력
정적 메소드 사용
정적 변수 x의 값: 10
20
20
정적변수는 생성된 모든 객체가 공유한다. 즉, 정적변수에 저장된 값이 변경되면 그 정적변수를 갖는 모든 객체의 정적변수값이 변경된다는 의미이다. 그래서 생성된 객체들이 공통으로 가져야 하는 값을 정적변수로 정의한다.
다음 예제는 원을 정의한 클래스다. 원주율은 모든 원이 공통으로 가지는 값이므로 static키워드를 붙인 상수로 선언했다. 물론 필요에 따라 변수로 선언해도 된다.
public class Circle {
private double x;
private double y;
private double r;
public static final double PI = 3.14;
public Circle() { }
public Circle(double x, double y, double r) {
this.x = x;
this.y = y;
this.r = r;
}
public double round() {
return 2*Circle.PI*r;
}
// pow()메소드는 Math클래스의 정적 메소드이므로 Math객체 생성없이 바로 사용할 수 있다.
public double area() {
return Circle.PI*Math.pow(r, 2);
}
public void display() {
System.out.println("x좌표: " + x);
System.out.println("y좌표: " + y);
System.out.println("원의 둘레: " + round());
System.out.println("원의 넓이: " + area());
}
}
public class CircleApp {
public static void main(String[] args) {
Circle c1 = new Circle(10, 10, 5);
Circle c2 = new Circle(0, 0, 7);
c1.display();
System.out.println();
c2.display();
}
}
출력
x좌표: 10.0
y좌표: 10.0
원의 둘레: 31.400000000000002
원의 넓이: 78.5
x좌표: 0.0
y좌표: 0.0
원의 둘레: 43.96
원의 넓이: 153.86
정적메소드는 유틸리티 클래스에서 주로 사용된다. 유틸리티 클래스의 메소드들은 멤버변수와 상호작용이 없고, 여러 객체에서 자주 사용하는 기능들이다. 즉, 메소드가 인스턴스 변수를 필요로 하지 않고 객체의 속성과 무관하게 메소드를 사용하고자 한다면 정적메소드로 정의한다.
유틸리티 클래스는 위의 예제에서 활용했던 java.lang.Math클래스를 포함하여 ava.util.Arrays, java.util.Collections, java.util.Objects 등이 있다.
또한 정적메소드는 인스턴스멤버를 사용할 수 없다. 정적멤버는 클래스가 로딩될 때 항상 존재하지만 인스턴스멤버는 로딩 후, 객체가 생성되어야 존재한다. 따라서 인스턴스멤버가 존재하는 시점에 정적멤버는 반드시 존재하지만, 정적멤버가 존재하는 시점에는 인스턴스멤버는 존재하지 않을 수도 있다. 이러한 이유로 정적메소드는 인스턴스멤버를 사용할 수 없다.
클래스가 Static영역에 로딩되면 그 클래스가 포함하는 정적멤버는 Static영역의 일부분에 따로 할당된다. 그리고 최초로 클래스가 로딩되었을 때 포함하던 정적멤버는 사라진다. 다음은 이 과정을 도식화한 것이다.

Sample객체를 생성하는 코드가 컴파일되는 즉시 Sample클래스가 Static영역에 로딩된다.
Sample클래스의 정적멤버들이 따로 할당된다.
Sample객체들이 생성되고 각각 참조변수sample1과 sample2에 그 주소값이 대입된다. 생성된 객체들은 정적멤버를 공유한다.