[STUDY HALLE] 2주차 - 자바 데이터 타입, 변수 그리고 배열

ByWindow·2021년 1월 2일
0

Java_Live_Study

목록 보기
2/4
post-thumbnail

목표

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

학습할 것

  • 프리미티브 타입 종류와 값의 범위 그리고 기본 값
  • 프리미티브 타입과 레퍼런스 타입
  • 리터럴
  • 변수 선언 및 초기화하는 방법
  • 변수의 스코프와 라이프타임
  • 타입 변환, 캐스팅 그리고 타입 프로모션
  • 1차 및 2차 배열 선언하기
  • 타입 추론, var

프리미티브 타입

자료형

우리가 사용하는 값, 즉 변수에는 여러 종류가 있는데 그 종류에 따라 값이 저장될 공간의 크기와 저장형식을 정의한 것이 자료형(data type)이다.
자료형은 크게 '기본형(primitive type)''참조형(reference type)'으로 나눌 수 있다.

primitive type

  • '기본형' 이라고도 한다
  • 실제 값(data)를 저장한다
  • Java는 C언어와 달리 참조형 변수 간의 연산을 할 수 없으므로 실제 연산에 사용되는 것은 모두 기본형 변수이다
  • 기본형에는 모두 8개의 data type이 있다
분류타입메모리 크기(byte)저장 가능한 값의 범위기본값
논리형boolean1false, truefalse
문자형char2(유니코드)'\u0000'~'\uffff'(0~65535, 0~216-1)'\u0000'
정수형byte1-128~127(-27~27-1)0
short2-32,768~32,767 (-215~215-1)0
int4-231~231-10
long8-263~263-10L
실수형float(부동소수점)41.4E-45 ~ 3.4E380.0f
double84.9E-324 ~ 1.8E3080.0

논리형

  • boolean 한가지 밖에 없다
  • false와 true 중 하나를 값으로 갖으며, 조건식과 논리적 계산에 사용된다
  • 두 가지의 값만을 표현하면 1 bit만으로도 충분하지만, Java에서는 데이터를 다루는 최소단위가 byte이기 때문에 boolean의 메모리 크기가 1 byte이다.

문자형

  • char 한가지 자료형 밖에 없다
  • 변수 당 단 하나의 문자만을 저장할 수 있다
  • 실제로는 초기화하는 문자가 아니라 문자의 유니코드(정수)가 저장된다
  • char ch = 'A'; 라는 코드에서 char형의 변수 ch에는 문자 'A'의 유니코드인 65가 저장된다.
    따라서 이 코드는 char ch = 65; 와 동일한 결과를 보인다.
  • 위의 특징을 이용하여 어떤 문자의 유니코드를 알고 싶을 때 (int)로 형변환을 하면 된다
  • 문자를 유니코드로 변환하는 과정을 인코딩, 그 역을 디코딩이라고 한다.

정수형

  • 정수값을 저장하는 데 사용된다
  • 크기별로 4개의 자료형이 있으며, byte부터 long까지 1 byte부터 시작해서 2배씩 크기가 증가한다
  • 기본 자료형은 int이고, 주로 int와 long이 사용된다
  • byte : 이진데이터를 다루는데 주로 사용됨
  • short : C언어와의 호환을 위해서 추가됨
  • 기본적으로 int타입을 사용하고 int의 범위를 넘긴다면 long을 사용하자
  • byte나 short는 성능보다 저장공간을 절약하는 것이 중요할 때 사용한다
  • byte를 예로 들어서 표현형식을 살펴보자
    byte의 표형형식(8 bit)종류값의 개수
    00000000~011111110, 양수27개
    10000000~11111111음수27개

실수형

  • 실수를 저장하는데 사용된다(주로 double이 사용됨)
  • 값을 부동소수점 형태로 저장한다(부호 + 지수 + 가수)
  • float : 부호(1 bit) + 지수(8 bit) + 가수(23 bit) = 32bit
  • double : 부호(1 bit) + 지수(11 bit) + 가수(52 bit) = 64bit
  • float은 연산속도 향상이나 메모리 절약에 이점이 있고, double은 float보다 더 큰 값의 범위라던가 더 높은 정밀도가 필요할 때 사용한다

reference type

  • '참조형'이라고도 한다
  • 참조 변수는 null 또는 어떤 값이 저장되어 있는 주소(memory address)를 값으로 갖는다
  • 객체의 주소는 4 byte로서 (0x0~0xffffffff)를 값으로 갖는다
  • C언어와 달리 참조형 변수 간의 연산을 할 수 없다
  • 참조형 변수를 선언할 때, 변수의 타입으로 클래스의 이름을 사용한다
  • 참조 타입의 종류로는 배열, 열거, 클래스, 인터페이스가 있다

