Java에서 데이터 유형 이해하기

저자는 Free and Open Source Fund를 선택하여 기부를 받았습니다. 이는 Write for DOnations 프로그램의 일환입니다.

소개

Java정적으로 유형이 지정된 프로그래밍 언어입니다. 이는 변수를 만들 때 해당 변수의 데이터 유형도 지정해야 한다는 것을 의미합니다. 이것은 동적으로 유형이 지정된 언어와 대조적이며, 예를 들어 PHP와 같습니다. 동적으로 유형이 지정된 언어에서는 변수의 데이터 유형을 지정할 필요가 없어 보일 수 있습니다.

그러나 데이터 유형을 알고 적절하게 사용함으로써 개발자는 코드를 최적화할 수 있습니다. 각 데이터 유형은 특정한 리소스 요구사항이 있기 때문입니다. 또한 하나의 데이터 유형을 지정하고 다른 유형을 저장하려고 하면 (예를 들어 실수로) 코드를 컴파일할 수 없습니다. 따라서 정적으로 유형이 지정된 언어에서는 테스트 이전에도 오류를 감지할 수 있습니다.

자바에는 데이터 유형이 두 가지 있습니다: 기본참조 (또는 비 기본이라고도 함). 이 자습서에서는 자바 프로그램에서 정보를 저장하고 사용하기 위해 변수를 사용하여 자바에서 일반적으로 사용되는 몇 가지 데이터 유형에 대해 알아보겠습니다. 이 자습서는 모든 데이터 유형에 대한 철저한 개요는 아니지만, 어떤 옵션이 자바에서 사용 가능한지에 대해 익숙해지는 데 도움이 될 것입니다.

선수 조건

이 자습서를 따르려면 다음이 필요합니다:

  • 예제를 따라가기 위해 Java 프로그램을 실행할 수 있는 환경입니다. 로컬 머신에서 이를 설정하려면 다음이 필요합니다:

    • 머신에 설치된 Java(버전 11 이상) 및 Java 개발 키트(JDK)에서 제공하는 컴파일러가 필요합니다. Ubuntu 및 Debian의 경우, 튜토리얼의 옵션 1에 따라 우분투 22.04에 Apt를 사용하여 Java 설치하기를 참조하십시오. Mac 및 Windows를 포함한 다른 운영 체제의 경우, Java 설치에 대한 다운로드 옵션을 확인하십시오.
    • 코드 예제를 컴파일하고 실행하려면 이 튜토리얼에서는 Java Shell을 사용합니다. 이는 명령 줄에서 실행되는 Read-Evaluate-Print Loop (REPL)입니다. JShell을 시작하려면 JShell 소개 가이드를 확인하십시오.
  • 자바 및 객체 지향 프로그래밍에 대한 이해는 우리의 자습서에서 찾을 수 있습니다. 자바로 첫 번째 프로그램 작성하기.

원시 유형

자바의 원시 유형은 자바에서 가장 간단하고 기본적인 데이터 유형입니다. 숫자 및 문자와 같은 원시 값들을 나타냅니다. 가장 자주 사용되는 원시 데이터 유형은 int (정수), boolean (부울 값), 및 char (문자)입니다. 나머지는 공식 자바 데이터 유형 문서에서 찾을 수 있습니다.

정수

정수는 음수와 양수의 정수입니다. 자바에서는 이를 저장하기 위해 int를 사용합니다. int는 대부분의 목적에 충분히 큰 숫자를 수용할 수 있습니다: -2,147,483,648부터 2,147,483,647까지입니다.

int가 어떻게 사용되는지 예를 살펴보겠습니다:

int theAnswer = 42;

원시 유형은 항상 소문자로 시작합니다 (int). 자바 구문 규칙에 따라 먼저 데이터 유형을 지정하고(int), 그 후에 변수에 값을 할당할 때 등호(=)로 변수에 42를 할당합니다.

데이터 유형에 관계없이 특수 문자를 추가하지 않고 변수 이름을 직접 지정하여 변수를 사용합니다. 이는 Java가 변수로 인식할 수 있기 때문입니다.

참고: 이 튜토리얼에서 변수 theAnswer의 이름과 다른 모든 변수는 낙타 표기법으로 작성됩니다. 이를 사용할 필요는 없지만, 이것이 Java에서의 표준적인 네이밍 규칙입니다.

