데이터 타입

Coding Cat·2023년 12월 22일

JAVA

목록 보기
3/4

자바 데이터 타입

Primitve Type(원시 타입)

short, int, long, float, double, char, boolean, byte 등이 있다.
short, int, long은 숫자형으로 각각 나타낼 수 있는 숫자의 크기가 다르며, 이는 각 타입에 할당되는 메모리의 크기가 다르기 때문이다. 기본값이 존재하기 때문에 Null 개념이 존재하지 않는다. 만약 기본형 타입에 Null을 넣고 싶다면 래퍼 클래스를 활용하면 된다. 기본형 타입은 실제 값을 저장하는 공간으로, 스택(Stack) 메모리에 저장된다.

자바의 null

C언어에서는 생성된 메모리의 주소를 포인터라는 것이 가리키게 되어 포인터를 통해 데이터를 가져올 수 있다. NULL은 주소값이 없는 것(아무것도 가리키고 있지 않다)을 말하는 것이다.
자바의 참조 변수와 포인터의 정확한 공통점과 차이점은 둘다 주소 안의 메모리에 직접 접근한다는 공통점은 가진다. 참조 변수는 직접 메모리를 핸들링 할 수 없어 주소값을 변경할 수 없다. 반면 포인터는 주소값을 변경시켜 성능을 향상시킬 수 있지만 대신 안정성이 떨어진다는 특징이 있다.
참조형 타입은 기본형 타입과 달리 빈 객체를 의미하는 Null 개념이 존재한다. 값이 저장되어 있는 곳의 주소값을 저장하는 공간으로, 힙(Heap) 메모리에 저장된다. 자바에서 null은 참조가 없는 경우를 뜻하는데, 만일 null을 참조하는 레퍼런스 변수로 객체의 인스턴스 메서드를 호출하는 등의 객체 코드를 수행하려는 경우 이 때 NPE(NullPointerException)가 발생한다.
Java8이 등장하면서 null에 대한 처리를 정식적으로 지원하는 java.utill.Optional클래스가 추가 되었다. Optional 클래스는 '존재할 수 있지만 안 할 수도 있는 객체', 즉, 'null이 될 수도 있는 객체'를 감싸고 있는 일종의 래퍼 클래스이다.

참고한 주소
개발자들을 괴롭히는 자바 NULL 파헤치기
Optional: NULL을 처리하는 방법

Reference Type(참조형)

참조형은 기본적으로 java.lang.Object(모든 클래스의 슈퍼 클래스 별도의 import가 필요 없다. Object 클래스의 모든 멤버는 다른 클래스에서 사용하거나 오버라이딩 가능)를 상속 받는다. 참조형의 변수는 데이터를 다른 영역에 저장하고 그 주소만을 이용한다.

Class Type

클래스형은 기본형과 다르게 객체를 참조하는 형태이다.
아래 객체는 단순히 str변수를 갖는 클래스이다.

package com.devkuma.basic.datatype.ex1;

class MyObject {
    private String str;

    public MyObject(String str) {
        this.str = str;
    }

    public String getStr() {
        return str;
    }

    public void setStr(String str) {
        this.str = str;
    }
}

아래 객체는 MyObject를 활용하여 str 값을 표시해 주고 있다.

package com.devkuma.basic.datatype.ex1;

public class MyObjectMain {
    public static void main(String[] args) {
        MyObject a = new MyObject("a");
        MyObject b = new MyObject("b");

        // 초기값 표시
        System.out.println(a.getStr()); // a
        System.out.println(b.getStr()); // b

        // a를 b에 대입
        a = b;
        System.out.println(a.getStr()); // b

        // b의 str에 값 "c"를 대입
        b.setStr("c");
        System.out.println(a.getStr()); // c
    }
}

처음 객체 b를 a에 대입하고, a를 표시하면 “b"가 표시되는 것을 확인 할 수 있다. 그러고, b의 str 변수에 값 “c"를 대입해서 a를 표시하니 “c"가 표시되었다. 이는 객체 a와 b라는 변수가 가지는 것은 실제 객체가 아닌 객체의 주소를 갖기 때문이다. a와 b는 같은 객체의 주소를 가지고 있기 때문에 어느 한쪽이 변하더라도 값이 동일한 것이다.

String Type

클래스형에서도 String 클래스는 조금 특별하다. 이 클래스는 참조형에 속하지만 기본적인 사용은 기본형처럼 사용한다. 그리고 불변(immutable) 객체이다. String 클래스에는 값을 변경해주는 메서드들이 존재하지만, 해당 메서드를 통해 데이터를 변경한다면 새로운 String 클래스 객체를 만들어내는 것이다. 일반적으로 기본형 비교는 == 연산자를 사용하지만 String 객체간의 비교는 .equals() 메서드를 사용해야 한다.

Wrapper Class


Wrapper Class 구조도
기본형은 앞에서 언급했듯이 객체가 아니기 때문에 null을 넣을 수 없지만, Wrapper Class를 사용하면 null을 넣어야 있게 된다. 이를 래퍼 클래스는 기본형을 클래스로 감싼 형태의 객체이기에 null이 선언할 수 있게 된다.
박싱 : 기본타입의 데이터 -> 래퍼 클래스의 인스턴스로 변환하는 과정
언박싱 : 래퍼 클래스의 인스턴스에 저장된 값 -> 기본 타입의 데이터로 꺼내는 과정

// 박싱
// Integer 래퍼 클래스 num 에 21 의 값을 저장
Integer num = new Integet(21);
// 언박싱
// 래퍼 클래스 num 의 값을 꺼내 가져온다.
int n = num.intValue();

JDK 1.5 부터는 박싱과 언박싱이 필요한 상황에 자바 컴파일러가 자동으로 처리해준다. 자동화된 박싱과 언박싱을 오토 박싱 (AutoBoxing) 과 오토언박싱 (AutoUnBoxing) 이라고 부른다.

public class Wrapper_Ex {
    public static void main(String[] args)  {
        String str = "10";
        String str2 = "10.5";
        String str3 = "true";
        
        byte b = Byte.parseByte(str);
        int i = Integer.parseInt(str);
        short s = Short.parseShort(str);
        long l = Long.parseLong(str);
        float f = Float.parseFloat(str2);
        double d = Double.parseDouble(str2);
        boolean bool = Boolean.parseBoolean(str3);
  
        System.out.println("문자열 byte값 변환 : "+b); //10
        System.out.println("문자열 int값 변환 : "+i); //10
        System.out.println("문자열 short값 변환 : "+s); //10
        System.out.println("문자열 long값 변환 : "+l); //10
        System.out.println("문자열 float값 변환 : "+f); //10.5
        System.out.println("문자열 double값 변환 : "+d); //10.5
        System.out.println("문자열 boolean값 변환 : "+bool); //true
    }
}

래퍼 클래스의 주요 용도는 기본 타입의 값을 박싱 해서 포장 객체로 만드는 것이지만, 문자열을 기본 타입 값으로 변환할 때에도 사용된다. 대부분의 래퍼 클래스에는 parse + 기본 타입명으로 되어있는 정적 메서드가 있다. 이 메서드는 문자열을 매개 값으로 받아 기본 타입 값으로 변환한다.

  • 사용하는 이유
  1. 래퍼 클래스는 기본 데이터 타입을 Object로 변환할 수 있다. 메소드에 전달된 인수를 수정하려는 경우 오브젝트가 필요하다. (기본 유형은 값에 의한 변경 Object는 참조에 의한 변경이기 때문이다.)
  2. java.util 패키지의 클래스는 객체만 처리하므로 Wrapper class는 이 경우에도 도움이 된다.
  3. ArrayList 등과 같은 Collection 프레임 워크의 데이터 구조는 기본 타입이 아닌 객체만 저장하게 되고 Wrapper Class를 사용하여 자동 방식과 언방식이 일어 난다.

Interface Type

아래처럼 인터페이스를 만들어 보자. 여기서 T는 제내릭 타입으로 옵션이다.

interface MyInterface<T> {
    void add(T value);
}

인터페이스를 만들게 되면 새로운 참조 자료형을 만드는 것과 같다. 그리고 인터페이스도 자료형이기 때문에 자료형으로써 자신을 구현한 객체의 주소를 가질 수 있다. 다만, 인터페이스에 정의된 메소드만 사용할 수 있게 된다.

Array Type

배열형은 기본형으로도 만들 수 있고 참조형으로도 만들 수 있다.

int[] num1 = new int[2];
Integer[] num2 = new Integer[3];

자료형에 대해 []를 선언함으로 배열을 지정할 수 있다. 배열형 변수 또한 배열의 주소를 가지고 있는 것이기 때문에 클래스형의 특징과 동일하다. 그래서 같은 객체의 주소를 참조하게 되면 동일한 배열을 가리키게 된다.
그리고 아래 코드처럼 [][]등으로 중첩 괄호를 사용하게 된다면 다중 배열로 사용할 수 있다.

Object[][] obj = new Object[2][3];

Enum Type

enum(열거형)이란, 복수의 정수를 한꺼번에 다루기 위한 데이터 형이다.

enum(열거형) 정의

[modifier] enum name {
  member, ...
}
  modifier: 한정자(`public`, `strictfp`만)
  name: 열거형의 이름
  member: 열거 상수

열거형의 선언에는 enum 키워드를 사용한다. enum 블록 아래에 이름(열거 상수)을 쉼표로 구분하여 나열한다. 상수와 같이 다루므로 이름은 언더스코어(_) 형식(모두 대문자, 단어의 단락은 언더스코어)로 정하는 것이 일반적이다.

예를 들어, 다음은 요일을 나타내는 WeekdayEnum 열거형을 정의하는 예제이다.

public enum WeekdayEnum {
    Sunday,
    Monday,
    Tuesday,
    Wednesday,
    Tursday,
    Friday,
    Saturday
}

정의한 열거형에는 Weekday.Sunday와 같이 형명.상수의 형식으로 액세스 할 수 있다.

enum(열거형) 메서드

열거형은 암묵적으로 Enum 클래스(java.lang 패키지)를 상속한 클래스의 일종이다. 그리고 열거 상수를 참조한 “Weekday.Sunday"는 Enum 객체이다. Enum 객체에서는 다음과 같은 메서드를 사용할 수 있다.

메서드개요
String name()열거 상수의 이름을 반환
int ordinal()열거 상수의 순서를 반환(0 시작)
toString()열거 상수의 이름을 반환
E[] values()열거형에 포함되는 모든 열거 정수를 반환

예를 들어, 다음 예제는 Weekday 열거형에 정의된 열거 상수의 이름을 나열한다.

for (WeekdayEnum w : WeekdayEnum.values()) {
  System.out.println(w.name());
}

생성자/필드/메서드 정의

열거형도 클래스의 일종이기 때문에 부하에 생성자나 필드/메소드를 정의하는 것도 가능하다.

public enum WeekdayEnum {
    Sunday("sun"),
    Monday("mon"),
    Tuesday("tue"),
    Wednesday("wed"),
    Thursday("thu"),
    Friday("fri"),
    Saturday("sat");
 
    // 필드
    private String name;
 
    // 생성자
    private WeekdayEnum(String name) {
        this.name = name;
    }
 
    // 메서드
    @Override
    public String toString() {
        return this.name;
    }
}

System.out.println(WeekdayEnum.Monday.toString());  // 결과 : mon

열거값에 그 자신의 식별자와는 별도로 (예를 들어) 표시를 위한 값을 갖게 하고 싶은 경우에는 이 예제와 같이 필드(속성)를 선언한다. 이 예제에서는 요일의 단축 이름을 name 필드에 갖는다. 필드는 일반적인 클래스와 같이 생성자로 초기화할 수 있다. 구문은 기본적으로 클래스와 동일하지만, 접근 제한자는 private 고정된다.

생성자를 정의한 후에는 열거 상수도 이에 따라 열거 상수(인수, ...) 형식으로 선언해야 한다. 열거 정의 마지막에는 ";" 세미콜론을 넣는다.

마지막으로 메소드의 정의이다. 여기서는 name 필드의 값을 검색할 수 있도록 toString 메서드를 정의한다. 구문은 클래스와 동일하다.

참고한 사이트
https://www.devkuma.com/docs/java/data-type/

profile
나의 archive

0개의 댓글