Notice
Recent Posts
Recent Comments
Link
«   2025/12   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31
Tags
more
Archives
Today
Total
관리 메뉴

기록하자..

자바 데이터 타입, 변수 그리고 배열 | 백기선님 LIVE-STUDY 본문

자바

자바 데이터 타입, 변수 그리고 배열 | 백기선님 LIVE-STUDY

P23Yong 2022. 3. 24. 10:50

학습할 것

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

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

프리미티브 타입에는 int, byte, short, long, float, double, boolean, char 총 8가지의 타입이 있다.

Type Size(bits) Minimum Maximum
byte 8 -27 27-1
short 16 -215 215-1
int 32 -231 231-1
long 64 -263 263-1

다음과 같은 범위를 계산하는 방법은 메모리 크기와 연관이 있다.

n개의 비트가 있다면 첫 번째 비트는 부호를 나타내게 되고 나머지 n-1개의 비트를 이용해 수를 표현하게 된다. 따라서 범위는 -2n-1 부터 2n-1이 된다.

Type Size(bits) Default value Range
float 32 0.0f -3.4E38 ~ -1.4E-45, 1.4E-45 ~ 3.4E38 (정밀도 7자리)
double 64 0.0d (1.7 * 10 -308 ) ~ (1.7 * 10 308 )의 근사값

실수형에서는 값을 부호, 지수, 가수로 나누어 저장하게 된다. 그렇기에 실수형은 원래 저장하려던 값과 실제 저장된 값이 차이가 날 수 있다. 이는 가수 부분의 데이터크기와 관련이 되어 있다.

위의 그림을 보자. float의 경우 가수 부분은 23bit 가능하다. 223은 106정도 되기 때문에 정밀도가 6자리까지 나온다.

double의 경우는 가수부분이 52bit인데 위의 과정으로 정밀도가 15자리까지 나온다.

Type Size(bits) Default value Range
boolean 8 false true, false
char unsigned 2byte '\u0000' 0 ~ 65,535

참 혹은 거짓을 나타내는 boolean타입은 1bit로도 표현이 가능하지만 Java가 데이터를 다루는 최소 범위가 1byte이기 때문에 1byte를 할당한다. (오라클 자바 튜토리얼, 데이터 타입 에서는 정확히 정의할 수 없다고 나와있다."but its "size" isn't something that's precisely defined.")

문자형 char는 유니코드를 사용하기 때문에 2byte를 사용한다.

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

데이터 타입은 기본 타입(primitive type)과 참조 타입(reference type)으로 나눌 수 있다.
프리미티브 타입은 위에서 살펴봤던 정수, 실수, 문자, 논리 데이터를 저장하는 타입을 말한다.
레퍼런스 타입은 객체의 번지(주소)를 참조하는 타입으로 프리미티브 타입을 제외한 타입을 말한다.

프리미티브 타입은 실제 값을 저장하지만, 레퍼런스 타입은 힙 영역의 참조를 값으로 갖는다는 것을 알아야 한다.

리터럴

소스 코드 내에서 직접 입력된 값을 말한다. 리터럴은 값에 따라 정수 리터럴, 실수 리터럴, 문자/문자열 리터럴, 논리 리터럴로 구분이된다.

  • 정수 리터럴

    • 0, 14, -123
    • 1_000, 1_000_000
    • 0b로 시작되는 리터럴은 2진수로 간주된다.
      • 0b1101
    • 0으로 시작되는 리터럴은 8진수로 간주한다.
      • 02, -03
    • 0x, 0X로 시작하고 09숫자나 AF또는 a~f로 끝나는 리터럴은 16진수로 간주한다.
      • 0x4, 0xA, 0xAC08
  • 실수 리터럴

    • 0.24, 3.14, -1.2
    • E또는 e가 있는 리터럴은 10진수 지수와 가수로 간주한다.
      • 10E3 -> 10 * 103
      • 0.1e-5 -> 0.1 * 10-5
  • 문자/문자열 리터럴

    • 작은 따옴표로 묶은 텍스트는 하나의 문자 리터럴로 간주한다.
      • 'A', 't', '일'
    • 역슬래쉬가 붙은 문자 리터럴은 이스케이프 문자라고도 한다.
      • '\t' : 수평 탭
      • '\n' : 줄 바꿈
      • '\r' : 리턴
      • '\"' : 쌍따옴표
      • \' : 따옴표
      • '\' : \
    • 큰 따옴표로 묶은 텍스트는 문자열 리터럴로 간주한다.
      • "안녕하세요"
  • 논리 리터럴

    • true, false

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

