[JAVA]자바 데이터 타입, 변수 그리고 배열

홍준표·2022년 6월 2일
0

java 스터디

목록 보기
2/8

목표

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


학습할 것

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

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

Primitive Type 이란 ?

기본자료형 혹은 원시자료형 이라고 불리는 프리미티브 타입은 값이 할당되면 JVM Runtime Data Area 영역 중 Stack 영역에 값이 저장된다.

우리가 주로 사용하는 값의 종류는 크게 문자와 숫자로 나눌 수 있으며 여기서 숫자는 다시 정수와 실수로 나뉜다. 기본형은 모두 8가지의 타입(자료형)이 있으며, 크게 논리형, 문자형, 정수형, 실수형으로 구분된다.

타입 종류

정수형은 가장 많이 사용되기에 타입이 4가지나 제공된다. 각 타입별로 범위가 다르기에 범위에 맞는 값을 사용하면 된다.

타입 범위

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

자료형은 크게 '기본형(Primitive Type)' 과 참조형(Reference Type)으로 나눌 수 있습니다.

  • 기본형(Primitive Type)
    : 논리형(boolean), 문자형(char), 정수형(byte, int, short, long), 실수형(float, double) 계산을 위한 실제 값을 저장한다.
  • 참조형(Reference Type)
    : 객체의 주소를 저장한다. 기본적으로 Java.lang.Object를 상속받을 경우 참조형이 된다.
    즉, 기본형을 제외하고는 참조형이라고 생각해도 된다.

추가적으로 기본형은 메모리영역의 스택영역에 실제 값들이 저장된다면, 참조형은 실제 인스턴스는 힙영역에 생성되있고, 그 영역의 주소를 스택영역에서 저장하고 있다고 보면 된다.

리터럴

리터럴은 변수나 상수에 저장되는 값 자체를 의미한다. 그 종류로는 정수, 실수, 문자, boolean, 문자열 등이 있다.

boolean result = true;
int i = 2020;

위 예시에서 true와 2020이 리터럴이다.

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

변수 선언

변수를 사용하기위해서는 우선 변수를 선언해야 하며 아래와 같이 선언합니다.

int i; // 변수타입 변수이름;
  • 변수 타입: 변수에 저장될 값이 어떤 타입(type)인지 지정하는 것.

  • 변수 이름: 변수에 붙힌 이름. 변수가 값을 저장할 수 있는 메모리 공간을 의미하므로 변수 이름은 이 메모리 공간에 이름을 붙혀주는 것.

이렇게 변수를 선언하면, 메모리의 빈 공간에 '변수타입'에 알맞은 크기의 저장공간이 확보되고, 변수 이름을 붙혀서 이 이름을 통해 해당 저장공간을 사용할 수 있게 된다.

변수 초기화

변수를 사용하기 전 처음으로 값을 저장하는 것

변수를 선언하면 메모리에 변수의 저장공간이 확보되어있지만, 이 공간안에 어떠한 값이 저장되어있을지는 알 수 없다. 여러 프로그램에 의해 공유되기 때문이다. 그렇기에 초기화를 해줘야한다.

변수에 값을 저장할 때는 대입 연산자 = 을 사용한다. 아래 예시를 보면 int 변수 타입과 i 라는 변수 이름을 가진 변수에게 200 이라는 값을 대입한다.

int i = 200

대입연산자의 우측의 있는 값을 좌측에 있는 변수에 저장합니다.

변수의 종류에 따라 변수의 초기화를 생략할 수 있는 경우도 있지만, 변수는 사용되기 전에 적절한 값으로 초기화 하는 것이 좋다.

지역변수는 사용하기 전 반드시 초기화 해야 한다.

그밖의 초기화의 종류

지역변수는 변수의 초기화로 충분하지만, 멤버변수의 초기화는 몇가지 방법이 더 있다.

1. 명시적 초기화(explicit initialization) : 변수 선언과 동시에 초기화 하는 것을 명시적 초기화라 하는데, 위에서 소개한 변수의 초기화와 동일하며, 클래스 및 지역변수 어디서든 사용가능하며 여러 초기화 방법중 최우선적으로 고려한다.

