출처 : 혼자공부하는 자바
클래스에 선언된 필드와 메소드가 모두 객체 내부에 포함되는 것은 아니다. 일부는 포함되겠지만, 포함이 되지 않고 클래스에 그대로 남아 있는 것도 있습니다.
클래스는 객체의 설계도이다. 클래스 멤버(필드,메소드)는 당연히 객체에도 포함되어 있어야한다. 하지만 이것이 과연 효율적인지 생각해 볼 필요가 있다.
클래스로부터 인스턴스(객체) 는 여러개 만들어 질수 있다. 이 경우 클래스 멤버들을 객체마다 모두 가지고 있어야 되나?
예를 들어 , 객체마다 필드값이 달라야 한다면 해당 필드는 개체마다 가지고 있는 것이 맞다. 하지만 객체의 필드값이 모두 같아야 한다면 이 필드를 객체마다 가지고 있을 필요가 있을까요? 만약 객체마다 갖고 있다면 메모리 낭비가 되며, 모든 객체의 필드값을 같게 맞추는 추가적인 작업이 필요할 수도 있습니다. 오히려 이런 필드는 한곳에 위치시키고 객체들이 공유하는 것이 좋을수 있습니다.
자바는 이런 경우를 위해 클래스 멤버를 인스턴스 멤버와 정적 멤버로 구분해서 선언할 수 있도록 하고 잇다. 인스턴스 멤버는 객체마다 가지고 있는 멤버를 말하고, 정적 멤버는 클래스에 위치시키고 객체들이 공유하는 멤버를 말한다.
인스턴스 멤버란 객체(인스턴스)를 생성한 후 사용할 수 있는 필드와 메소드를 말하는데, 이들을 각각 인스턴스 필드, 인스턴스 메소드라고 부릅니다. 인스턴스 필드와 메소드는 객체에 소속된 멤버이기 때문에 객체 없이는 사용할 수 없습니다.
인스턴스 필드와 메소드 setSpeed 를 선언해보자
public class Car{
int gas; 필드
void setSpeed(int speed){ 메소드
}
}
gas 필드와 setSpeed() 메소드는 인스턴스 멤버이기 때문에 외부 클래스에서 사용하기 위해서는 우선 Car 객체를 생성하고 참조 변수 myCar 또는 yourCar로 접근해야한다
Car myCar = new Car();
myCar.gas = 10;
myCar.setSpeed(80);
위 코드가 실행된 후 메모리를 살펴보면 인스턴스 필드 gas는 객체마다 따로 존재하고, 인스턴스 메소드는 메소드 영역에 저장되고 공유된다.
그런데 왜 인스턴스 메소드는 개체에 소속된 멤버인데, 객체 내부에 존재하지 않고 메소드 영역에 저장되고 공유될까? 메소드는 코드 블록이므로 객체마다 동일한 코드 블록을 가지고 있을 필요가 없기 때문이다. 그렇다면 인스턴스라는 용어는 왜 붙었는가? 이유는 메모리 블록 내부에 인스턴스 필드 등이 사용되는 경우가 있기 때문이다. 인스턴스 필드가 사용되면 메소드 역시 객체 없이는 실행할 수 없다.
객체 외부에서 인스턴스 멤버에 접근하기 위해 참조 변수를 사용하는 것과 마찬가지로 객체 내부에서도 인스턴스 멤버에 접근하기 위해 this를 사용할수 있다. 우리가 자신을 '나'라고 가리키듯이 객체는 자신을 this라고 한다. 따라서 this.model은 자신이 가지고 있는 model 필드라는 뜻이다. this는 주로 생성자와 메소드의 매개 변수 이름이 필드와 동일한 경우, 인스턴스 멤버인 필드임을 명시하고자 할 때 사용된다.
Car(String model){
this.model = model;
}
void setModel(String model){
this.model = model
}
정적 멤버와 static
정적은 고정된 의미이다. 정적 멤버는 클래스에 고정된 멤버로서 객체를 생성하지 않고 사용할 수 있는 필드와 메소드를 말한다. 이들을 각각 정적 필드, 정적 메소드라고 부른다.
정적 필드와 정적 메소드를 선언하려면 필드와 메소드 선언시 static 키워드를 추가적으로 붙이면된다. 다음은 정적 필드와 정적 메소드를 선언하는 방법을 보여준다
public class 클래스{
static 타입필드 [=초기값];
static 리턴 타입 메소드 (매개변수 선언, ...){}
}
정적 필드와 정적 메소드는 클래스에 고정된 멤버이므로 클래스 로더가 클래스를 로딩해서 메소드 영역에 적재할 때 클래스별로 관리된다. 따라서 클래스의 로딩이 끝나면 바로 사용할 수 있다.
필드를 선언할 때는 인스턴스 필드로 선언할 것인가 아니면 정적 필드로 선언할 것가의 판단 기준이 필요하다.
객체마다 가지고 있어야 할 데이터라면 인스턴스필드로 선언하고. 객체마다 가지고 있을 필요가 없는 공용 데이터라면 정적 필드로 선언하는것이 좋다
예를들어 Calculator 클래스에서 원의 넓이나 둘레를 구할 때 필요한 파이(pi) 는 Calculator 객체마다 가지고 있을 필요가 없는 변하지 않는 공용 데이터이므로 정적 필드로 선언하는 것이 좋다. 그러나 Calculator별로 색깔이 다르다면 color는 인스턴스 변수로 선언해야한다.
public class Calculator {
String color; // 계산기 별로 색깔이 다를 수 있다.
static double pi = 3.14159; //계산기에서 사용하는 파이 값은 동일하다
}
메소드 역시 인스턴스 메소드로 선언할 것인가. 아니면 정적 메소드로 선언할것인가의 대한 판단 기준이 필요하다. 인스턴스 필드를 포함하고 있다면 인스턴스 메소드로 선언하고, 인스턴스 필드를 포함하고 잇지 않다면 정적 메소드로 선언한다.
예를 들어 Calculator 클래스의 덧셈, 뺄셈 기능은 인스턴스 필드를 이용하기 보다는 외부에서 주어진 매개값들을 가지고 덧셈과 뺄셈을 수행하므로 정적 메소드로 선언하는 것이 좋습니다. 그러나 인스턴스 필드인 색깔을 변경하는 메소드는 인스턴스 메소드로 선언해야한다.
public class Calculator{
String color;
void set Color(String color){this.color = color);
static int plus(int x, int y){retrun x+y}
}
객체가 없어도 실행된다는 특징 때문에 정적 메소드를 선언할 때는 이들 내부에 인스턴스 필드나 인스턴스 메소드를 사용할 수 없다. 또한 객체 자신의 참조인(this)키워드도 사용이 불가능하다.
정적 메소드에서 인스턴스 멤버를 사용하고 싶다면 객체를 먼저 생성하고 참조 변수로 접근해야한다
public class ClassName {
int field1;
void method1(){}
static int field2;
static void method2(){}
static void method3(){
ClassName cls = new ClassName();
cls.field1 = 3;
cls.method1();
}
}
또한 인스턴스 필드와 인스턴스 메소드를 바로 사용할수 없으며 항상 그랬듯이 인스턴스 객체를 참조변수에 넣고 거기서 꺼내 쓴다.