[JAVA] 변수 타입 변환, 오토박싱 & 언박싱, 형변환

dejeong·2024년 9월 6일
0

JAVA

목록 보기
5/24
post-thumbnail

자바에서 타입 변환(Type Conversion)은 데이터 타입을 다른 타입으로 변환하는 과정을 말한다.
이는 프로그래밍에서 매우 일반적인 작업으로, 데이터의 정확성과 프로그램의 효율성을 유지하기 위해 중요하다. 타입 변환에는 크게 자동 타입 변환(묵시적 타입 변환)강제 타입 변환(명시적 타입 변환) 두 가지 방법이 있다.

타입 변환(Type Conversion)

타입 변환은 변수나 리터럴의 데이터 타입을 다른 타입으로 변경하는 과정으로 데이터의 정확성과 프로그램의 효율성을 유지하기 위해 중요하며, 타입 변환에는 크게 자동 타입 변환(묵시적 타입 변환)강제 타입 변환(명시적 타입 변환) 두 가지 방법이 있다.
예를 들어, int 타입을 double 타입으로 변환하거나, double 타입을 int 타입으로 변환할 수 있다.

자동 타입 변환 (Implicit Type Conversion)

자동 타입 변환은 작은 크기의 타입을 큰 크기의 타입으로 변환하는 것으로, 개발자가 별도의 조치를 취하지 않아도 컴파일러가 자동으로 변환해준다. 이는 데이터 손실이 발생하지 않는 안전한 변환이다.

자동 타입 변환의 예시

  • byteint
  • charint (문자형을 정수형으로 변환 시 유니코드 값이 됨)
  • intlong
  • intdouble

예시 코드

public class AutoCasting {
    public static void main(String[] args) {

        ForceCasting fc = new ForceCasting(); // 참조 타입 변수, class 선언

        byte byteValue = 10;
        int intValue = byteValue;        // 타입 변환 (byte -> int)
        System.out.println(intValue);

        char charValue = '가';
        intValue = charValue;               // char 타입에서 int 타입으로 변환하면 유니코드가 된다.
        System.out.println("'가'의 유니코드= " + intValue);

        intValue = 500;                    //  500으로 초기화
        long longValue = intValue;        // 타입 변환 (int -> long)
        System.out.println(longValue);

        intValue = 200;                    // int 에 200 이라는 정수형값을 넣고 실수형(double) 값으로 변환
        double doubleValue = intValue;    // 타입 변환 (int -> double), 타입이 변환되면서 더 큰 숫자로 변환된다.(200.0)
        System.out.println(doubleValue);
    }
}
10
'가'의 유니코드= 44032
500
200.0

유니코드 (Unicode)

유니코드는 전 세계의 모든 문자를 컴퓨터에서 일관되게 표현하고 다루도록 하는 표준이다.
예를 들어, char 타입을 int로 변환하면 해당 문자의 유니코드 값이 된다.

강제 타입 변환 (Explicit Type Conversion)

강제 타입 변환은 큰 크기의 타입을 작은 크기의 타입으로 변환하는 것으로, 데이터 손실이 발생할 수 있기 때문에 개발자가 명시적으로 변환을 지시해야한다. 이를 캐스팅(Casting)이라고 한다.

강제 타입 변환의 예시

  • doubleint (소수점 이하 버림)
  • longshort
  • intbyte

예시 코드

public class ForceCasting {
    public static void main(String[] args) {
        // long -> int 변환 || 변형이 일어나지는 않음 (값의 범위 내이기 때문)
        long longValue = 300L;
        int intValue = (int) longValue; // long을 int로 명시적 변환 (캐스팅)
        System.out.println("longValue = " + longValue);
        System.out.println("intValue = " + intValue); // 300 출력

        // double -> int 변환 || 변형이 일어남 (소수점 이하 손실)
        double pi = 3.14;
        int convertedInt = (int) pi; // double을 int로 명시적 변환 (캐스팅)
        System.out.println("pi = " + pi);
        System.out.println("convertedInt = " + convertedInt); // 소수점 이하가 버려져서 3 출력

        // String -> char (캐스팅 불가)
        String stringValue = "A";
        // char ver = (char) stringValue; // 컴파일 오류 발생 (캐스팅 불가)

        // charAt() 메서드를 사용하여 String에서 char 추출
        char changedValue = stringValue.charAt(0);
        System.out.println("stringValue = " + stringValue);
        System.out.println("changedValue = " + changedValue); // 'A' 출력
    }
}
longValue = 300
intValue = 300
pi = 3.14
convertedInt = 3
stringValue = A
changedValue = A 

연산식에서의 자동 타입 변환

