① [ public | ... ]    ②   [ static | ... ]    ③   [ void | ... ]  main  (   ④  [ String[] | ... ]  ⑤   args ) 

 

자바에서 static (정적) 란 것은 클래스에 고정된 변수를 의미한다.

 

따라서 static 이라는 클래스 변수가 사용되는 경우는

1) 전역적으로 쉽게 재사용되는 변수

2) 데이터 값이 잘 변하지 않는 변수

3) 메소드로써 static 를 사용하는 것.

 

=> 왜냐하면 한 번 선언하고 난 뒤에는 클래스 호출을 추가적으로 하거나, 객체를 생성(new) 할 필요 없이 즉각적으로 사용할 수 있기 때문이다.

 

1.클래스를 설계할 때, 멤버변수 중 모든 인스턴스에 공통적으로 사용해야하는 것에 static을 붙인다.

 - 인스턴스를 생성하면, 각 인스턴스들은 서로 독립적이기 때문에 서로 다른 값을 유지한다경우에 따라서는 각 인스턴스들이 공통적으로 같은 값이 유지되어야 하는 경우 static을 붙인다.

public class Counter  {
    int count = 0;
    Counter() {
        this.count++;
        System.out.println(this.count);
    }
    public static void main(String[] args) {
        Counter c1 = new Counter(); // 출력값 : 1
        Counter c2 = new Counter(); // 출력값 : 1
    }
}

 c1 과 c2 가 1, 1이라는 출력값이 나온다. 왜냐하면 count 라는 인스턴스는 static 변수가 아닌 객체 변수이기 때문에

c1이라는 객체 안에서 count++ 를 한 번 시행하고,

c2 라는 객체 안에서 count++ 를 한 번 시행한 것이기 때문이다.

public class Counting {
        static int count = 0;
        Counting() {
            this.count++;
            System.out.println(this.count);
        }
        public static void main(String[] args) {
            Counting c1 = new Counting(); // 출력값 : 1
            Counting c2 = new Counting(); // 출력값 : 2
        }
    }

반면, static int count = 0; 이라는 클래스 변수를 바탕으로 인스턴스 변수를 활용하면, 클래스 변수의 값이 공유되어 출력값이 1, 2와 같이 증가하게 된다.

 

2. static이 붙은 멤버변수는 인스턴스를 생성하지 않아도 사용할 수 있다.

 - static이 붙은 멤버변수(클래스변수)는 클래스가 메모리에 올라갈때 이미 자동적으로 생성되기 때문이다.

 => 즉 Calculator ca = new Calculator(); ... 와 같은 생성이 불필요하다는 것이다.

 

3. static이 붙은 메소드(함수)에서는 인스턴스 변수를 사용할 수 없다.

static 메소드라 함은 ex)

public class Counter  {
    static int count = 0; // Counter 라는 class 필드에서 정의된 class 변수
    Counter() {
        this.count++;
    }
    public static int getCount() {  // static 라는 키워드가 붙은 메소드를 의미한다.
        return count;
    }
    public static void main(String[] args) {
        Counter c1 = new Counter();
        Counter c2 = new Counter();
        System.out.println(getCount()); // 'Counter.' 라는 부분이 불필요한 이유는 getConunt가 참조하는 count 클래스 변수와 main 이 같은 클래스에 존재하기 때문
    }
}

 여기서는 getCount()라는 static 메소드가 추가되었다. 

그리고 getCount() 라는 메소드 안에서는 대표적으로 new 를 활용하는, 인스턴스 변수(객체 변수)의 생성과 접근은 불가능하다.

실제로, return count; 라는 명령어에서 count 는 Counter라는 class 필드에서 static int 로 정의된 클래스 변수이다.

 

- static이 붙은 메소드는 인스턴스 생성 없이 호출가능한 반면, 인스턴스 변수는 인스턴스를 생성해야만 존재하기 때문에... static이 붙은 메소드(클래스메소드)를 호출할 때 인스턴스가 생성되어있을수도 그렇지 않을 수도 있어서 static이 붙은 메소드에서 인스턴스변수의 사용을 허용하지 않는다. (반대로, 인스턴스변수나 인스턴스메소드에서는 static이 붙은 멤버들을 사용하는 것이 언제나 가능하다. 인스턴스변수가 존재한다는 것은 static이 붙은 변수가 이미 메모리에 존재한다는 것을 의미하기 때문이다.)

class MemberCall {
      int iv = 10;
      static int cv = 20;

      int iv2 = cv;
//   static int cv2 = iv;  에러. 클래스변수는 인스턴스 변수를 사용할 수 없음.
      static int cv2 = new MemberCall().iv;   // 굳이 사용하려면 이처럼 객체를 생성해야함.
      
      static void classMethod1() {
            System.out.println(cv);
//         System.out.println(iv);  에러. 클래스메소드에서 인스턴스변수를 바로 사용할 수 없음.
            MemberCall c = new MemberCall();      
            System.out.println(c.iv);   // 객체를 생성한 후에야 인스턴스변수의 참조가 가능함.
     }
      void instanceMethod1() {
            System.out.println(cv);             
            System.out.println(iv);  // 인스턴스메소드에서는 인스턴스변수를 바로 사용가능.
     }
      static void classMethod2() { // 클래스메소드
            classMethod1();
//         instanceMethod1(); 에러. 클래스메소드에서는 인스턴스메소드를 바로 호출할 수 없음.
            MemberCall c = new MemberCall();
            c.instanceMethod1(); // 인스턴스를 생성한 후에야 인스턴스메소드를 호출할 수 있음.
      }
      void instanceMethod2() { // 인스턴스메소드에서는 인스턴스메소드와 클래스메소드
            classMethod1();         // 모두 인스턴스생성없이 바로 호출이 가능하다.
            instanceMethod1();
     }
}

4. 메소드 내에서 인스턴스 변수를 사용하지 않는다면, static을 붙이는 것을 고려한다.

 - 메소드의 작업내용중에서 인스턴스 변수를 필요로 한다면, static을 붙일 수 없다. 반대로 인스턴스변수를 필요로 하지 않는다면, 가능하면 static을 붙이는 것이 좋다. 메소드 호출시간이 짧아지기 때문에 효율이 높아진다. (static을 안붙인 메소드는 실행시 호출되어야할 메소드를 찾는 과정이 추가적으로 필요하기 때문에 시간이 더 걸린다.)

 

class MyMath2 {
      long a, b;
      // 인스턴스변수 a, b를 이용한 작업을 하므로 매개변수가 필요없다.
      long add() {  return a + b; }
      long subtract() {  return a - b; }
      long multiply() {  return a * b; }
      double divide() {  return a / b; }
      
      // 인스턴스변수와 관계없이 매개변수만으로 작업이 가능하다.
      static long add(long a, long b) {       return a + b; }
      static long subtract(long a, long b) {       return a - b; }
      static long multiply(long a, long b) {       return a * b; }
      static double divide(double a, double b) {       return a / b; }
}
class MyMathTest2 {
      public static void main(String args[]) {
            MyMath2 mm = new MyMath2();
            mm.a = 200L;
            mm.b = 100L;
            // 인스턴스메서드는 객체생성 후에만 호출이 가능함.
            System.out.println(mm.add());
            System.out.println(mm.subtract());
            System.out.println(mm.multiply());
            System.out.println(mm.divide());
            
            // 클래스메서드 호출 즉 class MyMath2 에서의 long a, b라는 인스턴스 변수를 사용하는 것이 아니라 매개변수를 직접 지정함
            System.out.println(MyMath2.add(200, 100));
            System.out.println(MyMath2.subtract(200, 100));
            System.out.println(MyMath2.multiply(200, 100));
            System.out.println(MyMath2.divide(200.0, 100.0));
}

 

5. 클래스 설계시 static의 사용지침

 - 먼저 클래스의 멤버변수중 모든 인스턴스에 공통된 값을 유지해야하는 것이 있는지

    살펴보고 있으면, static을 붙여준다.

 - 작성한 메소드 중에서 인스턴스 변수를 사용하지 않는 메소드에 대해서 static

    붙일 것을 고려한다.

 

일반적으로 인스턴스변수와 관련된 작업을 하는 메소드는 인스턴스 메소드(static이 안붙은 메소드) 이고 static변수 (클래스변수)와 관련된 작업을 하는 메소드는 클래스 메소드(static이 붙은 메소드)라고 보면 된다.

 

 

 

 

 

 

참고자료 :

https://taewooblog.tistory.com/entry/java-%EC%9E%90%EB%B0%94-static-%EB%9E%80-%EC%82%AC%EC%9A%A9%ED%95%98%EB%8A%94-%EC%9D%B4%EC%9C%A0

https://mi-nya.tistory.com/251

https://kephilab.tistory.com/46

https://vaert.tistory.com/101

https://wikidocs.net/228

BELATED ARTICLES

more