본문 바로가기

Java

[WS live-study] 2주차: 자바 데이터 타입, 변수 그리고 배열

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

프리미티브 타입은 기본자료형이다. 프리미티브 타입의 종류는 8개이고, 크게 논리형, 문자형, 정수형, 실수형으로 4가지로 나눠진다. 

 

정수형은 많이 사용되므로 타입이 4종류나 지원이 된다. 정수형 타입 중에는 대부분 int형이 많이 사용되는데 이는 CPU가 효율적으로 처리할 수 있는 타입이기 때문이다. 메모리를 줄이고 싶다면 그보다 크기가 작은 타입으로 사용하면 된다.

 

논리형인 boolean을 제외하고는 나머지 7가지는 서로 연산이 가능하다.

 

  타입 크기  범위 기본값
논리형 boolean 1byte / 8bit false, true false
문자형 char 2byte / 16bit '\u0000' ~ '\uffff' (0~65,535) '\u0000'
정수형 byte 1byte / 8bit -128 ~ 127 0
short 2byte / 16bit -32,768 ~ 32,767 0
int 4byte / 32bit -2,147,483,648 ~ 2,147,483,647 0
long 8byte / 64bit -9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807 0L
실수형 float 4byte / 32bit -3.4E38 ~ 3.4E38  0.0F
double 8byte / 64bit -1.7E308 ~ 1.7E308 0.0

 

값의 범위를 정확히 외울 필요는 없지만 크기는 알아두면 좋다. 크기를 알아두면 표현할 수 있는 범위를 대략적으로 알 수 있다. 정수값을 저장하는 범위는 -2^(n-1) ~ 2^(n-1)-1 이다. 범위를 넘어설 경우 overflow가 발생한다.

 

잘못된 범위를 저장하려 했을때 아래와 같은 컴파일 에러 발생)

 

 

2. 프리미티브 타입(Primitive Type)과 레퍼런스 타입(Reference Type)

 

Primitive Type (실제값을 저장하는 기본 타입)

  • null이 존재하지 않는다.
  • 기본값이 있다.
  • 실제값은 스택으로 저장된다.
  • primitive type 으로 인한 에러는 주로 컴파일에러로 발생한다. (overflow 등)

Reference Type (주소값을 저장하는 참조 타입)

  • null 이 존재한다.
  • 기본값은 null이다. 
  • 실제값이 아닌 저장되어 있는 주소값(참조값)을 변수에 저장하고 변수가 저장되는 영역은 힙(heap)이다. 
  • 기본형을 제외한 모든 타입은 참조변수에 해당한다.
  • 할당되는 메모리의 크기 4byte
  • 주로 런타입에러가 발생한다. (Ex - NullPointException 등)

 

3. 리터럴

변수가 데이터를 담는 그릇이라고 하면 리터럴은 그 그릇에 담는 데이터라고 할 수 잇다. 즉 데이터 자체는 변하지 않는다.

 

int value = 100;

 

여기서 value는 변수이고, 100은 리터럴을 의미한다.

 

리터럴의 종류

리터럴은 정수, 실수, 문자, 논리, 문자열 리터럴이 있다.

정수형의 경우 long타입의 리터럴은 'l' 또는 'L'의 접미사를 붙이며, 접미사가 없을 경우 int타입의 리터럴을 사용한다.

byte와 short 타입의 리터럴은 별도로 존재하지 않는다.

정수 리터럴

  • 10진수 리터럴
    • int a = 15;  ⇒ 15 출력
  • 8진수 리터럴
    • 값이 0으로 시작 
    • int b = 015; ⇒ 13 출력
  • 16진수 리터럴
    • 값이 0x로 시작
    • int c = 0x15; ⇒ 21 출력
  • 2진수 리터럴
    • 값이 0b로 시작
    • int d = 0b0101; ⇒ 5 출력

실수 리터럴

실수 타입의 리터럴은 float 타입을 사용할 경우에는 'f' 또는 'F'의 접미사를 붙이고, double 타입을 사용할 경우에는 'd'또는 'D'를 사용한다. 하지만 접미사가 없을 경우 double 타입의 리터럴을 사용한다.

  • float f = 0.1234f;
  • double d = 1.1234d;

실수 리터럴에서 기본 자료형은 double 이기 때문에 float을 사용할 경우 f를 붙여야한다.

아래의 예에서 float 타입 변수에 해당 값이 저장 가능한데도 에러가 나는 이유는 f를 붙이지 않았기 때문에 float 타입 변수에 double 타입 변수를 저장하는 꼴이 된다.

 

  • float f = 3.123; ⇒ 에러. float 타입에 double 타입 리터럴 저장불가

