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

연산자

연산자

1. 산술 연산자 구분 연산자 연산 피연산자 타입 사칙 연산과 나머지 + 덧셈 정수, 실수, 복소수, 문자열 - 뺄셈 정수, 실수, 복소수 * 곱셈 정수, 실수, 복소수 / 나눗셈 정수, 실수, 복소수 % 나머지 정수, 실수, 복소수 비트 연산 & AND 비트연산 정수 | OR비트 연산 정수 ^ XOR비트 연산 정수 &^ 비트 클리어 정수 시프트 연산 « 왼쪽 시프트 정수 « 양의 정수...

Read More
@OneToMany 관계시 발생한 에러

@OneToMany 관계시 발생한 에러

  • Error
  • 2021년 4월 11일

JPA의 구현체인 hiberante를 이용해서 엔티티간의 상속관계를 설정하고 처음 사용해보는데 발생한 에러인 A collection with cascade=“all-delete-orphan” was no longer referenced by the owning entity instance 문제 해결한 방법을 기록하려고 한다. User의 엔티티와 Customer엔티티간의 1:N 양방향 연관관계를 맺기 위해 User에는 @OneToMany를 Customer에는 @ManyToOn...

Read More
[MST] Kruskal 알고리즘

[MST] Kruskal 알고리즘

그래프 중에서 MST (Minumum Spannig Tree) 를 찾는 알고리즘중에 하나로 Union-Find알고리즘을 이용하며, 간선 (edge)의 가중치(weight)를 오름차순으로 정렬하여 가중치가 사이클이 생기지 않는 낮은 간선을 먼저 선택하는 방법이다. 사이클의 여부를 확인할때 union-find 알고리즘을 이용하여 찾는 알고리즘이다. union find 알고리즘 설명 보기 1. 특징 탐욕적인 방...

Read More