변수를 선언한 후에는 다음과 같이 메서드에서 해당 변수를 참조하여 사용할 수 있습니다:

int theAnswer = 42;
System.out.println("The answer to all questions is " + theAnswer);

두 번째 줄에서는 System.out 패키지의 내장 메서드 println을 사용하여 콘솔에 theAnswer를 출력합니다. 이는 변수가 예상대로 선언되었는지 확인하는 가장 간단한 방법입니다.

이 코드가 실제로 작동하는 것을 확인하려면 Java Shell 도구를 사용하십시오. Java를 설치한 후에는 로컬 컴퓨터의 터미널이나 명령 프롬프트를 열고 jshell을 입력하십시오:

  1. jshell

출력은 다음과 유사하게 나타납니다:

Output
| Welcome to JShell -- Version 11.0.16 | For an introduction type: /help intro jshell>

이 튜토리얼의 코드 예제를 콘솔에 붙여넣을 수 있습니다. 완료되면 jshell을 종료하려면 /exit를 입력하십시오.

int를 선언하고 사용하려면 다음 줄을 jshell 콘솔에 붙여넣으십시오:

  1. int theAnswer = 42;
  2. System.out.println("The answer to all questions is " + theAnswer);

다음 출력이 표시됩니다:

Output
theAnswer ==> 42 The answer to all questions is 42

이 출력은 int 변수 theAnswer가 42로 올바르게 설정되었음을 확인합니다 (theAnswer ==> 42). 또한 theAnswer를 메서드에 전달하여 성공적으로 사용하고 메서드가 예상한 변수 값을 생성했습니다.

부울(Boolean)

부울(Boolean) 값은 true 또는 false입니다. 자바(Java)에서는 이를 저장하기 위해 boolean을 사용합니다. 예를 들어, 자바가 재미있는지를 정의하는 boolean 변수를 만들어 보겠습니다:

boolean isJavaFun = true;

isJavaFun 변수를 true로 정의합니다. 대안적인 boolean 값은 false입니다.

위의 변수를 사용하여 다음과 같이 문장 Java is fun: true을 출력할 수 있습니다:

  1. boolean isJavaFun = true;
  2. System.out.println("Java is fun: " + isJavaFun);

jshell에서 이 코드를 실행하면 다음 출력이 생성됩니다:

Output
isJavaFun ==> true Java is fun: true

int 예제와 유사하게, println 메서드는 괄호 안에 제공된 인수를 출력합니다. 덧셈 기호(+)는 문자열 “Java is fun: “을 변수 isJavaFun과 연결하여 실제로 하나의 인수인 문자열 Java is fun: true를 만듭니다.

문자

단일 알파벳 문자를 저장하려면 char를 사용합니다. 예를 들어:

char firstLetter = 'a';

문자 a가 작은 따옴표로 둘러싸여 있는 것을 주목하세요. 작은 따옴표는 char 값에만 사용됩니다. 큰 따옴표는 문자열에 사용됩니다. 이에 대해 나중에 배우게 될 것입니다.

char은 특별히 유용한 유형이 아닌 것으로 보입니다. 왜냐하면 단일 문자에 할당된 변수가 필요하지 않을 가능성이 높기 때문입니다. 그러나 char은 기본적으로 String과 같은 문자열 클래스의 구성 요소로 사용됩니다. 이러한 클래스들은 기본적으로 char 값의 모음입니다.

이 섹션에서 본 것처럼 기본 유형 변수의 선언과 사용은 정수와 같은 간단한 값들을 나타내기 때문에 간단합니다. 이러한 값들은 사용할 준비가 되어 있으며 객체를 생성하거나 메서드를 호출하는 등의 추가 작업이 필요하지 않습니다.

참조 유형

이 시리즈의 첫 번째 자습서인 자바에서 첫 번째 프로그램을 작성하는 방법에서 Java 코드가 클래스로 구성되고 이러한 클래스가 객체를 생성하는 템플릿으로 사용됨을 배웠습니다. 이러한 객체들이 변수에 할당될 때, 여러분은 이러한 객체를 가리키거나 참조합니다. 이러한 경우에 변수는 참조 유형으로 분류됩니다. 이러한 변수는 기본 유형 변수가 객체를 가리킬 수 없기 때문에 비 기본이라고도 알려져 있습니다.

