- 인스턴스 멤버: 객체마다 가지고 있는
멤버(필드, 메소드)
- 정적 멤버(클래스 멤버): 클래스에 위치시키고 객체들이 공유하는 멤버
정적 멤버를 따로 구분하는 이유: 객체 마다 공통의 값을 가지는 필드를 효율적으로 관리하기 위함
위의 예시 사진처럼 객체마다 공통된 값을 공유하는 playerCount 필드를 모든 객체마다 갖고 있다면 메모리의 낭비 뿐만이 아니라, playerCount 값이 바뀔 때 마다 모든 객체의 필드값을 변경해야 하는 추가작업이 필요하여 효율적이지 못하다. 이렇게 공통적인 값을 객체들이 공유하고 쉽게 접근하여 사용할 수 있도록 인스턴스 멤버와 구분하여 정적멤버로 관리한다.
그렇다면 위와 같은 메소드를 인스턴스 메소드라 칭하는 이유는 무엇일까?
인스턴스 메소드는 메모리 블록 내부에 인스턴스 필드가 사용되기 때문에 인스턴스 메소드 역시 객체 없이 실행할 수 없기 때문이다.
*Method area: JVM이 시작할 때 생성되어 클래스 별로 런타임 상수풀, 필드 데이터, 메소드 데이터, 메소드 코드, 생성자 코드 등을 분류해 저장하는 영역
인스턴스 필드 vs 정적 필드의 선언 기준
객체마다 각기 달리 가지고 있어야 할 데이터라면 인스턴스 필드로, 객체마다 동일한, 공통적인 데이터라면 정적 필드로 선언하는 것이 좋다.
인스턴스 메소드 vs 정적 메소드의 선언 기준
객체마다 다른 값을 가지는 인스턴스 필드를 이용하거나 건드린다면 인스턴스 메소드로, 인스턴스 필드와 무관하게 파라미터 등을 이용하여 실행한다면 정적 메소드로 선언하는 것이 좋다.
public class Calculator{
String color; // 인스턴스 필드
void setColor(String color){this.color = color}; // 인스턴스 메소드
static int plus(int x, int y){return x + y}; // 정적 메소드
static int minus(int x, int y){return x - y}; // 정적 메소드
}
위의 Calculator 클래스처럼 덧셈, 뺄셈 기능은 인스턴스 필드를 이용하기보다는 외부에서 주어진 매개값들을 가지고 덧셈과 뺄셈을 수행하므로 정적 메소드로 선언하는 것이 좋다.
public class Calculator{
static double pi = 3.14159; // 정적 필드
static int plus(int x, int y){return x + y}; // 정적 메소드
static int minus(int x, int y){return x - y}; // 정적 메소드
}
// 객체 생성 없이 클래스를 통해 정적 멤버 접근
double result1 = 10 * 10 * Calculator.pi;
int result2 = Calculator.plus(10, 5);
int result3 = Calculator.minus(10, 5);
// 객체 생성 후
Calculator myCalcu = new Calculator();
// 객체 참조 변수를 통해 정적 멤버에 접근
double result1 = 10 * 10 * myCalcu.pi; // 가능은 하나 별로인 예시
위의 예시처럼 객체를 생성하지 않고 클래스를 통해 정적 멤버를 사용한다. 또한 객체를 생성한 후 객체 참조 변수를 통해서도 정적 멤버에 접근이 가능하나, 클래스로 접근하는 것이 원칙이라고 한다.
정적 멤버의 이러한 객체가 없어도 실행된다는 특징 때문에 정적 메소드를 선언할 때는 이들 내부에서 객체를 생성하지 않는 한 인스턴스 필드나 인스턴스 메소드를 사용할 수 없다.
정적 메소드에 인스턴스 멤버를 사용하고 싶은 경우도 가능하며, 이러한 경우에는 정적 메소드 안에 객체를 먼저 생성한 후 참조 변수로 접근해야 한다.
public class ClassName{
// 인스턴스 필드와 메소드
int field1;
void method1(){...}
// 정적 필드와 메소드
static int field2;
static void method2() {...}
// 정적 메소드 >> 에러 문법
static void method3(){
this.field1 = 10; // 컴파일 에러
this.method1(); // 컴파일 에러
field2 = 10;
method2();
}
// 정적 메소드 >> 옳바른 문법
static void method3(){
ClassName obj = new ClassName();
obj.field1 = 10;
obj.method1();
}
}
❗️이는 main()메소드
에서도 동일한 규칙으로 적용된다.
main() 메소드도 정적 메소드이므로 객체 생성 없이 인스턴스 멤버를 main() 메소드에서 바로 사용할 수 없다!
public class Car{
int speed;
void run() {...}
// 아래 선언한 변수와 메소드를 찾을 수 없다는 컴파일 에러
public static void main(String[] args){
speed = 60;
run ();
}
}
// 올바른 예시
public class Car{
int speed;
void run() {...}
public static void main(String[] args){
Car myCar = new Car(); // 객체 생성 후
myCar.speed = 60;
myCar.run();
}
}