티스토리 뷰
이번에는
변수나 메소드를 정적으로
다룰 수 있게 해주는
static 기능을
알아보도록 하겠습니다.
===============================================================
정적 변수와 메소드 : static
1. 프로그래밍에서 정적이란 무엇일까?
살면서 한 번쯤은 정적, 동적이라는 단어를 들어봤을 것입니다. 통상적으로 말하는 단어의 의미는 비슷할 수 있겠지만 막상 프로그래밍에서의 정적과 동적을 들었을 때는 의아했습니다.
먼저 프로그래밍 언어에 따른 동적 언어, 정적 언어가 존재합니다.
정적 언어의 경우 대표적으로 C, C#, C++, Java 등의 언어가 있습니다. 이들 언어의 공통점은 변수에 들어갈 데이터 값의 형태에 따라 자료형을 지정해줘야하고,
이 자료형에 대한 정보를 컴파일 시에 결정하기 때문에 자료형이 맞지 않는다면 컴파일 에러에 의해 문제점을 초기에 찾을 수 있는 안정성과 속도가 빠르다는 장점이 있습니다. 하지만 사용자가 직접 타입을 변수마다 다르게 지정해주어야 한다는 단점이 있죠. 이런 것을 정적인 언어라고 합니다.
보통 정적을 고정되어있다 라고 해석하는데 변수의 자료형이 고정되어있다고 해석하면 빠를 것 같습니다.
동적 언어는 대표적으로 JavaScript, Python, Ruby 등이 있습니다. 이들은 정적 언어와 달리 컴파일 시 자료형을 결정하지 않고 실행 시에 결정합니다. 그렇기 때문에 변수를 선언할 때 자료형이 따로 필요 없고 들어오는 데이터 타입에 따라 자동으로 자료형이 결정되는 것입니다. 이는 사용자가 따로 자료형에 대해 고민을 하지 않아도 된다는 큰 장점이 있죠. 하지만 그에 따른 단점도 있습니다. 컴파일 시에 자료형에 대한 에러 체크가 불가능하기 때문에 예상치 못한 데이터가 변수에 들어온다면 Type Error라는 것이 발생한다고 합니다.
동적의 경우 움직인다 라고 해석을 많이 합니다. 그 뜻을 바탕으로 적용시켜본다면 데이터값에 따라 유동적으로 처리할 수 있는 것으로 생각할 수 있습니다.
2. static 기능이 있다는 것은 무엇일까?
자바는 앞서 포스팅한 것과 같이 객체 지향 프로그래밍언어입니다. 모든 데이터를 객체로 처리하는 것을 지향한다는 것이죠.
가위바위보를 열 번 하여 많이 이긴 사람이 최종 우승하는 게임을 만든다 가정해보겠습니다.
그리고 두 Player 객체를 만들어 게임을 진행합니다.
이때 Player 객체로 생성된 두 유저가 한 게임에서 대결을 한다 했을 때 공통으로 가지게 되는 부분이 존재합니다.
예를 들어 round 같은 부분은 두 유저 모두 같은 round를 가지게 되죠.
하지만 이런 round를 각 객체에서 처리하게 된다면 게임에서 round가 끝날 때마다 각 객체에 접근하여 처리해줘야 하는 불필요한 상황이 발생할뿐더러
같은 변수를 두 개 생성하는 것으로 메모리 낭비가 되는 것입니다. 만약 Player 객체의 수가 증가할수록 낭비는 극심해지겠죠.
이럴 때 사용하는 기능이 static입니다.
클래스를 설계할 때 round 변수에 static을 지정해두면 round 값을 가진 변수는 모든 객체에서 공통으로 참조하는 변수가 됩니다.
즉, 하나의 변수만 생성하고 모든 객체가 제어하는 것이죠.
여기에서의 static은 고정되어 한 번만 생성되고 모든 객체가 참조할 수 있도록 하는 기능이라고 해석하면 될 것 같습니다.
3. static 변수는 어떤 객체의 변수인가?
엄밀히 보면 클래스 안에 설계된 static 변수나 메소드는 객체의 변수가 아니라 클래스의 변수가 됩니다. 클래스의 변수이기 때문에 모든 객체가 같은 주소로 참조할 수 있게 되는 것입니다.
일반적으로 클래스의 변수나 메소드는 어떠한 객체를 생성하지 않는다면 사용할 수 없습니다. 하지만 static으로 선언된 변수나 메소드는 클래스 변수(메소드)이기 때문에 객체를 따로 생성하지 않고도 사용할 수 있게 됩니다.
4. 클래스의 변수??
클래스의 변수라는 말이 이상할 수도 있습니다. 보통 클래스는 설계도일 뿐이고 객체를 생성했을 때 메모리에 적재되고 변수에 값이 저장되기 때문입니다.
하지만 static의 경우 메모리의 적재되는 시기가 달라집니다.
(메모리의 적재되는 시기가 다르기 때문에 객체 생성하지 않아도 정적변수나 메소드를 호출할 수 있습니다.)
static은 JVM이 클래스를 읽어 들일 때 이미 자동적으로 메모리에 적재됩니다.
그렇기 때문에 객체를 생성할 때는 정적 변수나 메소드는 따로 생성하지 않고 객체를 생성한 다음 JVM이 클래스를 읽어 들일 때 적재해둔 메모리를 참조하여 static 변수나 메소드를 이용하는 것이죠.
5. Math.random()을 예로 들어보자.
이 함수를 어떤 구조인지 모르고 사용했었더라도 특이한 점은 느꼈을 것입니다.
"Math가 대문자로 시작하는 것을 보아하니 클래스를 의미하는 것이고, 그 안에 메소드를 호출하는 것이구나."
(저는 아무것도 모르고 봤을 때 이렇게 생각했습니다 ㅎㅎ)
사실 맞습니다. Math도 이미 정의되어있는 클래스이고, 그 안에 존재하는 random() 메소드를 사용하는 것입니다.
그렇다면 여기서 유추할 수 있는 것은 random()이라는 메소드는 static으로 정의되어 있기 때문에 Math 객체를 생성하지 않아도 사용할 수 있는 것입니다.
(public과 같은 접근제어자는 후에 다루겠습니다.)
6. static 변수의 초기화는 어떻게 해야 하지?
static의 변수는 객체 생성자와 비슷하게 정의할 수 있습니다.
class Enemy {
static int health;
int damaged;
Enemy() {
health = damaged = 0;
System.out.println("Enemy 객체 생성자");
}
static void heal(int d) {
health += d;
}
void attacked(int dmg) {
damaged += dmg;
health += dmg;
}
String info() {
return "health = " + health + "/ damaged = " + damaged;
}
간단한 게임을 생각하여 Enemy 클래스를 정의했습니다.
각 Enemy 객체는 health를 공유하고 받은 damaged를 저장합니다.
이때 Enemy 객체가 생성될 때 static 변수인 health를 초기화된 값으로 지정하고 싶다면 다음과 같은 코드를 생성자와 비슷하게 입력해 주시면 됩니다.
static {
health = 0;
System.out.println("Enemy 자체 생성자");
}
실제로 이 static 초기화 메소드는 클래스 변수나 메소드로 메모리에 적재될 때 한번만 작동되는 코드입니다.
그렇기 때문에 다른 객체를 생성한다 해도 health의 값은 고정되게 됩니다.
7. 정적 메소드 설계 시 주의할 점?
정적 메소드를 설계했다면 객체를 설계하지 않고도 사용할 수 있다 했습니다.
여기서 좀 더 생각해본다면 객체를 설계하지 않고 사용하기 때문에 인스턴스 변수나 메소드는 사용하지 못한다는 것이죠.
그렇기 때문에 정적 메소드 안에는 인스턴스 메소드나 인스턴스 변수가 포함되면 안됩니다.
다시 한번 좀 더 생각해봅시다. 그럼 거꾸로 인스턴스 메소드나 변수는 static이 붙은 맴버를 사용할 수 있을까요?
맞습니다. 이것도 메모리 적재 시기를 생각하면 편합니다. 인스턴스 메소드나 변수를 사용한다는 것은 객체를 생성했다는 것이고 객체를 생성하기 전에 이미 클래스 멤버로 정적 멤버가 생성되어 있기 때문에 사용할 수 있습니다.
제가 초기에 공부할 때는 사실 그냥 외우는 것과 같이했는데 static 부분은 메모리에 적재되는 시기를 잘 생각하면 답이 딱 나오는 것 같습니다.
마지막으로 개발자마다 다르겠지만 메소드 내에서 인스턴스 변수를 사용하지 않는다면, static을 붙이는 것을 권장하는 사람이 많다 합니다.
=========================================================================================================
인터넷 글들을 보면 면접 시 질문사항으로 static에 대해 많이 질문한다고 합니다.
생성되는 시기와 어떤 경우에 사용하는지 유의하여 알아두면 좋을 것 같습니다.
추가 + ) 메인 클래스의 static 의미에 대해 알아보겠습니다.
메인 클래스의 static을 해석할 때는 static을 사용하면 객체를 생성하지 않고 메소드를 호출할 수 있다는 점에 초점을 맞추면 됩니다. 메인 메소드 호출은 JVM에서 호출되기 때문에 객체 생성없이 메모리에 할당시켜 호출 가능한 형태로 만들어야하기 때문입니다. cmd창에서 java 메인클래스 메소드를 이용해 사용하면 JVM은 메인 클래스의 객체를 생성하는 것이 아니라 클래스의 static으로 선언된 메소드를 객체 생성없이 메모리에 할당시키고 할당된 메소드 중 "main으로 네이밍된 메소드를 차아 호출하게 되는 것입니다. 그렇기 때문에 메인 메소드는 무조건 static으로 정의되어 있어야하는 것입니다.
'Java > 문법' 카테고리의 다른 글
7. 상속 : extends (31) | 2018.10.11 |
---|---|
6. 접근 제어자 : Access Modifier (14) | 2018.10.09 |
4. 가비지 컬렉터 : Garbage Collector & 메모리 (0) | 2018.10.05 |
3 . 생성자 : Constructor (0) | 2018.10.03 |
2. 객체지향 프로그래밍 : OOP(Object-Oriented-Programming) (0) | 2018.10.02 |
- Total
- Today
- Yesterday
- 예제
- 원리
- @subselect
- SDK
- join subquery
- @EventListener
- playbackRate
- oauth
- Animation
- 장점
- map
- API
- QueryDSL
- 로그인
- list
- 특징
- 의미
- 네트워크
- playsinline
- on('seek')
- 관리자 도구
- Multi IN Clause
- login
- beforeunload
- 자바
- IN Clause
- SET
- jwplayer
- Queue
- @subquery
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |