른록노트

[Java] 자바 데이터 타입, 변수 그리고 배열 본문

Programming/[Java]

[Java] 자바 데이터 타입, 변수 그리고 배열

른록 2021. 1. 24. 05:44

목표

자바의 프리미티브 타입, 변수 그리고 배열을 사용하는 방법을 익힙니다.

학습할 것

  • 프리미티브 타입 종류와 값의 범위 그리고 기본 값
  • 프리미티브 타입과 레퍼런스 타입
  • 리터럴
  • 변수 선언 및 초기화하는 방법
  • 변수의 스코프와 라이프타임
  • 타입 변환, 캐스팅 그리고 타입 프로모션
  • 1차 및 2차 배열 선언하기
  • 타입 추론, var

자바의 타입은 크게 두가지 타입으로 나눌 수 있습니다.

  • 기본 자료형(Primitive data type)
  • 참조 자료형(Reference data type)

먼저 기본 자료형(프리미티브 타입)에 대해서 먼저 알아보겠습니다.

프리미티브 타입 종류와 값의 범위 그리고 기본 값

기본 자료형은 숫자와 boolean으로 분류 할 수 있고, 숫자에선 정수형과 소수형으로 나눠져 있습니다.

  • 정수형
    • byte
    • short
    • int
    • long
    • char
  • 소수형
    • float
    • double
  • 기타
    • boolean

아래의 표는 기본 자료형 값의 범위와 기본값입니다.

타입 최소 최대 기본값
byte -128 (-2^7) 127 (2^7-1) 0
short -32,768 (-2^15) 32,767 (2^15-1) 0
int -2,147,483,648 (-2^31) 2,147,483,647 (2^31-1) 0
long -9,223,372,036,843,775,808 (-2^63) 9,223,372,036,843,775,807 (2^63-1) 0
char 0 ('\u0000') (0) 65,535 ('\uffff') (2^16-1) \u0000
float (2^-149) ((2-2^-23)*2^127) 0.0
double (2^-1074) ((2-2^-52)*2^1023) 0.0
boolean false true false

byte는 8비트 - 1바이트

short는 16비트 - 2바이트

int는 32비트 - 4바이트

long은 64비트입니다. - 8바이트

제일 첫번째 비트는 부호 비트이고 MSB(Most Significant Bit - 최상위 비트)라고 말합니다.

 

* 자바 8 버전부터는 unsigned int / unsigned long이 추가되었습니다.

참고사이트 (gs.saro.me/dev?tn=361)

 

* JVM 내부에서는 전부 4바이트 크기로 만들어서 관리한다고합니다. 그러므로 기본 자료형을 사용할 때

4바이트보다 작은 타입에 대해서는 int를 사용하는게 성능에 조금이라도 도움이 될 것 입니다.

 

아래는 기본 자료형의 디폴트 값을 확인하기위한 코드입니다.

만약 지역 변수로 기본자료형의 기본값을 사용하려고 한다면 컴파일 에러가 날 것 입니다. 그래서 테스트 하기위해서는 인스턴스 변수나 클래스 변수, 매개변수를 사용해야 컴파일 에러가 발생하지 않습니다.

public class PrimitiveTypes {
  byte aByte;
  short aShort;
  int anInt;
  long aLong;
  char aChar;
  double aDouble;
  float aFloat;
  boolean aBoolean;

  public static void main(String[] args) {
    PrimitiveTypes primitiveTypes = new PrimitiveTypes();
    primitiveTypes.printDefaultValues();
  }

  private void printDefaultValues() {
    System.out.println(aByte);
    System.out.println(aShort);
    System.out.println(anInt);
    System.out.println(aLong);
    System.out.println(aChar);
    System.out.println(aDouble);
    System.out.println(aFloat);
    System.out.println(aBoolean);
  }

}

* 추가로 기본 자료형 중 실수 부분에서 부동소수점 오류가 발생할 수 있는데 이것은 자바언어의 문제가 아니라

컴퓨터는 실수 표현을 부동소수점을 이용하기 때문에 정확한 실수를 저장할 수 없으며, 최대한 완벽에 가깝기를 바라는 근사치를 저장합니다. 그래서 정확한 소수점 계산을 위해 BigDecimal 타입을 사용해야합니다.

