Live Study #2. 자바 데이터 타입, 변수 그리고 배열

콜드펌킨·2020년 11월 21일
0
post-thumbnail

1. 변수 선언 및 초기화

변수 선언

변수를 선언하기 위해서는 변수의 타입과 변수 명이 필요하며, 타입 변수명;과 같은 형식으로 선언한다. 변수 선언 시 변수의 타입에 맞는 메모리 공간이 확보되고, 변수 명을 통해 이 메모리에 저장된 값을 사용할 수 있게 된다.

int price;  // int: 변수 타입, price: 변수 명

변수 초기화

변수 초기화란 변수를 사용하기 전에 값을 처음으로 지정해 주는 것을 말한다. 변수를 초기화 할 때는 대입 연산자를 이용해 변수 선언과 초기화를 동시에 할 수 있다.

int price = 10000;	   // 변수 선언과 동시에 초기화
int age = 30, count = 0;   // 동시에 여러개 변수 초기화

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

자바 코드를 작성할 때 우리는 우선 사용하고자 하는 데이터의 타입이 무엇인지 고민해봐야 한다. 데이터 타입에는 문자형, 정수형, 실수형 등이 있으며, 데이터 타입에 해당하는 적절한 키워드를 사용하여 변수를 선언해야 한다.

프리미티브 타입

프리미티브 타입(Primitie type, 기본형)은 사용하고자 하는 데이터의 실제 값을 저장하는 타입으로, 스택 메모리 영역에 저장된다. 논리형(boolean), 문자형(char), 정수형(byte, short, int, long), 실수형(float, double) 등 총 8개 타입이 존재한다.

레퍼런스 타입

프리미티브 타입을 제외한 모든 데이터 타입을 말한다. 연산에 필요한 실제 값을 저장하는 프리미티브 타입과 달리, 레퍼런스 타입은 어떤 데이터가 저장되어 있는 주소 값을 값으로 가지며, 힙 메모리 영역에 저장된다.

3. 프리미티브 타입 종류, 범위, 그리고 기본값

분류타입메모리 크기저장 가능한 값의 범위기본값
논리형boolean1 bytetrue, falsefalse
정수형byte1 byte27-2^7 ~ 27+12^7+10
short2 byte215-2^{15} ~ 215+12^{15}+10
int4 byte231-2^{31} ~ 231+12^{31}+10
long8 byte263-2^{63} ~ 263+12^{63}+10L
실수형float4 byte1.410451.4*10^{-45} ~ 3.410383.4*10^{38}0.0F
double8 byte4.9103244.9*10^{-324} ~ 1.8103081.8*10^{308}0.0
문자형char2 byte(유니코드)27-2^7 ~ 27+12^7+1'\u0000'
  • 문자형(char)은 변수 하나 당 하나의 문자를 저장할 수 있으며, 내부적으로 데이터를 정수(유니코드)로 저장하기 때문에 정수형 또는 실수형과 연산도 가능하다.
  • int는 CPU가 가장 효율적으로 처리할 수 있는 타입이다.
  • 실수형(float, double)은 부동 소수점 형식을 사용하는데, 연산 시 오차가 발생할 수 있다.
    - 정밀도 : float 7자리, double 15자리

4. 리터럴

리터럴(literal)은 변수나 상수에 저장하고자 하는 값 그 자체를 의미한다.

int age = 30;   // age는 변수, 30은 리터럴
char ch = 'a';  // ch는 변수, 'a'은 리터럴
final int MAX_PRICE = 10000;  // MAX_PRICE는 상수, 10000은 리터럴

리터럴 타입과 형식

