JAVA/온라인 스터디

2주차 자바 데이터 타입, 변수 그리고 배열

oozoo 2020. 11. 21. 15:55

목표

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

 

학습할 것

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

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

3. 리터럴

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

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

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

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

8. 타입 추론, var


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

프리미티브 타입(Primitive Type)은 우리나라 말로 기본형 타입으로서, 이를 이해하기 위해서는 먼저 데이터 타입 (Data Type)에 대한 이해가 필요하다. 데이터 타입(Data Type)에서 타입이란 데이터의 속성이다. 데이터 타입을 이용하여 프로그래머는 컴파일러나 인터프리터에게 데이터를 어떻게 처리 할지 정할 수 있다. (출처:en.wikipedia.org/wiki/Data_type)

C나 Java와 같은 프로그래밍 언어는 타입과 일치하는 데이터만 입력이 되는데, 이를 정적 타입 언어(static typed languague)라고 한다. (cf. 자바 스크립트의 경우 변수에 타입이 존재하지 않아, 모든 타입의 데이터를 저장할 수 있다. 실행시, 변수에 저장된 데이터 타입을 동적으로 바꿀 수 있다. 이는 동적 타입 언어(dynamic typed language)라고 한다.) (출처:limboy.tistory.com/382)

데이터 타입은 크게 기본형 타입(Primitive Type)참조형 타입(Reference Type)이 존재한다. (출처:gbsb.tistory.com/6) 이와 관련하여서는 아래에서 구체적으로 설명하고, 먼저 가장 기본적인 기본형 타입에 대해 설명하겠다. 

 

그렇다면, 기본형 타입은 어떤 종류가 있고, 값의 범위, 기본 값은 무엇일까? 이를 이해하기 위해서는 표를 보면 편리하다. 

값의 종류 타입 할당 메모리 크기 *기본값 데이터 표현 범위
논리형 boolean 1 byte 8 bit false true, false
정수형 byte 1 byte 16 bit 0 -128 ~ 127
short 2 bytes 16 bit 0 -32,768 ~ 32,767
int 4 bytes 32 bit 0 -2,147,483,648 ~ 2,147,483,647
long 8 bytes 64 bit 0L -9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807
실수형 float 4 bytes 32 bit 0.0F 7개의 유효 숫자 -3.4E+38의 근사값 ~ 7개의 유효 숫자 
3.4E + 38의 근사값
double 8 bytes 64 bit 0.0 15개의 유효 숫자 -1.7E+308의 근사값 ~
15개의 유효 숫자 1.7E+308의 근사값
문자형 char 2 bytes 8 bit '\u000' 0 ~ 65,535

출처: gbsb.tistory.com/6 & you9010.tistory.com/151

 

 

*기본값이 존재하여, NULL이 존재하지 않는다. 

 

참고자료

1. en.wikipedia.org/wiki/Data_type

2. gbsb.tistory.com/6

3. hyeonstorage.tistory.com/135


2. 프리미티브 타입(Primitve Type)과 레퍼런스 타입(Reference Type)

기본형 타입과 참조형 타입의 데이터들은 그럼 어떤 차이점을 가지고 있을까? 왜 이 둘을 구분지을 수 있는 가장 큰 기준은 "메모리 참조 타입"입니다. 각각의 타입을 변수로 선언할 시, 메모리에 공간이 할당된다. 이때, 메모리에 직접 데이터를 담으면 기본형 타입이 되고, 메모리가 담긴곳의 주소값을 담으면 참조형이 된다. 간단하게 참조형 타입은 기본형 타입을 제외한 전부라고 이해하면 쉽다. 

  기본형 타입 참조형 타입
설명 변수 자체가 값을 가짐
선언 이후 특별히 값을 입력하지 않음
변수 자체가 값을 가지지 않음
복합적인 내용의 값이 담겨있는 곳
값 저장 방식 값을 그대로 저장 값이 저장된 주소값을 할당
타입 종류 정수 타입
부동소수점 타입
클래스 타입
인터페이스 타입
배열 타입
열거 타입

 

참조형 타입 구체적 설명

타입 예시 기본값 할당 메모리 크기
클래스 (Class) String str =
new String("Hello");
Null 4 byte (객체 주소값)
인터페이스 (Interface)   Null
배열 (Array) int[] arr = new int[5]; Null
열거 (Enumeration)   Null

출처: gbsb.tistory.com/6?category=735872

 

그렇다면, 메모리에 직접 저장하고, 주소값을 저장한다는 것을 무엇을 의미할까? 다음 예시를 보면 이해가 쉽다. 

 

왼쪽은  i 변수에 int 기본형 타입으로 선언했다. 그 후, i 변수를 14라고 선언을 했다. int형은 기본형 타입으로 이렇게 직접 메모리에 14가 담긴것을 볼 수 있다. 

