# 정적(static)

## 정적 처리

정적 처리 키워드인 `static`을 사용하면 객체 지향에서 발생할 수 있는 여러 문제점들을 해결할 수 있다.

### 데모 1 : 객체 지향의 문제점

객체 지향 디자인만으로 프로그래밍을 할 경우 다음 문제가 발생할 수 있다.

* 기능을 사용하기 위해서는 객체를 반드시 생성해야 한다.
* 객체간에 공유되는 데이터를 사용할 수 없다.

이는 다음 예제에서 확인할 수 있다.

```java
class Calculator {
    private int a, b;
    public Calculator(int a, int b){
        this.a = a;
        this.b = b;
    }
    public int plus(){
        return this.a + this.b;
    }
}

public class NonStaticExample01 {
    public static void main(String[] args){
        //10 + 20을 Calculator를 이용하여 처리
        Calculator c1 = new Calculator(10, 20);
        int a = c1.plus();
        System.out.println("100+200 = "+a);
        
        //100 + 200 + 300을 Calculator를 이용하여 처리
        Calculator c2 = new Calculator(100, 200);
        int b = c2.plus();
        Calculator c3 = new Calculator(b, 300);
        int c = c3.plus();
        System.out.println("100+200+300 = "+c);
    }
}
```

변수에 값을 설정해서 무엇인가 하려고 할 때 코드가 매우 길어지고 복잡해진다는 것을 확인할 수 있다. 이는 객체를 매 계산마다 만들어야 하기 때문에며, 메소드를 변경해도 최소한 한 개의 객체가 필요하다는 사실은 변하지 않는다.

### 데모 2 : 객체지향의 문제점

```java
class Galaxy20s {
    private String company;
    private String number;
    private int price;
    
    public Galaxy20s(String company, String number, int price){
        this.setCompany(company);
        this.setNumber(number);
        this.setPrice(price);
    }
    
    public void setCompany(String company){
        this.company = company;
    }
    public void setNumber(String number){
        this.number = number;
    }
    public void setPrice(int price){
        this.price = price;
    }
    public String getCompany(){
        return this.company;
    }
    public String getNumber(){
        return this.number;
    }
    public int getPrice(){
        return this.price;
    }
    public void print(){
        System.out.println("## 갤럭시 20s 정보 ##");
        System.out.println("제조사 : "+this.company);
        System.out.println("전화번호 : "+this.number);
        System.out.println("가격 : "+this.price+"원");
    }
}

public class NonStaticExample02 {
    public static void main(String[] args){
        Galaxy20s a = new Galaxy20s("삼성", "010-1212-3434", 1500000);
        Galaxy20s b = new Galaxy20s("삼성", "010-3434-5656", 1550000);
        Galaxy20s c = new Galaxy20s("삼성", "010-5656-7878", 1600000);
        
        a.setCompany("화웨이");
        
        a.print();
        b.print();
        c.print();
    }
}
```

출력을 해보면 a만 제조사가 화웨이로 나오는 것을 확인할 수 있다. 생각해보면 같은 휴대폰이 3대가 있는데 1대만 제조사를 바꾼다는 것은 이상하다. 즉, 모든 객체가 일괄적으로 사용할 수 있는 데이터가 있어야 하는데 이러한 부분은 객체로만 해결할 수 없다.

### 데모 3 : 데모 1번을 개선

```java
class Calculator {
    public static int plus(int a, int b){
        return a + b;
    }
}

public class StaticExample01 {
    public static void main(String[] args){
        int a = Calculator.plus(10, 20);
        System.out.println("10+20 = "+a);
        
        int b = Calculator.plus(30, 40);
        System.out.println("30+40 = "+b);
    }
}
```

멤버 필드를 없에고 `static` 키워드를 추가하면 별도의 메모리에 시작과 함께 등록이 되기 때문에 따로 객체를 만들지 않아도 클래스 이름으로 접근이 가능하다. 이러한 메소드를 `static 메소드` 또는 `클래스 메소드`라고 부른다. 메모리를 점유한다는 단점이 있지만 위치에 상관없이 객체를 만들지 않고 호출할 수 있다는 장점이 있기 때문에 **자주 사용해야 하는 기능**이며 **객체처럼 사용하지 않는 기능**이라면 `static 메소드`로 만드는 것을 고려해봐야 한다.

### 데모 4 : 데모 2번 개선

```java
class Galaxy20s {
    private static String company = "삼성";
    public static void setCompany(String company){
        Galaxy20s.company = company;
    }
    public static String getCompany(){
        return Galaxy20s.company;
    }
    
    private String number;
    private int price;
    public Galaxy20s(String number, int price){
        this.setNumber(number);
        this.setPrice(price);
    }
    public void setNumber(String number){
        this.number = number;
    }
    public void setPrice(int price){
        this.price = price;
    }
    public String getNumber(){
        return this.number;
    }
    public int getPrice(){
        return this.price;
    }
    public void print(){
        System.out.println("## 갤럭시 20s 정보 ##");
        System.out.println("제조사 : "+Galaxy20s.company);
        System.out.println("전화번호 : "+this.number);
        System.out.println("가격 : "+this.price+"원");
    }
}

public class StaticExample02 {
    public static void main(String[] args){
        Galaxy20s a = new Galaxy20s("010-1212-3434", 1500000);
        Galaxy20s b = new Galaxy20s("010-3434-5656", 1550000);
        Galaxy20s c = new Galaxy20s("010-5656-7878", 1600000);
        
        Galaxy20s.setCompany("LG");
        
        a.print();
        b.print();
        c.print();
    }
}
```

제조사의 경우 일괄적으로 관리되는 항목이므로 객체에 포함시키지 않고 `static` 키워드를 통해 공용 데이터 처리할 수 있다. 이 경우 객체 내부에 저장되는 것이 아니라 `static` 메모리에 별도로 저장되기 때문에 바꿀 경우 해당 클래스로 만들어진 모든 인스턴스가 일괄적으로 갱신되는 효과가 발생한다. 따라서 데모 2번처럼 하나의 휴대폰만 제조사가 변경되는 문제점이 사라지게 된다.

주의할 사항은 `static` 변수에 대한 setter/getter 메소드는 `static`으로 처리해야 한다는 것이며, 객체에 포함되지 않기 때문에 `this` 대신 `Galaxy20s`와 같이 클래스 이름을 이용하여 접근하도록 코드의 변경이 필요하다.

이 외에도 다양한 용도로 `static`을 사용할 수 있으며, 객체가 아닌 외부 영역에 저장되어 클래스 이름을 통해 호출된다는 것을 알고 상황에 맞게 이용할 수 있는 능력이 필요하다.
