on
2주차 과제: 자바 데이터 타입, 변수 그리고 배열.
해당 글을 백기선 님의 자바 스터디 2주차 과제를 공부하고 공유하기 위해서 작성되었습니다.
목표
자바의 프리미티브 타입, 변수 그리고 배열을 사용하는 방법을 익힌다.
학습할 것
- 프리미티브 타입 종류와 값의 범위 그리고 기본 값
- 프리미티브 타입과 레퍼런스 타입
- 리터럴
- 변수 선언 및 초기화하는 방법
- 변수의 스코프와 라이프타임
- 타입 변환, 캐스팅 그리고 타입 프로모션
- 1차 및 2차 배열 선언하기
- 타입 추론, var
프리미티브 타입 종류와 값의 범위 그리고 기본 값
프리미티브 타입 중 boolean을 제외한 나머지 7개는 서로 연산과 변환이 가능하다.
정수는 가장 많이 사용되므로 타입을 4가지 제공한다. 각 타입마다 저장할 수 있는 값의 범위가 다르므로 저장할 값의 범위에 맞는 타입을 선택하면 된다.
일반적으로 int를 많이 사용하는데, CPU가 가장 효율적으로 처리할 수 있는 타입이기 때문이다.
크기 | 1 byte | 2 byte | 4 byte | 8 byte |
종류 | ||||
논리형 | boolean | |||
문자형 | char | |||
정수형 | byte | short | int | long |
실수형 | float | double |
기본형의 크기와 범위
자료형 | 저장 가능한 값의 범위 | 크기 | |
bit | byte | ||
boolean | false, true | 8 | 1 |
char | '\u0000' ~ '\uffff' (0 ~ 216-1, 0 ~ 65535) | 16 | 2 |
byte | -128 ~ 127 (-27 ~ 27-1) | 8 | 1 |
short | -32,768 ~ 32,767 (-215 ~ 215-1) | 16 | 2 |
int | -2,147,483,648 ~ 2,147,483,647 (-231 ~ 231-1, 약 ±20억) | 32 | 4 |
long | -9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807 (-263 ~ 263-1) | 64 | 8 |
float | 1.4E-45 ~ 3.4E38 (1.4x10-45 ~ 3.4x1038) | 32 | 4 |
double | 4.9E-324 ~ 1.8E308 (4.9x10-324 ~ 1.8x10308) | 64 | 8 |
기본값
분류 | 자료형 | 기본값 |
논리형 | boolean | false |
문자형 | char | '\u0000' |
정수형 | byte | 0 |
short | 0 | |
int | 0 | |
long | 0L | |
실수형 | float | 0.0F |
double | 0.0 |
프리미티브 타입과 레퍼런스 타입
주로 사용하는 값(data)의 종류(type)는 크게 ‘문자와 숫자’로 나눌 수 있고, 숫자는 다시 ‘정수와 실수’로 나눌 수 있다.
이러한 값(data)의 종류(type)에 따라 값이 저장될 공간의 크기와 저장형식을 정의한 것을 자료형(data type)이라고 한다.
자료형은 크게 ‘기본형(primitive type)’과 ‘참조형(reference type)’ 두 가지로 나눌 수 있는데, 기본형 변수는 실제 값(data)를 저장하는 반면, 참조형 변수는 어떤 값이 저장되어 있는 주소(memory address)를 값으로 갖는다.
프리미티브 타입(primitive type)이란?
프리미티브 타입(primitive type), 즉 기본형 타입은 모두 8개의 타입(자료형)이 있으며, 크게 논리형, 문자형, 정수형, 실수형으로 구분된다.
boolean | |
true와 false 중 하나를 값으로 가지며, 조건식과 논리적 계산에 상용된다. | |
char | |
문자를 저장하는데 사용되며, 변수에 하나의 문자만 저장할 수 있다. | |
byte, short, int, long | |
정수를 저장하는데 사용되며, 주로 int가 사용된다. byte는 이진 데이터를 다룰 때 사용되며, short는 C 언어와의 호환을 위해서 추가되었다. |
|
float, double | |
실수를 저장하는데 사용되며, 주로 double이 사용된다. |
레퍼런스 타입(reference type)이란?
레퍼런스 타입(reference type), 참조형 변수 또는 참조변수는 객체의 주소를 저장하고 8개의 기본형을 제외한 나머지 타입이다.
선언할 때 변수의 타입으로 클래스의 이름을 사용하므로 클래스의 이름이 곧 참조변수의 타입이 된다. 따라서 새로운 클래스를 작성하는 것은 새로운 참조형을 추가하는 것과 같다.
리터럴
상수
상수(constant)는 변수와 마찬가지로 ‘값을 저장할 수 있는 공간’이지만, 값을 한 번 저장하면 다른 값으로 변경할 수 없다. 선언하는 방법은 변수와 동일하며, 변수의 타입 앞에 키워드 final
을 붙여주기만 하면 된다.
또한 상수는 반드시 선언과 동시에 초기화해야 하며, 이 후 상수의 값을 변경하는 것은 허용되지 않는다.
JDK 1.6부터는 사용하기 전에만 초기화하면 되도록 바뀌었다.
리터럴
상수란 원래 ‘변하지 않는 수’라는 뜻으로 1, 23, 3.14, ‘A’와 값은 값들은 모두 ‘상수’이다. 하지만 프로그래밍에서 상수를 ‘한 번 저장하면 변경할 수 없는 저장공간‘으로 정의하였기 때문에 이와 구분하기 위해 리터럴(literal)이라는 용어를 사용한다.
| 출처 | https://dololak.tistory.com/676
리터럴의 타입과 접미사
변수에 타입이 있는 것처럼 리터럴에도 타입이 있다. 변수의 타입은 저장될 값의 타입, 즉 리터럴의 타입에 의해 결정된다.
정수형과 실수형의 경우 여러 타입이 존재하므로, 접미사를 붙여서 타입을 구분한다.
정수형의 경우, long 타입의 리터럴에 접미사 ‘l’ 또는 ‘L’을 붙이고, 접미사가 없으면 int 타입의 리터럴이다. byte와 short 타입의 리터럴은 별도로 존재하지 않으며 byte와 short 타입의 변수에 값을 저장할 때는 int 타입의 리터럴을 사용한다.
실수형에서는 float 타입의 리터럴에 ‘f’ 또는 ‘F’를 붙이고, double은 기본 자료형이기 때문에 생략이 가능하다. 리터럴에 소수점이나 10의 제곱을 나타내는 기호 E나 e가 포함되어 있으면 실수형 리터럴로 간주한다.
문자형에서는 영문자 이외에 tab이나 backspace 등의 특수문자를 저장하기 위해 조금 다른 방법을 사용해야 한다.
특수문자 | 문자 리터럴 |
tab | \t |
backspace | \b |
form feed | \f |
new line | \n |
carriage return | \r |
역슬래쉬 | \\ |
작은따옴표, 큰따옴표 | \', \" |
유니코드(16진수)문자 | \u유니코드 (ex: char a = '\u0041') |
변수 선언 및 초기화하는 방법
변수 선언
변수를 사용하기 위해서는 변수를 선언해야한다.
int a; // a라는 이름의 변수를 선언
int
는 변수의 타입으로 변수에 저장될 값이 어떤 타입인지를 지정하는 것이다.
a
는 변수이름으로 말 그대로 변수에 붙인 이름이다. 변수는 ‘값을 저장할 수 있는 메모리 공간’이므로 변수의 이름은 메모리 공간에 이름을 붙여주는 것이다. 따라서 같은 이름의 변수가 여러 개 존재해서는 안된다.
변수를 선언하면 메모리의 빈 공간에 ‘변수타입’에 맞는 크기의 저장공간이 확보되고, 이 저장공간은 ‘변수이름’을 통해 사용할 수 있게 된다.
변수의 초기화
변수를 선언한 이후부터 변수를 사용할 수 있지만, 그 전에 변수를 초기화(initialization)해야 한다.
메모리는 여러 프로그램이 공유하는 자원이므로 다른 프로그램에 의해 저장된 ‘알 수 없는 값(쓰레기 값, garbage value)’이 남아있을 수 있기 때문이다.
변수에 값을 저장할 때는 대입 연산자 =
을 사용한다. 대입연산자는 오른쪽의 값을 왼쪽(변수)에 저장하는 연산자이다.
변수의 종류에 따라 변수의 초기화를 생략할 수 있지만, 사용되기 전에 적절한 값으로 초기화 하는 것이 좋다.
지역변수는 사용되기 전에 초기화를 반드시 해야 하지만 클래스변수와 인스턴스변수는 초기화를 생략할 수 있다.
멤버변수의 초기화
멤버변수(클래스변수와 인스턴스변수)는 지역변수와 달리 초기화 방법이 여러가지이다.
- 명시적 초기화(explicit initialization)
- 생성자(constructor)
- 초기화 블럭(initialization block)
명시적 초기화는 변수를 선언과 동시에 초기화하는 것이다. 가장 기본적이고 간단한 초기화 방법으로 우선적으로 고려되어야 한다.
class 클래스이름 {
int a = 1; // 기본형(primitive type) 변수의 초기화
Number n = new Number(); // 참조형(reference type) 변수의 초기화
}
생성자는 인스턴스가 생성될 때 호출되는 인스턴스 초기화 메서드이다. 인스턴스변수의 초기화 작업에 주로 사용되며, 인스턴스 생성 시에 실행되어야 할 작업을 위해서도 사용된다.
생성자는 메서드처럼 클래스 내에 선언되며, 리턴 값이 없다.
클래스이름 (타입 변수명, 타입 변수명, ...) {
// 인스턴스 생성 시 수행될 코드
// 주로 인스턴스 변수의 초기화 코드를 적는다.
}
초기화 블럭에는 ‘클래스 초기화 블럭’과 ‘인스턴스 초기화 블럭’ 두 가지 종류가 있다. 각각의 이름처럼 클래스 초기화 블럭은 클래스변수의 초기화에 사용되고, 인스턴스 초기화 블럭은 인스턴스 변수의 초기화에 사용된다.
인스턴스 초기화 블럭은 클래스 내에 블럭{ }을 만들고 그 안에 코드를 작성하면 된다. 클래스 초기화 블럭은 인스턴스 초기화 블럭 앞에 static을 붙이면 된다.
class 클래스이름 {
static {
// 클래스 초기화 블럭
}
{
// 인스턴스 초기화 블럭
}
}
변수의 스코프와 라이프타임
변수의 스코프
변수의 스코프는 변수의 사용 범위를 말한다. 대부분의 경우 변수가 선언된 블럭이 그 변수의 사용범위이다.
public class ValueScope {
int globalScope = 10;
public void scopeTest(int value) {
int localScope = 10;
System.out.println(globalScope);
System.out.println(localScope);
System.out.println(value);
}
}
globalScope
는 클래스의 속성으로 선언되었으므로 사용범위는 클래스 전체이다.value
는 블럭 밖에 존재하지만, 메서드 선언부에 존재하므로 사용범위는scopeTest
메소드 블럭 내 이다.localScope
는 메소드 블럭 내에서 선언되었으므로 사용범위는scopeTest
블럭 내 이다.
하지만 static 메소드에서는 globalScope
와 같은 인스턴스 변수를 사용할 수 없다. static 변수만 static 메소드에서 사용할 수 있다.
public class ValueScope {
int globalScope = 10;
static int staticVal = 7;
public void scopeTest(int value) {
int localScope = 10;
System.out.println(globalScope);
System.out.println(localScope);
System.out.println(value);
}
public static void main(String[] args) {
System.out.println(globalScope); // 오류
System.out.println(localScope); // 오류
System.out.println(value); // 오류
System.out.println(staticVal);
}
}
변수의 라이프타임
라이프타임은 변수가 메모리에 살아있는 시간, 남아있는 시간을 말한다.
- 인스턴스 변수 : 클래스의 객체가 메모리에 남아있는 동안
- 클래스 변수 : 프로그램이 종료될 때 까지
- 로컬 변수(지역 변수) : 프로그램의 실행(컨트롤)이 지역 변수가 선언된 블록을 떠날 때 까지
타입 변환, 캐스팅 그리고 타입 프로모션
서로 다른 타입간의 연산을 수행해야하는 경우에 타입을 일치 시켜야 한다. 변수 또는 상수의 타입을 다른 타입으로 변환하는 것을 타입 변환 또는 형변환(casting)이라고 한다.
기본형에서는 boolean을 제외한 나머지 타입들은 서로 형변환이 가능하다. 기본형과 참조형간의 형변환은 불가능하다.
캐스팅 방법
형변환하고자 하는 변수나 리터럴 앞에 변환하고자 하는 타입을 괄호와 함께 붙여주면 된다. 이 때 사용되는 괄호 ( )는 ‘캐스트 연산자’ 또는 ‘형변환 연산자’라고 불린다.
(타입)피연산자
형변환 연산자는 피연산자의 값을 읽어서 지정된 타입으로 변환하고 그 결과를 반환하는 것이기 때문에, 피연산자인 변수의 값은 형변환 후에도 변화가 없다.
타입 프로모션
캐스팅이 명시적 형변환이라면 타입 프로모션은 자동 형변환으로 크기가 작은 자료형을 큰 자료형에 대입할 때, 자동으로 큰 자료형으로 변환된다.
기본형의 형변환
정수형간의 형변환에서 큰 타입에서 작은 타입으로, int에서 byte, 변환하는 경우 ‘값 손실(loss of data)’가 발생할 수 있다. 반대로 작은 타입에서 큰 타입으로 변환하는 경우 나머지 빈 공간이 0 또는 1로 채워진다.
원래의 값을 채우고 남은 빈공간은 0으로 채우는 게 보통이지만, 변환하려는 값이 음수인 경우에는 빈 공간을 1로 채운다.
실수형간의 형변환에서 작은 타입에서 큰 타입으로 변환하는 경우, 빈 공간을 0으로 채운다.
float 값을 double타입으로 변환하는 경우, 지수(E)는 float의 기저인 127을 뺀 후 double의 기저인 1023을 더해서 변환하고, 가수(M)는 float의 가수 23자리를 채우고 나머지를 0으로 채운다.
반대로 double타입에서 float타입으로 변환하는 경우, 지수(E)는 double의 기저인 1023을 뺀 후 float의 기저인 127을 더하고, 가수(M)는 double의 가수 52자리 중 23자리만 저장되고 나머지는 버려진다.
이 때 가수의 24번째 자리에서 반올림이 발생할 수 있다.
float타입의 범위를 넘는 값을 float로 형변환하는 경우 ‘±무한대’ 또는 ‘±0’을 결과로 얻는다.
참조형의 형변환
참조변수도 형변환이 가능하다. 단, 서로 상속관계에 있는 클래스 사이에서만 가능하기 때문에 자손에서 조상으로, 조상에서 자손으로의 형변환만 가능하다.
물론 조상의 조상으로도 형변환이 가능하다. 따라서 모든 참조변수는 Object클래스 타입으로 형변환이 가능하다.
자손타입에서 조상타입으로 형변환하는 경우 형변환을 생략할 수 있지만, 반대의 경우는 생략할 수 없다. 자손에서 조상으로 변환하는 것을 업캐스팅(up-casting), 조상에서 자손으로 변환하는 것을 다운캐스팅(down-casting)이라고 한다.
기본형과 같이 캐스트 연산자를 사용하며, 괄호 ( )안에 변환하고자 하는 타입의 이름(클래스명)을 적어주면 된다.
1차 및 2차 배열 선언하기
배열(array)이란?
같은 타입의 여러 변수를 하나의 묶음으로 다루는 것을 ‘배열(array)’이라고 한다.
배열을 선언하는 방법은 2가지이다. 원하는 타입의 변수를 선언하고 변수 또는 타입에 배열을 의미하는 대괄호 [ ]를 붙이면 된다.
int[] score; // 타입[] 변수이름
String name[]; // 타입 변수이름[]
배열의 생성
배열을 선언한 다음에는 배열을 생성해야 한다. 선언하는 것은 배열을 다루기 위한 참조변수의 공간이 만들어진 것이고 배열을 생성해야 값을 저장할 수 있는 공간이 만들어진다.
배열을 생성하기 위해서는 연산자 new
와 함께 배열의 타입과 길이를 지정해 주어야 한다.
type[] val_name; // 배열을 선언(배열을 다루기 위한 참조변수 선언)
val_name = new type[length]; // 배열을 생성(실제 저장공간을 생성)
1차 배열과 2차 배열
배열의 선언과 생성에서 1차원 배열을 다뤘다. 2차원 이상의 배열, 다차원 배열도 존재하는데 메모리의 용량이 허용하는한 차원의 제한은 없다.
2차원 배열을 선언하는 방법은 1차원 배열에 괄호를 하나 더 추가하면 된다.
int[][] score; // 타입[][] 변수이름
int[] score[]; // 타입[] 변수이름[]
int score[][]; // 타입 변수이름[][]
2차원 배열은 주로 테이블 형태의 데이터를 담는데 사용된다. 생성하는 방법도 1차원 배열과 동일하다.
type[][] val_name;
val_name = new type[row_length][column_length];
타입 추론, var
타입 추론이란 타입이 정해지지 않은 변수의 타입을 컴파일러가 유추하는 기능이다. 자바에서는 일반 변수에 대해 타입 추론을 지원하지 않기 때문에 자바에서의 타입 추론은 제네릭과 람다에 대한 타입 추론을 뜻한다.
컴파일러는 대입되는 값을 통해서 타입을 유추한다.
Java 7에서 다이아몬드 연산자라는 방식이 추가되었다. 제네릭에 대해서 다이아몬드 연산자로 타입을 넘겨주지만 실제론 한계가 있다. 제네릭은 소거자(erasure)에 의해 구현되어 컴파일 시에만 자신의 타입 제약을 지키게 하고 런타임 시에는 자신의 타입정보를 소거한다.
Java 10에서 var
키워드가 추가되었는데, 이 키워드는 선언과 동시에 초기화가 필수적으로 요구된다.
String message = "Hello"; // java 9 이하
var message = "Hello" // java 10 이상
다이아몬드 연산자와 var를 함께 사용하게 되면 컴파일 에러가 발생한다고 한다.
Reference
- https://ko.wikipedia.org/wiki/
- 자바의 정석 3/e
- Java in a Nutshell
- https://programmers.co.kr/learn/courses/5/lessons/231
- https://www.learningjournal.guru/article/programming-in-java/scope-and-lifetime-of-a-variable/
- https://velog.io/@bk_log/Java-%ED%83%80%EC%9E%85-%EC%B6%94%EB%A1%A0/
- https://futurecreator.github.io/2018/07/20/java-lambda-type-inference-functional-interface/
Comments
JAVA STUDY HALLE 의 다른 글
-
15주차 피드백 06 Mar 2021
-
15주차 과제: 람다식. 28 Feb 2021
-
14주차 피드백 27 Feb 2021
-
14주차 과제: 제네릭. 22 Feb 2021
-
13주차 피드백 20 Feb 2021
-
13주차 과제: I/O. 08 Feb 2021
-
12주차 피드백 06 Feb 2021
-
12주차 과제: 애노테이션. 01 Feb 2021
-
11주차 피드백 30 Jan 2021
-
11주차 과제: Enum. 24 Jan 2021
-
10주차 피드백 23 Jan 2021
-
10주차 과제: 멀티쓰레드 프로그래밍. 18 Jan 2021
-
9주차 피드백 16 Jan 2021
-
9주차 과제: 예외 처리. 10 Jan 2021
-
8주차 피드백 09 Jan 2021
-
8주차 과제: 인터페이스. 03 Jan 2021
-
7주차 피드백 02 Jan 2021
-
7주차 과제: 패키지. 28 Dec 2020
-
6주차 피드백 27 Dec 2020
-
6주차 과제: 상속. 21 Dec 2020
-
5주차 피드백 20 Dec 2020
-
5주차 과제: 클래스. 14 Dec 2020
-
4주차 피드백 13 Dec 2020
-
4주차 과제: 제어문. 30 Nov 2020
-
3주차 피드백 29 Nov 2020
-
3주차 과제: 연산자. 22 Nov 2020
-
2주차 피드백 21 Nov 2020
-
2주차 과제: 자바 데이터 타입, 변수 그리고 배열. 15 Nov 2020
-
1주차 피드백 15 Nov 2020
-
1주차 과제: JVM은 무엇이며 자바 코드는 어떻게 실행하는 것인가. 08 Nov 2020