2. 초기화 블럭(initialization block) : 초기화 블럭은 클래스 초기화 블럭과 인스턴스 초기화 블럭으로 나뉜다.

public class Test { static{ // 클래스 초기화 영역 } { // 인스턴스 초기화 영역 } }
  • 클래스 초기화 블럭: 클래스변수의 복잡한 초기화에 사용. 블럭내에서는 로직도 추가할 수 있기 때문에 명시적 초기화만으로 부족할 때 사용한다.

  • 인스턴스 초기화 블럭: 인스턴스 변수의 복잡한 초기화에 사용. 모든 생성자가 공통으로 수행해야 하는 로직이 있을 때 사용한다.

3. 생성자(constructor) : 생성자는 말 그대로 인스턴스 생성시에 생성자 함수 안에서 명시적 초기화가 이뤄진다.

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

변수는 클래스변수, 인스턴스변수, 지역변수 모두 세 종류가 있다. 변수의 종류를 결정짓는 중요한 요소는 변수의 선언 위치 이므로 변수의 종류를 파악하기 위해서는 변수가 어느 영역에 선언되었는지를 확인하는 것이 중요하다.

선언 위치에 따른 변수의 종류

public class Test {
    int instanceValue; // 인스턴스 변수
    static int classValue; // 클래스변수( static 변수, 공유변수 )

    void method(){
        int localValue; // 지역변수
    }
}

클래스 내부에 선언되는 변수를 멤버변수라고 한다. 여기서 키워드 static과 함께 선언되는 변수를 클래스 변수, 붙지 않은 것을 인스턴스 변수라고 한다. 그리고 멤버변수를 제외한 나머지 변수들은 모두 지역변수이다.

  • 변수의 종류와 특징

  1. 인스턴스 변수(instance variable)

: 클래스 영역에 선언되며, 클래스의 인스턴스를 생성할 때 만들어진다. 그렇기에 인스턴스 변수 값을 읽어오거나 저장하기 위해서는 먼저 인스턴스를 생성해야한다.

인스턴스 별로 별도의 저장 공간을 확보하기에 인스턴스별 다른 값을 가질 수 있다.

  1. 클래스 변수(class variable)

: 멤버변수에 static 키워드를 붙힐경우 클래스 변수가 되며 한 클래스의 모든 인스턴스가 값을 공유한다. 클래스 변수는 인스턴스를 생성 하지 않고 클래스가 메모리에 올라갔을때 선언되기 때문에 인스턴스에서는 언제든 바로 접근해서 사용할 수 있습니다. 그렇기에 어디서나 접근 할 수 있는 전역변수(global variable)의 성격을 가진다.

  1. 지역 변수(local variable)

: 메소드 내에 선언되어 메소드 내에서만 사용 가능하며 메소드 종료와 함께 소멸된다. for 문이나 while문같은 반복문도 동일하게 블럭내에서 선언된 지역변수는 블럭을 벗어나면 소멸된다.

public static void main(String[] args) {
		for (int i = 0; i < 10; i++) {
        System.out.println("i = " + i);
    }
    System.out.println("i = " + i);//Checked Exception 발생
}

초기화 시기와 순서(라이프 타임)

  • 초기화 시점

    프로그램 실행도중 클래스에 대한 정보가 요구될 때 클래스는 메모리에 로딩된다. (만약 이미 메모리에 로딩되어 있다면 또다시 로딩하지 않는다.)

  • 초기화 순서

class InitTest {
	static int classValue = 1;
	int instanceValue = 1;

	static {
		classValue = 2;
	}
	InitTest() {
		instanceValue = 3;
	}
}

