[자바 라이브 스터디] 2주차 - 자바 데이터 타입, 변수 그리고 배열
•
목표) 자바의 프리미티브 타입, 변수 그리고 배열을 사용하는 방법을 익힙니다.
1. 프리미티브 타입 종류와 값의 범위 그리고 기본 값
•
정의) 자바가 제공하는 기본 타입(Primitive type) 종류는 총 8개임
•
특징)
◦
기본 타입 종류
저장되는 값 | 타입 종류 | 메모리 사용 크기 | 저장되는 값의 허용 범위 | 기본값 |
정수 타입 | byte | 1 byte (8 bit) | ~ | 0 |
short | 2 byte (16 bit) | ~ | 0 | |
int (기본) | 4 byte (32 bit) | ~ (21억…) | 0 | |
long | 8 byte (64 bit) | ~ | 0L | |
char | 2 byte (유니코드) | ~ | '\u0000' | |
실수 타입 | float | 4 byte | ~
(소수점 아래 7자리) | 0.0F |
double (기본) | 8 byte | ~ (소수점 아래 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가 없으면 어떤 데이터 타입이 들어오는지 확인하기 어려움
참고