연산식에서 서로 다른 타입의 변수가 연산에 사용되면, 더 큰 크기의 타입으로 자동 변환된다.
이는 데이터 손실을 방지하고 연산의 정확성을 유지하기 위한 것이다.

예를 들어, intdouble 타입의 값을 더하면 intdouble로 자동 변환되어 연산이 수행되는데, 결과를 int로 내고 싶다면, double타입을 int캐스팅해주면 된다.

  • 실수형 뒷 자리수를 버리고 싶을 때 int 로 강제 캐스팅 하는 방법이 사용될 수 있다. (소수점 버림)

예시 코드

public class AutoCastingInOperand {
    public static void main(String[] args) {
        int intValue = 10;
        double doubleValue = 5.5;

        // 연산식에서 자동 타입 변환이 일어남 (int -> double)
        double result = intValue + doubleValue; // intValue가 double로 자동 변환되어 연산이 수행됨
        System.out.println("intValue + doubleValue의 결과 (double result) = " + result); // 15.5 출력

        // int 타입으로 연산을 수행하려면 doubleValue를 int로 강제 변환
        int intResult = intValue + (int) doubleValue; // doubleValue의 소수점 이하가 버려짐
        System.out.println("intValue + (int)doubleValue의 결과 (int result) = " + intResult); // 15 출력
    }
}
intValue + doubleValue의 결과 (double result) = 15.5
intValue + (int)doubleValue의 결과 (int result) = 15

문자열(String)과 문자(char) 간의 변환

문자열을 문자로 변환: 문자열(String)을 직접 char 타입으로 변환할 수는 없지만, String 클래스의 charAt(index) 메서드를 사용하여 특정 인덱스의 문자를 char 타입으로 가져올 수 있다.

예시 코드

public class StringToCharExample {
    public static void main(String[] args) {
        // 문자열 "A"를 char로 변환
        String stringValue = "A";
        char changedValue = stringValue.charAt(0); // 문자열의 첫 번째 문자를 char로 변환

        // 결과 출력
        System.out.println("문자열 stringValue = " + stringValue);
        System.out.println("변환된 문자 changedValue = " + changedValue);
    }
}
문자열 stringValue = A
변환된 문자 changedValue = A 

기본 자료형과 참조 자료형

저장 형태

기본 자료형:

  • 기본 자료형 변수는 실제 값(리터럴)을 직접 저장한다.
  • 이 값들은 스택(Stack) 메모리 영역에 저장된다.

참조 자료형:

  • 참조 자료형 변수는 실제 데이터를 저장하지 않고,
    데이터가 저장된 메모리 위치(주소, 번지수)를 저장한다.
  • 참조 변수 자체는 스택에 저장되지만, 실제 데이터는 힙(Heap) 메모리 영역에 저장된다.
  • 예를 들어, String s = "Hello";라고 선언하면 s 변수는 "Hello" 문자열이 저장된 메모리 주소를 가리키게 된다.

힙 메모리와 스택 메모리:

  • 스택은 메소드 호출 시 생성되고, 메소드가 끝나면 사라지는 메모리 공간이다.
  • 힙은 동적으로 할당되는 메모리 공간으로, 참조 타입 변수는 힙에 실제 값을 저장하고, 그 주소를 스택에 보관한다.

가비지 컬렉터:

  • 힙에 저장된 데이터가 더 이상 참조되지 않으면, 자바의 가비지 컬렉터가 이를 자동으로 정리하여 메모리를 회수한다.

예시 코드

public class ReferenceTypeExample {
    public static void main(String[] args) {
        // 기본 자료형 변수
        int primitiveValue = 42;

        // 참조 자료형 변수
        String referenceValue = "Hello";

        // 메모리 상태
        // primitiveValue는 스택에 42라는 값을 직접 저장
        // referenceValue는 스택에 문자열 "Hello"의 주소값을 저장하고, 문자열은 힙에 저장

        System.out.println("primitiveValue = " + primitiveValue); // 42 출력
        System.out.println("referenceValue = " + referenceValue); // "Hello" 출력
    }
}

초기화

기본 자료형의 초기화:

  • 기본 자료형 변수는 선언과 동시에 리터럴 값을 할당한다.
  • 예: int a = 10;

참조 자료형의 초기화:

  • 참조 자료형 변수는 new 키워드를 사용하여 초기화한다.
  • 예: String str = new String("Hello");
  • 단, String은 리터럴 값으로도 초기화할 수 있다.
    • 예: String str = "Hello";

