전체 보기

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

작성일자
2023/06/08
태그
SUB PAGE
프로젝트
백기선 자바
책 종류
1 more property

[자바 라이브 스터디] 2주차 - 자바 데이터 타입, 변수 그리고 배열

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

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

정의) 자바가 제공하는 기본 타입(Primitive type) 종류는 총 8개임
특징)
기본 타입 종류
저장되는 값
타입 종류
메모리 사용 크기
저장되는 값의 허용 범위
기본값
정수 타입
byte
1 byte (8 bit)
27-2^7 ~ 2712^7-1
0
short
2 byte (16 bit)
215-2^{15} ~ 21512^{15}-1
0
int (기본)
4 byte (32 bit)
231-2^{31} ~ 23112^{31}-1 (21억…)
0
long
8 byte (64 bit)
263-2^{63} ~ 26312^{63}-1
0L
char
2 byte (유니코드)
00 ~ 21612^{16}-1
 '\u0000' 
실수 타입
float
4 byte
1.410451.4*10^{-45} ~ 3.410383.4*10^{38} (소수점 아래 7자리)
 0.0F
double (기본)
8 byte
4.9103244.9*10^{-324} ~ 1.8103081.8*10^{308} (소수점 아래 15자리)
 0.0
논리 타입
boolean
1 byte
true, false
false
long 타입 변수에 정수 리터럴 저장할 때, 정수 리터럴이 int타입의 허용 범위 이내라면 L 붙이지 않아도 됨.
long a=10; ← OK
long a=100000000000000; ← 컴파일 에러
long a=100000000000000L; ← OK
float, double vs BigDecimal 클래스
float, double : 변수의 타입(primitive type)
내부적으로 수를 이진수의 근사치로 저장
사칙 연산 시 기대한 값과 다른 값 출력함 (부동 소수점 연산)
소수점의 정밀도에 있어 한계가 있음
BigDecimal : java.math 패키지에 있는 클래스
내부적으로 수를 십진수로 저장
정확한 소수점 연산을 수행할 수 있어서 신뢰성이 높은 계산이 가능
Java에서 숫자를 정밀하게 저장하고 표현할 수 있는 유일한 방법으로, 돈과 소수점 다룰 때 필수
소수점 이하의 자리수에 대한 제한이 없으며, 거의 무한한 정밀도를 제공
속도가 기본 타입보다 느림
int vs Integer 클래스
int : 변수의 타입(primitive type)
산술 연산 가능함
null로 초기화 불가
Integer : 래퍼 클래스 (Wrapper class)
Unboxing( ex. Integer to int )하지 않을 시 산술 연산 불가능함
null값 처리 가능
래퍼 클래스
정의) 기본형을 객체로 다루기 위해 사용하는 클래스들
예시) 모든 기본형은 래퍼 클래스 생성할 수 있음
Primitive type
Wrapper class
byte
Byte
short
Short
int
Integer
long
Long
char
Character
float
Float
double
Double
boolean
Boolean
특징) 사용하는 경우는 아래와 같음
메소드에 전달된 파라미터를 수정하려 할 때
파라미터로 객체가 전달되면 얕은 복사가 일어나 객체의 참조를 복사하기 때문에, 원래 객체와 전달된 파라미터는 같은 객체를 가리킴
기본형 값이 아닌 객체로 저장해야 할 때
제네릭 컬렉션에 기본 데이터 타입을 저장하려면 해당 기본 데이터 타입의 Wrapper 클래스를 사용 → ArrayList<Integer> numbers = new ArrayList<Integer>();)
객체 간 비교가 필요할 때
null 값을 처리할 수 있어야 할 때
데이터베이스나 외부 API와 상호작용할 때 유용

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

정의) 기본 타입은 실제 값을 변수 안에 저장하지만, 참조 타입은 값이 저장된 메모리 상의 주소를 변수 안에 저장함
특징)
참조 타입 종류
타입 종류
예시
배열
int[] arr = new int[5];
열거
enum Hi {HI, HELLO}
클래스
String str = "test";
인터페이스
기본값은 전부 null이고, 할당되는 메모리 크기는 전부 4byte(객체의 주소값)임
메모리 생성 위치
기본 타입의 메모리 생성 위치는 스택임
기본 타입 변수는 스택 영역에 직접 값을 저장함
참조 타입의 메모리 생성 위치는 힙임
참조 타입 변수는 힙 영역에 저장된 실제 객체의 주소 값을 스택 영역에 저장해 객체를 참조함
JVM이 사용하는 메모리 영역
메소드 영역
정의) JVM이 시작될 때 생성되고, 모든 스레드가 공유하는 영역
특징) 컴파일 된 바이트 코드(.class)들이 저장됨
정적 필드(static field)
상수(constant)
메소드(method) 코드
생성자(constructor) 생성자
과정) 생성 과정
1.
소스 코드 작성 (.java)
2.
컴파일 : 바이트 코드 파일 생성 (.class)
3.
자바 프로그램을 실행하면 바이트 코드 파일이 메소드 영역에 로딩된다.
힙 영역
정의) 객체와 배열이 저장되는 영역
특징)
힙 영역에 생성된 객체와 배열은 JVM 스택 영역의 변수에서 참조함
참조를 잃어버린 객체나 배열은 변수가 꺼내올 수 없으므로(의미 없는 객체가 되기 때문에), 자동으로 Garbage Collector(쓰레기 수집기)에 의해 힙 영역에서 제거됨
JVM 스택 영역
정의) 각 스레드마다 하나씩 존재하며 스레드가 시작될 때 할당되는 영역
특징)
메소드를 호출할 때 프레임 추가하고, 해당 프레임은 메소드가 종료될 때 제거함
프레임 내부의 로컬 변수 스택에 변수들이 추가되거나 제거됨
변수 생성 시점은 변수가 초기화될 때(값 저장될 때)
변수 제거 시점은 선언된 블록을 벗어났을 때

