DataType과 변수

  • Java
  • 2021년 1월 22일

백기선님의 유튜브 로 진행하시는 스터디를 진행하며 올리는 정리 블로그입니다.


자바에서 데이터 타입은 크게 원시(Primitive) 타입참조(Reference) 타입 이 있다.


1. Primitive Type

정수, 실수, 문자, 논리 리터럴과 같은 실제 데이터 값을 저장하는 타입

종류데이터 타입크기(byte)기본 값범위
논리형boolean1bytefalsetrue, false
문자형char2byte\u00000 ~ 65,535
정수형byte1byte0-128~ 127
정수형short2byte0-2^15 ~ 2^15 - 1
정수형int4byte0-2^31 ~ 2^31 - 1
정수형long8byte0L-2^63 ~ 2^63 - 1
실수형float4byte0.0F1.4E-45 ~ 3.4028235E38
실수형double8byte0.04.9E-324 ~ 1.7976931348623157E308

1) boolean

c와 같이 true와 false를 표현하는데 1bit만 있으면 될 것 같지만 Java는 데이터 최소범위가 1Byte이기 때문에 boolean도 1byte의 크기를 갖는다.

2) char

c의 경우 1byte의 크기를 같지만 Java는 유니코드를 표현하기 위해 기본 2byte를 갖으며, Java의 원시 데이터타입중 유일하게 unsigned형태이다.

3) 정수형

JVM의 스택이 기본적으로 피연산자를 4byte 단위로 저장하기 때문에 int보다 작은 자료형의 값을 계산할때 int형으로 형변환되어서 연산이 수행되기 때문에 굳이 byte와 short형을 사용할 필요는 없어 보인다.

JVM은 int형을 정수형의 기본 데이터 타입으로 사용하기 때문에 long을 사용하고자 한다면 뒤에 l or L을 붙여야 한다.

Note

Java8 이후부터는 Integer와 Long의 Wrapper클래스에 unsigned 관련 메소드가 추가되어 unsigned 형태도 이용이 가능하다.


4) 실수형

double형이 기본 데이터 타입으로 float형을 사용하고자 한다면 뒤에 f or F를 붙여 주어야 한다.

메모리 크기는 int,long과 같지만 실수형은 부동소수점 방식으로 저장하여 더 많은 범위를 저장 할 수 있다.

float의 경우 부호(1bit)+지수(8bit)+가수(23bit), double의 경우 부호(1bit)+지수(11bit)+가수(52bit)로 나누어 저장하게 되어 표현범위가 고정 소수점방식보다 넓지만 실수 표현에 있어 근사치를 표현하기 때문에 오차가 존재하는 단점을 갖고있다.

(0.1을 1000번 더하게 되면 100이 되어야 하지만 100.09999… 와 같은 근사값이 출력된다.)

float의 경우 소수점 아래 9자리, double의 경우 18자리까지 표현이 가능하다.

같은 데이터 타입에서도 int,long / float,double형으로 나눈 이유는 메모리를 효율적으로 사용하기 위해서 이다.

닭 잡는데 소 잡는 칼을 사용하는 것은 낭비이기 때문이다.



2. Refrerence Type

영어 의미 그대로 참조 타입으로 저장되는 값이 원시데이터와 다르게 실제 값이 아닌 메모리 주소값이 저장되는 타입으로 문자열,배열,enum,class,interface등이 있다.

JVM의 Runtime Data Area중 참조 타입 변수는 런타임 스택 영역에 실제 객체는 힙 영역에 저장되어 객체를 사용할때 마다 참조 변수에 저장된 객체의 주소를 불러와 사용한다.

위에서 말한것과 같이 실제 데이터는 힙 영역에 저장되며 데이터 크기는 정해져있지 않고 동적으로 할당되며 참조하는 변수가 없다면 Garbage Collector가 제거하여 메모리를 관리한다.

1) Boxing : 원시 타입을 참조 타입으로 변환시키는 것

2) Unboxing : 참조 타입을 원시 타입으로 변환 시키는 것

Auto Boxing기능으로 명시적으로 작성하지 않아도 자동으로 Boxing 을 해준다.

int i= 1;
Integer integer = i; //Auto Boxing

3) 특징

  • null을 포함할 수 있다.

    int example = null; //error
    Integer integer = null;
    
  • 제네릭 타입에서 사용할 수 있다

    List<int> list; //error
    List<Integer> list;
    
  • 데이터 접근 속도가 원시타입에 비해 느리다

    원시타입은 스택에서 바로 사용이가능하나 참조타입은 스택에서 메모리주소를 갖고 힙에 접근하는 방법으로 값을 필요할때마다 Unboxing을 거쳐야하기 때문에 접근속도가 느려지게 된다.

    하지만, 큰 크기의 데이터 접근이 아닌 전달,복사의 경우에는 원시타입보다는 참조타입이 좋을 수도 있다.



3. 리터럴

메모리에 저장되어 변하지 않는 값을 뜻하며 컴파일 타임에 정의되어 그대로 사용하는 값

대입 연산에서 모든 우항의 값들을 보통 리터럴이라고 부른다.

