'자바 Basic/자바언어의핵심'에 해당되는 글 14건

  1. 2007.11.30 자바공부-13.클래스 변수와 클래스 메소드 (static variable & static method)
클래스와 인스턴스의 차이는 존재하는 객체에 대한 추상적인 개념을 정리한 것과 

그 추상적인 개념을 현실화한 것의 차이 등으로 간명하게 정리할 수 있었습니다.

 

클래스에는 객체의 행위를 실현하는 메소드와 객체의 상태를 실현하는 멤버변수를

적절하게 설계하여 구현 하고자 하는 객체의 틀을 구성합니다.

이때의 메소드는 인스턴스 메소드, 변수는 인스턴스 변수라고 부릅니다.

 흔히 멤버 메소드,멤버변수라고 부릅니다.

하지만 때로는 멤버 메소드와 멤버 변수만 가지고 클래스를 설계하기에는 부족한 경우가

있습니다.

 

 스타크래프트 게임에 등장하는 질럿이 유지해야 하는 상태는 체력과 쉴드가 대표적입니다.

하지만 게임을 해보면 질럿이 유지해야하는 상태는 체력과 쉴드 뿐 아니라 기본 공격력값,

기본 아머값 이라는 정보를 갖고 있습니다.

기본 공격력은 질럿이 다른 유닛을 공격할 때 다른 유닛에게 입히는 데미지(damage)

수치를 말하고, 기본 아머는 다른 유닛으로 부터 자신이 공격을 당할 때 상쇄하는 데미지의

수치를 말합니다. , 기본공격력이 높을수록 상대에게 많은 데미지를 입히고,

기본 아머가 높을수록 상대로부터 적은 데미지를 받습니다.

 

 모든 질럿은(new 키워드를 통해서 만들어진 모든 질럿 객체) 기본 공격력과 기본 아머가

동일한 반면에, 쉴드와 체력은 처음 만들어 질때만 동일하고 시간이 지나면 제 각각이

됩니다. 전투를 많이 한 질럿은 쉴드와 체력이 많이 감소 했을테고, 갓 만들어진 질럿은

체력과, 쉴드가 100으로 가득 채워져 있을 테니까요.

여기서 한가지 분명한 것은 개별 질럿의 체력과 쉴드의 많고 적음과 관련이 없이

개별 질럿의 기본 공격력과 기본 아머는 동일하다는 것 입니다.

 

이런 스타크래프트의 질럿을 클래스로 설계한다고 했을 때 기본 공격력과 기본 아머는

체력과 쉴드와는 성격이 다른 상태 변수임을 알 수 있습니다.

즉 체력과 쉴드의 값은 개별 객체별로 상태가 유지,관리되어야 하지만, 기본 공격력과

기본 아머등의 값은 질럿 종족(질럿 클래스)전체로 관리 되어야 한다는 것입니다.

 

 자바에서는 객체별로 상태가 유지, 관리되어야 하는 변수를 멤버변수,

클래스 별로(스타크래프트 유닛으로 말한다면 유닛별로)상태가 유지,관리되어야하는 변수를

클래스변수라고 합니다.

멤버변수와 클래스변수의 눈에 보이는 차이는 변수 앞에 static 키워드가 있으면 그 변수는

클래스 변수이고, 그렇지 않다면 멤버변수 입니다.

그래서 클래스 변수를 static 변수라고 합니다.

 

예제 1- 18 Zealot클래스에는 static 변수인 attack armor를 도입했습니다.

 

 

 

 

             class Zealot {

                           static int attack;                               // 기본 공격력

                           static int armor;                                // 기본 아머

                           int strength;

                           int shields;

                           Zealot () {

                                        strength = 100;

                                        shields = 100;

                           }

             }

예제 1 - 18

 

static 변수를 정의할 때 static의 의미를 정확히 이해하고 있어야 하겠습니다.

클래스에 존재하는 static 변수는 객체의 상태를 유지하기 위해 존재하는 변수가 아닙니다.  static 변수는 클래스 전체에 공통적으로 적용되는 상태를 유지하기 위해 존재하는 변수이고, 클래스별로 단 하나만 갖게 됩니다.

반면 객체의 상태를 유지하기 위해서 존재하는 변수인 멤버변수는 각각의 객체에 대한

상태정보를 독립적으로 유지 해야하므로 객체별로 자기의 멤버변수를 가지고 있습니다.

 

 

             Zealot z1 = new Zealot();

             Zealot z2 = new Zealot();

예제 1 - 19

 

예제 1 - 19에서 z1 질럿의 체력과 z2 질럿의 체력은 각각 strength 멤버변수를 갖고

있어서 각각 독립적으로 유지,변화하게 됩니다. 

z1의 체력이 증가 또는 감소했다고 해서 z2의 체력이 영향을 받을 수는 없는 노릇입니다. 

 

이와는 다르게 z1 질럿의 기본 공격력 attack z2의 기본 공격력 attack는 항상 같은

같은 값을 가져야 합니다.

static 변수인 attack의 값은 포지(Forge)에서 공격력 업그레이드를 하게 되면 z1 질럿의

attack의 값이나 z2 질럿의 attack의 값이 모두 증가가 됩니다.

그 뿐만 아니라 그 이후로 만들어지는 모든 질럿은 공격력이 증가된 상태 즉, attack의 값

이 증가한 상태에서 만들어 집니다. 이렇게 z1 질럿의 attack, z2 질럿의 attack의 값이

항상 같은 값을 가지게 되고, 새롭게 만들어지는 질럿의 attack값도  증가된 값을

가지게 되는 이유는 attack의 변수가 클래스별로 단 하나 밖에 없기 때문입니다.

