static과 private차이를 물으셨는데.
우선 static과 static이 아닌 것의 차이를 설명드리겠습니다.
1. static이 붙고 안붙은 변수의 차이:
public class Human{
pulbic static long population;/*인구수 static이 붙었습니다.*/
public int age;/*나이 static이 안붙었습니다.*/
}
이런 클래스를 만들었습니다.
인간의 인구수는 변수가 한개만으로 충분하겠지요? 그래서 static을 붙였습니다.
그리고 나이라는 변수는 사람마다 나이가 틀리겠죠? 그래서 static을 안붙였습니다.
사용할 때는 아래와 같습니다.
1.1 static인 변수에 값을 대입하기
Human.population = 7000000000L;
static이므로 new해서 인스턴스를 만들지 않고 direct Access해서 값을 대입하여 사용합니다.
(long형자료형인 경우 숫자뒤에 L을 붙여야 하는거는 아시죠?)
1.2 static이 아닌 변수에 값을 대입하기
Human aMan = new Human();// 1.먼저 생성한 후
aMan.age=26; // 2.대입합니다.
Human aMan2 = new Human();// 1.먼저 생성한 후
aMan2.age=27;// 2.대입합니다.
System.out.println("두명의 나이를 더하면?"+ (aMan.age+aMan2.age));
static이 아니므로 new로 인스턴스를 생성하여 해당인스턴스변수에 값을 대입합니다.
변수에 static이 붙은 변수를 "클래스변수" 혹은 "스태틱변수"라고 하고 static이 안붙은 변수를
"인스턴스변수"라고 합니다. (class와 instance 의 차이는 아시죠? class는 자료형의 템플릿(거푸집)이고 instance는 자료형의 실체 잖아요?)
결론: static이 붙고 안붙는 변수의 차이는 아래 표로 정리를 해보았습니다.
static 키워드가 붙은 변수는 전역(global)으로 값이 사용됩니다.
|
static이 붙는 변수 |
static이 안붙는 변수 |
전역여부 |
O
전역변수
|
X
전역이 아님, 인스턴스변수
|
직접대입가능 |
O
Human.population 처럼
다이렉트 Access가 가능합니다.
|
X
Human aMan = new Human();
aMan.age=10;
static이 안붙는 변수를 사용하기 위해 반드시 new를 사용하여 클래스의 인스턴스를 먼저 만들어야지만 사용이 가능합니다.
|
private,public과의 관계 |
관계는 없지만
주로 public이 사용됨.
public static int a;
이런식으로 주로 public이 static앞에 붙습니다.
왜냐하면 static변수는 주로 전역으로 사용되기 때문이죠.
- 굳이 private사용하기 사례
private static int m_age;
public static int getAge()
{
return m_age;
}
public static int setAge(int v)
{
m_age = v;
}
m_age변수는 private를 사용하여 감추고
getAge나 setAge는 public을 사용하여 외부에 노출하였습니다.
|
- 관계없음.
|
머라고 부르나? |
클래스변수 |
인스턴스변수=속성=멤버변수
cf. 그럼 지역변수(로컬변수)는 먼가?
{}[단위블럭]안에서 생명주기를 가지는 변수를 지역변수라고 합니다.
static Method의 {}안에서 선언된 변수변수는 별개의 thread에 의해 동시에 진입되더라도 독립된 메모리영역에서 생성되어진 값으로 사용됩니다. 즉
static Methoid의 {}안의 선언된 변수와
static 아 아닌 Method의{} 안의 선언된 변수는 똑같이 local variable입니다.
|
메모리공간 |
1개
해당자료형의크기만큼자리
잡힙니다.
|
n개
- new로 생성된 수만큼 확보
- 선언된시점의 {}[중괄호블럭]안에서 유효하며 {}바깥에서는 메모리에서 적절히 소멸됨.
|
2. static이 붙고 안붙은 method사례:
아래 class참고
public class Human{
pulbic static long population;/*인구수 static이 붙었습니다.*/
public int age;/*나이 static이 안붙었습니다.*/
static
{
population = 7000000000L;//static블럭안에서 static변수의 값을 초기화 할 수도 있습니다.
}
public static void addPopulation(long val)
{
population += val;
//age = 3;//<-- static Method안에서 인스턴스변수의 값을 access 하는 것은 불가능합니다.
//System.out.println(this.hashCode());//<--static Method안에서 this를 access할 수 없습니다.
// this가 클래스의 인스턴스기 때문이죠.
}
public void setAge(int val)
{
age = val;
//System.out.println("인류인구:"+Human.population);//static변수는 전역이므로 어디서는 사용가능합니다.
}
}
위와 같은 클래스를 만들어보았습니다.
2.1 static 키워드가 붙은 함수를 static method[스태틱 메쏘드]라고 합니다.
static메쏘드는 업무로직이 구현된 함수이며,
new를 하지 않고 편리하게 사용이 가능합니다.
- 인스턴스변수를 static함수 내부에 사용할 수 없습니다.
예) int a = Integer.parseInt("3");//<--- parseInt는 static 메소드이므로 new 없이 사용가능합니다.
2.2 static 키워드가 안붙은 함수는 instance함수라고 하는데
get이 붙은 함수는 getter[겟터], set이 앞에 붙은 함수는 setter[셋터]라고 합니다.
위의 예시에서 setAge는 age라고 하는 인스턴스의 속성의 값에
특정한 값을 셋팅하는 setter 입니다.
- new를 한 후 사용할 수 있습니다.
- 인스턴스변수를 매개변수로 전달하지 않고 사용할 수 있습니다.
this.인스턴스변수명 으로 함수내부에서 사용이 가능합니다. this.은 생략 가능합니다.
3. 관련 디자인패턴:
singleton:
만약 인스턴스를 static방법으로 Access하고자하는 경우
싱글톤디자인패턴으로 개발하면 되겠습니다.
싱글톤디자인 패턴은 위에서 설명한 메모리공간에 static은 1개만 들어가는 특징이 있는데
인스턴스도 1개만 만들어서 static변수에 대입하여 사용하는 디자인 패턴입니다.
4. 개발시 유의사항: static변수를 다루는데 있어서 쓰레드 구현시 유의사항이 있습니다.
앞에서 static변수는 전역변수라고 설명드렸습니다.
또한 static변수로 선언된 변수는 전역자원(global resource, global data)에 해당됩니다.
물리적으로 하나의 메모리 공간에 있는 데이터를 처리할 때
유의해할 것은 동시성 제어를 해야 할 때입니다.
즉 동시에 한개의 자원(혹은 데이터)을 가져와서
n개의 쓰레드가 동시에 해당 변수에 접근하였을 때
값을 읽어와서 쓰려고 하는 과정에서 문제가 생길 수 있습니다.
전역자원은 배열의 형태일수도 있는데 for문을 돌리는 있는 중간에 다른 쓰레드에 의해서
배열의 크기가 바뀌거나 할 수 있습니다. 그러면 오류가 생기게 됩니다.
access오류라든지(가령 ConcurrentModificationException)
연산오류(정합성체크를 못하는 연산오류)
그렇기 때문에 전역자원을 멀티쓰레드(쓰레드는 static자원이 아닙니다.)가 다룰때
synchronize를 해줘야 하는 경우가 있습니다. 하나의 thread에 의해서만 해당 자원이 다루어
져야 한다면 synchronize(해당자원){구현...} 이렇게 하면 다음쓰레드는 해당 코드에 동시에
진입하지 않고 먼저실행된 threa의 {}블럭이 끝날때 까지 기다렸다가 다음쓰레드가 실행되겠습니다.
static에 대해 제가 알고 있는 전부라고 해도 과언이 아닙니다.
도움이 되시길 바랍니다.
코드샘플은 제가 이해하시기 좋을 것같은 예로 제가 직접작성하였지만 실제로 돌려보지는 않았습니다.