boolean isTrue = true;
char c = 'C';
int i = 1001;
long il = 1001L;
float f = 1.1234F;
double d = 1.1234;
String str = "hello";

와 같이 우항에 있는 내가 정의한 값들로 변하지 않는 값들을 의미한다.

int i = 100_000_000;

Java 8 이후에은 리터럴에 _ 를 구분자로 사용하여 큰 숫자사이에 , 을 찍어 보기편하게 하는 것처럼 이용을 할 수 있다.



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

1) 변수 선언

(데이터 타입) (변수명1),(변수명 2)... ;

--Example --
int i;
int j,k,l;

위와 같이 하나의 변수를 선언이 가능하고 동시에 여러개도 가능하다.


2) 변수 초기화

  • 선언 후 초기화

    int i;
    i =10;
    
  • 선언과 동시에 초기화

    int i=10;
    



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

변수의 스코프란 해당 변수에 접근할 수 있는 범위를 나타내는 것으로 중괄호 {} 를 통해 스코프를 나누는 블록 스코프이고 해당 변수가 언제까지 존재하는지가 라이프 타임이다.

지역변수의 라이프타임과 스코프는 코드 블럭에 국한된다.

public class example {
    public static void main(String[] args){
        int i =1;
        if(true){
            int j=2;
            System.out.println(i);
        }
        System.out.println(j); //error
    }
}

위의 코드에서 if내에서 i를 접근할때 if의 코드 블럭에서 i를 찾고 없으면 그보다 상위 블럭인 class 블럭에서 i를 찾아 접근이 가능하지만 j는 if내에 선언되어 if의 블럭({}) 에 국한되기 때문에 if밖에 나와서는 접근이 불가능하고 if의 블럭이 끝나면서 if에 국한되어있던 지역 변수들은 스택영역에서 소멸된다.

레퍼런스 타입저장시에 저장되는 힙 영역데이터의 라이프 타임은 가비지 컬렉터가 관리한다.

public class example {
    public static void main(String[] args){
        String str = "Test";
        System.out.println(str);
        str = null;
        System.out.println(str);
    }
}

str은 Test라는 힙영역에 저장된 데이터를 참조하는 변수인데, str=null; 부분을 통해 Test를 가리키는 변수는 더이상 존재하지 않게 되어 가비지 컬렉터가 힙영역에서 Test라는 데이터를 제거하게 된다.

이처럼 참조 타입의 힙 영역에 저장되는 데이터는 아무도 참조하지 않게 되었을때 소멸된다.



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

특정 데이터 타입의 값을 다른 데이터 타입의 값을 변환 하는 것

1) 타입 프로모션

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

byte -> int, int-> long 와 같이 더 큰 범위를 갖는 데이터 타입으로 변환의 경우가 속하거나 int -> float 와 같이 같은 크기여도 표현범위를 모두 포함할 수 있다면 프로모션이다.

float -> long 의 경우 데이터 크기로만 보면 프로모션이라고 생각할 수 있지만, long은 실수를 저장할 수 없기 때문에 데이터 손실이 일어나 프로모션이라고 할 수 없고 캐스팅이라고 볼 수 있다.

long l = 1234L;
float f = l;

위 코드와 같이 프로모션의 경우 데이터 손실이 발생하지 않고 자동으로 형변환을 시켜준다.


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

int->byte, long -> int 와 같이 큰 데이터크기에서 작은 크기의 데이터 타입으로 변환할때나 float -> long 과 같이 데이터 표현범위가 달라지는 경우에 속하며 데이터 손실이 일어 난다.

float f = 1.234f;
long l = f;

위의 코드와 같이 자동으로 캐스팅을 하려고한다면 데이터 손실이 발생할 수 있기 때문에 컴파일타임에 오류를 발생 시킨다.

그래도 형변환을 하고 싶다면 강제형변환을 사용할 수 있지만 데이터 손실이 발생하게 된다.

float f = 1.234f;
long l = (long)f;
System.out.println(l); // 1



7. 1차, 2차 배열 선언

배열 변수 선언과 동시에 초기화를 통해 선언 하는 방식과 new를 이용하는 방식이 있다.

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

        //2차원 배열
        int[][] array3 = {{1, 2}, {3, 4}};
        int[][] array4;
        array4 = new int[2][2];
        array4[0][0] = 1;
        array4[0][1] = 2;
        array4[1][0] = 3;
        array4[1][1] = 4;

    }
}

1) 1차원 배열

alter-text
사진 출처: https://www.notion.so/2-38b5d67c7f5a48238529bb8f1617ea0d

1차원 배열의 변수(array1,array2)는 스택영역에 존재하며 힙 영역의 주소값을 갖는다.

힙 영역에는 데이터 타입 크기와 요소 개수에 맞게 할당되어 사용이된다.

2) 2차원 배열

alter-text
사진 출처 : https://www.notion.so/2-38b5d67c7f5a48238529bb8f1617ea0d

2차원 배열의 변수(array3,array4)는 스택영역에 존재하며 힙 영역의 주소값을 갖는다.