  • 클래스변수 초기화(1~3) : 클래스가 처음 메모리에 로딩될 때 차례대로 수행된다.
  • 인스턴스변수 초기화(4~7) : 인스턴스를 생성할 때 차례대로 수행한다.
  • 클래스 변수는 항상 인스턴스 변수보다 먼저 생성 및 초기화된다.

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

타입 변환

변수 또는 상수의 타입을 다른 타입으로 변환하는 것

프로그램을 작성하다보면 서로 다른 타입간의 연산을 수행하야 하는 경우가 있다. 이럴 때 연산을 수행하기 전 서로의 타입을 일치시켜야하는데, 이렇게 변수나 리터럴의 타입을 다른 타입으로 변환하는 것을 형변환이라고 한다.

캐스팅(명시적 형변환)

(타입)피연산자

변환할 변수나 리터럴 앞에 타입을 괄호와 함께 붙여주기만 하면 된다. 이 때 형 변환 연산자는 그저 피연산자의 값을 읽어서 지정된 타입으로 형변환하고 그 결과를 반환할 뿐이기에 기존의 변수나 리터럴이 변화되지는 않는다.

double d = 810.4;
int i = (int)d; // 810

기본형 변수 중 boolean을 제외한 나머지 타입들은 서로 형변환이 가능하다. 하지만 타입간에 각 가지고 있는 크기가 다르기 때문에 형변환을 통해 크기의 차이만큼 값이 잘려나감으로써 값 손실(lost of data)이 발생할 수 있다.

타입 프로모션(묵시적 형변환)

경우에 따라 형변환을 생략할 수 있다. 컴파일러가 생략된 형변환을 자동적으로 추가하여 생략할 수 있게 되었다.

하지만 변수가 저장할 수 있는 크기보다 더 큰 값을 저장하려는 경우에 형변환을 생략하면 에러가 발생한다. 이는 더 작은 값으로 할당되며 값 손실이 발생할 수 있기 때문에 이를 명시적 형변환으로 바꾸어 주면 에러가 발생하지 않는다.

byte b = 10000; // 에러 발생, byte의 범위를 초과한다.
byte c = (byte)10000; //명시적 형 변환으로 에러가 발생하지 않는다.

타입 프로모션 규칙

기존의 값을 최대한 보존할 수 있는 타입으로 자동 형변환한다.

표현범위가 좁은 타입에서 넓은 타입으로 형변환 할 때 값 손실이 없기에 두 타입 중 표현범위가 더 넓은 쪽으로 형변환 됩니다.

1차 및 2차 배열 선언하기

class ArrayExample {
	public static void main(String[] args) {
        //1차원 배열
        int[] oneDimensionArrayEx1 = {1, 2, 3, 4, 5};
        int[] oneDimensionArrayEx2;
        oneDimensionArrayEx2 = new int[10];

        //2차원 배열
        int[][] twoDimensionArrayEx1 = {{1, 2}, {3, 4}};
        int[][] twoDimensionArrayEx2;
        twoDimensionArrayEx2 = new int[10][10];
    }
}
  • 1차원 배열
    • oneDimensionArrayEx1 은 Runtime Stack 영역의 힙 영역 주소값을 가짐
    • Heap 영역에 int 타입 크기의 요소 5개를 할당하여 사용됨
  • 2차원 배열
    • Runtime Stack 영역의 twoDimensionArrayEx1은 2개의 요소 크기(2개의 요소에 주소값을 가지고 있음)를 가진 힙 영역 주소값을 가짐
    • 힙 영역에는 실제 값이 들어있는 요소들과 주소값이 들어있는 요소들로 존재하게됨

타입 추론, var

Type Inference 이란 정적인 언어에서 컴파일러가 컴파일 시점에서 변수를 초기화하는 리터럴을 판단하여 해당 타입으로 변환하는 것을 말한다.
자바는 JDK 10부터 Local Scope 내에서 var이라는 새로운 Type을 지원하게 되었다.

사용 시 주의점

  • 초깃값 (리터럴)이 없다면 컴파일 에러가 발생한다. var num;
  • null로 초기화하면 작동하지 않는다. var num = null;
  • local 변수가 아니라면 작동하지 않는다. public num = "String";
  • 람다 표현식에는 var 타입의 변수를 사용할 수 없다. var foo = (String s) → s.length() > 10;
  • 타입 없이 배열 초깃값을 넘겨도 작동하지 않는다. var arr = { 1, 2, 3 };
public void someMethod() {
    var str = "Hello world";
    assertTrue(str instanceof String);

        var num = 10;
    var numB = 10.10D;
    System.out.println(numB+num); // 20.1
}
profile
프로그래밍 시작

0개의 댓글