많은 개발자들이 static 메서드란 객체 생성 없이 호출 가능한 메서드임을 알고 있을 것이다.
그런데 아래와 같은 질문을 받았을 때 대답하기 어렵다면 공부가 필요하다.
"메서드를 만들었을 때, static을 붙일지 말지를 어떻게 결정하냐?"
개발자는 메소드를 만들었을 때 해당 메소드에 static을 붙일지 말지 결정할 줄 알아야 한다.
결론을 먼저 말하자면 static 키워드는 iv(instance variable, 인스턴스 변수)를 사용하지 않는 메소드에 붙인다.
인스턴스 메서드와 static 메서드, 둘의 차이는 아래와 같다.
용어 정리
- iv(instance variable): 인스턴스 변수
- lv(local variable): 로컬 변수
- cv(class variable) : 클래스 변수
- im(instance method): 인스턴스 메소드
아래와 같은 코드가 있을 때 static이 붙은 add() 메소드는 인스턴스 메소드이고,
static이 붙은 static add() 메소드는 static 메소드이다.
class MyMath2 {
//instance variable
long a, b;
//인스턴스 메서드
long add() {
return a + b;
}
//static 메서드(클래스 메서드)
//local variable
static long add(long a, long b) {
return a + b;
}
}
class MyMathTest2 {
public static void main(String args[]){
//(1) 인스턴스 생성
MyMath2 mm = new MyMath2();
mm.a = 200L;
mm.b = 100L;
//(2) 인스턴스 메서드 호출
System.out.println(mm.add());
}
}
ex.Math.random()
class MyMathTest2 {
public static void main(String args[]){
//클래스 메서드 호출
System.out.println(MyMath2.add(100L, 200L));
}
}
결론적으로 둘의 차이는 iv(instance variable)의 사용 여부 차이에 있다.
static 메서드는 객체를 생성하지 않고 사용하기에,
객체 생성 후에 메모리에 올라가는 iv를 사용할 수 없는 것이다.
- 💡 객체는 iv의 묶음, 메서드는 명령문의 집합이다.
위에서 메소드가 인스턴스 멤버(iv, im)를 사용하지 않을 때 static 키워드를 붙인다고 했다.
변수에서는 언제 static 키워드를 붙일까?
아래와 같이 CARD 라는 클래스가 있다고 하자.
CARD의 무늬, 숫자는 개별 속성이고, 폭과 넓이는 공통 속성이다.
이때 공통 속성인 폭과 넓이에 static을 붙인다.
class Card{
String kind;
int number;
static int width = 100;
static int height = 250;
}
관례로 cv(클래스 변수,static 변수)를 초기화할 때에는 아래와 같이 '클래스 이름.cv이름'으로 사용한다.
BAD 케이스가 불가능한 것은 아니지만 iv로 오해할 수 있기에 좋은 코드는 아니다.
Card c = new Card();
c.kind = "HEART";
c.number = 5;
//BAD
c.width = 200;
c.height = 300;
//GOOD
Card.width = 200;
Card.height = 300;
왜냐하면 아래 코드처럼 c1, c2 두개 Card 객체를 생성하고
c1의 공통 속성(width, height)만 바꾸었음에도 c2의 공통 속성까지 변하기 때문이다.
class Ex6_3 {
public static void main(String args[]) {
System.out.println("Card.width = " + Card.width);
System.out.println("Card.height = " + Card.height);
Card c1 = new Card();
c1.kind = "Heart";
c1.number = 7;
Card c2 = new Card();
c2.kind = "Spade";
c2.number = 4;
System.out.println("c1은 " + c1.kind + ", " + c1.number + "이며, 크기는 (" + c1.width + ", " + c1.height + ")");
System.out.println("c2는 " + c2.kind + ", " + c2.number + "이며, 크기는 (" + c2.width + ", " + c2.height + ")");
System.out.println("c1의 width와 height를 각각 50, 80으로 변경합니다.");
c1.width = 50;
c1.height = 80;
System.out.println("c1은 " + c1.kind + ", " + c1.number + "이며, 크기는 (" + c1.width + ", " + c1.height + ")");
System.out.println("c2는 " + c2.kind + ", " + c2.number + "이며, 크기는 (" + c2.width + ", " + c2.height + ")");
}
}
class Card {
String kind;
int number;
static int width = 100;
static int height = 250;
공통 속성을 가지는 static 변수(cv)는 초기화 시 생성된 모든 객체의 값도 변경되므로
iv처럼 오해하지 않도록 '클래스명.cv명' 으로 아래 코드처럼 사용하는 것이 좋다.
Card c = new Card();
c.kind = "HEART";
c.number = 5;
//GOOD
Card.width = 200;
Card.height = 300;
인스턴스화에 대한 이해도를 높일 수 있는, 한번쯤 생각해볼만한 포인트들을 제시해드릴게요.
Python에서도 클래스 내부에서 쓰이는 @staticmethod라는 데코레이터가 있습니다. 이 static도 Java의 static과 의미가 같다고 하는데, 완전한 OOP일 필요가 없는 Python에서는 왜 저 데코레이터를 쓸까요?
자바에서 상수를 만들땐 private final static내지 final static이라는 키워드 조합을 씁니다. 각각 다른 의미를 뜻하는 예약어일텐데, 왜 final static은 서로 붙여서 사용될까요? 여기서의 static은 무슨의미일까요?