힙 영역에는 실제 데이터값들과 2차원배열의 각 행의 시작주소를 갖는 주소값들이 존재한다.



8. 타입 추론

Java 10 이후부터 생겨난 기능으로 컴파일러가 값을 보고 데이터 타입이 무엇인지 추론하는 것으로 Js의 var,let와 비슷하다.

1) 제네릭

public class example{
    public static void main(String[] args){
        HashMap<String,Integer> hashMap = new HashMap<>();
    }
}

위와 같이 우항의 <> 안에 값을 입력하지 않아도 좌항의 값을 보고 타입을 추론하여 생성하는 경우

2) var

JS의 var,let과 같이 추론형 데이터 타입으로 생각할 수 있는데, 다른점으로 지역 변수와 선언과 동시에 값이 할당 되어야 한다는 점에서 let과 const를 합친 느낌이다.

public class example{
    var i = 10; //error
    public static void main(String[] args){
        var j; //error
    }
}





Reference

https://velog.io/@gillog/%EC%9B%90%EC%8B%9C%ED%83%80%EC%9E%85-%EC%B0%B8%EC%A1%B0%ED%83%80%EC%9E%85Primitive-Type-Reference-Type

https://wikidocs.net/81917

https://www.notion.so/2-38b5d67c7f5a48238529bb8f1617ea0d

https://blog.naver.com/hsm622/222144931396

Tags :

Related Posts

Topological Sort (위상 정렬)

Topological Sort (위상 정렬)

조건 : 방향이 있고 사이클이 없는 그래프 (Directed Acyclic Graph) DAG일때, 방향성을 거스르지 않고 나열하는 것으로 순서가 있는 작업을 차례로 수행해야할때 순서를 결정해주기 위해 사용하는 알고리즘이다. 대학 커리큘럼의 선수과목이나 엄무의 일정을 시간 순서대로 배치한것이 그 예 이다. 1. 특징 방향이 있는 그래프이어야 한다. (directed) 사이클이 없어야 한다. (Acyclic) 2. Pesudo Code 1) InDegree 이용방법 2) dfs 이용방법 3. 구현 방법 1) InDegree 이용 모든 vertex에 대해 InDegree값을 초기화 진입 차수 (indegree)가 0인 값을 큐에 삽입 큐에서 1개 vertex, v를 pop v를 stack에 쌓기 (정렬한 값을 담는 것이 stack) v에 연결된 vertex들의 indegree값을 1감소 진입 차수가 0인 정점들을 큐에 삽입 3-6번을 Vertex수만큼 반복 만약에 큐가 비어있다면, 사이클이 존재하는 그래프 (큐가 비어있다면 indegree가 0인 값이 없었다는 소리. 즉, 사이클 발생) 2) dfs 이용 방문하지 않은 vertex들을 dfs함수 진행. dfs 해당 vertex 방문표시 인접 vertex에 대해 방문하지 않았다면 dfs함수 진행 dfs함수 종료시 stack에 push 4. 시간 복잡도 indegree방법은 초기화하는데 O(V), 큐에 삽입, 제거 하는게 O(V)번씩 소요되며, indegree를 1감소 시켜주는게 O(E)번 일어난다. (indegree를 1감소해주는건 edge를 삭제해주는거와 같기 때문) 따라서, O(V+E)의 시간복잡도를 갖는다....

Read More
표준 입출력

표준 입출력

GoLang의 표준 입출력은 다른 언어와 같이 터미널이 기본이며, 파일등으로 수정이 가능하고 fmt패키지에서 제공을 한다. 입출력은 BitStream형태로 되어있다. 1. 표준 출력 1) 함수 함수 기능 Print() 입력값들을 출력 Println() 마지막에 개행문자를 포함한 입력값들을 출력 Printf() c의 printf와 같이 특정 포맷에 맞게 출력 2) 포맷 서식 포맷형태 설명 %d 정수 %f 실수(소수점 6자리까지 표현) %v 기본형태(자동으로 맞는 값으로 변경) %g 길이에 맞는 실수형태로 변경해서 출력(%v로 사용시 실수의 경우 %g로 바뀜) %3d 3자리 칸에 맞춰 오른쪽 정렬해 출력 %03d 3자리 칸에 맞춰 출력하는데 빈칸을 0으로 채움 %-3d 3자리 칸에 맞춰 왼쪽정렬해 출력...

Read More
함수형 인터페이스와 람다식

함수형 인터페이스와 람다식

  • Java
  • 2021년 3월 1일

1. 소개 함수형 인터페이스란 추상 메소드가 하나만 선언된 인터페이스이다. 1) 함수형 VS. 객체지향 Java 개발자에게 익숙한 객체지향 프로그래밍과의 차이를 비교하자면, 값을 취급하는 단위가 어디까지 인지 나눌 수 있다. Java 는 값(상태)과 행위를 다루기 위한 기본 단위를 객체로 정의하고, 이 객체를 클래스라는 형태로 구현한다. 함수형 프로그래밍은 행위(로직)를 값으로 취급한다. 입력에 의해서만 출력이 결정되는 순수 함수를 기본 단위로 정의한다....

Read More