객체는 고급 속성을 가지고 있으며, 해당 메서드를 트리거하면 작동할 수 있기 때문에 강력합니다. 그러나, 변수가 그들을 가리키지 않으면 이러한 객체들은 접근할 수 없고 거의 사용할 수 없습니다. 이것이 Java 및 객체 지향 프로그래밍 전체에 필수적인 참조 유형 변수입니다.

참고: 참조 유형은 클래스에서 생성된 객체를 가리킵니다. 혼란을 피하기 위해 다음 예제에서 참조 유형과 생성된 객체는 동일한 클래스일 것입니다.

그러나 복잡한 프로그램에서는 이런 경우가 거의 없습니다. Java에서 인터페이스는 특정 동작에 대한 요구 사항 그룹이며, 이러한 요구 사항은 하나 이상의 클래스에 의해 충족될 수 있습니다. 인터페이스의 요구 사항을 충족하는 클래스는 이 인터페이스를 구현한다고 합니다. 따라서 복잡한 프로그램에서는 인터페이스의 참조 유형 변수를 선언하는 것이 일반적입니다. 이렇게 하면 변수가 구체적인 동작 구현에 묶이지 않고도 변수가 사용되는 방식을 변경하지 않고도 변수가 가리키는 구현을 쉽게 변경할 수 있습니다. 이 복잡한 개념은 Java 시리즈의 별도 튜토리얼로서 상속과 다형성에 관한 더 고급 주제의 일부입니다.

다음은 몇 가지 원시 유형만 있지만, 참조 유형은 클래스(및 인터페이스)의 수에 제한이 없으므로 사실상 무제한입니다. 각 클래스는 참조 유형을 나타냅니다. 자바에는 필수 기능을 제공하는 많은 내장 클래스가 있습니다. 가장 자주 사용되는 것들은 핵심 `java.lang` 패키지에 있습니다. 이 섹션에서 일부를 검토하겠습니다.

`String` 클래스

`String` 클래스는 문자의 조합을 나타냅니다. `String` 또는 다른 참조 유형 변수를 선언하려면 먼저 해당 유형을 지정한 다음 이름을 지정합니다. 그런 다음 등호를 사용하여 값을 할당합니다. 지금까지는 원시 유형으로 작업하는 것과 유사합니다. 그러나 참조 유형은 객체를 가리키므로 아직 객체가 생성되지 않았다면 객체를 생성해야 합니다. 다음은 예입니다:

String hello = new String("Hello");

`hello`는 참조 유형 `String`을 가진 변수의 이름입니다. 새 `String` 객체에 할당합니다. 새 `String` 객체는 `new` 키워드와 클래스 이름인 `String`과 함께 생성됩니다. 클래스 `String`은 대문자로 시작합니다. 관례상 모든 클래스 및 따라서 참조 유형은 대문자로 시작합니다.

각 클래스에는 새 객체를 만드는 데 사용되는 특별한 메서드인 생성자가 있습니다. 클래스 이름 끝에 괄호(())를 추가하여 이 생성자를 호출할 수 있습니다. 생성자는 매개변수를 받을 수 있으며, 예제에서와 같이 String에 대한 생성자에 "Hello" 매개변수가 적용된 것처럼요.

예상대로 hello 변수가 작동하는지 확인하려면 다음과 같이 println 메서드에 다시 전달하십시오:

  1. String hello = new String("Hello");
  2. System.out.println(hello);

jshell에서 이러한 라인을 실행하면 다음과 같은 출력이 생성됩니다:

Output
hello ==> "Hello" Hello

이번에는 출력이 hello 변수가 Hello로 설정되었음을 확인합니다. 그 후에는 동일한 Hello가 새로운 줄에 인쇄되어 println() 메서드가 그것을 처리했음을 확인합니다.

래퍼 클래스

이전 섹션에서는 자주 사용되는 String 참조 유형을 다루었습니다. 다른 인기 있는 참조 유형은 기본 유형의 래퍼입니다. 래퍼 클래스는 기본 데이터를 래핑하거나 포함하기 때문에 그 이름이 지어졌습니다. 모든 기본 유형에는 래퍼 상응물이 있으며, 여기에 몇 가지 예가 있습니다:

  • Integer: int 값을 래핑합니다.
  • Character: char 값을 래핑합니다.
  • Boolean: boolean 값을 래핑합니다.