문자 리터럴, 문자열 리터럴

작은 따옴표('')로 문자 하나를 표현한다. 두개 이상의 문자를 표현할 때는 큰 따옴표("")로 감싸야하며 이는 문자열 리터럴이다.

  • char ch = 'J';   // 문자 리터럴
  • String name = "Java"   // 문자열 리터럴

문자열 리터럴은 빈 문자열도 허용하나, 문자 리터럴은 반드시 하나의 문자가 있어야한다.

  • String str = "";   // 저장가능
  • char ch = '';   //error. 빈 값은 저장 안됨.
  • char ch = ' ';  //저장 가능. 공백 문자로 ch 변수를 초기화.

논리 리터럴

boolean 타입의 리터럴은 true, false로 저장해야하지만 비교연산자의 결과 등도 저장 가능하다.

  • boolean a = true;
  • boolean b = 10 > 0;

단, C와 달리 1,0 으로 참, 거짓을 표현할 수 없다.

 

 

 

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

 

기본 타입 변수 선언

int a;

 

위와 같이 타입과 함께 변수를 선언한다. 아직 값이 초기화 되지는 않았지만 stack 영역에 int 타입 크기인 4byte가 할당되고 이 메모리의 이름을 a로 사용한다.

 

두개를 선언할 때 타입이 같은 경우에는 int a, b;  같이 변수이름을 한번에 선언하는 것도 가능하다.

 

참조 타입 변수 선언

Color color;

 

위와 같이 참조 변수일 경우 주소값 크기 4byte가 stack 영역에 저장된다. 객체를 생성하여 저장될 경우 그 객체의 주소값이 선언 시 확보된 stack 영역에 저장된다.

 

 

변수 초기화

초기화는 변수를 선언하고, 처음으로 값을 저장하는 것을 의미한다. 변수는 멤버 변수(클래스 변수, 인스턴스 변수), 지역 변수가 있다.  멤버 변수는 따로 초기화를 하지 않아도 기본 자료형의 기본값으로 초기화가 된다.

하지만 멤버변수의 초기화를 해야한다면 3가지 방법이 있다.

 

1. 명시적 초기화

class Color {
    int red = 1;
    int blue = 2;
    int green = 3;
}

2. 생성자

class Color {
    int red;
    int blue;
    int green;

    Color() {
        red = 4;
        blue = 5;
        green = 6;
    }
}

 

3. 초기화 블럭

class Color {
    static int red;
    int blue;
    int green;
    
    // 클래스 초기화 블럭
    static {
        red = 7;
    }
    
    // 인스턴스 초기화 블럭
    {
        blue = 8;
        green = 9;
    }
}

멤버변수의 초기화 시기

클래스 변수 초기화 시점 : 클래스가 로딩될 때 단 한번

인스턴스 변수 초기화 시점 : 인스턴스가 생성될 때마다

 

순서

 

멤버변수는 기본값을 설정하고 싶다면 따로 초기화를 해주지 않아도 되지만 지역변수는 선언과 동시에 초기화를 해주어야 한다. 

 

 

 

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

 

변수의 스코프(Scope)란? 

→ 변수에 접근할 수 있는 영역이다. 그리고 그 영역은 변수가 속한 블록 내(ex- 메서드, 클래스 등) 에서 사용 가능하다. 

멤버변수일 경우에는 해당 클래스 내에서 사용가능하고, 지역변수일 경우 선언된 해당 블록 내에서 사용가능하다.

 

변수의 라이프타임(Lifetime)란?

→ 변수가 메모리에 적재되어 있는 시간을 말한다. 변수가 로딩될 때부터 변수가 선언된 블록 종료 또는 프로그램 종료 시까지다.

멤버변수

클래스(static) 변수

변수의 라이프타임: 클래스 로드 ~ 프로그램 종료

클래스 변수의 스코프: 인스턴스 블록 제외한 클래스 내에서 사용 가능

 

인스턴스 변수

변수의 라이프타임: 객체 생성 ~ 객체 소멸시까지

인스턴스 변수의 스코프: 클래스 블록 제외한 클래스 내에서 사용 가능

지역변수

변수의 스코프: 변수 속한 메서드 블록 시작('{')하고 변수가 선언된 순간부터 ~ 블록 종료('}')

변수의 라이프 타임: 변수 선언 ~ 메서드 종료

 

 

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