변수를 선언한다는 것은 메모리에 데이터를 저장할 공간을 할당해 준다는 것이다. 즉 변수란, 하나의 값을 저장할 수 있는 메모리 공간이다.

변수의 선언은 어떤 타입의 데이터를 저장할지와 변수의 이름을 결정한다. 방법은 다음과 같다.

// 변수타입, 변수명
int a;

변수의 이름은 메모리 주소에 붙여진 이름이고, 변수 타입에 해당하는 만큼 메모리 공간이 할당된다.

자바에서는 다음과 같은 종류의 변수들이 있다.

  • 인스턴스 변수(non-static field)
    • static키워드 없이 선언된 필드이다. 클래스의 인스턴스 별로 서로 다른 값을 가질 수 있기 때문에 인스턴스 변수라 불린다.
    • 인스턴스가 생성될 때 생성된다.
  • 클래스 변수(static field)
    • static키워드로 선언된 필드이다. 인스턴스화 된 횟수와 상관 없이 클래스별로 하나의 값을 가질 수 있다. 클래스명으로 접근이 가능하고 클래스 하나에 하나의 값이기 때문에 클래스 변수라 불린다.
    • 클래스가 로딩될 때 생성된다.
  • 지역 변수
    • 메서드 영역에 선언되는 변수로 다른 클래스에서 접근할 수 없는 변수이다.
  • 매개 변수
    • 메서드의 인자로 전달되는 변수이다.

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

변수의 스코프는 변수가 사용되고 유효한 영역을 의미한다. 변수의 종류에 따라 변수의 스코프가 결정된다.

  • 인스턴스 변수(Instance variables)
    • 스코프 : static 메서드를 제외한 클래스 전역
    • 라이프타임 : 클래스의 객체가 메모리에 남아있을 동안
  • 클래스 변수(Class variables)
    • 스코프 : 클래스 전역
    • 라이프타임 : 프로그램이 끝날때 까지
  • 지역 변수(Local variables)
    • 스코프 : 변수가 선언된 블록 내부
    • 라이프타임 : 변수가 선언된 블록을 벗어날 때까지

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

자바는 데이터 타입이 맞지 않을 때 타입 변환을 지원한다.

확장 (자동 형변환)

확장은 두 개의 데이터 타입이 맞지 않아 자동적으로 바뀔 때 일어난다. 조건이 있는데,

  • 두 개의 타입이 호환이 되어야 한다.
  • 작은 크기의 데이터 타입의 값을 큰 크기의 데이터 값에 할당할 때 일어난다.

자바에서 숫자 타입의 데이터는

 byte -> short -> int -> long -> float -> double

순으로 일어난다.

축소 (명시적 형변환)

축소는 큰 데이터 타입의 값을 작은 크기의 데이터 타입에 넣으려 할 때 발생한다.

  • 자동 형변환이 일어나지 않을 때 사용한다.
  • 호환되지 않는 데이터 타입에서도 사용할 수 있다.

타입 프로모션

식을 계산할 때, 중간에 피연산자의 값의 범위를 넘어버리는 경우가 발생하는데, 이때 자동으로 값이 승격된다. 이를 타입 프로모션이라고 한다.

  • 자바에서는 byte, short, char 값이 int로 프로모션된다.
  • 피연산자가 long, float, double 인 경우, 전체 표현식이 각각 long, float, double로 프로모션된다.

1차 및 2차 배열 선언하기

배열은 같은 타입의 많은 양의 데이터를 다루는 특별한 객체이다. 배열에 담기는 값들은 배열의 타입에 따라 결정이 된다. 만약 다른 타입을 저장하려고 하면 Type mismatch(타입 불일치) 컴파일 오류가 발생한다.

배열의 또 다른 특징은 배열은 한 번 생성되면, 그 크기를 늘리거나 줄일 수 없다.

배열 타입

배열 변수는 참조 변수에 속한다. 그렇기에 배열은 객체이고 힙 영역에 생성되며 배열 변수는 힙 영역의 배열 객체를 참조하게 된다.

또한 배열은 인스턴스인데, java.lang.Object를 상속받는다. 따라서 배열은 Cloneable interface를 구현한다. 그렇기에 배열을 복사하면 객체 자신의 메모리 주소를 복사하게 된다.

배열 선언

배열을 사용하기 위해선, 배열변수를 선언해야 한다. 다음과 같이 작성할 수 있다.

