Unicorns

All the things

ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Java Study] - 자바 데이터 타입, 변수 ,배열
    Java 2021. 9. 22. 14:44

    Primitive Type 종류와 값의 범위 그리고 기본 값

    Primitive Type 은 자바의 기본 데이터 타입으로

    문자형 1개 , 정수형 4개, 실수형 2개, 참/거짓 1개 총 8개다.

    메모리에는 0과 1을 저장하는 최소 기억 단위인 비트(bit)가 있다. 그리고 8개의 비트를 묶어서 바이트(byte)라고 한다.

    Primitive Type은 정해진 메모리 사용 크기(바이트 크기)로 값을 지정하는데

    바이트 크기가 클수록 표현하는 값의 범위가 크다.

    Character

    char

    • 하나의 문자만을 저장할 수 있는 문자형 타입으로 문자는 꼭 ''(작은 따옴표)로 감싸야 한다.
    • 한 문자를 유니코드로 저장
      • 세계 각국의 문자들을 2byte(0~65535) 코드값으로 매핑한 국제 표준 규약
      • 0~127 까지는 아스키 문자(특수 기호 및 영어 알파벳)
      • 44032~55203까지는 한글 11172자 
    • 메모리 크기 : 2byte (16bits)
    • 기본 값 : ‘\u0000’ (0)
    • 범위 : ‘\u0000’ (0) ~ ‘\uffff’ (65535)
    public class DataType {
        public static void main(String[] args) {
            char var1 = 'A';
            char var2 = 'B';
            char var3 = '가';
            char var4 = '각';
    
            // 유니코드를 알고 싶은 경우
            int uniCode = var1;
            System.out.println(uniCode); // 65
            uniCode = var3;
            System.out.println(uniCode); // 44032
        }
    }

    Integer

    byte

    • 8bits 크기의 메모리만 저장할 수 있는 아주 작은 정수 데이터 타입으로 이진 데이터를 다루는데 사용된다.
    • 메모리 크기 : 1byte (8bits)
    • 기본 값 : 0
    • 범위 : -128 ~ 127

    값의 범위를 초과하면 컴파일 에러가 발생한다.

    실행 중에 값의 범위를 초과할 경우

    (127을 넘으면 -128부터 , -128 보다 작아지면 127 부터) 다시 시작

    public class DataType {
        public static void main(String[] args) {
            byte b = -128;
            System.out.println(b); // -128
            b--;
            System.out.println(b); //  127
    
            b++;
            System.out.println(b); // -128
        }
    }

    short

    • c언어와의 호환을 위해 추가되었다.
    • 자바에서는 잘 사용되지 않는 타입
    • 메모리 크기 : 2byte (16bits)
    • 기본 값 : 0
    • 범위 : -32768 ~ 32767

    int

    • 정수형 타입의 기본이 되는 타입으로 정수를 저장할 때 가장 많이 사용 된다.
    • 메모리 크기 : 4byte (32bits)
    • 기본 값 : 0
    • 범위 : – 2,147,483,648 ~ 2,147,483,647
    public class DataType {
        public static void main(String[] args) {
            int num = 10;
        }
    }​

    long

    • int 타입의 2배 크기를 저장할 수 있는 타입
    • int 타입의 저장 범위를 넘어서는 큰 정수는 반드시 뒤에 L은 붙여야 한다.
    • 메모리 크기 : 8byte (64bits)
    • 기본 값 : 0
    • 범위 : -9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807

    Floating-Point

    float 와 double의 메모리 사용 크기는 각각 int 와 long의 크기와 같지만, 정수 타입과는 다른 저장 방식 때문에

    정수 타입보다 훨씬 더 큰 범위의 값을 저장 할 수 있다.

     

    실수는 부동 소수점 (floating-point) 방식으로 저장된다.

     

    가수 m 의 범위 :  0 <= m < 1

    float 타입과 double 타입은 가수와 지수를 저장하기 위해 전체 bit를 나누어 사용한다.

     

    float

    • 소수 점 7자리 까지 표현 할 수 있는 실수형 타입으로 값 제일 뒤에 f 나 F를 꼭 붙여야 한다. 그렇지 않으면 컴파일러가
      double형 타입으로 인식한다.
    • 메모리 크기 : 4byte (32bits)
    • 기본 값 : 0.0f
    • 범위 : 1.4 x 10-45 ~ 3.4 x 1038

    double

    • float 타입 크기의 2배로 소수 점 16자리 까지 표현 할 수 있다.
    • 메모리 크기 : 8byte (64bits)
    • 기본 값 : 0.0
    • 범위 :4.9 x 10-324 ~ 1.7 x 10308

    부동 소수점 방식의 오차

     

    부동 소수점 방식은 10진수를 정확하게 표현할 수 없다.

    public class DataType {
        public static void main(String[] args) {
            double num = 0.1;
            for (int i=0; i<1000; i++) {
                num += 0.1; // 0.1을 1000번 더함
            }
            System.out.println(num); // 100.09999999999859
        }
    }

    0.1을 1000번 더하면 100이 나와야 하는데 100.09999999999859가 나왔다.

    컴퓨터는 실수를 가지고 수행하는 모든 연산에서 언제나 작은 오차가 존재한다.

     

    float형과 double형의 정밀도 차이

    public class DataType {
        public static void main(String[] args) {
            float num1 = 1.23456789f;
            double num2 = 1.23456789;
            System.out.println("float형 변수 num1 = " + num1);
            System.out.println("double형 변수 num2 = " + num2);
        }
    }

    float형 타입 : 소수 6자리까지 정확하게  표현할 수 있다.

    double형 타입 : 소수 부분 15자리 까지 정확하게 표현할 수 있다.

     

    그 이상 넘어가면 두 타입 모두 작은 오차가 발생한다. 

     

     

     

    Boolean

    boolean

    • true/false 중 하나의 값을 가지며 , 조건식과 논리적 계산에 사용된다.
    • 메모리 크기 : 1bit 만 저장 할 수 있다.
    • 기본 값 : false
    • 범위 : true or false

    Primitive Type 과 Reference Type

    Primitive Type

    • 자바의 기본 데이터 타입 (총 8개)
    • 실제 값을 저장

     

    Reference Type

    • 기본형을 제외한 나머지
    • 객체가 참조하고 있는 메모리 주소를 저장
     public static void main(String[] args) {
            int num = 5;
            String str = "hello";
        }

    변수는 스택 영역에 객체는 힙영역에 저장되는데

    int 타입인 변수 num 에는 실제 값이 5가 저장되고
    문자열 클래스 String 참조 타입인 변수 str에는
    값이 저장되는 것이 아니라 힙에 생성된 hello 라는 문자열의 메모리 주소를 저장한다.

    즉, str은 hello 문자열의 메모리 주소를 참조하는 것이다.
    그렇기 때문에 변수 str을 참조 변수라고 부른다.

    리터럴

    리터럴(literal) 은 소스 코드 내에서 직접 입력된 값을 말한다.

     public static void main(String[] args){
            int num= 5;
            String str= "hello";
            boolean check= true;
    }

    5 , "hello" , true 가 리터럴이다.

    여기서 각 타입에 따라
    정수 리터럴 , 문자열 리터럴 , 실수 리터럴 , 논리 리터럴, 문자 리터럴이라고 부르는 것이다.

    정수 리터럴

    • 소수점이 없는 정수 리터럴 : 10진수 , ex) 0, 75
    • 0으로 시작되는 리터럴 : 8진수 , ex) 02 , -04
    • 0x 또는 0X로 시작하고 0~9 숫자나 A,B,C,D,E,F 또는 a,b,c,d,e,f로 구성된 리터럴 : 16진수, ex) 0x5 , 0xA, 0xB3 , 0xAc08

    실수 리터럴

    • 소수점이 있는 리터럴은 10진수 실수로 간주 ex) 0.25 , -3.14
    • 대문자 E 또는 소문자 e가 있는 리터럴은 10진수 지수와 가수로 간주 ex) 5E7 <- 5 X 107 , 0.12E-5 <- 0.12 X 10 -5

    문자 리터럴

    작은 따옴표(')로 묶은 텍스트는 하나의 문자 리터럴로 간주한다.

    문자열 리터럴

    큰따옴표(")로 묶은 텍스트는 문자열 리터럴로 간주한다.

    논리 리터럴

    true 와 false는 논리 리터럴로 간주한다.

     

     

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

    변수란 ?

    하나의 값을 저장할 수 있는 메모리 공간을 말한다.

    변수의 선언

    값을 저장할 변수를 선언 해보자

    int age;

    나이의 값을 저장해주는 age 라는 변수를 선언 하였는데
    나이는 숫자로 나타내기 때문에 정수형 int 타입을 사용하였다.

    이제 메모리에 age라는 저장 공간이 생겼고 이제 값을 넣어주면 된다.

    int age;
    age = 28;

    대입 연산자를 사용해서 age 변수에 28이라는 값을 저장하였다.

    위와 같이 변수에 처음으로 값을 저장하는 것을 초기화라고 한다.

     

    변수의 스코프(scope)와 라이프타임(lifetime)

    • 변수의 scope : 프로그램 안에서 변수가 접근할 수 있는 영역을 말한다. -where
    • 변수의 lifetime : 변수가 메모리에 얼마나 오래동안 있는지 나타낸다. - how

    변수눈 선언된 블록 내에서 사용 가능하며 선언 위치에 따라 세 가지 타입으로 나눌 수 있다.

    1. 인스턴스 변수 : 메서드 영역을 제외한 클래스 안에 선언된 변수
    2. 클래스 변수 : 인스턴스 변수 앞에 static 키워드가 붙어있는 변수
    3. 로컬 변수: 인스변수, 클래스 변수 외에 모든 변수 (메서드, 생성자 , 초기화 블럭 내부)
    변수 타입 스코프(scope) 라이프타임(lifetime)
    인스턴스 변수 static 메서드를 제외한 클래스 전체 객체 인스턴스가 메모리에 있을 때
    클래스 변수 클래스 전체 프로그램이 종료 될 때
    로컬 변수 선언된 블록({ }) 내부 블록이 끝나는 지점

     

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

    타입 변환은 말 그대로 타입을 다른 타입으로 변환하는 것을 말한다.

    타입 변환에는 자동 타입 변환과 강제 타입 변환이 있다.

     

    자동 타입 변환

    • 작은 크기를 가지는 타입이 큰 크기를 가지는 타입에 저장될 때 발생한다.
    • 컴파일 타임에 저동적으로 변환 된다.
    • implicit conversion(묵시적 타입 변환) 이라고 한다.

    ex)

    int x = 20;
    long y = x;  // 자동 타입 변환

    강제 타입 변환

    • 강제적으로 큰 데이터 타입을 작은 데이터 타입으로 쪼개어서 저장하는 것으로 캐스팅(Casting)이라고도 한다.
    • 개발자나 사용자가 캐스팅 연산자 '()'를 사용하여 임의로 변환한다.
    • explicit conversion(명시적 타입 변환) 이라고 한다.

    ex)

    int i = 2;
    byte b = (byte) i;

    ※ 타입 변환 시 float는 4byte 크기 인데 long (8byte) 보다 더 큰 타입으로 표시되는 이유는 표현할 수 있는 값의 범위가 float가 더 크기 때문이다.

     

    타입 프로모션(type promotion)

    • 연산을 하였을 때 자료형의 크기가 더 큰 것으로 자동 변환 되는 것을 말한다.
    int i = 5; 
    long l = 10; 
    long result = l + i;

     

    1차 및 2차 배열 선언하기

    배열 : 같은 타입의 데이터를 연속 된 공간에 나열시키고, 각 데이터에 인덱스(index)를 부여해 놓은 자료구조

    • 배열은 같은 타입의 데이터만 저장할 수 있는 객체로 힙영역에 생성된다.
    • 배열은 객체이기 때문에 배열 변수는 참조 변수에 속한다.
    • 배열 변수는 힙 영역의 배열 객체를 참조하게 된다.
    • 만약 다른 타입의 값을 저장하려고 하면 타입 불일치(Type mismatch) 컴파일 오류가 발생한다.
    • 한 번 생성된 배열은 길이를 늘리거나 줄일 수 없다.

     

    배열 선언

    배열을 사용하기 위해 배열을 선언해보자

    배열 변수를 선언할 때 대괄호 []를 사용하는데

    타입 [] 변수;
    타입 변수 [];

    대괄호 []는 타입 뒤에 붙을 수도 있고 변수 뒤에 붙을 수 도 있다.

     

    배열 생성

     

    값 목록으로 배열 생성

    배열을 생성 할 때 중괄호{} 안에 선언된 값으로 초기화 할 수 있다.

    초기화된 값이 들어있는 배열 객체의 주소를 변수가 참조한다.

    데이터 타입[] 변수 = {값1, 값2, 값3, 값4};

    ex)

    int arr[] = {10,13,23,35};

    위의 배열은 데이터 타입이 primitive type(기본 타입)으로 배열 인덱스에 값을 직접 저장한다.

     

    반면에 배열 데이터 타입이 String과 같은 참조 타입이면 배열 인덱스에 객체의 주소를 저장한다.

    String fruits[] = {"orange" ,"apple", "banana" ,"mango"};

    new 연산자로 배열

    생성값을 초기화 하지 않고 값들을 저장할 배열을 미리 만들고 싶을 때 사용한다.

    배열 객체 안에 있는 값들은 지정된 데이터 타입의 초기값이 설정 되어있다.

    데이터 타입[] 변수 = new 타입[길이];

    위의 코드 처럼 배열의 길이를 지정할 수 있다.

    ex)

    int arr[] = new int[4];

    값을 지정하지 않았기 때문에 int 데이터 타입의 기본값인 0으로 초기화

    이후 각 인덱스별로 값을 초기화 할 수 있다. 

    arr[0] = 21; // 값 21  초기화
    arr[1] = 15; // 값 1 초기화
    arr[2] = 20; // 값 20 초기화
    arr[3] = 19; // 값 19 초기화
    arr[4] = 45; // ArrayIndexOutOfBoundsException 발생

    이때 인덱스 범위를 벗어나면 런타임 에러가 발생한다.

     

     

    String fruits = new String[4];

    값을 지정하기 않았기 때문에 String 데이터 타입의 기본값인 null로 초기화

     

    2차원 배열

    행과 열로 구성된 배열을 2차원 배열이라고 한다.

    타입[][] 변수; 
    타입 변수[][];
    int [][] arr = new int[2][3]; // 2행 3열

    행의 크기가 2 , 열의 크기가 3인 2차원 배열이다.

    0번 인덱스와 1번 인덱스에 각 각 크기가 3인 배열의 참조 주소가 저장되어있다.

    값은 int 형의  기본 값인 0이다.

     

    그런데 자바에서는 수학 행렬 구조가 아닌 계단식 구조를 가질 수 있다.

    즉, 열의 크기가 제각기 다른 2차원 배열을 만들수 있다.

    int [][] arr = new int[2][];

    행의 크기만 정해 놓고 열의 크기는 각 행에 따로 지정할 수 있다.

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

    배열 초기화 하기

     arr[0][0] = 1;
     arr[0][1] = 5;
     arr[0][2] = 10;
     arr[1][0] = 2;
     arr[1][1] = 25;
     arr[1][2] = 30;
     arr[1][3] = 35;

     

    값 목록으로 배열 생성

    public class JaggedArray {
        public static void main(String[] args) {
            int arr[][] = {{1,5,10} , {2,25,30,35}}; // 크기가 각각 3, 4 인 배열을 참조
            // 1 5 10
            // 2 25 30 35
            System.out.println(arr[0][0]); // 1
            System.out.println(arr[0][1]); // 5
            System.out.println(arr[0][2]); // 10
            System.out.println(arr[1][0]); // 2
            System.out.println(arr[1][1]); // 25
            System.out.println(arr[1][2]); // 30
            System.out.println(arr[1][3]); // 35
            System.out.println(arr[1][4]); // ArrayIndexOutOfBoundsException 에러 발생
        }
    }

     

    배열 복사

    배열을 다른 배열에 복사해서 사용 할 수 있는데,  깊은 복사(deep copy)와 얕은 복사(shallow copy)가 있다.

    깊은 복사(deep copy)

    배열은 객체라고 하였다.  그렇게 때문에 값이 저장되는 것이 아니라 참조 주소가 저장되는데,

    깊은 복사는 참조하는 객체를 새로 생성해서 값만 복사하는 것 을 말한다. 

     

    public class DeepCopy {
        public static void main(String[] args) {
            int arr[] = {3, 5, 10};
            int newArr[] = new int[arr.length];
            for (int i = 0; i < arr.length; i++) {
                newArr[i] = arr[i];
            }
            System.out.println(newArr == arr); // false
    
        }
    }

    clone() 메서드를 사용해서 깊은 복사를 할 수도 있다.

    public class DeepCopy {
        public static void main(String[] args) {
            int arr[] = {3, 5, 10};
            int newArr[] = arr.clone();
            System.out.println(arr == newArr); // false
        }
    }

    복사 한 뒤 배열 값 수정

    참조하는 주소값이 다르기 때문에

    배열의 인덱스를 변경하여도 원본 배열에는 지장이 없다.

    public class DeepCopy {
        public static void main(String[] args) {
            int arr[] = {3, 5, 10};
            int newArr[] = arr.clone();
            newArr[0] = 5;
            System.out.println(arr == newArr); // false
            System.out.println(Arrays.toString(arr)); // [3,5,10];
            System.out.println(Arrays.toString(newArr)); // [5,5,10];
        }
    }

     

    얕은 복사(shallow copy)

    참조하는 주소값을 복사한다. 

    그렇기 때문에 참조하는 주소가 같다.

    public class ShallowCopy {
        public static void main(String[] args) {
            int arr[] = {3, 5, 10};
            int newArr[] = arr; // 얕은 복사
            System.out.println(arr == newArr); // true
            newArr[0] = 5;
            System.out.println(Arrays.toString(arr));
        }
    }

     

    복사 한뒤 배열 값 수정

    얕은 복사는 배열을 복사 한 뒤 값을 수정 할 때 주의해야 한다.

    public class ShallowCopy {
        public static void main(String[] args) {
            int arr[] = {3, 5, 10};
            int newArr[] = arr; // 얕은 복사
            System.out.println(arr == newArr); // true
            newArr[0] = 5;
            System.out.println(Arrays.toString(arr)); // [5,5,10]
            System.out.println(Arrays.toString(newArr)); // [5,5,10]
        }
    }

    같은 객체를 참조하기 때문에 

    복사한 배열의 값을 수정하면 원본 배열의 값도 함께 수정 된다.

    이 점을 주의해서 사용해야 한다.

     

     

    같은 객체를 참조하기 때문에 두 배열 모두 0번 인덱스 값이 5로 수정되었다.

     

    타입 추론, var

    java 10 이후 부터 java 에서 지원되는 것으로
    컴파일러가 데이터 타입을 자동으로 결정해주는 것을 말한다.

    • 변수에 데이터 타입을 지정해주는 대신 'var' 키워드를 사용하면 타입 추론이 가능하다.
    public static void main(String[] args) { 
    var message ="Good bye , java 9"; 
    }
    • 컴파일러가 message에 선언된 초기값을 통해 데이터 타입을 String 타입으로 결정하였다.
    • 타입 추론은 오로지 로컬 변수에서 사용 가능하다. 인스턴스 변수 , 클래스 변수에서 사용하면 컴파일 에러가 발생한다.
    • 타입 추론시 반드시 초기값을 설정해주어야 한다. 초기 값을 설정하지 않고 선언만 할 경우 컴파일 에러가 발생한다.

    REFERENCE

    https://techvidvan.com/tutorials/data-types-in-java/
    https://www.atnyla.com/tutorial/variable---in-java/0/31
    https://www.learningjournal.guru/article/programming-in-java/scope-and-lifetime-of-a-variable/
    http://tcpschool.com/java/java_datatype_floatingPointNumber
    https://www.javatpoint.com/array-in-java
    자바의 정석
    이것이 자바다

     

     

    댓글

Designed by Tistory.