스타크래프트의 마린(유닛)을 예로 들었습니다.

마린의 최고체력은 static을 붙여야겠죠. 현재체력은 붙이면 안되고요. 모든 마린들의 최고체력은 같으니까요. 현재체력은 마린(인스턴스)마다 다르겠죠. 마린의 공격력 역시 static을 붙여야겠죠? 모든 마린의 공격력은 같아야하니까요. 마린의 공격력을 향상시키는 upgradeWeapon()함수가 있다면 이 함수는 static변수인 마린의 공격력을 향상시키는 일을 한다고 가정하고요. 이 함수에는 static을 붙여야 합니다. 이 함수는 static변수에 대한 작업을 하니까요. 만일 마린의 체력을 소모시키는 steamPack()메서드에는 static을 붙일 수 있을까요? 붙일 수 없습니다. 현재체력을 감소시키는 일을 해야하니까... 인스턴스 변수에 대한 작업을 해야하니까요.

인스턴스라는 것 자체가, 별개의 것이라는 뜻이라고 이해하세요. static은 예외적으로 공통적이라는 의미를 갖습니다. 원칙적으로는 인스턴스들은 서로 개별적인 것이므로 서로 달라야하는데... 공통적으로 관리되어야하는 것에는 static을 붙입니다. 공통적으로 관리되어야하는 값을 static을 붙이지 않고 놔둔다면, 인스턴스마다 다른 값을 가질 가능성(오류의 가능성)이 있죠. 관리도 힘들고요.

클래스는 변수와 함수의 집합입니다. 같은 클래스에 있는 변수와 함수라면, 서로 깊은 관계가 있기 마련이죠... 같은 클래스의 함수는 보통 같은 클래스의 변수를 가지고 작업하는 경우가 많습니다.  여러분이 작성한 메서드가 인스턴스 변수에 대한 작업만을 한다면, 인스턴스 메서드(static이 안붙은 메서드)로 작성하시면 되고요. 메서드가 인스턴스 변수에 대한 작업을 하지 않거나, 인스턴스 메서드를 호출하는 경우가 아니라면, static으로 하는 것이 좋습니다. 반드시 그렇게 해야하는 것은 아닙니다. 인스턴스 메서드가 인스턴스를 생성해야만 사용할 수 있는 이유는 바로 이 때문입니다. 인스턴스 변수에 대한 작업을 해야하는데 인스턴스를 만들어야만 비로서 인스턴스 변수를 가지고 작업할 수 있기 때문에 인스턴스를 만들기 전에는 인스턴스 메서드를 호출할 수 없는 겁니다. 반면에 static메서드는 지역변수만으로 작업을 하거나 static변수(필요한 즉시 자동 생성)를 가지고 작업을 하기 때문에 인스턴스 생성없이도 호출이 가능한 것이지요. 쓰다보니 함수라는 용어와 메서드라는 용어를 섞어서 썼는데 둘다 같은 뜻으로 보시면 됩니다.

 결론... 여러분들이 클래스를 작성하실때... 멤버변수 중에 인스턴스마다 같은 값을 유지해야하는 경우 (위에서 말하는 마린의 최대체력)에는 static을 붙여서 모든 인스턴스가 같은 값을 공유하도록 합니다. 함수(메서드)의 경우... 함수내에서의 작업에 인스턴스 변수가 필요하다면(또는 인스턴스메서드를 호출하는경우) static을 붙이면 안됩니다. 그 외에는 static을 붙이시는 것이 좋습니다. 

static메서드는 컴파일시에 연결(early-binding)되기 때문에, 실행 시에 연결(late-binding)되는 인스턴스 메서드보다 더 빠릅니다. early-binding은 컴파일시에 이미 호출될 함수가 결정되기 때문에 실행시에 어떤 함수를 호출할 것인지 결정하는 시간을 줄일 수 있습니다. late-binding은 실행 시에 클래스 타입 체크(RTTI, Run-Time Type Identification)를 통해서 호출될 함수를 결정하기 때문에, 호출된 함수를 찾는 시간이 더 걸립니다. 실행 시 타입을 체크하는 것이 이러한 단점이 있기는 하지만 객체 지향 언어의 가장 큰 장점 중의 하나인 다형성을 가능하게 한다는 점에서 큰 의미를 가집니다.

클래스변수(static 변수)와 인스턴스 변수의 차이를 이해하기 위한 예로 카드 게임에 사용되는 카드를 클래스로 정의해보자. 

 

카드 클래스를 작성하기 위해서는 먼저 카드를 분석해서 속성과 기능을 알아 내야한다. 속성으로는 카드의 무늬, 숫자, 폭, 높이 정도를 생각할 수 있을 것이다. 이 중에서 어떤 속성을 클래스 변수로 선언할 것이며, 또 어떤 속성들을 인스턴스 변수로 선언할 것인지 생각해보자.

class Card { 
         String kind ; // 카드의 무늬 - 인스턴스 변수 
         int number; // 카드의 숫자 - 인스턴스 변수 
         static int width = 100 ; // 카드의 폭 - 클래스 변수 (static 변수) 
         static int height = 250 ; // 카드의 높이 - 클래스 변수 (static 변수)
  } 

각 Card인스턴스는 자신만의 무늬(kind)와 숫자(number)를 유지하고 있어야 하므로 이들을 인스턴스변수로 선언하였고, 각 카드들의 폭(width)과 높이(height)는 모든 인스턴스가 공통적으로 같은 값을 유지해야하므로 클래스변수로 선언하였다. 만일 카드의 폭을 변경해야할 필요가 있을 때는 모든 카드의 width값을 변경하지 않고, 한 카드의 width값만 변경해도 모든 카드의 width값이 변경되는 셈이다. 


출처: 자바의정석

'언어 > Java' 카테고리의 다른 글

[Java] mybatis 비교 및 범위 쿼리 사용시 주의할 점  (0) 2017.02.22
[Java] static 사용 예제  (0) 2017.02.10
[Java] 자바 용어 정리  (0) 2017.02.10

+ Random Posts