https://github.com/whiteship/live-study
백기선님 자바 기초 스터디 2주차
목표
자바의 프리미티브 타입, 변수 그리고 배열을 사용하는 방법을 익힙니다.
학습할 것
- 프리미티브 타입 종류와 값의 범위 그리고 기본 값
- 프리미티브 타입과 레퍼런스 타입
- 리터럴
- 변수 선언 및 초기화하는 방법
- 변수의 스코프와 라이프타임
- 타입 변환, 캐스팅 그리고 타입 프로모션
- 1차 및 2차 배열 선언하기
- 타입 추론, var
프리미티브 타입 종류와 값의 범위 그리고 기본 값
프리미티브 타입
프리미티브 타입에는 모두 8개의 타입이 있다.
분류 | 타입 |
논리형 | boolean |
true와 false 중 하나를 값으로 갖으며, 조건식과 논리적 계산에 사용된다. | |
문자형 | char |
문자를 저장하는데 사용되며, 변수에 하나의 문자만 저장할 수 있다. | |
정수형 | byte, short, int, long |
정수를 저장하는데 사용되며, 주로 int가 사용된다. byte는 이진 데이터를 다룰 때 사용되며, short는 C언어와의 호환을 위해서 추가되었다. | |
실수형 | float, double |
실수를 저장하는데 사용되며, 주로 double이 사용된다. |
프리미티브 타입 범위와 기본 값
자료형 | 값의 범위 | 크기(byte) | 기본값 |
boolean | false, true | 1 | false |
char | 유니코드: '\u0000' ~ '\uffff' (0~216-1) | 2 | '\u0000' |
byte | -128 ~ 127 (-27~27-1) | 1 | 0 |
short | -32,768 ~ 32,767 (-215~215-1) | 2 | 0 |
int | -2,147,483,648 ~ 2,147,483,647 (-231~231-1) | 4 | 0 |
long | -9,223,372,036,854,775,808 ~ -9,223,372,036,854,775,807 (-263~263-1) | 8 | 0L |
float | 1.4*10-45~3.4*1038 | 4 | 0.0f |
double | 4.9*10-324~1.8*10308 | 8 | 0.0d or 0.0 |
각 자료형이 가질 수 있는 값의 범위를 정확히 외울 필요는 없고, 정수형의 경우 -2n-1 ~ 2n-1-1(n은 bit수)이라는 정도만 기억하고 있으면 된다.
why?
정수형 리터럴은 이진수로 바뀌어 저장되는데, 다음과 같은 표현 형식을 따른다.
왼쪽의 첫 번째 비트를 부호 비트(sign bit)로 사용하고, 나머지는 값을 표현하는데 사용한다.
그래서 n비트로 표현할 수 있는 값의 개수인 2n개에서, 절반인 '0'으로 시작하는 2n-1개의 값을 양수(0도 포함)의 표현에 사용하고, 나머지 절반인 '1'로 시작하는 2n-1개의 값은 음수의 표현에 사용된다.
-> n비트로 표현할 수 있는 정수의 범위: -2n-1 ~ 2n-1-1
최대값에서 1을 빼는 이유는 범위에 0이 포함되기 때문이다.
프리미티브 타입과 레퍼런스 타입
프리미티브 타입
- 계산을 위한 실제 값을 저장한다. 모두 8개
- 논리형(boolean), 문자형(char), 정수형(byte,short,int,long), 실수형(float,double)
레퍼런스 타입
- 객체의 주소를 저장한다. 8개의 프리미티브 타입을 제외한 나머지 타입.
- 클래스의 이름이 레퍼런스 타입이 된다.
리터럴
12, 123, 3.14, 'A'처럼 그 자체로 값을 의미하는 것을 리터럴이라고 한다.
변수에 타입이 있는 것처럼 리터럴에도 타입이 있다.
종류 | 리터럴 | 접미사 |
논리형 | false, true | 없음 |
정수형 | 123, 0b0101, 077, 0xFF, 100L | L |
실수형 | 3.14, 3.0e8, 1.4f | f, d |
문자형 | 'A', '1', '\n' | 없음 |
문자열 | "ABC", "123", "A", "true" | 없음 |
정수형과 실수형에는 여러 타입이 존재하므로, 리터럴에 접미사를 붙여서 타입을 구분한다.
정수형
long타입의 리터럴에 접미사 'l' 또는 'L'을 붙이고, 접미사가 없으면 int타입의 리터럴이다.
byte와 short타입의 리터럴은 별도로 존재하지 않으며, int타입의 리터럴을 사용한다.
기본적으로 10진수를 제공하지만, 10진수 외에도 2, 8 ,16진수로 표현할 수 있다.
- 2진수는 접두사 '0b'를 붙인다. ex) 0b10 -> 2진수 10 -> 10진수 2
- 8진수는 접두사 '0'을 붙인다. ex) 010 -> 8진수 10 -> 10진수 8
- 16진수는 접두사 '0x'를 붙인다. ex) 0x10 -> 16진수 10 -> 10진수 16
+) 자바7부터 정수형 리터럴의 중간에 구분자 '_'를 넣을 수 있게 되어서 큰숫자를 편하게 읽을 수 있게 되었다.
long big = 100_000_000_000L; //long big = 100000000000L;
실수형
float타입의 리터럴에 접미사 'f' 또는 'F'를 붙이고, double타입의 리터럴에 접미사 'd' 또는 'D'를 붙인다.
정수형에서는 int가 기본 자료형인 것처럼 실수형에서는 double이 기본 자료형이라서 접미사 'd'는 생략이 가능하다.
문자열
"Java"와 같이 두 문자 이상을 감싼 것을 문자열 리터럴이라고 한다.
타입은 String 객체, 즉, 레퍼런스 타입을 사용하고, char타입과 달리 큰 따옴표(")로 감싸야 한다.
+) 참고
덧셈 연산자를 이용하여 문자열을 결합할 수 있다.
- "Ja" + "va" -> "Java"
- "Java" + 8.0 -> "Java8.0"
덧셈 연산자(+)는 피연산자 중 어느 한 쪽이 String타입이면 나머지 한쪽을 String으로 변환한 다음 두 String을 결합한다. 프리미티브 타입과 레퍼런스 타입 구별 없이 어떤 타입의 변수도 문자열과 덧셈연산을 수행하면 그 결과가 문자열이 된다.
: 문자열 + any type -> 문자열 + 문자열 -> 문자열
변수 선언 및 초기화하는 방법
변수란, 단 하나의 값을 저장할 수 있는 메모리 공간이다.
변수 선언
변수의 선언 방법은 다음과 같다.
int age; //age라는 이름의 변수를 선언
여기서 "int"를 변수 타입, "age"를 변수 이름이라고 한다.
변수 타입
변수에 저장될 값이 어떤 '타입'인지를 지정한다.
변수 이름
변수에 붙인 '이름'이다. 이 이름을 이용해서 변수에 값을 저장하고, 읽어올 수 있다.
단, 같은 이름의 변수가 여러 개 존재해서는 안된다.
-> 변수를 선언하면, 메모리의 빈공간에 '변수타입'에 알맞은 크기의 저장공간이 확보되고, 앞으로 이 저장공간은 '변수이름'을 통해 사용할 수 있게 된다.
변수의 초기화
변수를 선언한 이후, 변수를 사용하기 전에 반드시 변수를 '초기화'해야 한다.
변수의 초기화 방법은 다음과 같다.
int age = 25; //변수 age를 선언하고 25로 초기화 한다.
변수에 값을 저장할 때는 대입 연산자(=)를 사용한다. 오른쪽의 값을 왼쪽(변수)에 저장하라는 뜻이다.
변수의 스코프와 라이프타임
변수의 스코프
변수에 접근할 수 있는 유효 범위
일반적인 규칙은 변수가 선언된 블록({ }) 내에서만 접근할 수 있다는 것이다.
다음 예시를 보자.
public class Test {
int var1;
void foo() {
int var2;
}
}
class { } 안에 var1이라는 변수는 클래스 전체에서 접근할 수 있다. 즉, foo() 메서드 안에서도 사용할 수 있다는 것이다.
그러나 var2는 foo() { } 안에서만 접근할 수 있다.
변수의 라이프타임
변수가 메모리에서 살아있는 기간
다음 예시를 통해 변수의 종류에 따른 스코프와 라이프타임을 알아보자.
public class Test {
int var1; //인스턴스 변수
static int var2; //클래스 변수
void foo() {
int var3; //지역 변수
}
}
인스턴스 변수
인스턴스 변수는 클래스 내에서 선언되지만, 메서드 및 블록({ }) 외부에 선언되는 변수를 말한다.
객체가 생성될 때 변수가 생성되고, 참조가 없을 때 가비지 컬렉터가 객체를 지워버리게 되는데 이 때, 인스턴스 변수도 같이 소멸한다.
- 스코프: 정적 메서드(static method)를 제외한 클래스 전체
- 라이프타임: 클래스 객체 생성 ~ 클래스의 객체가 메모리에 남아 있을 때까지
클래스 변수
클래스 변수는 인스턴스 변수의 조건(클래스 내부, 블록 외부)을 만족하며 static 키워드가 포함된 변수를 말한다.
클래스가 처음 로딩 되면서 생성이 되고, 자바 애플리케이션이 종료되는 시점에 같이 소멸된다.
- 스코프: 클래스 전체
- 라이프타임: 클래스 처음 로딩 ~ 애플리케이션 종료
지역 변수
지역 변수는 인스턴스 변수와 클래스 변수가 아닌 변수를 말한다.
- 스코프: 선언된 블록 안에서만 사용 가능
- 라이프타임: 블록 { ~ }에서 프로그램이 도는 동안
타입 변환, 캐스팅 그리고 타입 프로모션
모든 변수와 리터럴에는 타입이 있다는 것을 알았다.
프로그램을 작성하다 보면 서로 다른 타입간의 연산을 수행해야 하는 경우가 있다. 이럴 때는 연산을 수행하기 전에 타입을 일치시켜야 하는데, 변수나 리터럴의 타입을 다른 타입으로 변환하는 것을 '타입 변환'이라고 한다.
타입 변환은 2가지 종류가 있는데, '캐스팅'과 '프로모션'이 있다.
캐스팅
형변환하고자 하는 변수나 리터럴의 앞에 변환하고자 하는 타입을 괄호와 함께 붙여준다. (강제 형변환)
다음 예시를 보자.
int score = (int)85.4;
85.4는 double타입으로 더 작은 크기인 int타입 변수에 저장할 수 없다.
그래서 85.4라는 double타입을 int타입으로 캐스팅해서 int타입 변수에 대입하는 것이다.
이 때, score에는 소수점이 버려지고 85가 저장되기 때문에 값 손실이 발생한다.
프로모션
원래 타입에서 더 큰 타입으로 변경할 때 프로모션 변경이 발생한다. (자동 형변환)
다음 예시를 보자.
float f = 1234;
우변은 int타입의 리터럴이고, 이 값을 저장하려는 좌변 변수의 타입은 float타입이다. 서로 타입이 달라서 타입 변환이 필요하지만 더 작은 크기인 int타입 1234가 자동으로 float타입으로 변환되어 저장되기 때문에 '(float)1234'와 같이 캐스팅을 굳이 해줄 필요가 없다.
또한 덧셈 연산자에서도 프로모션 변환을 볼 수 있다.
int i = 3;
double d = 1.0 + i;
서로 다른 두 타입간의 덧셈에서는 두 타입중 크기가 큰 타입으로 타입 변환하여 타입을 일치시킨 다음에 연산을 수행한다.
예시의 경우 int타입인 i가 double타입으로 변환된 후 덧셈 연산을 수행하게 된다.
타입 변환 규칙
- 프리미티브 타입과 레퍼런스 타입 간에은 타입 변환할 수 없다.
- 프리미티브 타입은 boolean을 제외한 나머지 7개 타입들은 서로 타입 변환이 가능하다.
- 기존의 값을 최대한 보존할 수 있는 타입으로 자동 형변환한다.
- 화살표방향으로의 변환, 즉 왼쪽에서 오른쪽으로의 변환은 프로모션, 자동 형변환
- 그 반대 방향으로의 변환은 캐스팅, 강제 형변환 필요
+) long(8byte) -> float(4byte)의 경우 의아해할 수 있는데, 실수형은 정수형과 값을 표현하는 방식이 다르기 때문에 같은 크기일지라도 실수형이 정수형보다 훨씬 더 큰 표현 범위를 갖기 때문에 float이 long보다 오른쪽에 위치한다.
1차 및 2차 배열 선언하기
- 배열을 원하는 타입의 변수를 선언하고 변수 또는 타입에 배열임을 의미하는 대괄호[ ]를 붙이면 된다.
- 생성은 연산자 'new'와 함께 배열의 타입과 길이를 지정해준다.
int[] score = new int[5]; //길이가 5인 int배열
이 때, score는 레퍼런스 타입이고 연속적인 int타입 메모리를 참조하게 된다.
추가로 자바에서는 다음과 같이 배열을 간단히 초기화 할 수 있는 방법을 제공한다.
int[] score = new int[] { 50, 60, 70, 80, 90 }; //배열의 생성과 초기화를 동시에
int[] score = { 50, 60, 70, 80, 90 }; //new int[]를 생략할 수 있음
이 때, [ ] 안에 배열의 길이는 생략 가능하다.
new int[]를 생략한 방식의 경우 배열의 선언과 초기화를 같이 하는 경우에만 가능하다는 점을 주의하자.
즉, 다음과 같은 예시는 에러를 발생시킨다.
int[] score;
score = { 50, 60, 70, 80, 90 }; //에러. new int[]를 생략할 수 없음
2차원 배열은 1차원 배열과 별 다를바 없이 차원을 하나 추가하면 된다.
int[][] score = new int[2][3]; //2행 3열 2차원 배열 score를 생성
int[][] score = new int[4][3] { {1, 2, 3}, {4, 5, 6} }; //선언과 동시에 초기화
int[][] score = { {1, 2, 3}, {4, 5, 6} }; //new int[][] 생략
타입 추론, var
타입 추론이란 코드 작성 당시 타입이 정해지지 않았지만, 컴파일러가 알아서 그 타입을 유추하는 것이다.
자바 10부터 타입 추론을 지원하는 var타입이 추가되었다.
다음 예시를 보자.
String str1 = "Hello";
var str2 = "Hello";
지금까지는 str1처럼 String과 같은 명시적인 타입을 선언했다.
그러나 str2는 변수의 타입을 따로 명시하지 않았다. 대신 str2 변수 앞에 var타입을 선언해주었다.
그리고 컴파일 시점에, 컴파일러가 오른쪽에 있는 초기화 리터럴 값으로 타입을 추론한다.
-> 결국 str2의 타입은 String으로 선언된다.
주의사항
1. var는 초기화값이 있는 지역변수로만 선언이 가능하다.
var는 인스턴스 변수, 또는 메소드의 파라미터, 리턴 타입으로 사용이 불가능하다.
private var i = "Hello"; //에러, 인스턴스 변수에 사용 불가능
또한, 무조건 선언할 때, 초기화 값이 있어야 한다.
var i; //에러, var타입은 초기화값을 선언부에 명시해주어야한다.
2. var는 키워드(예약어)가 아니다.
그래서 int를 변수 이름으로 사용할 수 없지만, var는 변수 이름으로 사용할 수 있다.
int var = 3;
3. var로 선언된 변수는 런타임 중간에 타입이 절대 변경되지 않는다.
-> 컴파일 시점에 var는 초기화된 값을 보고 타입 추론을 하기 때문
var i =3; //컴파일 시점에 int타입으로 추론
i = "Hello"; //에러
4. 예외
var타입 변수에는 null 혹은 배열이 들어갈 수 없다. 이 경우, 타입을 직접 명시해 주어야 한다.
var i = null; //에러
var arr = { 1, 2, 3 }; //에러
'java > java' 카테고리의 다른 글
[Java] 배열의 복사 (0) | 2021.06.23 |
---|---|
[Java] 배열의 출력 (0) | 2021.06.23 |
[Java] javac - error: error while writing 오류 (0) | 2021.06.12 |
[Java] 'javac'은(는) 내부 또는 외부 명령, 실행할 수 있는 프로그램, 또는 배치 파일이 아닙니다. (0) | 2021.06.12 |
[Java] Java 환경 변수 설정 - Window (0) | 2021.06.12 |