static이란 "고정된", "정적인" 이라는 뜻의 단어이다. Java, C# 등의 프로그래밍 언어에서는 정적 변수(static variable)를 선언하기 위해 사용되는 키워드이다. 이번에 static 키워드에 대해서 포스팅하는 이유는 최근에 Java로 HashMap을 이용하여 간단하게 메모리에 데이터를 저장하고 조회하는 기능을 구현하는 와중에 static 키워드로 변수를 선언하지 않은 이유로 NullPointerException이 발생했기 때문이다...
개발을 하는 과정에서 여러 인스턴스가 공통으로 사용하는 변수가 필요한 경우가 있다.
예를 들면,
public class Student {
int studentCnt = 0; // 전체 학생 수
private int id; // 학번
private String name; // 이름
private int age; // 나이
private String major; // 전공
public Student(int id, String name, int age, String major) {
this.id = id;
this.name = name;
this.age = age;
this.major = major;
}
@Override
public String toString() {
return "Student{" +
"studentCnt=" + studentCnt +
", id=" + id +
", name='" + name + '\'' +
", age=" + age +
", major='" + major + '\'' +
'}';
}
}
이라는 학생 인스턴스를 생성하는 Student 클래스를 만들었다. 위의 Student 클래스로 여러 개의 객체를 생성해보자.
public class Main {
public static void main(String[] args) {
Student student1 = new Student(1, "adam", 27, "computer science");
student1.studentCnt++;
Student student2 = new Student(2, "julie", 24, "business administration");
student1.studentCnt++;
student2.studentCnt = student1.studentCnt;
Student student3 = new Student(3, "john", 30, "architecture");
student1.studentCnt++;
student2.studentCnt++;
student3.studentCnt = student2.studentCnt;
System.out.println(student1.toString());
System.out.println(student2.toString());
System.out.println(student3.toString());
}
}
Student{studentCnt=3, id=1, name='adam', age=27, major='computer science'}
Student{studentCnt=3, id=2, name='julie', age=24, major='business administration'}
Student{studentCnt=3, id=3, name='john', age=30, major='architecture'}
위의 코드처럼 객체를 생성할 때에는 studentCnt 변수의 값을 매번 바꿔줘야 하는 아쉬움이 있다. 즉, studentCnt는 모든 객체들이 공유하는 값이라고 보면 된다. 따라서, static 키워드를 붙이게 되면 객체의 개수와 상관없이 단 하나만 생성이 된다는 뜻이다.
public class Student {
static int studentCnt = 0; // 전체 학생 수
private int id; // 학번
private String name; // 이름
private int age; // 나이
private String major; // 전공
public Student(int id, String name, int age, String major) {
this.id = id;
this.name = name;
this.age = age;
this.major = major;
}
@Override
public String toString() {
return "Student{" +
"studentCnt=" + studentCnt +
", id=" + id +
", name='" + name + '\'' +
", age=" + age +
", major='" + major + '\'' +
'}';
}
}
public class Main {
public static void main(String[] args) {
Student student1 = new Student(1, "adam", 27, "computer science");
Student.studentCnt++;
Student student2 = new Student(2, "julie", 24, "business administration");
Student.studentCnt++;
Student student3 = new Student(3, "john", 30, "architecture");
Student.studentCnt++;
System.out.println(student1.toString());
System.out.println(student2.toString());
System.out.println(student3.toString());
}
}
위처럼 매번 Student 객체를 생성할 때마다 각 객체의 studentCnt 변수에 접근해서 값을 수정하지 않아도 된다. 그리고 특이한 점은 static이 붙은 멤버변수는 객체를 생성하지 않아도 쓸 수 있다.
이번에는 static 키워드가 변수가 아닌 메소드에 붙었을 때에 대해 설명할 것이다.
public class Student {
static int studentCnt = 0; // 전체 학생 수
private int id; // 학번
private String name; // 이름
private int age; // 나이
private String major; // 전공
public Student(int id, String name, int age, String major) {
this.id = id;
this.name = name;
this.age = age;
this.major = major;
studentCnt++;
}
public int getStudentCnt() {
return studentCnt;
}
@Override
public String toString() {
return "Student{" +
"studentCnt=" + studentCnt +
", id=" + id +
", name='" + name + '\'' +
", age=" + age +
", major='" + major + '\'' +
'}';
}
}
이전의 Student 클래스에서 전체 학생 수를 반환하는 getStudentCnt()
메소드를 추가하였다. (생성자에 studentCnt++
의 코드도 삽입했다.) 해당 메소드는 아직 static 키워드가 없기 때문에 사용할려면 다음과 같이 실행 코드를 설계해야 한다.
public class Main {
public static void main(String[] args) {
Student student = new Student(1, "michael", 33, "philosophy");
int studentCnt = student.getStudentCnt();
System.out.println("전체 학생 수: " + studentCnt);
}
}
위의 실행 코드에선 Student 클래스의 getStudentCnt()
메소드를 사용하기 위해서 객체를 선언할 수 밖에 없었다. 그러나 getStudentCnt()
메소드는 단순히 전체 학생의 수를 반환하는 메소드인데 굳이 객체까지 생성할 필요가 있었을까.
public class Student {
...
public static int getStudentCnt() {
return studentCnt;
}
...
}
getStudentCnt()
메소드에 static 키워드를 삽입하였다. 실행 코드는 다음과 같이 수정할 수 있다.
public class Main {
public static void main(String[] args) {
// Student student = new Student(1, "michael", 33, "philosophy");
// int studentCnt = student.getStudentCnt();
// System.out.println("전체 학생 수: " + studentCnt);
int studentCnt = Student.getStudentCnt();
System.out.println("전체 학생 수: " + studentCnt);
}
}
Student 클래스를 이용하여 하나의 객체를 생성하지 않아도 위와 같이 getStudentCnt()
메소드를 호출할 수 있다. 단, static 메소드를 사용하려면 해당 메소드에서 사용되는 변수가 static int studentCnt = 0;
처럼 static 변수여야만 한다.
위처럼 static 키워드를 사용한 코드에는 몇가지 특징이 있다.
https://dev-coco.tistory.com/23
위에서 언급했듯이 static 키워드는 변수를 공유한다는 느낌이 있다.
// Computer Science의 CS이다...
class CS {
String major = "computer science";
}
public class Main {
public static void main(String[] args) {
CS person1 = new CS();
CS person2 = new CS();
}
}
위와 같은 코드를 볼 때, CS 클래스를 만들고 객체를 생성할 때마다 major 변수를 저장하기 위한 별도의 메모리가 필요하다. 그런데 CS 클래스로 생성될 객체의 major 변수는 모두 "computer science"로 동일하게 설계할 예정이기에 위의 코드처럼 메모리를 낭비하면서 설계할 필요가 없다.
class CS {
static String major = "computer science";
}
따라서 위의 코드처럼 static 키워드를 넣어준다면 Java는 메모리 할당을 딱 한번만 하게 되어 메모리 사용에도 이점이 있다.