JAVA 2011. 6. 17. 00:58
클래스의 기본적인 용도는 객체를 생성하는 것이고 , 클래스에 선언된 필드와 메소드는 객체를

생성하고나면 생성된 객체에 속하게 된다. 하지만 때로는 클래스 자체에 속하는 구성요소를 

선언해야 될 때도 있는데 그런 구성요소를 클래스의 정적(static) 구성요소라고 부른다.

정적 필드

일반적으로 필드는 객체의 고유한 데이터 값을 저장하기 위해 사용하지만 경우에 따라서는

클래스 자체에 속하는 데이터를 지정할 변수도 필요하다, 이럴 때 사용하는 것이 

정적 필드 (static field)  이다. 이 필드는 클래스 전체에서 사용가능하므로 클래스 내부

어디든 이 필드에 값을 넣을 수있지만, 일단 넣으면 그 값을 썻던 모든 곳이 새 값으로 교체된다.

public class staticExam {
int total = 0;
static int grandTotal = 0;
void staticExam(int value){
total += value;
grandTotal += value;
}
}

위 빨간 부분이 정적필드의 생성과 사용부분이다. 

total  필드는 객체마다 따로 생기지만 grandTotal 필드는 특정 객체에 상관없이 클래스 자체에 

하나만 생기는 정적 필드이다. 다음 소스로 정적필드의 특성을 알아보자.

class StaticFieldExam{
public static void main(String args[]){
staticExam se1 = new staticExam();
staticExam se2 = new staticExam();
se1.staticExam(10);
se2.staticExam(20);
System.out.println("se1.total :"+se1.total); 
System.out.println("se1.grandTotal :"+se1.grandTotal); 
System.out.println("se2.total :"+se2.total); 
System.out.println("se2.grandTotal :"+se2.grandTotal); 
}
}

이 프로그램을 보자, 우선 앞 소스인 staticExam을 인스턴스화하여 두가지 객체를 만들었다.

se1에는 staticExam 매소드에 10을 파라미터로 넘겼고, 그럼 

void staticExam(int value){
total += value;
        grandTotal += value;
}
 이 구문이 수행되어 total과 grandTotal에 10이 들어갈 것이다. 그리고 다시 제자리로 돌아가

다음줄인 se2에 20을 실어 메소드에 보내면 total은 인스턴스 필드기 때문에 20이란 새로운

필드가 만들어졌고 grandTotal은 클래스자체에 속하는 정적 필드기 때문에 아까 10과 지금의

20을 더하여 가지고 있는다. 결과를 보자

se1.total :10
se1.grandTotal :30
se2.total :20
se2.grandTotal :30

이렇게 나온다. total은 se1과 se2의 필드에 각각 들어가 있는 반면 grandTotal 필드에는 값이

누적되있다. 정적 필드는 클래스 자체에 속하기 때문에 앞에 객체 이름 대신 클래스 이름을 붙여서 

사용 할 수도있다.  staticExam.grandTotal; 이렇게 말이다

상수의 선언

정적필드에 final 키워드 까지 붙이면 크 필드는 소스 코드에서 주어진 초기값을 프로그램 실행중에

절대 바꿀 수 없게 된다. 그래서 자바에서는 상수를 사용하고 싶을 때는 final과 static을 모두 붙여

필드를 만들고 이를 상수 변수(constant variable) 라고 부른다. 상수는 변하지 않는 값을 말한다. 

public class staticfinal {
final static int LIMIT = 1000;
int value;
void setValue(int value){
if(value < LIMIT)
this.value = value;
else
this.value = LIMIT;
}
}

이런식으로 상수 변수를 만들었다.

class staticfinalExam2{
public static void main(String args[]){
staticfinal sf = new staticfinal();
sf.setValue(1010);
System.out.println("sf.value :"+sf.value); 
System.out.println("상한값  :"+staticfinal.LIMIT); 
}
}

이런식으로 1010을 파라미터로 넘기면 위 소스에서 1010 < 1000 이기 때문에

else로 빠지고 this.value엔 1000이 들어간다 . 결과값은

sf.value :1000
상한값  :1000

이렇다.

정적 메소드 

static을 붙여 만든 메소드를 정적 메소드(static method) 라고 한다. 예를 보자

public class staticMethod {
int total = 0;
static int grandTotal = 0;
void Method(int value){
total += value;
grandTotal += value;
}
static int getGrandTotal(){
return grandTotal;
}
이런식으로 정적 메소드를 선언 할 수 있다. 

class StaticMethodExam{
public static void main(String args[]){
staticMethod sm1 = new staticMethod();
staticMethod sm2 = new staticMethod();
sm1.Method(10);
sm2.Method(20);
int grandTotal = staticMethod.getGrandTotal();  //정적 메소드 호출
System.out.println("sm1.total :"+sm1.total); 
System.out.println("sm2.total :"+sm2.total); 
System.out.println("총계 :"+grandTotal); 
}
}
프로그램 소스를 보자, 우선 staticMethod클래스의 객체를 각각 sm1,sm2를 만들고

Method 메소드의 파라미터에 sm1은 10, sm2는 20을 넣었다. 그럼 우선 total에는

인스턴스 필드이기 때문에 sm1에는 10이 sm2에는 20이 들어 갈 것이다. 그리고 

그 값들은 차례로 정적 필드인 grandTotal에 쌓인다, 그리고 정적 메소드 getGrandTotal()

에서 grandTotal을 리턴하기 때문에 프로그램상에서 이 정적 메소드를 호출하면 

grandTotal이 리턴 값으로온다 , 즉 30이 리턴된다. 결과는 이렇다.

sm1.total :10
sm2.total :20
총계 :30


기능적인 메소드 선언에 유용한 정적 메소드

특정 객체에 종속되지 않고 기능을 수행하는 메소드를 기능적인 메소드라 할 수 있다. 그런 메소드는

정적 메소드로 선언하는 것이 좋다.

정적 초기화 블록

정적 필드는 특정 객체에 속하지 않기 떄문에, 생성자에서 초기값을 대입하면 안된다. 그렇기에

정적 필드의 초기값을 필드 선언문에서 대입할 수 없을 때에는  

정적 초기화 블록( static initialization 또는 static initializer)을 사용하여야 한다.


public class staticBlock {
static int arr[];
static{
arr = new int[100];
for(int i = 0; i < 100; i++){
arr[i] = i;
}
}
}

이런식으로 정적 초기화 블록을 선언해두면 자바 가상 기계는 이 클래스가 사용되기전에 한 번

이 블록 안의 명령문을 실행 한다. 그렇기 때문에 위 arr을 사용하기전에 이미 0~99를 채워 놓는다.

class staticExam{
public static void main(String args[]){
System.out.println(staticBlock.arr[20]); 
System.out.println(staticBlock.arr[15]); 
System.out.println(staticBlock.arr[67]); 
}
}

이렇게 하면 이미 채워 놓기 때문에 바로 찍혀나온다.

둘 이상의 정적 초기화 블록을 갖는 클래스 

한 클래스 안에 둘 이상의  정적 초기화 블록을 선언 할 수도 있는데 그러면 클래스 내에 쓰여진 

순서대로 수행을 하게 된다.

public class staticinit {
static int arr1[];
static{
arr1 = new int[10];
for(int i = 0; i < 10; i++){
arr1[i] = i+1;
}
}
static int arr2[];
static{
arr2 = new int[10];
for(int i = 0; i < 10; i++){
arr2[i] = (i+1) * 10000;
}
}
static int arr3[];
static{
arr3 = new int[10];
for(int i = 0; i < 10; i++){
arr3[i] = arr1[i] + arr2[i];
}
}
}

이런식으로 세가지 정적 초기화 블록이 있다면 

class staticExam{
public static void main(String args[]){
for(int i = 0; i < 10; i++){
System.out.println(staticinit.arr3[i]); 
}
}
}
이것을 실행 시켰을 때

10001
20002
30003
40004
50005
60006
70007
80008
90009
100010

이렇게 나온다. 이유는 첫번째 arr1이 1부터 10까지를, 두번째 arr2이 1000부터 10000까지를,

세번째 arr3이 이 둘을 더한 것을 출력한다. 마지막 arr3만 찍었는데 저렇게 나왔다는 것은,

이미 arr1과 arr2 가 수행 되었을 거란 것이고, 이는 정적 초기화 블록이 여러개 있다면 위에서부터

쓰여진 순서대로 계산이 된다라는 것을 알 수 있다.



static이 붙으면 클래스 모든 곳에서 넣는 값이 다 들어가서 뭣도 모를 때 자주 썼지만, 아마 이놈이

메모리를 많이 차지하는 것으로 알고 있다.. 쉽게말해 남용하면 안되는 놈이다 , 그래서 static을

한동안 안썼다.. 안쓰면 좋은거니까. 하지만 일을 하다보니 static없이 하면 코드가 더러워지는

경우가 있다.. 결과적으로 필요할 때 딱 써야되는데 그 '필요할 때'만 쓰기가 참 어렵다. 










출판사 : 한빛미디어 , 저자 : 김윤명 님의 뇌를 자극하는 Java프로그래밍에서 공부한 내용입니다.

'JAVA' 카테고리의 다른 글

JAVA] String 원하는 만큼 잘라내기  (0) 2011.08.04
JAVA] 21. 클래스의 상속  (0) 2011.06.22
JAVA] 19. 메소드  (0) 2011.06.15
JAVA] 18. 필드  (0) 2011.06.14
자바에서의 인스턴스란?  (1) 2011.06.13
posted by 젊은쎄오
: