2017년 7월 3일 월요일

[Java] static 키워드

자바는 메소드나 데이터를 static 키워드르 붙여 static으로 정의할 수 있다. static은 기본적으로 변수나 메소드가 인스턴스가 아닌 클래스에 속하게 한다.
즉, 인스턴스를 통해 변수에 접근하는게 아니라, 클래스를 통해 접근하고, 이때문에 여러개의 인스턴스에 서로 달리 존재하는 일반적인 변수,메소드와 달리 한개의 클래스에 존재하기 때문에 한개밖에 존재하지 않는다.
위 한문장만 읽으면 조금 헷갈리는데, static 변수와 static 메소드를 각각보면 좀 이해하기 쉽다.


private static int staticVariable;

public static void staticMethod(){
}

일반적인 변수가 객체(인스턴스)당 1개씩 존재하는 반면 static으로 정의된 변수는 클래스당 1개씩 존재한다. 예를들어 vehicle 객체 중 4륜객체가 1이라는 코드를 가지고 이 코드를 저장하는 정수형 변수가 id라고 할때 vehicle 객체는 아래와 같을거다.


public class Vehicle {

   private static int id = 1;
   public static String brand = "Hyundai";
   private String model;

//생성자함수와 다른 mutator, accessor 메소드는 생략
...
}

위의 객체를 생성하고 id 변수와, model 변수에 접근하고, 수정할때 결과를 본다면 아래와 같은 결과가 나온다.


Vehicle a = new Vehicle("Avantte");
Vehicle b = new Vehicle("Prius");

System.out.printf("ID: %d || Model: %s\n",a.getId(),a.getModel());
//ID: 1 || Model: Avantte

System.out.printf("ID: %d || Model: %s\n",b.getId(),b.getModel());
//ID: 1 || Model: Prius

//id 및 model 값 변경
a.setId(2);
a.setModel("Sonata");
 
System.out.printf("ID: %d || Model: %s\n",a.getId(),a.getModel());
//ID: 2 || Model: Avantte

System.out.printf("ID: %d || Model: %s\n",b.getId(),b.getModel());
//ID: 2 || Model: Prius

System.out.printf("브랜드: %s", Vehicle.brand);
//브랜드: Hyundai

위 코드를 실행하게되면, a 객체의 id 변수를 변경했는데, b 객체의 id 변수도 변경된것을 알 수 있다. 이는 id 변수가 static이기 때문이고, static 변수가 아닌 model 변수는 a 객체가 변경되도 b 객체에서 변하지 않는다. 그러니 한 클래스에서 인스턴스화된 모든 객체가 static 변수를 공유한다고 생각하면 된다.
또한 static 변수가 public 으로 선언된다면, 객체생성을 하지 않고, Vehicle.brand처럼 그냥 클래스를 통해 바로 호출이 가능하다.
이런 static 변수들은 보통 final 키워드와 함께 선언되어 Math.PI 변수 처럼 불변(immutable)하는 상수로 이용된다.
우리가 자주쓰는 System.out객체도 static과 final 속성을 가지고 있다. 또한 public 속성과 final 속성을 함께가지는 변수는 객체의 캡슐화를 훼손하지 않는다.

데이터 또는 메소드를 static으로 정의한다면 해당 메소드는 객체에서 실행되지 않는다. 대표적인 예로 Math.pow같은 Math 클래스의 메소드들이 있다. x의 제곱을 계산하는데 우리는 아무 객체도 생성않고 바로 pow 메소드를 호출해 결과값을 반환받는다. 그러니 결과적으로 implicit 파라미터가 필요하지 않다.


public class Vehicle {

   private static int id = 1;
   private static String brand = "Hyundai";
   private String model;

   public static String getBrand(){
   return brand;
   }
//생성자함수와 다른 mutator, accessor 메소드는 생략
...
}

위의 Vehicle 객체에 brand 변수가 private 속성을 가지고 brand 변수에 대한 static accessor 메소드가 존재할 때 우리는 아무런 객체를 생성하지 않고 brand 변수에 접근이 가능하다. 만약 brand 변수의 accessor 메소드가 static 속성을 가지고 있지 않다면 아래와 같이 객체 생성없이 brand 값에 접근할수는 없다.


System.out.println("브랜드: " + Vehicle.brand);
// 브랜드: Hyundai

static 메소드들은 다음과 같은 상황에서 사용하면 된다


  • 메소드가 필요한 모든 파라미터들이 explicit 파라미터로 제공되어 객체의 상태(State)에 접근할 필요가 없을 때
  • 메소드가 클래스의 static 필드에만 접근하면 될때


static 메소드의 대표적인 예는 main 메소드가 있다. main 메소드는 어떤 객체에서도 실행되지 않는다. 다만 프로그램이 실행될때, 아무런 객체도 생성되지 않았기 때문에 main 메소드가 실행되고 프로그램에 필요한 객체들을 생성한다. main 메소드는 어느 클래스든 사용될수 있으니, 객체 설계 후 테스트를 할때도 사용할수있다.

댓글 없음:

댓글 쓰기