이러한 래퍼는 간단한 원시 값에서 강력한 객체로 업그레이드 할 수 있도록 존재합니다. 각 래퍼에는 해당 값을 저장하기 위해 설계된 준비된 메서드가 있습니다.

예를 들어, Integer를 살펴보겠습니다. 이전 섹션에서 new 키워드를 사용하여 String 객체를 만들었습니다. 그러나 일부 클래스는 객체를 얻기 위해 특수한 메서드를 제공하며, 사용을 권장하기도 합니다. Integer도 그 중 하나입니다. Integer의 경우, 특수한 메서드를 사용하는 것은 주로 리소스 최적화와 관련이 있지만, 다른 경우에는 복잡한 객체를 구성하는 것을 단순화하기 위함일 수도 있습니다.

다음 예제에서는 valueOf 메서드를 사용하여 값을 42로 가지는 Integer 변수인 theAnswer를 생성합니다:

  1. Integer theAnswer = Integer.valueOf(42);
  2. System.out.println(theAnswer);

jshell에서는 다음과 같은 출력을 받게 됩니다:

Output
theAnswer ==> 42 42

Integer 메서드 valueOf(42)를 호출하여 Java에게 해당 값을 가진 객체를 반환하도록 지시합니다. 자바는 내부적으로 해당 값과 일치하는 객체가 이미 캐시에 있는지 확인합니다. 있다면, 해당 객체가 theAnswer 변수에 연결됩니다. 그렇지 않으면, 새로운 객체가 theAnswer 변수에 생성됩니다.

많은 내장 클래스들은 성능상의 이유로 이러한 메서드를 제공하며, 사용을 권장하거나 필수적으로 사용해야 합니다. Integer의 경우, 여전히 new 키워드를 사용하여 객체를 생성할 수 있지만, 경고 메시지가 표시됩니다.

또한 String 및 래퍼(wrapper) 외에도 유용한 내장 참조 유형이 있습니다. 이러한 유형은 java.lang 패키지 개요에서 찾을 수 있습니다. 이러한 고급 참조 유형 중 일부를 완전히 이해하기 위해서는 추가 설명이나 사전 지식이 필요합니다. 따라서 우리는 다음 자바 시리즈 강좌에서 이들 중 일부를 다룰 것입니다.

Literals

리터럴은 코드에서 직접 사용할 수 있는 고정된 값으로, 원시 및 참조 유형 양쪽에 모두 할당할 수 있습니다. 다음과 같이 분류할 수 있는 몇 가지 유형의 리터럴이 있습니다.

Primitive Type Literals

이미 원시 유형 섹션에서 몇 가지 리터럴을 사용했습니다. 각 원시 유형에는 예제에서 보았던 것과 같이 리터럴이 있습니다: 42, 'a', true 등입니다. 42와 같은 정수는 정수 리터럴입니다. 마찬가지로 'a'와 같은 문자는 문자 리터럴이며, truefalse은 부울 리터럴입니다.

기본 유형 리터럴은 참조 유형의 값을 만드는 데 사용될 수 있습니다. int 리터럴은 코드 Integer.valueOf(42)를 사용하여 Integer 객체를 생성하는 데 사용되었습니다. 이에 대한 단축형도 있으며, 다음과 같이 값을 직접 할당할 수 있습니다:

Integer theAnswer = 42;

42는 정수 리터럴로, 다른 정수와 마찬가지로 theAnswer 변수에 추가적인 문장없이 직접 할당할 수 있습니다. 이것은 편리하기 때문에 종종 이렇게 Integer를 선언하는 것을 볼 수 있습니다.

이 단축형 접근 방식은 다른 기본 유형 리터럴 및 해당 상대 참조 유형에 대해 작동합니다. 예를 들어 Boolean에 대한 true와 같은 것도 있습니다:

Boolean isFun = true;

true는 리터럴이며, 이는 Boolean 유형의 isFun 변수에 직접 할당됩니다. 이와 같이 할당할 수 있는 false 리터럴도 있습니다.

