본문 바로가기
☕️ JAVA

JAVA의 변수와 타입

by kukim 2021. 11. 1.

Primitive type, Constant, Literal, Casting을 살펴봅니다.

1. 변수의 선언과 초기화

프로그래밍에서 변수(Variable)란 하나의 값을 저장할 수 있는 메모리 공간이다.
하나의 변수에 단 하나의 값만 저장할 수 있으므로, 새로운 값을 저장하면 기존의 값은 사리진다.
변수를 사용하기 위해선 변수 선언을 해야한다. '변수 타입'과 '변수 이름'을 통해 변수 선언을 할 수 있다.

// 변수 선언
int score; // score 라는 실수형 변수를 선언 
// int : 변수 타입
// score : 변수 이름

int math_score = 100;

변수 선언을 하면 메모리가 할당되어 사용할 수 있다. 이때 C 언어는 초기화 해주지 않으면 메모리 공간에 garbage value(쓰레기 값)이 들어있기 때문에 초기화를 해주는데 JAVA는 Default values가 들어있다. 하지만 defalut values를 의존하는 코딩은 지양해야 하며, 지역 변수에서는 default value가 없기 때문에 초기화를 해야한다.

자바의 변수 타입에는 2가지가 있다.

  1. Primitive Type(기본형)
    • 변수의 값 = 실제 data를 저장
  2. Reference type(참조형)
    • 변수의 값 = 메모리 주소(memory address) 값

2. Primitive type(기본형)

변수 타입 중 Primitive type은 변수 값에 실제 값(data)를 저장하고 있다. 다시 말해 스택 영역에 변수와 그 값을 모두 가지고 있다.

자바 8가지 Primitive type 변수

  • 정수형

    1.byte : 1byte

    2.short : 2byte

    3.int : 4byte

    4.long : 8byte

  • 실수형

    5.float : 4byte

    6.double : 8byte

  • 문자형

    7.char : 2byte

  • 논리형

    8.bollean : 1bit (But, JVM마다 다르고 정확하게 정의되지 않음)

특별한 점은 Primitive type에서 unsigned(부호 없는 자료형)가 존재하지 않는다. (단, 유일하게 char는 unsigned type) int 형에서 unsigned 를 사용하려면 Interger라는 클래스를 사용해 int를 unsigned 처럼 사용할 수 있지만 불편하다.

int num = 2200000000 // 22억이 int범위를 넘어섰기 때문에 컴파일 에러
int num2 = Interger.parseUnsignedInt("2200000000") // OK

정수형

  • 정수형은 표현할 수 있는 범위를 넘으면 오버플로우를 발생시킨다.

1. byte

  • 크기 : 1byte(8bit)
  • 범위 : (-128 ~ 127, -2^7 ~ 2^7 - 1)
    • 8비트 중 가장 왼쪽 비트는 부호비트(sign)이고 나머지 7비트를 가지고 정수 표현
  • Default Value : 0

2. short

  • 크기 : 2byte(16bit)
  • 범위 : (-2^15 ~ 2^15 -1)
    • byte와 마찬가지로 부호비트1, 나머지 15비트로 정수 표현
  • Default Value : 0

3. int

  • 크기 : 4byte(32bit)
  • 범위 : (-2^31 ~ 2^31 -1)
    • 부호비트1, 나머지 31비트로 정수 표현
  • Default Value : 0

4. long

  • 크기 : 4byte(32bit)
  • 범위 : (-2^63 ~ 2^63 -1)
    • 부호비트1, 나머지 63비트로 정수 표현
  • Default Value : 0L