리터럴

리터럴을 살펴보기 위해 상수(constant)와의 비교가 필요하다고 생각한다

상수(constant)

  • '값을 저장하는 공간'이라는 면에서 변수와 비슷하지만, 한번 값을 저장하면 다른 값으로 변경할 수 없다
  • 선언 방법 : 변수의 타입 앞에 'final'울 붙여준다
  • 반드시 선언과 동시에 초기화해야 한다(그 후로는 절대 변경 불가)
  • 상수의 이름은 모두 대문자로 하는 것이 관례이다
  • 그렇다면 왜 상수를 써야할까???
    • 위에서 리터럴을 살펴볼 것이지만, 상수를 사용했을 때 코드의 이해와 수정을 더 쉽게 할 수 있다

리터럴(literal)

  • 원래 프로그래밍에서 어떤 값(data)을 상수라고 불렀었다. 하지만 상수(constant)의 개념이 새롭게 정의되고 이와 구분하기 위해 기존의 상수를 다른 이름으로 불러야했는데, 그것이 리터럴이다
/* 예시를 위한 Java 코드 */
int answer = 10;
final int MAX_VALUE = 100;
  • 위의 코드에서 answer는 변수, 10과 100은 리터럴, MAX_VALUE는 상수이다

리터럴의 타입

  • 앞서 공부한 변수의 타입은 저장될 리터럴의 타입에 의해 결정되므로, 리터럴에 타입은 필수적이다

    종류리터럴(예시)접미사
    논리형false, true없음
    정수형123, 0b0101(2진수), 077(8진수), 0xFF(16진수), 100LL(long), 없음(int, byte, short)
    실수형3.14, 3.0e8, 1.4f, 0x1.0p-1f(float), d(double)
    * d는 생략가능
    문자형'A', '1', '\n'없음
    문자열"ABC", "123"없음

변수 선언 및 초기화 방법

선언

Java에서 변수의 선언 방법은 변수타입 + 변수이름 형식으로 하고, 예를 들면 아래와 같다

int sum = 0;

변수를 선언하면, 메모리의 빈 공간에 변수타입에 알맞은 크기의 저장공간이 확보되고, 앞으로 이 저장공간은 변수이름을 통해서 사용된다

  • 변수타입 : 변수에 저장될 값이 어떤 타입인지를 지정하는 것이고
    논리형, 정수형, 실수형, 문자형이 이에 속한다
  • 변수이름 : 값을 저장하는 메모리 공간(변수)에 붙여주는 이름이다

변수의 초기화

변수의 초기화란, 변수를 사용하기 전에 처음으로 값을 저장하는 것이다

메모리는 여러 프로그램이 공유하는 자원이므로 전에 다른 프로그램에 의해 저장된 쓰레기값이 남아있을 수 있기 때문에 변수를 사용하기 전에 반드시 변수를 초기화해야 된다

변수에 값을 저장할 때는 간단하게 '='를 사용한다. 오른쪽의 값을 왼쪽(변수)에 저장하라는 의미이다

한 줄에 여러 개의 변수를 초기화할 수도 있다(by comma)
int a;
int b;
int x = 10;
int y = 10;
int a, b;
int x = 10, y = 10;

위의 두 소스코드는 서로 같은 의미이다.

식별자(identifier)

'변수이름'처럼 프로그래밍에서 사용하는 모든 이름을 식별자라고 한다
식별자는 같은 영역 내에서 서로 구분되어야 하며 다음과 같은 규칙이 존재한다

  • 대소문자가 구분되며 길이에 제한이 없다
  • 예약어를 사용하면 안된다
  • 숫자로 시작해서는 안된다
  • 특수문자는 '_'와 '$'만을 허용한다
  • 클래스 이름의 첫 글자는 항상 대문자로 한다
  • 변수와 메서드 이름의 첫 글자는 항상 소문자로 한다
  • 여러 단어로 이루어진 이름은 단어의 첫 글자를 대문자로 한다
  • 상수의 이름은 모두 대문자로 하고, 여러 단어로 이루어진 경우 '_'로 구분한다

개인적으로 생소한 것들도 있다(3번과 4번의 경우) 코딩을 하면서 아직 숫자로 시작하는 변수이름을 만든 적이 없었던 거 같다. 이번 기회에 알아두면 좋을 듯!

다음은 Java에서 사용되는 예약어이다. 코딩을 하다보면 차차 알게 될 거 같아 굳이 힘들게 외울 필요는 없을 것 같다

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

변수의 스코프란?

어떤 변수에 접근할 수 있는 범위
Java에서는 블록{ } 스코프를 사용한다

