구분 | 설명 |
인스턴스(instance) 멤버 | 객체에 소속된 멤버 (객체를 생성해야만 사용할 수 있는 멤버) |
정적(static) 멤버 | 클래스에 고정된 멤버 (객체 없이도 사용할 수 있는 멤버) |
1. 인스턴스 멤버
🚀 객체에 소속된 멤버를 말한다.
public class Car {
// 인스턴스 필드 선언
int gas;
// 인스턴스 메소드 선언
void setSpeed(int speed) { ... }
}
- gas 필드와 setSpeed() 메소드는 인스턴스 멤버이기 때문에 외부 클래스에서 사용하기 위해서는 Car 객체를 먼저 생성하고 참조 변수로 접근해서 사용해야 한다.
Car myCar = new Car();
myCar.gas = 10;
myCar.setSpeed(60);
Car yourCar = new Car();
yourCar.gas = 20;
yourCar.setSpeed(80);
👾 메소드는 코드의 덩어리이므로 객체마다 저장한다면 중복 저장으로 인해 메모리 효율이 떨어짐
👾 메소드 코드는 메소드 영역에 두되 공유해서 사용하고, 이때 객체 없이는 사용하지 못하도록 제한을 걸어둔 것
2. 정적 멤버
🚀 자바는 클래스 로더를 이용해서 클래스를 메소드 영역에 저장하고 사용한다.
🚀 정적 멤버란 메소드 영역의 클래스에 고정적으로 위치하는 멤버를 말한다.
➡️ 객체를 생성할 필요 없이 클래스를 통해 바로 사용이 가능
1) 정적 멤버 선언
⚒️ 필드와 메소드는 모두 'static 키워드'를 추가하면 정적 멤버가 될 수 있다.
public class 클래스 {
// 정적 필드 선언
static 타입 필드 [= 초기값];
// 정적 메소드
static 리턴타입 메소드( 매개변수, ... ) { ... }
}
- 객체마다 가지고 있을 필요성이 없는 공용적인 필드는 정적 필드로 선언하는 것이 좋다.
- 예를 들어 Calculator 클래스에서 원의 넓이나 둘레를 구할 때 필요한 파이(π)는 객체마다 가지고 있을 필요가 없기 때문에 정적필드로 선언
public class Calculator {
String color; // 계산기 별로 색깔이 다를 수 있다.
static double pi = 3.14159; // 계산기에서 사용하는 파이 값은 동일
}
- 인스턴스 필드를 이용하지 않는 메소드는 정적 메소드로 선언하는 것이 좋다.
- 예를 들어 Calculator의 plus() 메소드는 외부에서 주어진 매개값들을 가지고 처리하므로 정적 메소드로 선언하는 것이 좋다.
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; } // 정적 메소드
}
2) 정적 멤버 사용
⚒️ 클래스가 메모리로 로딩되면 정적 멤버를 바로 사용할 수 있는데, 클래스 이름과 함께 도트(.) 연산자로 접근하면 된다.
⚒️ 객체 참조 변수로도 접근이 가능
public class Calculator {
static double pi = 3.14159;
static int plus(int x, int y) { ... }
static int minus(int x, int 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;
int result2 = myCalcu.plus(10, 5);
int result3 = myCalcu.minus(10, 5);
3) 정적 블록
⚒️ 정적 필드는 필드 선언과 동시에 초기값을 주는 것이 일반적
⚒️ but, 복잡한 초기화 작업이 필요하다면 정적 블록을 이용
static {
...
}
- 정적 블록은 클래스가 메모리로 로딩될 때 자동으로 실행된다.
- 정적 블록이 클래스 내부에 여러 개가 선언되어 있을 경우에는 선언된 순서대로 실행된다.
public class Television {
static String company = "MyCompany";
static String model = "LCD";
static String info;
static {
info = company + "-" + model;
}
}
public class TelevisionExample {
public static void main(String[] args) {
System.out.println(Television.info);
}
}
4) 인스턴스 멤버 사용 불가
⚒️ 정적 메소드와 정적 블록은 객체가 없어도 실행된다는 특징 때문에 내부에 인스턴스 필드나 인스턴스 메소드를 사용할 수 없다.
⚒️ 객체 자신의 참조인 this 도 사용 X
⚒️ main() 메소드도 정적 메소드이므로 동일한 규칙이 적용된다.
➡️ 객체 생성 없이 인스턴스 필드와 인스턴스 메소드를 main() 메소드에 바로 사용할 수 없다.
public class Car {
// 인스턴스 필드 선언
int speed;
// 인스턴스 메소드 선언
void run() { ... }
// 메인 메소드 선언
public static void main(String[] args) {
speed = 60; // 컴파일 에러
run(); // 컴파일 에러
}
}
↓
public static void main(String[] args) {
// 객체 생성
Car myCar = new Car();
// 인스턴스 멤버 사용
myCar.speed = 60;
myCar.run();
}
사용 예제
class Cars {
static int wheel = 4; // 정적 멤버 -> 객체 생성 안하더라도 메모리에 올라가 있음
int speed; // 인스턴스 멤버
}
public class Test {
// 인스턴스 변수는 각각의 인스턴스마다 고유의 저장 공간을 가지고 있기 때문에 독립적으로 고유값을 저장 가능.
public static void main(String[] args) {
System.out.println(Cars.wheel); // 클래스 이름으로 접근 가능
System.out.println(Cars.speed); // 에러발생!
// 인스턴스 변수는 클래스 이름으로 접근 불가 -> 메모리에 올라와있지 않기 때문.
Cars myCar1 = new Cars();
System.out.println(Cars.wheel); // 4
System.out.println(myCar1.speed); // 0
Cars myCar2 = new Cars();
System.out.println("<변경 전>");
System.out.println("myCar1.speed: " + myCar1.speed); // 0
System.out.println("myCar2.speed: " + myCar2.speed); // 0
System.out.println("myCar1.wheel: " + Cars.wheel); // 4
System.out.println("myCar2.wheel: " + Cars.wheel); // 4
myCar2.speed = 100;
myCar2.wheel = 5;
System.out.println("<변경 후>");
System.out.println("myCar1.speed: " + myCar1.speed); // 0
System.out.println("myCar2.speed: " + myCar2.speed); // 100
System.out.println("myCar1.wheel: " + Cars.wheel); // 5
System.out.println("myCar2.wheel: " + Cars.wheel); // 5
// 인스턴스는 클래스 변수를 공유하기 때문에 같은 값이 됨.
}
}
정적 메소드와 인스턴스 메소드
class Area {
static void manual() { // 클래스 메서드
System.out.println("현재 사용 가능한 함수 목록");
System.out.println("triangle : 삼각형 넓이");
System.out.println("rectangle : 사각형 넓이");
System.out.println("입니다.");
}
double triangle(int a, int b) { // 인스턴스 메서드
return (double) a * b / 2;
}
int rectangle(int a, int b) { // 인스턴스 메서드
return a * b;
}
}
public class Test {
public static void main(String[] args) {
Area.manual(); // 클래스 메서드 접근 가능
// Area.triangle(3,5); 에러 발생.
// Area.rectangle(3,5); 에러발생.
Area cal = new Area();
cal.manual(); // 가급적 클래스 단위로 메서드 호출하는 것이 좋음.
System.out.println(cal.triangle(3, 5));
System.out.println(cal.rectangle(3,4));
}
}
* 내용 참고 - 책 '이것이 자바다'
'Programming Language > JAVA' 카테고리의 다른 글
[Java] Getter와 Setter · 싱글톤 패턴 (0) | 2024.08.11 |
---|---|
[Java] final 필드와 상수 · 접근 제한자 (0) | 2024.08.11 |
[Java] 생성자 Constructor (0) | 2024.08.10 |
[Java] 객체 지향 프로그래밍 (OOP) · 객체와 클래스 · 필드 (0) | 2024.08.10 |
[Java] JVM 메모리 구조 · 오버로딩 (0) | 2024.08.09 |