실수형

  • 실수형은 정수형과 마찬가지로 오버플로우가 발생하는데 그 값은 무한대가 된다. 또한 실수형으로 표현할 수 없는 아주 작은 값이 되면 언더플로우가 발생하며 그 값은 0이 된다.
  • 실수형은 정수형과 다르게 소수를 표현해야한다. 이는 IEEE754 표준에 따라 부호(sign), 지수(exponent), 가수(mantissa) 비트로 나누어 표현한다.
    • 부호 비트 : 0 = 양수, 1 = 음수
    • 지수 비트(Exponent)
      • float는 지수가 8비트로 -127 = 음의 무한대, 128 = 양의무한대, or NaN 값을 표현하고있으며 그 외 2^-126 ~ 2^127 의 자리를 표현할 수 있으며 이는 10진수로 10^-45 ~ 10^38 자리 이다.
    • 가수 비트(Mantissa)
      • M은 실제 값을 저장하는 부분이다.
      • float의 경우 23비트로 2진수 23자리, 10진수 7자리를 저장할 수 있다.
  • IEEE754 계산방법 (float, double)

5. float

  • 크기 : 4byte(32bit)
  • 범위 : (1.4*10^-45 ~ 3.4 * 10^38)
    • 부호비트1, 지수비트 8, 가수비트 23
  • Default Value : 0.0f

6. double

  • 크기 : 8byte(64bit)
  • 범위 : (4.9*10^-324 ~ 1.8 * 10^308)
    • 부호비트1, 지수비트 11, 가수비트 52
  • Default Value : 0.0d

문자형

7. char

  • 자바 기본형 중 유일한 unsigned
  • 크기 : 2byte(32bit)
  • 범위 : (0 ~ 2^16 -1, '\u0000' ~ '\uffff')
    • 자바 탄생 시 유니코드는 16비트 안에 모두 표현 가능했었음, 하지만 유니코드의 발전으로 u+ffff보다 큰 유니코드를 표현하려면 Reference type의 String을 사용해야한다.
  • Default Value : '\u0000'
  • 유니코드를 표현하지만 JAVA 표준에서 실제 값은 정수형이라고 함

논리형

8. boolean

2. Reference type(참조형)

  • Reference type은 Primitive type과 다르게 힙 영역에 데이터를 저장하고 있고 이 주소를 가르키는 변수이다. C언어에서 포인터, 동적 메모리를 사용하여 주소값을 참조하여 사용하는 것과 같다.
  • JAVA에서는 기본형 8가지를 제외하고 모두 참조형이다.

3. constant & literal (상수와 리터럴)

constant

상수는 변수와 마찬가지로 값을 저장하는 공간이지만 한번 값을 저장하면 다른 값으로 변경할 수 없다.

  • 선언과 동시에 초기화 해야함
// JAVA constant는 final 키워드를 사용
final int FINAL_SCORE = 100; // 상수 FINAL_SCORE를 선언하고 값을 100으로 초기화
// 상수는 대문자로 하는 것이 관례

literal

원래 프로그래밍에서 10, 3.14, 'A" 등의 값 자체는 '상수'인데 이미 상수의 정의를 한 번 저장하면 변경할 수 없는 저장공간 으로 정의하였기 때문에 상수 대신 다른 이름으로 부르기 위해 literal(리터럴)이라는 용어 사용

int year = 2020;
final int MIN_VALUE = 12;
// year : 변수
// 2020, 12 : 리터럴
// MIN_VALUE : 상수

정수형 리터럴 타입

// int의 리터럴 : 없음
int num1 = 1234;

// 2진수 리터럴 : 0b
int num2 = 0b11; // 10진수 3

// 8진수 리터럴 : 0
int num3 = 010; // 10진수 8

// 16진수 리터럴 : 0x
int num4 = 0xf; // 10진수 15

// long의 리터럴 : L or l
long num5 = 1234567890L;

// JAVA7(JDK1.7 버전) 이후 정수형 리터럴 중간에 구분자'_'사용 가능, 숫자 단위 구분할 때 자주 사용됨
int money = 3_000_000; // = money = 3000000

// Error!
long num6 = 2200000000; // 컴파일 에러!!
// long 범위는 22억이 넘지만 뒤의 숫자가 리터럴이 없기 때문에 int형으로 인식되기 때문에

// Fix!
long num7 = 2200000000L;