3. 리터럴

정의) 소스 코드에서 프로그래머에 의해 직접 입력된 값 (소스 코드의 고정된 값)
종류)
정수 리터럴 → byte, short, int, long, char에 저장됨
10진수(소수점 없는 숫자)
2진수(0b…, 0B…), 8진수(0…), 16진수(0x…, 0X…)
실수 리터럴 → float, double에 저장됨
10진수(소수점이 있는 숫자)
지수와 가수로 표현 : 5e2(500.0), 5E-2(0.05)
문자 리터럴 → char에 저장됨
하나의 문자를 작은 따옴표로 감싼 것
유니코드(세계 각국 문자를 2byte로 표현할 수 있는 숫자로 매핑한 국제 표준 규약)로 변환되어 저장됨
‘a’ → 유니코드 65
문자열 리터럴 → String에 저장됨
큰 따옴표로 감싼 문자들
논리 리터럴 → boolean에 저장됨
true, false, 10 > 0…
C와 달리 boolean 타입으론 1,0을 참,거짓으로 사용 불가

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

선언하고자 하는 변수들이 같은 타입일 경우, 한 줄로 동시에 선언 및 초기화 가능
int a = 10, b = 15; // 문제 X
Java
복사
이미 선언된 변수들은 동시에 초기화시킬 수는 없음
int c, d; // 변수 동시 선언 c = 15, d = 25; // 컴파일 에러 발생
Java
복사
변수 이름 명명 규칙
첫 번째 글자는 문자, $, _ 로 시작해야 하며, 숫자로 시작할 수 없음
영어 대소문자가 구분됨
자바에서 미리 정의된 예약어(keyword)는 사용 불가
문자 수 길이에 제한이 없고, 공백을 포함해서는 안됨
관례 : Camel Case (ex. numberOfStudents)
String 변수
String 객체가 생성된 후, String 변수가 해당 객체를 참조함
Sol 1) 문자열 리터럴로 생성
문자열 리터럴이 동일하다면, 같은 String 객체 공유하도록 되어 있음
String a = "hi"; String b = "hi"; // a, b는 동일한 String 객체를 참조하게 됨 a==b; // true a.equals(b); // true
Java
복사
==은 변수에 저장된 객체의 주소값이 동일한지 검사
equals()는 동일한 객체건 다른 객체건 상관 없이, 내부 문자열이 동일한지 검사
Sol 2) new 연산자로 생성
무조건 새로운 String 객체를 생성함
String c = new String("hi"); String d = new String("hi"); // c, d는 서로 다른 String 객체를 참조하게 됨 c==d; // false c.equals(d); // true
Java
복사

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

클래스 변수
정의) 클래스 내에서 static 키워드로 선언된 변수로서, 해당 클래스의 모든 인스턴스들이 공유하는 변수
특징)
클래스가 메모리에 로드될 때 할당되고, 프로그램이 종료될 때까지 유지됨
클래스 이름을 통해 접근하며, 객체를 생성하지 않고도 클래스 변수에 접근할 수 있음
클래스의 모든 인스턴스들이 동일한 클래스 변수의 값을 공유함
인스턴스 변수
정의) 클래스 내에서 선언된 변수로서, 클래스의 인스턴스(객체)마다 각각 별도의 값을 가질 수 있는 변수
특징)
객체가 생성될 때 메모리에 할당되고, 해당 객체의 라이프타임과 동일하게 유지됨
객체를 통해 접근하며, 각 인스턴스마다 독립적인 값을 갖기 때문에 서로 다른 객체에서 서로 다른 값을 가질 수 있음
로컬 변수
정의) 메소드, 생성자, 블록 내에서 선언된 변수로서, 해당 블록 내에서만 접근 가능한 변수
특징)
메소드 블록 내부에서만 사용되고 메소드 실행이 끝나면 메모리에서 자동으로 없어짐

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

