[코드스쿼드 코코아 과정] 클래스 맴버와 인스턴스 맴버

Kyu·2020년 11월 8일
0
Calculate c1 = new Calculate();
c1.setOprands(10, 20);
c1.sum();
c1.avg();

Calculate c2 = new Calculate();
c2.setOprands(20, 40);
c2.sum();
c2.avg();

c1과 c2는 left, right라는 똑같은 변수를 가지고 있지만 그 값은 다르다는걸 알수있다. 그렇기 떄문에 left와 right의 변수는 인스턴스의 변수이다.
그러면 인스턴스의 소유가 아닌 변수가 있을 수있나? 인스턴스의 소유가 아니고 클래스의 소유인 변수가 존재한다. 이 클래스의 변수는 인스턴스의 변수와 다른 특징을 가지고 있다.

클래스의 멤버 변수 (클래스의 소유인 변수) 는 모든 인스턴스에서 똑같은 값을 같는다. 또한 인스턴스를 생성하지 않고도 클래스의 변수에 접근해서 변수를 사용할수있다 (인디언 이름 짓기에서 내가 하고 싶었던 것)

인스턴스 변수는 인스턴스마다 다른 값을 가진다. 예를 들어서 left right에 아까 10,20 || 20,40 을 넣은거 처럼말이다. 그렇기 때문에 클래스의 변수가 아니라 인스턴스 변수라고 불리는 것이다.

클래스 변수는 클래스의 변수이기 때문에 클래스에 따라서 만들어진 모든 인스턴스는 자연스럽게 그 클래스의 변수를 가지게 된다.

class Calculator {
  static double PI = 3.14;
  int left, right;
  
  	public void setOprands(int left, int right) {
      this.left = left;
      this.right = right;
    }
  	// 이하 생략
}

여기서 int 클래스 변수는 그냥 선언해준거지만 double 데이터 타입의 왼쪽에 static이 붙었다. static 뒤에 따라오는 변수는 static한 변수가 된다는 뜻이고, 그리고 이 변수가 클래스의 소속이 된다는 뜻이다. 클래스의 소속이 된다는 것은 변수를 모든 메소드에서 모든 인스턴스에서 동일한 값으로 가져온다. 라는 뜻이다.

public class CalculatorDemo1 {
  public static void main(String[] args){
    
    Calculator c1 = new Calculator();
    System.out.println(c1.PI);
    
    Calculator c2 = new Calculator();
    System.out.println(c2.PI);
    
    System.out.println(Calculator.PI);
  }
}

그래서 위에 코드처럼 c1.PI || c2.PI || Calculator.PI 라고 불러왔을 때, 똑같은 3.14라는 결과를 같게 된다. 왜냐하면 c1 이든 c2 이든 전역변수 PI의 값은 같고 인스턴스에서 말고 클래스에서도 전역변수를 불러올 수 있기 때문이다.

클래스 메소드

클래스를 메소드처럼 쓸 수있나? 그렇다이다.

class Calculator3{
  
    public static void sum(int left, int right){
        System.out.println(left+right);
    }
     
    public static void avg(int left, int right){
        System.out.println((left+right)/2);
    }
}
 
public class CalculatorDemo3 {
     
    public static void main(String[] args) {
        Calculator3.sum(10, 20);
        Calculator3.avg(10, 20);
         
        Calculator3.sum(20, 40);
        Calculator3.avg(20, 40);
    }
 
}

위 코드처럼 만약 메소드가 인스턴스 변수를 참조하지 않는다면 클래스 메소드를 사용해서 불필요한 인스턴스의 생성을 막을 수 있다. 아까처럼 c1의 인스턴스를 생성하고 setOprands 메소드에 변수의 값(인스턴스 멤버)를 지정해서 sum이나 avg를 호출하는 이유는, 다른 인스턴스들과 구분되게 left와 right값의 상태가 다른 c1 c2 c3의 필요성이 있을때, 그 결과가 다르게 출력되어야 하는 경우에 인스턴스를 만들어야한다.

그런데 sum과 avg가 꼭 같은 상태가 아니라 필요할때마다 인자를 주어서 다르게 사용하고 싶을수가 있다. 같은 상태를 셋팅할필요없이 마치 일회용물품처럼 한번만 사용하면 된다면 굳이 메모리를사용하면서 코드를 길게해서 인스턴스를 만들어도 되지않다. 이럴경우에 클래스메소드를 만들경우 메모리도 절약하고 더 빨리 동작하는 어플리케이션을 만들수 있을것이다.

한가지 사실만 확인하자. 클래스는 이미 메모리에 할당 되어 있는 것이고 인스턴스의 변수는 인스턴스가 만들어지면서 생성이 된다.

마지막으로, 각각의 클래스와 인스턴스의 변수와 메소드를 비교하면 클래스와 인스턴스의 관계를 더 잘 이해할 수 있다.

class C1{
    static int static_variable = 1;
    int instance_variable = 2;
    static void static_static(){
        System.out.println(static_variable);
    }
    static void static_instance(){
        // 클래스 메소드에서는 인스턴스 변수에 접근 할 수 없다. 
        System.out.println(instance_variable);
    }
    void instance_static(){
        // 인스턴스 메소드에서는 클래스 변수에 접근 할 수 있다.
        System.out.println(static_variable);
    }
    void instance_instance(){        
        System.out.println(instance_variable);
    }
}
public class ClassMemberDemo {  
    public static void main(String[] args) {
        C1 c = new C1();
        // 인스턴스를 이용해서 정적 메소드에 접근 -> 성공
        // 인스턴스 메소드가 정적 변수에 접근 -> 성공
        c.static_static();
        // 인스턴스를 이용해서 정적 메소드에 접근 -> 성공
        // 정적 메소드가 인스턴스 변수에 접근 -> 실패
        c.static_instance();
        // 인스턴스를 이용해서 인스턴스 메소드에 접근 -> 성공
        // 인스턴스 메소드가 클래스 변수에 접근 -> 성공
        c.instance_static();
        // 인스턴스를 이용해서 인스턴스 메소드에 접근 -> 성공 
        // 인스턴스 메소드가 인스턴스 변수에 접근 -> 성공
        c.instance_instance();
        // 클래스를 이용해서 클래스 메소드에 접근 -> 성공
        // 클래스 메소드가 클래스 변수에 접근 -> 성공
        C1.static_static();
        // 클래스를 이용해서 클래스 메소드에 접근 -> 성공
        // 클래스 메소드가 인스턴스 변수에 접근 -> 실패
        C1.static_instance();
        // 클래스를 이용해서 인스턴스 메소드에 접근 -> 실패
        C1.instance_static();
        // 클래스를 이용해서 인스턴스 메소드에 접근 -> 실패
        C1.instance_instance();
    }
 
}

코드 출처: https://opentutorials.org/course/1223/5440

profile
TIL 남기는 공간입니다

0개의 댓글