클래스는 객체의 설계도이다. 클래스에는 객체를 생성하기 위한 필드와 메서드가 정의되어 있다. 클래스로부터 만들어진 객체를 해당 클래스의 인스턴스라고 한다.
// 설계도
class Calculator {
int left, right;
public void setOprands(int left, int right) {
// this는 새로 생성한 인스턴스(객체)를 가리킨다.
this.left = left;
this.right = right;
}
public void sum() {
System.out.println(this.left + this.right);
}
public void avg() {
System.out.println((this.left + this.right) / 2);
}
}
public class CalculatorDemo4 {
public static void main(String[] args) {
// c1 변수의 데이터타입은 그 객체의 이름을 갖는다
Calculator c1 = new Calculator(); // 인스턴스(객체) 생성
c1.setOprands(10, 20); // 연산의 대상을 인자로 전달
c1.sum();
c1.avg();
}
}
클래스에는 객체가 가져야 할 구성 멤버가 선언된다. 구성 멤버에는 필드, 생성자, 메서드가 있다. 이 구성 멤버들은 생략되거나 복수로 작성될 수 있다.
클래스는 객체의 설계도이다. 클래스 멤버(필드, 메서드)는 당연히 객체에도 포함되어 있어야 한다. 하지만 이것이 과연 효율적인지 생각해볼 필요가 있다.
클래스로부터 객체(인스턴스)는 하나가 아니라 여러 개가 만들어질 수 있다. 이 경우 클래스 멤버들을 객체마다 모두 가지고 있을 필요가 있을까?
객체마다 필드값이 달라야 한다면 해당 필드는 객체마다 가지고 있는 것이 맞다. 하지만 객체의 필드값이 모두 같아야 한다면 이 필드를 객체마다 가지고 있을 필요가 있을까? 만약 객체마다 갖고 있다면 메모리 낭비가 되며, 모든 객체의 필드 값을 같게 맞추는 추가적인 작업이 필요할 수도 있다. 오히려 이런 필드는 한 곳에 위치시키고 객체들이 공유하는 것이 좋을 수 있다.
자바는 이런 경우를 위해 클래스 멤버를 인스턴스 멤버와 정적 멤버로 구분해서 선언할 수 있도록 하고 있다. 인스턴스 멤버는 객체마다 가지고 있는 멤버를 말하고, 정적 멤버는 클래스에 위치시키고 객체들이 공유하는 멤버를 말한다.
정적(static) 멤버는 클래스에 고정된 멤버로서 객체를 생성하지 않고 사용할 수 있는 필드와 메서드를 말한다. 각각 정적 필드, 정적 메서드라고 부른다.
// 설계도
class Calculator1 {
// 클래스 변수 (클래스 멤버)이면서 정적 멤버 선언
static double PI = 3.14;
static int base = 0;
int left, right;
public void setOprands(int left, int right) {
this.left = left;
this.right = right;
}
public void sum() {
System.out.println(this.left + this.right);
}
public void avg() {
System.out.println((this.left + this.right) / 2);
}
}
public class CalculatorDemo {
public static void main(String[] args) {
Calculator1 c1 = new Calculator1();
System.out.println(c1.PI); // 3.14
Calculator1 c2 = new Calculator1();
System.out.println(c2.PI); // 3.14
// 클래스를 통해서 직접 접근할 수도 있다.
System.out.println(Calculator1.PI); // 3.14
}
}
인스턴스 변수는 인스턴스마다 다른 값을 가지고 클래스 변수는 클래스의 변수이기 때문에 그 클래스를 통해 만들어진 모든 인스턴스들은 자연스럽게 그 클래스 변수를 그대로 가지고 있다.
// 설계도
class Calculator2 {
// 클래스 변수 (클래스 멤버)
static double PI = 3.14;
static int base = 0;
int left, right;
public void setOprands(int left, int right) {
this.left = left;
this.right = right;
}
public void sum() {
System.out.println(this.left + this.right + base);
}
public void avg() {
System.out.println((this.left + this.right + base) / 2);
}
}
public class CalculatorDemo {
public static void main(String[] args) {
Calculator2 c1 = new Calculator2();
c1.setOprands(10, 20);
// 30 출력
c1.sum();
Calculator2.base = 10;
// 40 출력
c1.sum();
}
}
각각의 객체마다 다른 값을 대입해서 출력해야 할 때에는 인스턴스를 생성하지만, 고정 값만 필요할 경우에는 정적 메서드를 사용한다.
인스턴스를 생성하지 않기 때문에 메모리 절약에 도움이 된다.
// 설계도
class Calculator3 {
public static void sum(int left, int right) {
System.out.println(left + right);
}
public static void avg() {
System.out.println((left + right) / 2);
}
}
public class CalculatorDemo {
public static void main(String[] args) {
// 객체 생성 없이 클래스 메서드에 바로 접근 가능
Calculator3.sum(10, 20);
Calculator3.avg(10, 20);
}
}
정적 메서드 선언 시 주의할 점
객체가 없어도 실행된다는 특징 때문에 정적 메서드를 선언할 때는 이들 내부에 인스턴스 필드나 인스턴스 메서드를 사용할 수 없다. 또한 객체 자신의 참조인 this 키워드도 사용이 불가하다. 컴파일 에러가 발생한다.
참고
혼자 공부하는 자바
생활코딩 자바