타입[] 변수;

타입 변수[];
int[] intArray;
double[] doubleArray;

int intArray[];
double doubleArray[];

이제 배열을 생성해보자.

  • 먼저 값 목록을 통해 배열을 생성하는 법을 보자.

      int[] intArray = {1, 2, 3, 4, 5};

    다음과 같이 {}는 주어진 값들을 항목으로 가지는 배열 객체를 힙에 생성하고 배열 객체의 번지를 리턴하게 된다.

    값 목록을 통해 배열을 생성할 떄 주의할 점은, 배열 변수를 이미 선언한 후 다른 실행문에서 중괄호를 사용한 배열 생성은 불가능하다.

      int[] intArray;
      intArray = {1, 2, 3, 4, 5}; // 컴파일 에러

    이때는 다음과 같이 new연산자를 사용해 값 목록을 지정해 주면 된다.

      int[] intArray;
      intArray = new int[] {1, 2, 3, 4, 5};
  • new연산자로 배열 생성
    값의 목록을 모르지만, 후에 사용할 배열을 미리 만들고 싶다면 new연산자를 사용한다.

      int[] intArray = new int[5];

    배열을 생성하는데 있어서 배열의 크기를 지정해주는데, []안에 정수 값을 집어 넣어준다.

    위와 같이 new 연산자를 사용할 경우 초기값이 들어가 있는데 타입별로 살펴보자.

    분류 데이터 타입 초기값
    기본 타입 byte[] 0
    char[] '\u0000'
    short[] 0
    int[] 0
    long[] 0L
    float[] 0.0F
    double[] 0.0
    boolean[] false
    참조 타입 클래스[] null
    인터페이스[] null

2차원 배열

2차원 배열은 배열을 이루는 값들이 배열인 배열을 말한다(요소 자체가 배열). 자바는 2차원 배열을 중첩 배열 방식으로 구현한다.

다음과 같이 사용한다.

int[][] intArrays = new int[2][3];

2차원 배열은 각 요소 배열간 길이가 다를 수 있다.

타입 추론, var

타입 추론이란, 타입이 정해지지 않은 변수에 대해서 컴파일러가 변수의 타입을 스스로 찾아낼 수 있도록 하는 기능이다.

Java9까지는 우리는 변수를 사용할 때 명시적으로 데이터의 타입을 선언했어야 했다.

String message = "Good bye, Java 9";

하지만 Java10부터 우리는 다음과 같이 타입 추론을 사용할 수 있다.

var message = "Hello, Java 10";

우리는 message에 따로 데이터 타입을 제공해 주지 않고, 단순히 var라고 지정함으로써 컴파일러가 message의 타입을 오른쪽에 있는 값, 리터럴로 타입을 추론할 수 있는 것이다.

중요한 점이 있는데, var은 초기화 값이 있는 지역 변수로만 사용이 가능하다는 것이다.

var은 멤버변수, 메서드의 파리미터, 리턴 타입으로는 사용이 불가능하다. 이런데도 var을 사용하는 이유는 뭘까..?

Map<Integer, String> map = new HashMap<>();
var map = new HashMap<Integer, String>();

var을 사용하게 되면 변수의 타입이 아닌, 변수의 이름에 집중할 수 있게 된다. 또 한 가지 기억해야 할 것이 있다면, var은 키워드가 아니다. 어떠한 타입도 아니고, 클래스에 사용할 수 있는 예약어가 아니라는 소리다.

마지막으로 var는 런타임 오버헤드가 없으며 Java를 동적으로 유형이 지정된 언어로 만들지 않는다. 변수의 타입은 컴파일 시간에 결정이 되고, 후에 변경할 수 없다.

var의 잘못된 사용

var의 잘못된 사용을 보자.

  •   var n;
    • 초기화 없이 var를 사용할 수 없다.
  •   var emptyList = null;
    • null로 초기화 할 수 없다.
  •   public var = "hello";
    • 지역변수가 아닌 변수는 var을 사용할 수 없다.
  •   var p = (String s) -> s.length() > 10;
    • 람다식은 명시적인 타입이 필요하다.
  •   var arr = {1, 2, 3};
    • 배열은 명시적인 타입이 필요하다.

참고자료

이것이 자바다

오라클 자바 튜토리얼, variables

밸덩 변수의 스코프

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

GeeksForGeeks, Type-Conversion

stack overflow, java array cloneable

밸덩 LocalVariable Type inference