타입변환: 상수 또는 변수의 타입을 다른 타입으로 변환하는 것을 말한다. 연산을 수행할 때는 같은 타입끼리 수행이 가능한데 이 때 다른 타입이지만 특정 변수와 연산을 수행해야하고 형변환이 가능한 경우 타입변환을 해주어야한다. 

※ long이 8byte이고 float이 4바이트인데 long → float 변환 시 자동 형변환이 가능하다. 이유는 float이 표현할 수 있는 값의 크기가 더 크기 때문이다.

 

캐스팅 (강제 형변환)

: 큰 타입 → 작은 타입 변환

 

강제 형변환 시에는 대입하는 값 앞에 변환하고자 하는 타입을 명시해줘야 한다. 명시하지 않는다면 컴파일 에러가 발생한다.

 

예시)

 

하지만 큰타입의 값이 작은 타입의 범위 내의 값이 아니라면 벗어난 범위의 수치만큼 작은타입의 최소 값에서 계산되어 저장된다. 결국 원하는 값으로 저장되지 않는다.

 

예시)

위에서 변수 i의 값은 32770이라 short의 범위에서 3만큼 벗어난다. 따라서 최소 값으로 돌아가서 3이 더해져서 값이 -32766으로 출력된다.

 

 

타입프로모션 (자동 형변환)

: 큰 타입 → 작은 타입 변환

 

자동 형변환 시에는 따로 변환하고자 하는 타입을 명시하지 않아도 자동으로 변환되어 저장된다. 비유하자면 작은그릇에 있는 내용물을 큰그릇에 옮긴다면 별 문제가 되지 않는 것처럼 캐스팅에서의 에러는 나지 않는다. 다만 무조건 큰 타입의 변수를 사용한다면 메모리 낭비가 있을 수 있기 때문에 상황에 따라 적절히 선택하여 사용하여야 한다.

 

예시)

 

 

 

1차 및 2차 배열 선언하기

배열 : 같은 타입의 데이터를 여러개 저장할 수 있는 저장공간이다. 각 데이터는 인덱스가 부여되어 순서가 존재하는 자료구조이다.

 

1차 배열

1차 배열 선언하기

배열선언에는 두가지 방법이 있다.

1. 타입[] 변수

2. 타입 변수[], 타입 []변수

 

배열도 객체에 속하기 때문에 null 저장이 가능하다. 따라서 참조할 객체가 없다면 null 저장을 해도 된다.

1차 배열에 값 저장

초기화할 때 우선 타입과 크기만 부여해준 다음 저장하고자 하는 위치(인덱스)에 값을 저장할 수 있다.

 

또는 처음 초기화시 값을 한번에 부여해줄 수도 있다.

 

대신 주의할 점은 배열 변수를 이미 선언한 후에 중괄호를 이용해 값을 부여하면 컴파일 에러가 발생한다.

 

배열을 초기화할 때는 타입과 크기를 명시해준다. 한번 크기를 설정하면 해당 변수에서는 크기 변경이 불가하다.

인덱스를 초과해서 사용하면 ArrayIndexOutOfBoundsException 에러가 발생한다. 따라서 더 큰 크기를 배열을 사용하고 싶다면 새로운 배열에 원하는 크기를 설정하여 데이터를 담아줘야한다.

2차 배열

2차 배열 선언 & 값 저장

2차 배열은 배열안에 배열이다. 순서는 1차 배열과 동일하지만 2차는 괄호가 두개를 사용해야하고, 배열의 크기와 배열 안의 배열의 크기 이 두가지 크기를 부여해야한다.

 

다음 두가지 예시는 같은 결과의 배열 두개의 선언과 값 저장의 방법 예시이다.

 

 

 

 

타입 추론, var

타입 추론이란, 코드 작성시에 해당 변수의 타입을 선언하지 않고 var로 선언하여 값을 저장하면, 컴파일러가 이 값의 타입을 유추한다.

사용 시 주의해야할 부분

1. var는 java 10 버전부터 추가된 기능으로, 10버전 이상부터 사용이 가능하다.

 

2. var는 지역변수이면서 선언과 동시에 초기화를 해야한다.

var가 지역변수일 때 - 정상 작동
var가 멤버변수일 때 - 컴파일에러

 

3. 타입을 명시하지 않는 것이 가독성 면에서 좋을지는 고민해야하는 점이다. 타입이 명시되어 있지 않아서 해당 코드를 봤을 때 쉽게 예측할 수 없다.

 

 

 

 


정리하는데 참고했던 곳