분류리터럴접미사
논리형true, flase
정수형10, 0b101, 012, 0xFC, 12345Llong 타입의 경우 L
실수형3.14, 2.0e8, 1.5f, 0x1, 0p-1float 타입 f, double 타입 d (기본형이라 잘 사용x)
문자형'A', '5', 'c'
문자열"가나다", "abc", "123123"
  • 정수형의 경우 long 타입에는 접미사에 'l' 또는 'L'을 붙여준다.
  • 16진수의 경우 접두사에 0x 혹은 0X, 8진수의 경우 0, 2진수의 경우 0b을 붙여준다.
int octNum = 010;     // 출력 : 8 (8진수 10을 의미하며, 10진수 8로 출력됨)
int hexNum = 0xF;     // 출력 : 15 (16진수 F을 의미하며, 10진수 15로 출력됨)
int binNum = 0b100;   // 출력 : 4 (2진수 100을 의미하며, 10진수 4로 출력됨)
  • 문자형 리터럴은 작은 따옴표, 문자열 리터럴은 큰 따옴표로 감싼다. 두 문자 이상은 받드시 문자열 리터럴로 데이터를 지정해줘야 한다.
  • 문자형 리터럴은 빈 문자열을 허용하지 않지만, 문자열 리터럴은 빈 문자열을 허용한다.
String emptyStr = "";   // 빈 문자열 가능
char emptyChar = '';    // 에러!
char spaceChar = ' ';   // 하나의 공백은 가능

문자열 리터럴 vs new 연산자
문자열 리터럴을 저장하는 String은 프리미티프 타입이 아닌 레퍼런스 타입으로, 객체를 생성하는 new 연산자를 사용해 문자열을 생성할 수도 있다.

String str1 = "abc";   // 리터럴 방식으로 문자열 생성
String str2 = "abc";   
String str3 = new String("abc");  // new 연산자로 문자열 객체 생성

위 두 방식의 차이점은 무엇일까? new 연산자로 문자열 객체를 생성할 경우 JVM 메모리 영역 중 Heap 영역에 할당되고, 리터럴을 이용할 경우 String Constant Pool 이라는 영역에 할당된다. String Constant Pool은 Heap 영역 안의 Permanent area(고정 영역)에 생성되어 자바 프로세스가 종료될 때 함께 사라진다.

※ 이미지 출처 : https://iq.opengenus.org/string-pool-in-java/

new 연산자를 사용하면 문자열 객체를 생성할 때 마다 새로운 문자열 인스턴스가 생성되기 때문에, 각각의 인스턴스는 서로 다른 문자열 객체를 참조한다.
리터럴을 사용하면 먼저 String Constant Pool에 같은 문자열 객체가 있는지 확인하고, 있으면 해당 객체를 참조하며, 없으면 String Constant Pool에 새로운 객체를 생성한다.
아래 코드로 확인해보도록 하자.

String str1 = "abc";   // 리터럴 방식으로 문자열 생성 (String Constant Pool)
String str2 = "abc";   
String str3 = new String("abc");  // new 연산자로 문자열 객체 생성 (Heap)

System.out.println(str1 == str2);  // 주소비교 : true
System.out.println(str1.equals(str2)); // 값 비교 : true

System.out.println(str1 == str3);  // 주소비교 : false
System.out.println(str1.equals(str3)); // 값 비교 : true

리터럴 방식으로 똑같은 문자열을 지정한 str1str2의 주소를 비교하면 같은 한편, 리터럴 방식과 new 연산자를 이용해 똑같은 문자열을 지정했을 때는 두 주소 값이 다른 것을 확인할 수 있다.

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

스코프(Scope)란 변수를 사용할 수 있는 범위를 말한다. 변수가 선언된 위치에 따라 변수의 종류가 달라지며, 이에 따라 변수의 스코프와 라이프사이클이 결정된다.

변수의 종류선언 위치스코프라이프사이클
클래스 변수클래스 영역클래스 전체클래스가 메모리에 올라간 후 프로그램이 끝날 때 까지
인스턴스 변수클래스 영역static 블록과 static 메서드를 제외한 클래스 전체인스턴스가 생성 후 메모리에 살아있을 때 까지
로컬 변수메서드, 생성자, 초기화 블럭 내부변수가 선언된 블록 내부변수 선언 후 블록을 벗어날 때 까지

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