public class Main{

  static int a = 10;

  public static void main(String[] args){
      System.out.println(a); // 10이 출력됨
        int a = 30;
        System.out.println(a); // 30이 출력됨
  }
}

어떤 변수가 사용되는 위치를 기준으로 그 전에 선언된 변수를 찾는다라고 생각하면 된다.

라이프타임

레퍼런스 타입의 변수의 라이프 타임은 쓰레기 수집기 (GC : Garbage Collector)와 관련이 있다

이 GC는 가비지 컬렉션 힙 영역에 존재하는 참조 타입 변수의 객체에 대해 동작한다

힙 영역에 메모리가 부족할 경우 GC가 이 영역을 스캔하고, 아무곳에서도 사용하지 않는 즉, 참조 되고 있지 않은 객체를 제거해 버린다

런타임 스택 영역에 생성된 변수의 라이프 타임은 블록 스코프에 의존적이다

즉, 블록 내에서 선언된 변수는 블록이 종료될 때 런타인 스택 영역에서 함께 소멸한다

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

타입 변환

때때로 리터럴의 타입과 저장될 변수의 타입이 일치하지 않는 경우가 있다

  • 서로의 타입이 달라도 저장범위가 넓은 영역에 좁은 타입의 값을 저장하는 것은 허용된다
    • int a = 'A'; // 허용. 문자 'A'의 유니코드인 65가 변수 a에 저장됨
    • long a = 123; // 허용. int보다 long 타입의 범위가 더 넓다
    • double a = 3.13f; // 허용. float보다 double 타입의 범위가 더 넓다
  • 리터럴의 값이 변수의 타입의 범위를 넘어서거나, 리터럴의 타입이 변수의 타입보다 저장범위가 넓으면 컴파일 에러!
    • int a = 0x123456789; // 에러. int 타입의 범위를 넘는 값을 저장했다
    • float a = 3.14; // 에러. float 타입보다 double 타입의 범위가 더 넓다

프로그래밍을 하다보면 서로 다른 타입간의 연산을 수행해야하는 경우가 있는데 그럴 때는 어떻게 하냐?

그때에 필요한 것이 바로 형변환이다

즉, 형변환이란 변수 또는 상수의 타입을 다른 타입으로 변환하는 것이다

형변환 방법

(타입)피연산자
위와 같이 형변환하고자 하는 변수나 리터럴의 앞에 변환하고자하는 타입을 괄호와 함께 붙여주면 된다
이때 사용되는 괄호( )를 '캐스트 연산자' 또는 '형변환 연산자'라고 부르며, 형변환을 캐스팅(casting)이라고도 한다

double d = 20.2;
int a = (int)d; // double 타입의 변수 d의 값을 읽어와서 int 타입으로 형변환한다
System.out.println(a); // 20이 출력된다
System.out.println(d); // 피연산자는 형변환 후에 아무런 변화가 없으므로 20.2가 출력된다

타입 캐스팅과 타입 프로모션

타입 캐스팅 : 자신의 표현 범위를 모두 포함하지 못한 데이터 타입으로의 변환

타입 프로모션 : 자신의 표현 범위를 모두 포함한 데이터 타입으로의 변환

1차 및 2차 배열 선언하기

배열이란?

같은 타입의 여러 변수를 하나의 묶음으로 다루는 것

배열 선언

선언방법선언 예
타입[] 변수이름;int[] a
타입 변수이름[];int a[]

위와 같이 두가지 방법이 있지만, 나는 대괄호가 타입의 일부라 생각하여 첫번째 방법을 사용한다

배열 생성

배열의 선언은 단지 생성된 배열을 다루기 위한 참조변수를 위한 공간이 만들어지는 것이고,
배열을 생성해야만 비로소 값을 저장할 수 있는 공간이 만들어진다
배열을 생성하기 위해서는 연산자 'new'가 필요하다

타입[] 변수이름;
변수이름 = new 타입[길이];

이것을 한 줄로 줄이면,

타입[] 변수이름 = new 타입[길이];

배열의 길이

  • 배열의 요소(element) : 생성된 배열의 각 저장공간
  • 인덱스(index) : 배열의 요소마다 붙여진 일련번호로, 범위는 0부터 '배열길이-1'까지이다
  • 배열이름[인덱스]의 형식으로 배열의 요소에 접근한다

코드와 그림을 통해 단계별로 알아보자.

  1. int형 배열 참조변수 arr을 선언한다
  2. 연산자 'new'에 의해 메모리의 빈 공간에 5개의 int형 데이터를 저장할 수 있는 공간이 마련된다
  3. 각 배열요소는 int의 기본값인 0으로 초기화된다
  4. 마지막으로 대입연산자 '='에 의해 배열의 주소가 int형 배열 참조변수 arr에 저장된다
