[Java] 변수

JD_S·2022년 11월 14일
0

Java

목록 보기
6/21

변수(Variable)란 ?

변수(variable)란 데이터를 저장하기 위해 프로그램에 의해 이름을 할당받은 메모리 공간을 의미한다. 즉, 변수란 데이터를 저장할 수 있는 메모리 공간을 의미하며, 이렇게 저장된 값은 변경될 수 있다. 또한, 변수는 오직 하나의 값만 저장할 수 있다.

'상수(constant)'는 변수와 마찬가지로 '값을 저장할 수 있는 공간'이지만, 변수와 달리 값을 저장하면 다른 값으로 변경할 수 없다. 상수는 변수의 타입 앞에 키워드 final만 붙이면 된다.
그리고 상수와 비교되는 '리터럴(literal)'은 그 자체로 값을 의미하는 것이다.

  int age(변수) = 20(리터럴);
  final int MIN_AGE(상수) = 10(리터럴);

변수의 타입

기본형(primitive type) 변수

실제 값을 저장한다.

  • 정수형 : byte, short(2byte), int(4byte), long(8byte)
  • 실수형 : float(4byte), double(8byte)
  • 문자형 : char(2byte)
  • 논리형 : boolean(1byte)

참조형(reference type) 변수

객체의 주소를 저장한다. 8개의 기본형을 제외한 나머지 타입

선언위치에 따른 변수의 종류

변수의 종류를 결정짓는 중요한 요소는 '변수의 선언 위치'이다.

인스턴스 변수(instance variable) - 멤버 변수

  • 클래스 영역에 선언되며, 인스턴스를 생성할 때 만들어진다. 그래서 변수의 값을 읽어 오거나 저장하기 위해서는 일단 인스턴스를 생성해야 한다. 인스턴스마다 별도의 저장공간을 가지므로 서로 다른 값을 가질 수 있다. 인스턴스마다 고유한 상태를 유지해야하는 속성의 경우, 인스턴스 변수로 선언한다.

클래스 변수(class variable) - 멤버 변수

  • 인스턴스 변수 앞에 static을 붙이면 되고 클래스가 메모리에 올라갈 때 생성된다. 인스턴스마다 독립적인 공간을 갖는 인스턴스 변수와 달리, 클래스 변수는 모든 인스턴스가 공통된 저장공간(변수)을 공유하게 된다. 즉, 한 클래스의 모든 인스턴스들이 공통적인 값을 유지해야하는 속성의 경우, 클래스 변수로 선언해야 한다. 인스턴스 변수와 달리 인스턴스를 생성하지 않고 바로 사용이 가능하다. '클래스 명.클래스 변수'와 같이 말이다.

지역 변수(local variable)

  • 메서드 내에 선언되며 메서드 내에서만 사용 가능하다. 메서드가 종료되면 소멸.

기본형 매개변수 vs 참조형 매개변수

기본형 매개변수

  • 변수의 값을 읽기만 할 수 있다.(read only)
class Data { int x; }

class DTest {
  public static void main(String[] args) {
    Data d = new Data();
    d.x = 10;
    System.out.println("main() : x = " + d.x);
    
    change(d.x);
    System.out.println("After change(d.x)");
    System.out.println("main() : x = " + d.x);
  }
  static void change(int x) {
    x = 1000;
    System.out.println("change() : x = " + x);
  }
}

결과

main() : x = 10
change() : x = 1000
After change(d.x)
main() : x = 10

(1) change메서드가 호출되고 'd.x'가 change메서드의 매개변수 x에 복사됨

(2) change메서드에서 x의 값을 1000으로 변경

(3) change메서드가 종료되면서 매개변수 x는 스택에서 제거됨

'd.x'의 값이 변경된 것이 아니라, change메서드의 매개변수 x의 값이 변경된 것. 즉, 원본이 아니라 복사본이 변경된 것이라 원본에 아무런 영향x

참조형 매개변수

  • 변수의 값을 읽고 변경할 수 있다.(read & write)

class Data2 { int x; }

class DTest2 {
  public static void main(String[] args) {
    Data2 d = new Data2();
    d.x = 10;
    System.out.println("main() : x = " + d.x);
    
    change(d);
    System.out.println("After change(d)");
    System.out.println("main() : x = " + d.x);
  }
  static void change(Data2 d) {
    d.x = 1000;
    System.out.println("change() : x = " + d.x);
  }
}

결과

main() : x = 10
change() : x = 1000
After change(d)
main() : x = 1000

(1) change메서드가 호출되면서 참조변수 d의 주소값이 매개변수 d에 복사됨

(2) change메서드에서 매개변수 d로 x의 값을 1000으로 변경

(3) change메서드가 종료되면서 매개변수 d는 스택에서 제거됨

기본형과 달리 참조형 매개변수는 '값이 저장된 주소'를 가지고 와서 값을 읽는것 뿐만 아니라 변경도 가능 해졌다.

참조변수 - this

this는 참조변수로 인스턴스 자신을 가리킨다. 참조변수를 통해 인스턴스의 멤버에 접근할 수 있는 것처럼, this로 인스턴스 변수에 접근할 수 있는 것이다.

