[Java] static 을 언제 붙일지 모른다면 🥲

준우·2023년 2월 18일
0

Java

목록 보기
25/30
post-thumbnail

많은 개발자들이 static 메서드란 객체 생성 없이 호출 가능한 메서드임을 알고 있을 것이다.
그런데 아래와 같은 질문을 받았을 때 대답하기 어렵다면 공부가 필요하다.

"메서드를 만들었을 때, static을 붙일지 말지를 어떻게 결정하냐?"

개발자는 메소드를 만들었을 때 해당 메소드에 static을 붙일지 말지 결정할 줄 알아야 한다.
결론을 먼저 말하자면 static 키워드는 iv(instance variable, 인스턴스 변수)를 사용하지 않는 메소드에 붙인다.

인스턴스 메서드와 static 메서드, 둘의 차이는 아래와 같다.

들어가기 앞서

용어 정리

  • iv(instance variable): 인스턴스 변수
  • lv(local variable): 로컬 변수
  • cv(class variable) : 클래스 변수
  • im(instance method): 인스턴스 메소드

인스턴스 메서드와 static 메서드

아래와 같은 코드가 있을 때 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;
    }

}

인스턴스 메서드

  • 인스턴스 생성 후 '참조변수.메서드이름()'으로 호출
  • 인스턴스 멤버(instance variable, instance method)와 관련된 작업을 하는 메서드
  • 메서드 내에서 인스턴스 변수(iv) 사용 가능
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());
    }
}

static 메서드

  • 객체 생성 없이 '클래스이름.메서드이름()'으로 호출 ex.Math.random()
  • 인스턴스 멤버(iv, im)와 관련 없는 작업을 하는 메서드
  • 메서드 내에서 인스턴스 변수(iv) 사용 불가
class MyMathTest2 {
	public static void main(String args[]){
    								   //클래스 메서드 호출
    	System.out.println(MyMath2.add(100L, 200L));
    }
}

결론적으로 둘의 차이는 iv(instance variable)의 사용 여부 차이에 있다.
static 메서드는 객체를 생성하지 않고 사용하기에,
객체 생성 후에 메모리에 올라가는 iv를 사용할 수 없는 것이다.

  • 💡 객체는 iv의 묶음, 메서드는 명령문의 집합이다.

변수에는 static을 언제 붙일까?

위에서 메소드가 인스턴스 멤버(iv, im)를 사용하지 않을 때 static 키워드를 붙인다고 했다.
변수에서는 언제 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;

🫡 Reference

2개의 댓글

comment-user-thumbnail
2023년 2월 21일

인스턴스화에 대한 이해도를 높일 수 있는, 한번쯤 생각해볼만한 포인트들을 제시해드릴게요.

  • Python에서도 클래스 내부에서 쓰이는 @staticmethod라는 데코레이터가 있습니다. 이 static도 Java의 static과 의미가 같다고 하는데, 완전한 OOP일 필요가 없는 Python에서는 왜 저 데코레이터를 쓸까요?

  • 자바에서 상수를 만들땐 private final static내지 final static이라는 키워드 조합을 씁니다. 각각 다른 의미를 뜻하는 예약어일텐데, 왜 final static은 서로 붙여서 사용될까요? 여기서의 static은 무슨의미일까요?

1개의 답글