int[] arr = new int[5] // 길이가 5인 int배열. 인덱스의 범위는 0~4

배열에 값을 저장하고 읽어오는 방법은 변수에서와 비슷하다

arr[3] = 10; // 배열  arr의 4번째 요소에 10을 저장한다
int answer = arr[3]; // 배열 arr의 4번째 요소에 저장된 값을 읽어서 answer에 저장한다

배열의 장점은 index로 상수 대신 변수나 수식도 사용할 수 있다는 것이다

for(int i = 0; i < arr.length; i++){
	arr[i] = i * 10;
}
  • 배열이름.length
    • Java에서는 JVM이 모든 배열의 길이를 별도로 관리한다
    • 배열이름.length를 통해서 배열의 길이에 대한 정보를 얻을 수 있다
    • 배열은한번 생성하면 길이를 변경할 수 없기 때문에 '배열이름.length'는 상수이다
    • 위의 코드에서 arr.length의 값은 5이다
  • 배열의 길이를 변경하는 방법
    - 길이가 다른 배열을 새로 생성한다
    - 기존 배열의 내용을 새로운 배열에 복사한다
    하지만 이러한 작업들은 비용이 많이 든다. 따라서 처음부터 배열의 길이를 넉넉하게 잡는 것이 좋은데 너무 크게 잡으면 메모리를 낭비하게 되므로 기존의 2배 정도의 길이로 생성한다

배열의 초기화

세가지 방법이 있다
1.각 요소마다 값을 지정해준다

int[] arr = new int[3];
arr[0] = 10;
arr[1] = 20;
arr[2] = 30;

2.for문을 사용한다

int[] arr = new int[3];
for(int i = 0; i < arr.length; i++){
	arr[i] = (i+1) * 10;
}

3.배열의 선언과 생성을 동시에 한다

int[] arr = new int[]{10, 20, 30}; // 'new int[]' 는 생략할 수 있다

2차원 배열의 선언

선언 방법선언 예
타입[ ][ ] 변수이름;int[ ][ ] arr;
타입 변수이름[ ][ ];int arr[ ][ ];
타입[ ] 변수이름[ ];int[ ] arr[ ];
  • 앞의 [ ]는 행을, 두번째의 [ ]는 열을 나타낸다
int[][] arr = new int[4][3]; // 4행 3열의 데이터를 담기위한 2차원 배열이다

2차원 배열의 인덱스

2차원 배열은 행(row)과 열(column)로 구성된다
'행index'의 범위는 0 ~ 행의 길이-1 이다
'열index'의 범위는 0 ~ 열의 길이-1 이다
2차원 배열의 각 요소에 접근하는 방법은 '배열이름[행index][열index]'이다

int[][] arr = new int[4][3];

2차원 배열의 초기화

int[][] arr = new int[][]{ {1,2,3}, {4,5,6} };
int[][] arr = { {1,2,3}, {4,5,6} }; //new int[][] 가 생략됨
int[][] arr = { 
		{1,2,3}, 
            	{4,5,6} 
           }; //가독성을 높여주는 줄바꿈
           

가변 배열

Java에서는 2차원 이상의 배열을 '배열의 배열;의 형태로 처리한다는 사실을 이용하여 가변 배열을 구성할 수 있다

int[][] arr = new int[5][];
arr[0] = new int[4];
arr[1] = new int[3];
arr[2] = new int[2];
arr[3] = new int[1];
arr[4] = new int[0];
/* 
길이가 0인 배열도 생성 가능하다.
참조변수의 기본값은 null이지만, 배열을 가리키는 참조변수는 null대신 길이가 0인 배열로 초기화하기도 한다
*/

타입추론, var

타입추론(Type inference)이란?

  • 값을 보고 컴파일러가 데이터 타입이 무엇인지 추론하는 것
  • Kotlin에서 변수를 선언할 때 모두 var 혹은 val로 선언하는 것과 같다
  • 하나를 예로 들자면, ArrayList를 선언할 때 '='의 우측에는 ArrayList<>()를 하는데 이것도 좌측에 있는 것을 토대로 데이터 타입을 추론하는 것이다
  • var을 사용할 경우 제약 사항이 존재한다
    • 로컬 변수이어야 한다
    • 선언과 동시에 값이 할당되어야 한다
  • 관련 포스팅에 대한 링크이다
profile
step by step...my devlog

2개의 댓글

comment-user-thumbnail
2021년 1월 9일

꾸준히 공부하는 그대가 참 좋아요

1개의 답글