⭐ String 초기화 예외:

  • String은 리터럴 값을 사용하여 초기화할 수 있다.
    (new 키워드를 사용하여 선언도 가능하긴 하지만 거의 사용하지 않음)
  • 그러나 new String()으로 초기화하면 항상 새로운 객체를 생성한다.
  • 빈 값을 선언할 때는 ("") 으로 표현한다.
    null을 넣어도 되지만, 주소값이 없다는 것을 표현하기 때문에, 값에 참조를 위한 사용 시에 null pointer Exception이라는 에러가 날 수 있어 쌍따옴표("")를 사용하여 초기화 하는 것이 좋다 . → 코드 상에서 에러가 생기지 않고 컴파일 시에 에러가 나기 때문에 위험하다.
    ```java
    String str = "실제값";
    String str2 = new String("실제값");
    
    String str3 = "";  // null
    ```
    
    **⭐ new String vs " " 차이** (ch5.3장 참조 자료형 String의 동등 비교 참고)
    
    값을 저장하는 영역이 다르다(저장하는 방식이 다르다).
    리터럴로 저장하게 되면 특정 위치에 저장하고,
    new라고 선언하면 주소값을 저장한다.

예시 코드

public class Sample{
    public static void main(String[] args) {
        // 기본 자료형 변수의 초기화
        int a = 10;

        // 참조 자료형 변수의 초기화 (new 키워드 사용)
        String str1 = new String("Hello");

        // 참조 자료형 변수의 초기화 (리터럴 사용)
        String str2 = "Hello";

        // str1과 str2는 동일한 문자열 값을 가지지만, 서로 다른 메모리 주소를 가리킴
        System.out.println("str1 == str2: " + (str1 == str2)); // false 출력

        // 문자열의 값이 같은지 비교할 때는 equals() 메서드 사용
        System.out.println("str1.equals(str2): " + str1.equals(str2)); // true 출력

        // 같은 리터럴로 초기화된 문자열은 같은 메모리 주소를 가리킴
        String str3 = "Hello";
        System.out.println("str2 == str3: " + (str2 == str3)); // true 출력
    }
}
  • 기본 자료형은 스택 메모리에 실제 값이 저장되며, 직접 데이터를 처리한다.
  • 참조 자료형은 스택 메모리에 데이터의 주소값이 저장되며, 힙 메모리에 실제 데이터를 저장한다.
  • String은 특별한 참조 자료형으로, 리터럴 초기화와 new 키워드를 사용한 초기화 간에 메모리 처리 방식이 다르다.
  • 가비지 컬렉터는 더 이상 참조되지 않는 힙 메모리의 데이터를 자동으로 정리한다.

오토박싱 & 언박싱

기본 자료형을 객체처럼 다루기 위해 래퍼 클래스(Wrapper Class)를 사용한다.
래퍼 클래스를 사용하면 기본 자료형을 참조 자료형처럼 사용할 수 있으며, 이 과정에서 박싱과 언박싱이 발생한다.

박싱과 언박싱

  • Wrapper 클래스:
    • 기본 자료형을 객체로 다루기 위한 클래스
    • 기본 자료형: byte, short, int, long, float, double, char, boolean
    • 래퍼 클래스: Byte, Short, Integer, Long, Float, Double, Character, Boolean
  • 박싱(Boxing):
    • 기본형 타입을 래퍼 클래스로 감싸서 객체로 만드는 과정이다.
    • 예: Integer number = Integer.valueOf(10); // 박싱
  • 언박싱(Unboxing):
    • 래퍼 클래스의 객체를 다시 기본형 타입으로 변환하는 과정이다.
    • 예: int num = number.intValue(); // 언박싱
  • 오토박싱(Auto Boxing):
    • 기본형 타입이 자동으로 래퍼 클래스로 변환되는 과정이다.
    • 제네릭 컬렉션에 값을 추가하는 경우 유용하다.
    • 예: Integer number = 10; // 오토박싱
  • 오토언박싱(Auto Unboxing):
    • 래퍼 클래스 객체가 자동으로 기본형 타입으로 변환되는 과정이다.
    • 예: int num = number; // 오토언박싱

예시 코드

Integer number = Integer.valueOf(index);  // 박싱(Boxing)
Integer number = index;   // 오토박싱(Auto Boxing)

기본 자료형보다 wrapper 타입 크기가 더 크기 때문에 오토박싱해준다.
위 두 방법 모두 가능하지만 wrapper 클래스를 사용하여 박싱을 해주면 좀 더 명시적이다.

import java.util.ArrayList;

public class BoxingUnboxingExample {
    public static void main(String[] args) {
        // 박싱 예시
        int primitiveValue = 10;
        Integer wrappedValue = Integer.valueOf(primitiveValue); // 박싱
        System.out.println("박싱된 값: " + wrappedValue);

        // 언박싱 예시
        int unboxedValue = wrappedValue.intValue(); // 언박싱
        System.out.println("언박싱된 값: " + unboxedValue);

        // 오토박싱 예시
        Integer autoBoxedValue = primitiveValue; // 오토박싱
        System.out.println("오토박싱된 값: " + autoBoxedValue);

        // 오토언박싱 예시
        int autoUnboxedValue = autoBoxedValue; // 오토언박싱
        System.out.println("오토언박싱된 값: " + autoUnboxedValue);

        // 제네릭 컬렉션과 오토박싱
        ArrayList<Integer> list = new ArrayList<>();
        list.add(primitiveValue); // 오토박싱되어 리스트에 추가됨
        System.out.println("리스트의 첫 번째 값: " + list.get(0)); // 언박싱되어 출력됨
    }
}