문자열 리터럴

String 참조 유형에 대한 특별한 리터럴도 있으며, 그 값 주위에 있는 이중 인용부호로 인식됩니다. 이 예에서는 "Hello, World!"입니다:

String helloWorld = "Hello, World!";

리터럴을 사용하는 것이 간단하고 짧으며, 이것이 많은 프로그래머들이 선호하는 이유입니다. 그러나 참조 유형에 대한 섹션에서 이미 수행한 것처럼 String 변수를 새 String 객체로 선언할 수도 있습니다.

null 리터럴

하나 더 중요한 리터럴이 있습니다: null은 값의 부재나 객체의 비존재를 나타냅니다. null을 사용하면 객체를 가리키는 대신 null을 가리키도록 참조 유형을 만들 수 있습니다. null은 모든 참조 유형에 사용할 수 있지만 기본 유형에는 사용할 수 없습니다.

  1. String initiallyNullString = null;
  2. System.out.println("The class name is: " + initiallyNullString.getClass());

Output
initiallyNullString ==> null | Exception java.lang.NullPointerException | at (#4:1)

참고: 간단하게, 우리는 java.lang.NullPointerException을 기술적으로는 예외라고 하지만 에러로 표현합니다. 예외와 에러에 대한 자세한 내용은 자바 예외 처리 튜토리얼을 확인하세요.

오류를 해결하려면 다음과 같이 initiallyNullString 값을 다시 할당해야 합니다:

  1. String initiallyNullString = null;
  2. initiallyNullString = "not null any longer";
  3. System.out.println("The class name is: " + initiallyNullString.getClass());

수정된 새 코드는 다음 출력을 출력합니다:

Output
initiallyNullString ==> null initiallyNullString ==> "not null any longer" The class name is: class java.lang.String

위의 출력은 initiallyNullString이 처음에는 null이었다가 나중에 "not null any longer"을 포함하는 새 String 객체가 되는 방법을 보여줍니다. 그 다음, 인스턴스화된 객체에서 getClass() 메서드를 호출하면 java.lang.String을 얻게 되는데, 여기서 String은 클래스 이름이고 java.lang은 해당 패키지입니다. 마지막으로, 전체적이고 의미 있는 메시지가 출력됩니다: "The class name is: class java.lang.String".

이러한 null 값 선언은 레거시 코드에서 더 흔합니다. 이전에 변수를 생성한 다음 나중에 실제 값을 할당하는 데 사용되었습니다. 일반적으로 후자를 결정하는 논리를 거칩니다. 그러나 Java 버전 8부터는 Optional이라는 새로운 참조 유형이 있으며, 이것이 이전에 null이 사용된 경우에 더 적합합니다.

로컬 변수 형식 추론

지금까지 Java에서 변수를 정의하기 위해 일반적인 데이터 유형을 사용해 왔습니다. 그러나 Java 10에서는 로컬 변수 유형 추론이라는 새로운 기능을 소개했으며, 이 기능을 사용하면 새 변수 앞에 키워드 var를 사용할 수 있습니다. 이 기능을 사용하면 Java가 (즉, 자동으로 추측하는) 데이터 유형을 로컬 컨텍스트에서 추론합니다. 유형 추론은 변수 정의의 상세함과 대조되기 때문에 논쟁의 여지가 있습니다. 이러한 기능의 장단점은 논쟁의 여지가 있지만, C++과 같은 다른 정적 유형 언어에서는 유형 추론을 지원합니다.

어쨌든, 유형 추론은 메서드 내부에 있는 로컬 변수에만 작동하기 때문에 데이터 유형의 사용을 완전히 대체할 수 없습니다. var을 사용한 예제를 살펴보겠습니다:

  1. var hello = "Hello";
  2. System.out.println(hello);

var 키워드를 사용하여 변수 hello를 선언하여 Java가 해당 데이터 유형을 감지하도록 지시합니다. 그 후에는 기존 방식으로 콘솔에 출력하여 예상대로 작동하는지 확인합니다:

Ouput
hello ==> "Hello" Hello

이 예제는 Java 설치(더 구체적으로 JDK)가 버전 10보다 최신인 경우에만 작동합니다. var 키워드는 이전 버전에서 지원되지 않습니다.

유형 추론은 컴파일 프로세스 중에 발생합니다. 즉, 코드를 컴파일할 때 발생합니다. 컴파일 프로세스는 일반 텍스트 소스 코드를 기계 코드로 변환하고 유형 추론을 포함한 다양한 최적화를 적용합니다. 이를 통해 유형 추론된 변수에 대한 올바른 시스템 메모리 양이 사용 가능해집니다. 따라서 컴파일 후 실행되는 기계 코드는 모든 데이터 유형을 수동으로 지정한 것처럼 완전히 최적화됩니다.

이 예에서 var 키워드가 작동하는 이유는 변수가 지역 변수이기 때문이며, var 데이터 유형이 지역 변수와 함께만 작동하기 때문입니다. 지역 변수는 메서드 내에서 정의되며 메서드 내에서만 접근할 수 있으며, 이것이 그들을 “지역”이라고 부르는 이유입니다.

var가 지역 변수에만 사용될 수 있다는 것을 보여주기 위해 메인 메서드 외부에 배치하여 시도해보세요:

  1. public class Hello {
  2. var hello = "Hello";
  3. public static void main(String[] args) {
  4. // example code
  5. }
  6. }

위의 코드를 jshell에 붙여넣으면 다음 오류가 발생합니다:

Output
| Error: | 'var' is not allowed here | var hello = "Hello"; | ^-^

hello가 메서드 외부에 있고 더 이상 지역 변수로 간주되지 않기 때문에 거기에 var를 사용할 수 없습니다. 따라서 컨텍스트를 신뢰할 수 없기 때문에 비지역 변수에 대해서는 유형 추론이 작동하지 않습니다.

var를 사용하는 것은 도전적일 수 있고 필수적이지는 않지만, 아마도 마주치게 될 것이므로 알고 있는 것이 유용합니다.

예약된 키워드

Java에서 변수를 선언할 때, 알아두어야 할 중요한 규칙이 하나 더 있습니다. 변수 이름으로 사용할 수 없는 예약 키워드가 있습니다. 예를 들어, int 유형의 원시형을 new라고 이름 짓을 수는 없습니다. 이런 식으로:

  1. int new = 1;

이 예제를 시도하면 컴파일 오류가 발생합니다. 왜냐하면 new는 예약된 키워드이기 때문입니다.

Output
| Error: | '.class' expected | int new = 1; | ^ | Error: | <identifier> expected | int new = 1; | ^ | Error: | '(' or '[' expected | int new = 1; | ^ | Error: | unexpected type | required: value | found: class | int new = 1; | ^--^ | Error: | missing return statement | int new = 1; | ^----------^

new 키워드는 새로운 객체를 생성하는 데 사용되며, Java는 이 위치에서 이를 기대하지 않습니다. 이전 출력의 오류 목록에서 첫 번째 부분이 가장 중요합니다:

Output
| Error: | '.class' expected | int new = 1; | ^

오류 '.class' expectednew 키워드를 사용할 때 Java가 클래스를 기대한다는 것을 의미합니다. 이 시점에서 Java는 문을 해석할 수 없으며 나머지 오류가 이어집니다.

abstract, continue, default, for, break 등의 나머지 예약 키워드도 Java에서 특정 의미를 가지고 있으며 변수 이름으로 사용할 수 없습니다. 예약된 키워드의 전체 목록은 Java 언어 키워드 페이지에서 확인할 수 있습니다. 모든 예약 키워드를 기억하지 못해도 컴파일 오류를 사용하여 문제를 식별할 수 있습니다.

결론

이 튜토리얼에서는 Java의 기본 및 참조 데이터 유형에 대해 배웠으며, 이는 복잡하지만 필수적인 주제입니다. 여유롭게 연습하고 예제를 여러 번 통과하세요. 데이터 유형과 값 중 일부를 변경해 보세요. 코드가 성공적으로 실행되는 경우와 그렇지 않은 경우에 오류가 발생하는 시점에 주의를 기울여 성공적인 코드 실행에 대한 감각을 키우세요.

Java에 대한 더 많은 정보는 How To Code in Java 시리즈를 확인하세요.

Source:
https://www.digitalocean.com/community/tutorials/understanding-data-types-in-java