static 변수의 값이 변하게 되면 모든 객체가 영향을 받게 되는데 이런 근본적인 이유는

static 변수는 클래스별로 하나 뿐이고, 모든 객체가 그 static 변수를 공유하고 있기

때문 입니다. 이런 미묘한 점이 있기 때문에 클래스에 static 변수를 도입하여 사용하고자

할때는 그에 꼭 알맞은 개념이 필요한 경우에만 도입하는 것이 좋겠습니다.

 

클래스메소드와 멤버메소드의 눈에 보이는 차이는 클래스변수와 멤버변수 때와

마찬가지로 메소드 앞에 static 키워드가 있고 없음의 차이입니다.

하지만 static 메소드와 멤버메소드의 차이는 static 변수와 멤버변수의 차이와는 사뭇

다릅니다.

이름이 붙여진 형태로 봐서는 비슷한 차이일 것으로 짐작하겠지만 실상은 다른 개념

이라고 보는 것이 좋겠습니다.

static변수과 멤버변수의 관계를 짐작하면 static 메소드는 모든 객체가 공유하고 있는

메소드이고 멤버메소드는 객체에게 존재하는 메소드의 의미로 오해할 수 있는데,

전혀 상관없는 얘기입니다. static 메소드의 의미는 객체가 존재하지 않아도 사용할 수 있는

호출할 수 있는 메소드이다는 의미로 받아 들이면 좋겠습니다.

멤버메소드는 객체가 존재한다는 것을 기본으로 생각해야합니다. 즉 객체가 없으면 멤버

메소드도 없다는 것입니다.

 

예제 1-20에서 처럼 BigRib 햄버거의 가격을 알아보고자 한다면 반드시 BigRib햄버거를

먼저 만든 후에야 알아 볼 수 있습니다.

 

 

             new BigRib().getPrice();

예제 1 - 20

 

왜냐하면 int getPrice()는 멤버 메소드이고 멤버 메소드는 객체로 하여금 어떤 일을

(여기서는 가격을 알아보는 일)시키기 위해서 존재합니다.

일을 할 객체가 없는데 객체로 하여금 일을 시킨다는 것은 논리적으로 말이 안됩니다.

당연한 이치입니다. 멤버 메소드를 호출하고자 한다면 반드시 객체가 먼저 만들어

져야 합니다. 만들어진 객체가 메소드 호출에 대해서 반응을 하는 것입니다.

 

예제 1 - 21에서 처럼 질럿의 체력이 얼마 남았는지 알고자 한다면 반드시 질럿이 먼저

있어야 합니다. 질럿도 없는데 질럿의 체력을 알고 싶다는 것은 앞뒤가 맞지 않으니까요.

 

 

 

          Zealot z = new Zealot();

          z.getStrength();                                            // 체력을 구하는 메소드

예제 1 - 21

 

하지만 가끔 객체를 만들지 않고 메소드를 호출해야 하는 경우가 있습니다.

스타클래프트에서 프로토스 지상유닛의 공격력등을 업그레이드하는 건물인 포지에서

지상유닛의 공격력 업그레이드를 완성하게 되면 모든 질럿,모든 드라군등 지상유닛의

공격력을 한단계 올려주어야 합니다.

하지만 공격력을 올려주기 위해서 없는 객체를 만들어서 객체의 메소드를 호출 할 수는

없는 노릇입니다. 이런 경우에 적합한 메소드가 static 메소드입니다. 

static 메소드는 객체에게 어떤 행위를 요구하는 것이 아니기 때문에 실제 객체가 존재하지

않아도 호출할 수 있습니다. 다만 static 메소드의 내용은 객체의 존재를 기반으로하는

변수들은 올수 없습니다. , static 메소드는 객체의 존재와 상관없이 호출되어야 하는

메소드인데, static 메소드에서  특정 멤버변수의 값을 바꾸는 것은 불가능합니다.

왜냐하면 멤버변수는 객체의 존재를 기본으로 가정하고 있기때문입니다.

 

static 메소드와 멤버메소드의 눈에 보이는 차이는 static 변수와 멤버변수 때와

마찬가지로 static 키워드가 있고 없음의 차이입니다.

 

             class Zealot {

                           static int attack = 16;                         // 기본 공격력을 16을 초기화

                           static int armor = 1;                           // 기본 아머를 1로 초기화

                           int strength;

                           int shields;

                           Zealot() {

                                        strength = 100;

                                        shields = 100;

                           }

                           static void attackUpgrade() {                          // static 메소드

                                        attack++;

                           }

                           static void armorUpgrade() {                           // static 메소드

                                        armor++;

                           }

             }

예제 1 - 22

 

다시한번 강조하지만 static 메소드는 객체가 존재하지 않는 상황에서도 언제든 호출해서

사용 할 수 있는데, 이런 특성 때문에 객체가 존재하는 것을 기본으로하는 멤버변수와는

함께 공존할 수 없습니다. 모순의 관계가 성립하게 됩니다.

멤버변수는 객체가 존재한 후에 객체의 상태를 유지 관리하는 변수이므로 멤버변수가 의미

를 갖기위해서는 앞서 반드시 객체의 존재를 전제로 합니다. 

객체가 없어도 호출할 수있어야 하는 static 메소드에 반드시 객체가 존재하는

것을 전제로 하는 멤버변수가 자리잡고 있다면 모순이되겠지요.

이런 당연한 이유로 클래스 메소드안에서는 멤버변수는 존재할 수 없습니다.

 

 Zealot 클래스처럼 static 메소드에는 attack(기본공격력),armor(기본아머)등의 static 변수

는 존재할 수 있지만 멤버변수는 결코 있을 수 없습니다.

Posted by
,