자동 타입 변환(Promotion)
정의) 값의 허용 범위가 작은 타입이 큰 타입으로 저장될 때 발생하는 것
Widening type cast
byte < short < int < long < float < double
예시)
산술 연산에서의 자동 타입 변환
피연산자로 정수/실수 타입 변수가 사용되면, 두 피연산자 중 허용 범위가 큰 쪽으로 자동 타입 변환되어 연산 수행함
int x=1, y=2; double result1 = (double)(x/y); // 0.0 double result2 = (double)x/y; // 0.5
Java
복사
피연산자로 정수 타입 변수가 사용되면, int 타입보다 작은 byte, short 타입 변수는 int 타입으로 자동 타입 변환되어 연산 수행함
byte x=1, y=2; byte result1 = x+y; // 컴파일 에러 : cannot convert from int to byte // 이유 : (int)x+(int)y가 수행되어 int 타입을 byte에 넣으려 한 것이 되어서 byte result2 = 1+2; // OK. 피연산자가 변수가 아니므로 int 타입으로 변환 안함
Java
복사
byte, short 타입 변수는 무조건 int로 타입 변환되니, 처음부터 피연산자로 int 타입 변수를 사용하는 것이 타입 변환을 줄여 실행 성능 향상시키는 방법임
문자열 결합 연산에서의 자동 타입 변환
피연산자 중 하나가 문자열일 경우엔 나머지 피연산자도 문자열로 자동 변환되어 문자열 결합 연산 수행함
String str1 = 1+"2"; // "12" String str2 = 1+2+"3"; // (1+2)+"3" = 3+"3" = "33" String str3 = 1+"2"+3; // (1+"2")+3 = "12"+3 = "123"
Java
복사
강제 타입 변환(Casting)
정의) 값의 허용 범위가 큰 타입을 작은 타입으로 강제로 나눠서 저장하는 것
Narrow type cast
예시) 문자열과 기본 타입 간의 강제 타입 변환
기본 타입 → String
String str = String.valueOf(num); // 얜 결국 Integer.toString()을 호출함
String str = Integer.toString(num);
String → 기본 타입
int num = Integer.parseInt(str); //원시데이터인 int타입을 반환
int num = Integer.valueOf(str); // Integger 래퍼 객체를 반환
Autoboxing and Unboxing : Integer 객체 리턴 받아서 int 변수에 할당하면 자동 형변환 일어나서 둘 중 뭘 쓰던 상관 없음
Char[] → String
String str = String.valueOf(arr);
String → Char[]
char[] arr = str.toCharArray();
for문
char[] array = {'a','b'}; String str = ""; for (int i = 0; i < arr.length; i++) { str+= Character.toString(arr[i]); }
SQL
복사
번외
// 문자열 배열을 List로 변환 String[] temp = "abcde"; List<String> list = new ArrayList<>(Arrays.asList(temp)); // List를 문자열 배열로 변환 List<String> list = new ArrayList<>(); String[] temp = list.toArray(new String[list.size()]); // 정수 배열을 List로 변환 int[] temp = { 1123, 1412, 23, 44, 512132 }; List<Integer> list = new ArrayList<>(Arrays.asList(temp)); // List를 정수 배열로 변환 List<Integer> list = new ArrayList<>(); int[] temp = list.stream().mapToInt(i->i).toArray();
Java
복사

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

1차원 배열
int[] a = {1, 2, 3, 4, 5}; // int a[] int[] b; b = {1, 2, 3, 4, 5}; // 컴파일 에러 -> 이미 선언한 후엔 중괄호 사용한 배열 생성 허용 X b = new int[] {1, 2, 3, 4, 5}; // 새로운 배열을 참조함 b = new int[5]; // 모든 요소가 0(int타입의 초기값)으로 초기화된 새로운 배열을 참조함
Java
복사
중괄호 { }는 주어진 값들을 항목으로 가지는 배열 객체를 힙에 생성(int 타입 크기의 요소 5개를 할당)하고, 배열 객체의 주소값을 리턴함
배열 변수 a는 리턴된 주소값을 저장함으로써 참조 이루어짐
2차원 배열
int[][] aa= {{1, 2}, {3, 4}}; int[][] bb; bb = new int[2][2];
Java
복사
자바는 2차원 배열을 중첩 배열 방식으로 구현함

8. 타입 추론, var

정의) 타입이 정해지지 않은 변수에 대해서 컴파일러가 변수의 타입을 스스로 찾아낼 수 있도록 하는 기능
특징)
자바에선 10버전 이상부터 추가됨 var a = "hi";
타입을 명시하지 않아도 되기에 코드량 줄이고 코드 가독성 높일 수 있음
주의할 점)
초기화값이 있는 지역변수 (Local Vairable)로만 선언 가능
멤버변수, 파라미터, 리턴타입으로 사용 불가
var와 다이아몬드 연산자를 같이 사용하게 되면 컴파일 에러가 발생함
var b = new ArrayList<>(); // 컴파일 에러
IDE가 없으면 어떤 데이터 타입이 들어오는지 확인하기 어려움
참고