이와 달리 String형은 참조형 타입 중 Class 타입으로, str이라는 변수에 String 참조형 타입으로 선언했다. 그 후, new String ("Jae");는 생성자라는 것인데 이후에 설명하겠다. 여기서 new를 이용하여 앞서 선언한 str 변수에 어떤 내용을 메모리에 올릴것인지 정할 수 있다. 이렇게 메모리에 올라간 객체를 인스턴스라고 하며, 그림처럼 "Jae"라는 인스턴스가 생성된 것을 알 수 있다. str변수에는 메모리의 위치 값이 저장되여, str 변수는 String 인스턴스를 참조하여 "Jae"값을 가져오게 된다. 

 

참고자료

1. m.blog.naver.com/highkrs/220242895539

2. gbsb.tistory.com/6

3. programmers.co.kr/learn/courses/5/lessons/138#


3. 리터럴(Literal)

리터럴이란, 데이터 그 자체이자 변수에 넣어 변하지 않는 데이터를 의미하기도 한다. 이는 자바 언어가 처리하는 실제 데이터를 일컫기도 한다. 다음 예시를 보면, 쉽게 이해할 수 있다. 

int a = 14;

여기서 14는 리터럴이라고 일컫는다. 이런 리터럴은 앞서 공부한 데이터 타입에 따라 각각 다르게 표현한다. 각 데이터 타입별 리터럴 표현방법은 다음 표를 참고 하면 이해하기 쉽다. 

 

데이터 타입 설명 및 예시
정수(integer) 1, 14, 114, 1114 (10진수)
01, 07, 01, (8잔수)
0x15, 0x11 - 0~16 (16진수- a~f(A~F): 10~15)
long형의 경우 숫자 뒤에 알파벳 l or L을 추가한다. (ex. 3L)
부동 소수점
(floating point)
소수점 이하 (분수)를 가진 10진수 값
ex. 2.0, 3.1415, -0.6668
double형이 부동 소수점의 기본형으로 숫자 뒤에 알파벳을 추가할 수 있다. (d or D)
float형 부동 소수점의 기본형 숫자 뒤에 알파벳 f를 반드시 추가해야 한다.
문자 리터럴 단일 인용부호 ' '로 문자를 표현한다. 
'H'
문자열 리터럴 " "로 문자열을 표현한다. 
"JAVA"
논리타입 리터럴 boolean 타입 변수에 치환하거나 조건문에 이용
ex) boolean a = true;
번외 null 리터럴은 레퍼런스에 대입해서 사용한다. 
int a = null; (ERROR)
String str = null;
str = "JAVA";

출처: mine-it-record.tistory.com/100

 

번외) 인스턴스 (클래스 데이터)가 리터럴이 될 수 있을까? (출처:mommoo.tistory.com/14)

답: NO

인스턴스란 언제 바뀔지 모르는 값이기 때문에 리터럴이 될 수 없다. 이때 데이터가 변하지 않도록 설계를 한 클래스가 있는데 이는 불변 클래스 (immutable class)라고 한다. 해당 클래스는 생성 시, 객체 안의 데이터가 변하지 않으며, 변할 경우에는 새로운 객체를 만든다. 자바의 String, Color 같은 클래스가 해당한다. 

 

참고자료

1. www.devkuma.com/books/pages/29

2. mommoo.tistory.com/14


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

변수선언을 배우기 전에는 변수에 대한 이해가 필요하다. 변수(Variable)란, 데이터의 저장과 참조를 위해 할당된 메모리 공간입니다. 이런 변수를 변수명이라는 이름으로 분류하며, 이런 변수를 컴파일러에게 알려주는 것을 선언(Declaration)이라고 합니다. (출처: futurecreator.github.io/2017/01/27/java-variable-data-type/)

 

간단한 예시입니다. 이를 통해, 변수를 선언하는 방법과 초기화 하는 방법을 설명하겠다.

int num1;
num1 = 14;
int num2 = 24;

출처: futurecreator.github.io/2017/01/27/java-variable-data-type/

 

1) 변수 선언

위의 예시처럼 변수를 선언합니다. 이럴 경우, 이 데이터를 저장하기 위해 메모리 상에 공간이 할당됩니다. int는 앞서 배운내용처럼 데이터의 속성이 정수형이라는 것을 의미합니다. 이때, num1은 변수를 구분하기 위한 변수의 이름 (변수명)입니다. 즉 int num1 이란 int라는 정수형으로 저장하는 메모리 공간을 할당한다는 것을 의미합니다. 

num1 = 10;은 결국 num1 이라는 메모리 공간에 10이라는 값을 대입하겠다는 뜻입니다. 

 

2) 초기화(Initialize)