System.out.println(0.1-0.01);  // 결과 : 0.09000000000000001
BigDecimal a = new BigDecimal("0.1");
BigDecimal b = new BigDecimal("0.01");
System.out.println(a.subtract(b));  // 결과 : 0.09

프리미티브 타입과 레퍼런스 타입

프리미티브 타입(기본 자료형), 레퍼런스 타입(참조 자료형)
참조 자료형은 기본 자료형을 제외한 나머지 입니다.

 

기본 자료형과 참조 자료형이 생성되면 JVM의 Runtime Data Area에 저장됩니다.

그 중에서도 스택 영역과 힙 영역에 저장됩니다.

기본 자료형은 스택 영역에 값이 바로 저장되고, 참조 자료형은 스택 영역에 힙 영역의 주소값을 저장하고 힙 영역에 실제 객체를 생성하여 저장합니다.

 

(위의 메모리 그림은 '스프링 입문을 위한 자바 객체지향의 원리와 이해' 책의 T 메모리 구조를 참고하였습니다.)

기본 자료형과 참조 자료형의 차이는 객체를 생성할 때 new를 사용해서 객체를 생성하는가 이고,
기본 자료형은 +,-,/,* 등 연산자를 이용 할 수 있지만 참조 자료형은 연산자를 이용 할 수 없습니다.
하지만 특별히 참조 자료형인 String 타입은 new 없이도 객체를 생성할 수 있고 + 연산자를 사용할 수 있습니다.

 

기본 자료형과 참조 자료형의 가장 중요한 차이점은 "Pass by value"와 "Pass by reference"가 있습니다.

기본 자료형을 매개 변수로 사용할 때 "Pass by Value"로 데이터를 전달합니다. 즉 값만 전달합니다. 만약 메소드의 매개 변수로 기본 자료형을 넘기게되면 메소드에서 그 값을 변경하더라도 원래 값은 변하지 않습니다.

참조 자료형은 "Pass by reference"로 값의 주소값을 전달하기 때문에 메소드에서 그 값을 변경하게되면 원래 값도 같이 변하게 됩니다.

 

리터럴

리터럴은 실제로 저장되는 값 그 자체로 메모리에 저장되어 있는 값 그 자체를 뜻합니다.

예를들면 

int num = 1; // 1이 리터럴입니다.

 

상수와 많은 혼동을 하게되는데 상수는 값을 변할 수 없어서 항상 같은 수를 나타낸 다는 의미이므로 뜻이 서로 다르니 주의하는게 좋습니다.

 

변수 선언 및 초기화하는 방법

변수를 선언하는 방법은 "타입 변수명;" 으로 선언해줄 수 있습니다.

ex) int num;

 

변수를 초기화 하는 방법은 "변수명 = 값;" 으로 초기화 할 수 있습니다.

ex) num = 1;

 

그리고 선언과 초기화를 같이할 수도 있습니다.

int num = 1;

 

하지만 여기서 주의해야 할 사항은 선언과 초기화를 같이하게 되면 우리 눈엔

int num = 1; 이렇게 한줄로 되어있어서 한번만 동작하는것 처럼 보이지만

 

실제 소스파일을 오퍼레이션 코드로 보게되면 선언과 초기화를 순서대로 진행합니다.

//@EXP 소스 코드

public class VariableTest {
  public static void main(String[] args) {
    int num = 1; //선언과 초기화
  }
}


//@EXP 오퍼레이션 코드
public class llnote.study.livestudy.VariableTest {
  public llnote.study.livestudy.VariableTest();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: iconst_1 //선언
       1: istore_1 //초기화
       2: return
}

 

만약 멀티 스레드에서 선언과 초기화를 같이 할경우 데이터가 원치않게 저장될 수 있습니다.

그래서 이 부분은 synchronized 처리를 하거나 주의해서 사용해야합니다.

 

 

변수의 스코프와 라이프타임

변수는 크게 4가지가 있습니다.

변수 설명 스코프 라이프타임
인스턴스 변수 메소드 밖에, 클래스 안에 선언된 변수 클래스 내에서 접근 가능
객체를 생성한 후 접근 가능
클래스 객체가 생성될 때 변수가 생성되고 참조하는 객체가 없을때 GC에 의해서 소멸
클래스변수 메소드 밖에, 클래스 안에, static으로 선언된 변수 다른 클래스에서 접근 가능 프로그램이 시작될때 처음부터 스택에 올라와서 프로그램이 종료될 때까지 살아있음
매개 변수 메소드의 인자값으로 선언된 변수 메소드 내에서만 접근 가능 메소드가 시작될때 생성되고 메소드가 종료되면 소멸
로컬 변수 중괄호 안에서 선언된 변수 중괄호 내에서 접근 가능 중괄호가 시작될때 생성되고 중괄호가 끝날때 소멸

 

위 그림은 '스프링 입문을 위한 자바 객체 지향의 원리와 이해' 책의 T 메모리 구조로 설명하였습니다.

 

타입변환, 캐스팅 그리고 타입 프로모션

타입은 데이터 타입의 줄임말이고 데이터 타입은 다른말로 자료형이라고도 합니다.

특정 데이터 타입으로 표현된 리터럴은 다른 타입으로 변환 할 수 있는데 이것이 타입변환이고

상황에 따라 타입 캐스팅과, 타입 프로모션으로 나뉘게 됩니다.

타입 캐스팅은 타입을 변환할 시 더 좁은 범위의 타입으로 변환 할때를 말하고 반대로

타입 프로모션은 타입을 변환할 시 더 넓은 범위의 타입으로 변환 할때를 말합니다.

 

타입 캐스팅의 예를 들면

int a = 100;
short b = a; // 컴파일 에러발생

이런 상황은 int a 가 더 넓은 범위인데 short로 타입을 변경하려고 할 경우 더 좁은 범위로 타입을 변환하기 때문에 캐스팅이 필요합니다.

int a = 100;
short b = (int) a; // (int)가 캐스팅입니다.

 

대신 억지로 캐스팅을 할 경우 short의 허용 범위를 넘어갈 경우 그 위의 비트는 계산할 수 없습니다.
ex)

int a = 300000;
short b = (short)a;
System.out.println(b+""); // 결과 -27680

 

반대로 타입 프로모션의 예를 보자면

int a = 100;
long b = a; // 자동으로 타입 프로모션이 일어납니다.

 

 

1차 및 2차 배열 선언하기

기본적으로 배열은 레퍼런스 타입 즉 참조 자료형으로 취급됩니다.

그러므로 배열 선언시 스택 영역에 값이 아닌 주소값이 저장됩니다.

배열을 선언하는 방법은 다양합니다.

int intArr11[] = {10};
int intArr12[] = new int[10];
int intArr13[] = new int[]{10};
int intArr21[][] = {{10},{1}};
int intArr22[][] = new int [][]{{10},{1}};
int intArr23[][];

 

타입추론, var

자바 컴파일러에서 타입을 추론하는것을 Type inference라고 합니다.

자바 10부터 var라는 타입이 추가되었습니다. 로컬 변수를 선언할 때 var를 이용하면 컴파일러가 타입 추론을 할 수 있습니다.

 

사용조건은 아래와 같습니다.

  • 초기화된 로컬 변수 선언 시
  • 반복문에서 지역 변수 선언 시

var 활용

   var numbers = Arrays.asList(1, 2, 3, 4, 5);

    //지역변수 선언 var i = 0;
    for (var i = 0; i < numbers.size(); i++) {
      System.out.println("numbers = " + numbers.get(i));
    }

    //forEach
    for(var number : numbers){
      System.out.println("numbers = " + number);
    }

    //람다 (java 11부터 지원)
    numbers.stream().forEach((var i) -> System.out.println(i));

 

 

참고사이트 (catsbi.oopy.io/6541026f-1e19-4117-8fef-aea145e4fc1b)

 


참고문헌

 

  • 이상민(2017). 자바의 신 2. 서울: 로드북
  • 김종민(2015). 스프링 입문을 위한 자바 객체 지향의 원리와 이해. 경기: 위키북스
반응형
Comments