제네릭 컬렉션

제네릭(Generic)은 특정 타입의 객체만을 다룰 수 있도록 타입을 미리 지정하는 기능으로, 제네릭을 사용하면 컴파일 시점에서 타입 오류를 검출할 수 있어 안전한 코드 작성에 도움이 된다.


문자열과 숫자 변환

웹 페이지에서 사용자 입력을 받아 계산을 수행하거나, 숫자를 문자열로 변환하여 출력할 때 유용하다.

  • 문자열을 숫자로 변환:
    • Integer.parseInt(String s): 문자열을 int 타입으로 변환한다.
      • 예: int num = Integer.parseInt("123");
      • 주의: 문자열이 숫자로 변환할 수 없는 경우 NumberFormatException이 발생한다.
    • Integer.valueOf(String s): 문자열을 Integer 객체로 변환한다.
      • 예: Integer number = Integer.valueOf("123");
  • 숫자를 문자열로 변환:
    • Integer.toString(int i): 숫자를 문자열로 변환한다.
      • 예: String str = Integer.toString(123);
    • String.valueOf(int i): 숫자를 문자열로 변환한다.
      • 예: String str = String.valueOf(123);
    • + "" (캐스팅 방식): 숫자에 빈 문자열을 더하여 문자열로 변환한다.
      • 예: String str = 123 + "";

코드 예시

public class StringConvertor {
    public static void main(String[] args) {
        // String -> 숫자 변환
        String str = "12345";

        // 문자열을 int로 변환
        int primitiveInt = Integer.parseInt(str); // int로 변환
        int sum = primitiveInt + 1; // 12346
        Integer wrapperInt = Integer.valueOf(str); // Integer로 변환

        // 문자열을 long으로 변환
        long primitiveLong = Long.parseLong(str); // long 타입으로 변환
        Long wrapperLong = Long.valueOf(str); // Long 타입으로 변환

        String value = "10000.345";

        // 문자열을 float로 변환
        float primitiveFloat = Float.parseFloat(value); // float 타입으로 변환
        Float wrapperFloat = Float.valueOf(value); // Float 타입으로 변환

        // 문자열을 double로 변환
        double primitiveDouble = Double.parseDouble(value); // double 타입으로 변환
        Double wrapperDouble = Double.valueOf(value); // Double 타입으로 변환

        // 숫자 -> 문자열 변환
        int intValue = 10;
        String s1 = intValue + ""; // int를 문자열로 변환 (Casting 방식)
        String s2 = Integer.toString(intValue); // int를 문자열로 변환
        String s3 = String.valueOf(intValue); // int를 문자열로 변환

        System.out.println("문자열 '12345' -> int: " + primitiveInt);
        System.out.println("문자열 '12345' -> Integer: " + wrapperInt);
        System.out.println("문자열 '12345' -> long: " + primitiveLong);
        System.out.println("문자열 '12345' -> Long: " + wrapperLong);
        System.out.println("문자열 '10000.345' -> float: " + primitiveFloat);
        System.out.println("문자열 '10000.345' -> Float: " + wrapperFloat);
        System.out.println("문자열 '10000.345' -> double: " + primitiveDouble);
        System.out.println("문자열 '10000.345' -> Double: " + wrapperDouble);
        System.out.println("int 10 -> 문자열 (빈 문자열 추가): " + s1);
        System.out.println("int 10 -> 문자열 (Integer.toString): " + s2);
        System.out.println("int 10 -> 문자열 (String.valueOf): " + s3);

				// 숫자 -> 문자열 변환 결과 출력
        System.out.println(s1);
        System.out.println(s2);
        System.out.println(s3);
    }
}
  • 박싱과 언박싱:
    기본 자료형을 래퍼 클래스로 변환하거나, 그 반대의 과정을 의미한다.
    오토박싱과 오토언박싱은 자바 컴파일러가 이를 자동으로 처리하는 기능이다.
  • 문자열과 숫자 변환:
    문자열을 숫자로 변환할 때는 Integer.parseInt() 또는 Integer.valueOf()를 사용하며, 숫자를 문자열로 변환할 때는 Integer.toString() 또는 String.valueOf()를 사용한다.
profile
룰루

0개의 댓글