this(), this(매개변수)와 헷갈리지 않아야 한다. 이것들은 같은 클래스의 다른 생성자를 호출할때 쓰는 생성자이다.

여기서 중요한 점은 this를 사용할 수 있는 것은 인스턴스 뿐이라는 것이다. static메서드(클래스 메서드)에서 인스턴스 멤버들을 사용할 수 없는 것처럼, this역시 사용할 수 없다. 그 이유는 static메서드는 인스턴스를 생성하지 않고도 호출될 수 있어 static메서드가 호출된 시점에 인스턴스가 존재하지 않을 수도 있기 때문이다.

변수의 초기화

변수를 선언하고 처음으로 값을 저장하는 것을 '변수의 초기화'라고 한다. 멤버변수는 초기화하지 않고 사용해도 되지만, 지역변수는 사용하기 전 반드시 초기화를 해야 한다.

class Test {
  int x;		//인스턴스 변수
  int y = x;	//인스턴스 변수
  
  void testMethod() {
    int a;		//지역변수
    int b = a;	//에러. 지역변수를 초기화하지 않고 사용했기 때문
  }
}

필드의 초기화

지역변수와 달리 멤버변수는 각 타입의 기본값으로 자동 초기화된다. 그 다음에 명시적 초기화, 초기화 블럭, 생성자 초기화의 순서로 초기화 된다.

명시적 초기화(explicit initialization)

  • 변수를 선언과 동시에 초기화 하는 방법

    class Cat {
      int eye = 2;				//인스턴스 변수의 명시적 초기화
      static int foot = 4;		//클래스 변수의 명시적 초기화
      Animal a = new Animal();	//참조형 변수의 초기화
    }
  • 간단하고 명료하지만 보다 복잡한 초기화를 하기 위해서는 '초기화 블럭' 또는 생성자를 사용해야 한다.

초기화 블럭(initialization block)

  • 클래스 초기화 블럭 : 클래스 변수의 복잡한 초기화에 사용된다. 클래스가 처음으로 메모리에 로딩될 때 단 한 번만 실행된다.

    class InitBlock {
      static int classVar;	//클래스 변수
      int instanceVar;		//인스턴스 변수
      
      static {//클래스 초기화 블럭을 이용한 초기화
        classVar = 10;
      }
    }
    
    public class Member04 {
      public static void main(String[] args) {
        System.out.println(InitBlock.classVar);	//클래스 변수에 접근
      }
    }
    결과 : 10
  • 인스턴스 초기화 블럭 : 인스턴스 변수의 복잡한 초기화에 사용된다. 생성자와 마찬가지로 인스턴스가 생성될 때마다 실행. 하지만 언제나 인스턴스 초기화 블럭이 생성자보다 먼저 실행된다. 생성자와 차이가 거의 없으므로 잘 사용되지 않는다. 단, 여러 개의 생성자가 있으면 모든 생성자에서 공통으로 수행되어야 할 코드를 인스턴스 초기화 블럭에 포함하여 코드의 중복을 막을 수 있다.

    class Car {
      private String modelName;
      private int modelYear;
      private String color;
      private int maxSpeed;
      private int currentSpeed;
      
      {//인스턴스 초기화 블럭
        this.currentSpeed = 0;
      }
      
      Car() {}
      Car(String modelName, int modelYear, String color, int maxSpeed) {
        this.modelName = modelName;
        this.modelYear = modelYear;
        this.color = color;
        this.maxSpeed= maxSpeed;
      }
      
      public int getSpeed() {
        return currentSpeed;
      }
    }
    
    public class Member03 {
      public static void main(String[] args) {
        Car myCar = new Car();						//인스턴스 생성
        System.out.println(myCar.getSpeed());		//인스턴스 메서드의 호출
      }
    }
    결과: 0

생성자 초기화(constructor initialization)

  • 객체의 생성과 동시에 필드를 초기화 하는 방법
  • 따라서 생성자를 이용한 초기화는 인스턴스를 생성할 때까지 필드를 초기화 할 수 없다.

필드 초기화 순서

  • 클래스 변수 초기화 -> 인스턴스 변수 초기화

  • 클래스 변수 : 기본값 -> 명시적 초기화 -> 클래스 초기화 블럭

  • 인스턴스 변수 : 기본값 -> 명시적 초기화 -> 인스턴스 초기화 블럭 -> 생성자

    class InitBlock {
      static int classVar = 10;	//클래스 변수의 명시적 초기화
      int instanceVar = 10;		//인스턴스 변수의 명시적 초기화
      
      static { classVar = 20; }	//클래스 초기화 블럭을 이용한 초기화
      { instanceVar = 20; }		//인스턴스 초기화 블럭을 이용한 초기화
      InitBlock() { instanceVar = 30; }	//생성자를 이용한 초기화
    }
    
    public class Member05 {
      public static void main(String[] args) {
        System.out.println(InitBlock.classVar);
        InitBlock myInit = new InitBlock();
        System.out.println(myInit.instanceVar);
      }
    }
    결과 : 20
           30

Reference

profile
Whatever does not destroy me makes me stronger.

0개의 댓글