타입 변환이란 변수나 리터럴의 타입을 다른 타입으로 변환시키는 것을 말한다. 프리미티브 타입에서 boolean을 제외한 다른 타입들은 서로 간의 타입 변환이 가능하다.

캐스팅

캐스팅(Casting)은 저장 공간이 큰 타입의 데이터를 저장 공간이 더 작은 데이터 타입에 저장할 때, 리터럴 앞에 타입을 명시하여 강제로 대입하는 것을 말한다. 캐스팅 될 때, 변환되는 값이 양수인 경우 빈 저장 공간이 0, 음수인 경우 빈 저장 공간이 변환 할 값이 1로 채워진다. 캐스팅에서 주의할 점은, 이 과정에서 tobe 데이터 타입의 범위가 너무 작아 원래 값을 다 담지 못하는 경우, 값의 손실이 일어날 수 있다는 것이다.

double x = 90.5;
int y = (int)x;  // 90 : double 타입을 int 타입에 강제로 대입 

int x = 300;
byte y = x;  // (주의!) y는 44가 저장됨 

프로모션

프로모션(Promotion)은 저장 공간이 더 작은 타입의 데이터를 저장 공간이 더 큰 데이터 타입에 저장할 때, 자동으로 타입이 변환되는 것을 말한다. 이 때, 캐스팅과는 달리 따로 타입을 명시해주지 않아도 자동으로 타입 변환이 이뤄진다.

int x = 90;
double y = x;  // 90.0 : int 타입이 double 타입으로 자동 타입 변환되어 대입됨

7. 1차 및 2차 배열 선언하기

배열은 같은 타입의 변수들을 하나의 묶음으로 나타낸 자료형을 말한다.

for (int i = 0; i < 5; i++) {
    ages[i] = i * 15;
}

1차원 배열 선언하기

int[] ages = new int[5];  // 5개의 int형 데이터를 저장할 수 있는 배열 선언

위 예에서는 int형 값들 5개를 담을 수 있는 저장공간이 생성되며, 이 공간을 ages라는 이름으로 참조할 수 있게 된다.

1차원 배열에 값 저장하기

배열에 생성된 각각의 저장 공간을 배열의 요소(element)라고 하며, 인덱스로 접근할 수 있다. 인덱스의 범위는 0부터 시작하며, 배열의 길이-1 까지이다. 배열이름[인덱스] = 값 형태로 배열 값을 저장할 수 있다.

for (int i = 0; i < 5; i++) {
    ages[i] = i * 15;
}

2차원 배열 선언하기

2차원 배열은 테이블 형태의 저장공간에 데이터를 저장할 때 사용된다.

int[][] arr1 = new int[4][3];  // 4행 3열의 2차원 배열 생성
int[][] arr2 = { 
			{1, 2, 3}, 
			{4, 5, 6} 
		};  // 2행 3열의 2차원 배열 생성 및 초기화

2차원 배열에 값 저장하기

int[][] arr = new int[4][3];
for (int i = 0; i < arr.length; i++) {
    for (int j = 0; j < arr[i].length; j++) {
    	arr[i][j] = 100;
    }
}

8. 타입 추론, var

타입 추론(Type Inference)란, 타입이 정해지지 않은 변수에 대해 컴파일러가 타입을 스스로 추론 수 있도록 하는 기능이다. 자바 10 버전부터 타입을 명시하지 않아도 아래 케이스에 var 를 사용해 모든 타입의 변수를 선언할 수 있다.

  • 초기화된 지역 변수 선언
  • 반목분에서 지역변수 선언
var a = 1;
var greeting = "Hello";
var list = new ArrayList<String>();
var stream = list.stream();
profile
배우고 때때로 익히면 즐겁지 아니한가

0개의 댓글