초기화는 선언과 동시에 값을 대입하는 것을 의미합니다. 즉, 가장 마지막 줄에 있는 int num2 = 24; 이는 변수를 선언함과 동시에 값을 대입한 것입니다. 즉, num2이라는 메모리 공간은 정수형으로 저장할것이며, 그 안에는 20이라는 값을 대입하겠다는 뜻입니다. 

 

참고자료

1. futurecreator.github.io/2017/01/27/java-variable-data-type/


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

변수의 스코프(scope)와 라이프타임(lifetime)은 함께 이해하면 편리한 개념이다. 먼저, 스코프(scope)란 프로그램에서 변수가 접근할 수 있는 영역을 의미한다. 라이프타임(lifetime)은 메모리에서 변수가 살아있는 시간을 의미한다. (출처: www.learningjournal.guru/article/programming-in-java/scope-and-lifetime-of-a-variable/) 보다 더 쉽게 말하면, 변수의 스코프는 선언한 {} 범위;영역 내에서만 접근이 가능하다. 

 

변수의 스코프와 라이프타임은 변수의 종류에 따라 달라지는데, 이를 요약하여 표로 나타내면 다음과 같다. 

변수의 종류는 변수가 선언된 위치에 따라 달라집니다. (출처: itmining.tistory.com/20)

 

변수 타입 스코프 (Scope) Lifetime(라이프타임)
인스턴스 변수
(Instance Variable)
static method를 제외한 모든 class 메모리에서 접근이 가능할때 까지
클래스 변수
(Class Variable)
class내 모두 / Static로 선언된 경우. 
모든 인스턴스가 공통값 가진 경우.
프로그램이 끝날때 까지
로컬 변수
(Local Variable)
선언한 {} 영역 내에서
Instance와 Class 변수가 아닌 모든 것
컨트롤이 {}영역을 떠날때까지

출처: www.learningjournal.guru/article/programming-in-java/scope-and-lifetime-of-a-variable/

 

변수별 스코프와 라이프타임에 대한 상세 예시는 다음 이미지를 참고하면 이해하기 쉽다.

public class scope_and_lifetime {
       int num1, num2;             // Instance Variables
       static int result;             // Class Variable
       int add(int a, int b){      // Local Variables
             num1 = a;
             num2 = b;
             return a+b;
       }
       public static void main (String args[]){
             scope_and_lifetime ob = new scope_and_lifetime();
             result = ob.add(10,20);
             System.out.println("Sum = " + result);
       }
}

출처: www.learningjournal.guru/article/programming-in-java/scope-and-lifetime-of-a-variable/

 

번외) Nested Scope

코드 영역 내 새로운 코드를 사용할 수 있다. 이러한 프로그래밍 기술은 Nested Scope라고 불린다. 이럴 경우에는 바깥에 위치한 변수들을 안쪽에 위치한 변수들이 사용할 수 있다. 하지만, 안쪽에 위치한 변수를 바깥에서는 사용할 수 없다. 

public class scope_and_lifetime {
       public static void main (String args []){
             int a = 10;
             //Outer Block
             {
                   //Inner Block
                   int x = a;
                   {
                         int y = x;
                   }
             }
             System.out.printly(y);
       }
}

출처: www.learningjournal.guru/article/programming-in-java/scope-and-lifetime-of-a-variable/

 

위의 예시처럼, 안쪽의 영역에서 선언된 y의 변수에 대한 값을 바깥 영역에서 접근하려고 했지만, ERROR가 출력된다. 

 

 

참고자료

1. www.learningjournal.guru/article/programming-in-java/scope-and-lifetime-of-a-variable/

2. itmining.tistory.com/20


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

Type conversion, type casting, type promotion은 하나의 데이터 타입을 다른 데이터 타입으로 바꾸는 과정을 표현한 것이다. 

 

1) 타입 변환(Type conversion)

JAVA에는 타입 변환이 존재한다. 데이터 타입을 다른 타입으로 바꾸는 것을 의미한다. JAVA에서는 boolean형을 제외하고 나머지 기본형 타입 간에서는 자유롭게 변환을 할 수 있다. 이러기 위해서는 JAVA에서는 데이터를 모두 같은 타입으로 만든 후 수행을 한다. 그러다보니, 메모리에 할당받은 바이트의 크기가 큰 타입에서 작은 타입으로 변환할 경우 데이터의 손실이 발생한다.  JAVA 타입 변환에는 두 종류가 있는데, 자동 타입 변환과 강제 타입 변환이 있다.  (출처: www.tcpschool.com/java/java_datatype_typeConversion)

 

(1) 자동 타입 변환(묵시적 타입 변환 implicit conversion; Type Promotion)이란, 대입, 산술 연산에서 컴파일러가 자동으로 수행하는 타입 변환을 일컫는다. 또한, JAVA에서는 데이터의 손실이 발생하는 대입 연산은 불가능하다. 다음 그림은 앞서 살펴봤던 데이터 타입별 메모리 크기를 나타냈다. 

참고: https://kephilab.tistory.com/27

다음의 예제를 통해 구체적으로 살펴보겠다. 타입의 변환이 자동으로 일어날 때 실행 결과가 어떻게 나타나는지 볼 수 있다. 

 

(2) 강제 타입 변환(명시적 타입 변환 explicit conversion; type casting)

강제 타입 변환은 강제로 바이트를 쪼개서 1byte 타입 변수에 저장하는 방식이다. 구체적으로 큰 크기 바이트 타입이 작은 바이트 타입으로 자동으로 변환되지 않는 것을 변환하기 위해 1 바이트씩 쪼개서 변환을 한다. (하지만, 이럴경우 3바이트가 버려지게 된다. = 손실이 발생한다.)

 

 

참고자료

1. www.tcpschool.com/java/java_datatype_typeConversion

2. kephilab.tistory.com/27


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

1차 및 2차 배열을 선언하기 위해서는 배열이 무엇인지, 그리고 1차원과 2차원 배열이 어떻게 다른지 살펴보아야 한다. 

우선, 배열(array)이란 같은 타입의 변수들로 이루어진 집합이다. 배열은 주로 같은 종류의 데이터를 많이 다뤄야 할 경우 사용할 수 있는 가장 기본적인 자료 구조이다. 배열을 구성하는 (=집합 내) 각각의 값을 배열 요소(element)라하며, 배열에서의 위치를 가리키는 숫자를 인덱스(index)라고 한다. JAVA에서는 인덱스는 항상 0에서부터 시작한다. 배열의 선언 방식에 따라 1차원 배열, 2차원 배열등 다차원 배열로 선언이 될 수 있다. 

 

1) 1차원 배열 선언

1차원 배열은 다음과 같은 방법으로 선언이 가능합니다. 

(1) 타입[] 배열이름;

int[] n;

(2) 타입 배열이름[];

int n[];

 

이렇게 선언한 배열은 new 키워드를 이용하여 실제 배열로 생성할 수 있다. 

 

(3) 배열 이름 = new 타입[배열길이];

n = new int[3];

 

배열의 길이는 배열이 몇개의 배열 요소를 지녔는지 쓰면 된다. 

 

(4) 타입[] 배열이름 = new 타입[배열길이];

int [] n = new int[3];

 

위와 같이 배열은 선언과 생성을 동시에 할 수도 있다.

 

 

2) 2차원 배열(two dimensional array) 선언

2차원 배열은 배열의 요소로 1차원 배열을 가지는 배열이다. JAVA에서는 2차원 배열을 나타내는 타입을 따로 제공하지는 않는다. 대신, 1차원 배열의 배열 요소로 또 다른 1차원 배열을 사용하여 2차원 배열을 나타낼 수 있다. 

 

자바에서는 2차원 배열을 다음과 같은 방법으로 선언한다. 

1. 타입[][] 배열이름;

2. 타입 배열이름[][];

3. 타입[] 배열이름[];

 

타입은 배열요소로 저장되는 변수의 타입을 설정한다. 배열 이름은 배열이 선언된 후에 배열에 접근하기 위해 사용된다. 다음 그림은 2차원 배열을 이해하기 쉽도록 그림으로 표현했다. 

 

출처: http://www.tcpschool.com/java/java_array_twoDimensional

 

참고자료

1. www.tcpschool.com/java/java_array_oneDimensional

2. www.tcpschool.com/java/java_array_twoDimensional


8. 타입 추론, var

1) 타입 추론(Type Inference)

타입 추론이란 데이터 타입이 정해지지 않은 변수를 컴파일러가 유추하는 기능이다. JAVA에서는 JAVA 10부터 이를 사용 가능하게 되었으며, var를 통해 사용이 가능하다. 예시와 함께 설명하면 이해가 편하다. 

 

Java 9에서는 다음과 같이 모든 데이터에 타입을 입력을 해야 했다. 

String message = "Good bye, Java 9";

하지만, JAVA 10에서는 var를 이용하여 타입 추론이 가능해졌다. 

public void whenVarInitWithString_thenGetStringTypeVar() {
       var message = "Hello Java 10";
       assertTrue(message instanceof String);
}

위의 예시에서는 var는 = 오른쪽에 있는 "" 하지만 문구를 통해 message의 타입을 String으로 컴파일러가 유추하여 실행이 가능하다. 해당 기능은 지역 변수를 초기화 했을때에만 사용이 가능하다. 즉 컴파일러가 유추를 하기 위해서는 반드시 초기화와 함께 사용이 되어야 한다. 

 

참고자료

1. futurecreator.github.io/2018/07/20/java-lambda-type-inference-functional-interface/

2. www.baeldung.com/java-10-local-variable-type-inference