클래스를 정의할 때 멤버 앞에 static 키워드를 명시할 수도 있으며 static 키워드를 명시하면 정적 멤버라고 부릅니다.
static 키워드를 명시하지 않은 멤버 필드는 개체(인스턴스라고도 부름)마다 상태를 기억하기 위한 영역을 부여합니다. 하지만 static 키워드를 명시하면 멤버 필드를 캡슐화하면 해당 형식에 상태를 기억하기 위한 영역을 부여하며 정적 멤버 필드라고 부릅니다.
어떠한 곳에 정적 멤버 필드를 사용하는지 예를 들어 볼게요.
Unit 클래스를 정의한다고 가정합시다. 그리고 Unit 개체마다 일련 번호가 있고 생성 순서대로 1부터 순차적으로 부여하려고 합니다. 이를 위해서는 가장 최근에 부여한 Unit 개체의 일련 번호를 기억하고 있어야 합니다. 그런데 이 값은 어디에 기억하고 있어야 할까요? 가장 최근에 부여한 Unit 개체의 일련 번호는 Unit 개체마다 기억해야 하는 것이 아니고 Unit 클래스 전체 영역에 하나만 필요합니다. 이 때 정적 멤버 필드로 정의하는 것입니다.
그리고 public으로 접근 지정한 멤버를 다른 형식에서 접근할 때 개체의 멤버는 참조하는 변수로 접근하지만 정적 멤버를 접근할 때는 클래스 이름으로 접근합니다.
다음은 정적 멤버 필드를 이용한 개체의 일련 번호 부여하는 예제 코드입니다.
public class Unit { static int last_seq; int seq; public Unit(){ last_seq++; seq = last_seq; } public int getSeq(){ return seq; } public static int getLastSeq(){ return last_seq; } }
public class Program { public static void main(String[] args){ System.out.println("Unit의 가장 최근에 부여한 Seq No:"+Unit.getLastSeq()); Unit u1 = new Unit(); System.out.println("Unit의 가장 최근에 부여한 Seq No:"+Unit.getLastSeq()); Unit u2 = new Unit(); System.out.println("Unit의 가장 최근에 부여한 Seq No:"+Unit.getLastSeq()); System.out.println("u1의 Seq No:"+u1.getSeq()); System.out.println("u2의 Seq No:"+u2.getSeq()); } }
실행 화면
Unit의 가장 최근에 부여한 Seq No:0 Unit의 가장 최근에 부여한 Seq No:1 Unit의 가장 최근에 부여한 Seq No:2 u1의 Seq No:1 u2의 Seq No:2
정적 멤버 필드 중에 개체 상태의 최대값이나 최소값처럼 변하지 않는 상수를 지정할 때는 final 키워드를 사용합니다.
메서드 내에서 변하지 않는 상수를 표현할 때는 const 키워드를 붙여 상수를 표현하며 형식 전체에서 사용할 상수를 표현할 때는 static 키워드와 final 키워드를 사용합니다.
다음은 정적 멤버 필드에 fianl 키워드를 명시하여 상수를 지정한 예제 코드입니다.
public class Unit { static final int MAX_HP = 100; static final int MIN_HP = 0; int hp; public Unit(){ hp = MIN_HP; } public void play(int pcnt){ setHp(hp+pcnt); } private void setHp(int value) { if(value>MAX_HP){ value = MAX_HP; } if(value<MIN_HP){ value = MIN_HP; } hp = value; } public int getHp(){ return hp; } }
public class Program { public static void main(String[] args){ Unit unit = new Unit(); unit.play(30); System.out.println("유닛 HP:"+ unit.getHp()); unit.play(50); System.out.println("유닛 HP:"+ unit.getHp()); unit.play(30); System.out.println("유닛 HP:"+ unit.getHp()); } }
실행 화면
유닛 HP:30 유닛 HP:80 유닛 HP:100
물론 정적 멤버가 아닌 일반 멤버 필드에 final 키워드를 명시하면 개체의 변하지 않는 상수를 캡슐화할 수 있습니다. 예를 들어 학생 데이터를 표현할 때 번호를 생성할 때 부여하고 이 후에는 변하지 않게 상수화할 필요가 있다면 final 키워드를 명시하여 정의합니다.
다음 예제는 학생 클래스를 정의하는 예제입니다. 정적 멤버로 가장 최근에 부여한 학생의 번호를 기억하는 last_num이 있고 학생 변수를 fianl 키워드를 명시하여 상수화하였습니다.
//final을 이용하여 num 멤버를 상수화 public class Student { static int last_num=0; //정적 멤버 final int num; //상수화한 멤버 String name; public Student(String name){ this.name = name; last_num++; num = last_num; } public void View(){ System.out.print("이름"+name); System.out.println(" 번호:"+ Integer.toString(num)); } }
//fianl 키워드를 이용하여 멤버를 상수화 예 public class Program { public static void main(String[] args){ Student s1 = new Student("홍길동"); s1.View(); Student s2 = new Student("강감찬"); s2.View(); } }
실행 화면
이름홍길동 번호:1 이름강감찬 번호:2