실수형 리터럴 타입

// float 리터럴 : f or F
float num1 = 0.1f;
float num2 = 3.14F;

// double 리터럴 : d or D or 생략
double num3 = 1234.5678d;
double num4 = 1234.5678D;

// Error!
float pi = 3.14; // 컴파일 에러
// 3.14의 리터럴이 생략되어 double 리터럴이기 때문에 float에 그대로 넣으면 에러 발생

// Fix
double pi = 3.14;
float pi = 3.14f;

문자형, 논리형 리터럴

// char 리터럴 : '' 작은 따옴표
char ch = 'a';
char ch2 = '\u0001'; // 유니코드 표현 가능
char ch3 = '\n' // 이스케이프(escape)문자 : \ 붙여서 사용

// Error
char ch = ''; // 컴파일 에러
// 문자열 리터럴에는 꼭 하나 문자가 들어가야함, 공백을 넣고 싶으면

// Fix
char ch = ' ';

// 앗? 그렇다면 primitive type에서는 null값이 없는건가?
// 없다. null은 reference type에서만 사용할 수 있는 리터럴이다.
// java에서 null은 참조하고 있는 대상이 없는경우이다. (C에서 null 포인터)

// 논리형 리터럴 없음

4. Casting(형변환)

형변환이란 변수 또는 상수의 타입을 다른 타입으로 변환하는 것

primitive type 변수는 boolean을 제외하고 서로 형변환이 가능하다. 하지만 타입간의 크기가 큰 타입 → 작은 타입으로 변환하는 경우 크기 차이 만큼 값 손실(loss of data)이 발생한다. 반대의 경우는 문제없다.(작은 → 큰)

// 정수형(int) -> 정수형(long) 형변환
int score = 80;
long score2 = (long)score;

// 실수형(float) -> 실수형(double) 형변환
float score = 66.3f;
double score2 = (double)score;

// 정수형 -> 실수형 형변환
float f = 1.666f;
int i = (int)f; // 이 때 i는 반올림된 2가 아닌 1이다!

정수형 → 실수형 간의 형변환 문제점

일반적인 경우 정수형에서 실수형 변환하는 건 간단하다. 7 정수를 실수로 바꾸면 7.0 이지 않는가?

하지만 실수형에서 지수 부분이 표현할 수 있는 정밀도를 넘어섰을 때 오차가 발생할 수 있다.

float가 10진수를 표현할 수 있는 정밀도는 약 7자리이다. int가 7자리 넘는 수를 형변환 한다면 정밀도 차이에 의해오차가 생길 수 있다. 따라서 8자리 이상의 정수형을 실수형으로 형변환 할 때는 double로 해야한다.

int num = 81_234_567; // 8자리, 천만
float f = (float)i;

System.out.printf("f = %f", f);
// f의 결과는 81234567이 아닌 81234568.000000 이다.

자동 형변환 규칙(Type promotion)

작은 타입을 큰 타입에 넣으면 자동으로 형변환이 일어난다.

  • byte(1) < short, char(2) < int(4) < long(8) < float(4) < double(8)
byte b = 100;
int i = b // promotion

int value = 200;
double d_value = value // 자동 형변환
double d_value = (double)value // 위와 동일

char c = 'A';
int i = c // 문자 'A'는 정수로 65이고 그 값이 자동으로 형변환 되어 i에 들어간다.
int i = (int)c // 위와 동일

// Check point!
byte b = 65;
char c = b // 컴파일 Error! 
// 왜냐하면 char은 unsigned 이므로 음수의 범위를 갖는 byte 값이 들어갈 수 없다!

Reference 🌏

'☕️ JAVA' 카테고리의 다른 글

📕 소프트웨어의 품질과 그 특성들  (0) 2022.01.08
JAVA의 클래스  (0) 2021.11.01
JAVA의 제어문  (0) 2021.11.01
JAVA의 연산자  (0) 2021.11.01
JAVA의 컴파일과 실행  (1) 2021.11.01

댓글