구분 설명
인스턴스(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));
    }
}

 

 

 

* 내용 참고 - 책 '이것이 자바다'

+ Recent posts