Java

Java - Scanner / (메모리 heap 영역)

wy-family 2024. 11. 23. 04:35

Scanner 클래스는 Java에서 표준 입력 (키보드 입력)을 처리하기 위해 제공되는 유틸리티 클래스입니다. 주로 사용자가 데이터를 입력할 수 있도록 설계된 프로그램에서 사용됩니다. java.util 패키지에 포함되어 있으며, 다양한 데이터 타입의 입력을 처리할 수 있습니다.


1. Scanner 클래스의 기본 개념

  • Scanner는 Java의 표준 입력 스트림(System.in)을 통해 데이터를 읽습니다.
  • 사용자가 입력한 문자열을 파싱하여 원하는 데이터 타입으로 변환할 수 있습니다.
  • 공백(스페이스, 탭, 줄바꿈) 단위로 데이터를 구분하여 입력을 처리합니다.

2. Scanner 클래스 사용법

기본 구조

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        // Scanner 객체 생성
        Scanner scanner = new Scanner(System.in);

        // 정수 입력받기
        System.out.print("정수를 입력하세요: ");
        int num = scanner.nextInt();
        System.out.println("입력된 정수: " + num);

        // 문자열 입력받기
        System.out.print("문자열을 입력하세요: ");
        String str = scanner.next();
        System.out.println("입력된 문자열: " + str);

        // Scanner 객체 닫기
        scanner.close();
    }
}

3. 주요 메서드

Scanner 클래스는 입력 데이터를 다양한 타입으로 읽기 위한 여러 메서드를 제공합니다.

메서드설명예시

nextInt() 정수를 입력받습니다. int num = scanner.nextInt();
nextDouble() 실수를 입력받습니다. double num = scanner.nextDouble();
nextLine() 한 줄의 문자열을 입력받습니다. String line = scanner.nextLine();
next() 공백을 기준으로 한 단어를 입력받습니다. String word = scanner.next();
hasNextInt() 다음 입력값이 정수인지 확인합니다. if(scanner.hasNextInt())
hasNextDouble() 다음 입력값이 실수인지 확인합니다. if(scanner.hasNextDouble())
hasNextLine() 다음 줄이 존재하는지 확인합니다. if(scanner.hasNextLine())

4. 주요 특징과 유의점

1) next() vs nextLine()

  • next()는 공백(스페이스, 탭, 줄바꿈)을 기준으로 한 단어를 읽습니다.
  • nextLine()은 줄바꿈을 포함하여 한 줄 전체를 읽습니다.
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        System.out.print("next() 사용: ");
        String word = scanner.next();
        System.out.println("입력된 단어: " + word);

        scanner.nextLine(); // 버퍼 비우기

        System.out.print("nextLine() 사용: ");
        String line = scanner.nextLine();
        System.out.println("입력된 줄: " + line);

        scanner.close();
    }
}

출력 예시:

next() 사용: Hello World
입력된 단어: Hello
nextLine() 사용: 입력된 줄: World

2) 입력 버퍼 문제

  • nextInt()와 nextLine()을 함께 사용할 때, nextInt() 뒤에 nextLine()을 호출하면 버퍼에 남아있는 줄바꿈 문자(\n) 때문에 문제가 발생할 수 있습니다.

해결 방법:

scanner.nextLine(); // 추가로 호출하여 버퍼를 비운다.

5. 실용적인 예제

정수와 문자열 입력

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        System.out.print("나이를 입력하세요: ");
        int age = scanner.nextInt();
        scanner.nextLine(); // 버퍼 비우기

        System.out.print("이름을 입력하세요: ");
        String name = scanner.nextLine();

        System.out.println("나이: " + age + ", 이름: " + name);

        scanner.close();
    }
}

여러 개의 데이터 읽기

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        System.out.println("공백으로 구분된 숫자 3개를 입력하세요:");
        int num1 = scanner.nextInt();
        int num2 = scanner.nextInt();
        int num3 = scanner.nextInt();

        System.out.println("입력된 숫자: " + num1 + ", " + num2 + ", " + num3);

        scanner.close();
    }
}

6. Scanner를 사용할 때의 주의점

  1. Scanner 객체 닫기
    • 프로그램이 끝날 때 scanner.close()를 호출하여 자원을 해제해야 합니다.
    • 단, System.in을 사용하는 경우 프로그램에서 다른 곳에서 입력을 처리한다면 close()를 호출하지 않는 것이 좋습니다.
  2. 입력 형식 오류
    • 사용자가 입력 형식에 맞지 않는 데이터를 입력하면 InputMismatchException이 발생할 수 있습니다.
    • 이를 방지하기 위해 hasNextInt()와 같은 메서드를 사용하여 데이터의 유효성을 먼저 확인하는 것이 좋습니다.

7. Scanner와 관련된 실생활 비유

  • Scanner는 키보드에서 입력을 읽는 스캐너 기계와 비슷합니다.
    • 스캐너가 책의 텍스트를 읽고 필요한 정보를 전달하듯, Scanner 클래스는 키보드에서 입력한 데이터를 읽고 원하는 형태로 변환합니다.

 

Scanner scanner = new Scanner(System.in);

 

이 한 줄의 코드는 Java에서 표준 입력(주로 키보드 입력)을 처리하기 위해 사용되는 문장입니다. 이 문장을 하나씩 분석해서 상세히 설명하겠습니다.


1. Scanner

(1) 클래스 이름

  • Scanner는 Java의 표준 라이브러리 중 하나로, 입력 데이터를 처리하는 데 사용되는 클래스입니다.
  • java.util 패키지에 포함되어 있으므로 import java.util.Scanner; 문이 필요합니다.

(2) 역할

  • 사용자로부터 입력받은 데이터를 읽어오고, 이를 다양한 데이터 타입(int, double, String 등)으로 변환할 수 있습니다.
  • 파일, 문자열 등 다양한 입력 소스도 처리할 수 있지만, 여기서는 키보드 입력(System.in)에만 집중합니다.

2. scanner

(1) 변수 이름

  • scanner는 Scanner 클래스의 객체를 참조하는 변수입니다.
  • 프로그래머가 자유롭게 이름을 정할 수 있으며, scanner는 관용적으로 많이 사용되는 이름입니다.

(2) 역할

  • scanner는 Scanner 객체를 메모리에 생성하고 이를 통해 입력 데이터를 처리할 수 있게 합니다.
  • 이후 scanner.nextInt(), scanner.nextLine() 등의 메서드를 호출하여 입력 데이터를 읽습니다.

3. new

(1) 키워드

  • new는 Java에서 객체를 생성할 때 사용하는 키워드입니다.
  • 이 키워드는 메모리 힙(heap) 영역에 객체를 생성하고 해당 객체의 참조를 반환합니다.

(2) 역할

  • new Scanner(System.in)은 Scanner 클래스의 생성자를 호출하여 새로운 Scanner 객체를 만듭니다.

4. Scanner(System.in)

(1) 생성자 호출

  • Scanner 클래스의 생성자는 다양한 입력 소스를 처리할 수 있도록 설계되어 있습니다.
  • 이 경우, System.in을 매개변수로 전달하여 표준 입력 스트림(키보드 입력)을 입력 소스로 사용하는 객체를 생성합니다.
public Scanner(InputStream source) {
    // 표준 입력 소스를 초기화하는 코드
}

(2) System.in

  • 표준 입력 스트림으로, 키보드로부터 입력 데이터를 받을 수 있습니다.
  • Java의 System 클래스는 표준 입출력을 처리하는 정적 멤버를 제공합니다:
    • System.out : 표준 출력 스트림 (화면에 출력)
    • System.err : 표준 에러 스트림 (에러 메시지 출력)
    • System.in : 표준 입력 스트림 (키보드 입력 처리)

전체 흐름

1) 메모리 관점

  • Scanner scanner 선언: 메모리에 참조 변수를 생성합니다.
  • new Scanner(System.in): 힙 영역에 Scanner 객체를 생성하고, 입력 소스로 System.in을 설정합니다.
  • scanner 변수: 생성된 Scanner 객체를 참조합니다.

2) 실행 순서

  1. System.in이 Scanner 생성자의 매개변수로 전달됩니다.
  2. Scanner 객체는 System.in을 입력 소스로 사용하는 준비를 마칩니다.
  3. 이후 scanner.nextInt()와 같은 메서드를 호출하여 사용자가 입력한 데이터를 읽습니다.

비유로 설명

  • Scanner: 데이터(입력)를 읽는 장치. 키보드로 입력된 데이터를 스캔합니다.
  • scanner: 스캐너 기계를 참조하는 리모컨. 이 리모컨으로 명령(nextInt(), nextLine())을 내립니다.
  • new: 새로운 스캐너를 가져오는 주문서. 메모리에 새로운 스캐너를 요청합니다.
  • System.in: 스캐너가 데이터를 읽을 책. 여기서는 키보드 입력이 데이터의 소스입니다.

코드 예제로 확인

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        // Scanner 객체 생성
        Scanner scanner = new Scanner(System.in);

        // 정수 입력
        System.out.print("정수를 입력하세요: ");
        int number = scanner.nextInt();
        System.out.println("입력된 정수: " + number);

        // 문자열 입력
        scanner.nextLine(); // 버퍼 비우기
        System.out.print("문자열을 입력하세요: ");
        String text = scanner.nextLine();
        System.out.println("입력된 문자열: " + text);

        // Scanner 객체 닫기
        scanner.close();
    }
}

실행 예시

정수를 입력하세요: 25
입력된 정수: 25
문자열을 입력하세요: Hello World
입력된 문자열: Hello World

추가로 알아두면 좋은 내용

1. Scanner는 버퍼를 사용

  • Scanner는 입력 데이터를 버퍼라는 임시 저장 공간에 저장한 후 처리합니다.
  • 여러 입력 메서드를 섞어서 사용할 때 버퍼에 남아 있는 데이터를 주의해야 합니다.

2. Scanner를 닫아야 하는 이유

  • scanner.close()는 System.in 스트림을 닫습니다.
  • 입력 처리가 끝난 후 스트림을 닫는 것은 자원을 효율적으로 관리하기 위함입니다.

이 키워드는 메모리 힙(heap) 영역에 객체를 생성하고 해당 객체의 참조를 반환합니다.
이 말이 무슨 말인지?

이 문장은 new 키워드의 역할을 설명한 것입니다. Java에서 new 키워드는 객체를 생성할 때 사용하는 키워드이며, 객체가 메모리의 특정 영역인 힙(heap) 영역에 생성된다는 것을 의미합니다. 아래에서 하나씩 상세히 설명하겠습니다.


1. 힙(heap) 영역이란?

  • 힙 메모리는 Java 프로그램 실행 중에 **런타임(runtime)**에 동적으로 생성된 객체를 저장하는 메모리 영역입니다.
  • JVM(Java Virtual Machine)의 메모리 영역은 보통 크게 나뉩니다:
    1. 스택(stack):
      • 메서드 호출, 지역 변수, 참조 변수 등을 저장.
      • 빠르게 할당되고 해제되며, 메모리 크기가 고정적.
    2. 힙(heap):
      • 객체와 배열이 저장되는 동적 메모리 영역.
      • 객체는 필요하지 않을 때까지 힙에 남아 있으며, **가비지 컬렉터(Garbage Collector)**에 의해 자동으로 제거됩니다.

2. new 키워드의 역할

(1) 객체 생성

  • new 키워드는 힙 영역에 객체를 생성합니다.
  • 이 객체는 클래스의 **생성자(Constructor)**를 호출하여 초기화됩니다.

(2) 참조 반환

  • new 키워드는 생성된 객체의 **메모리 주소(참조값)**를 반환합니다.
  • 이 참조값은 변수(예: scanner)에 저장되며, 이후 이 변수로 해당 객체에 접근할 수 있습니다.

3. 과정 상세히 분석

예제 코드

Scanner scanner = new Scanner(System.in);

위 코드를 실행하면 다음 단계를 거칩니다:

  1. 힙 영역에 객체 생성
    • new Scanner(System.in)을 호출하면 Scanner 클래스의 객체가 힙(heap) 메모리 영역에 생성됩니다.
  2. 참조값 반환
    • 생성된 객체의 메모리 주소(참조값)가 반환됩니다.
  3. 참조 변수에 저장
    • 반환된 참조값이 scanner 변수에 저장됩니다.
    • 이제 scanner를 통해 힙에 있는 Scanner 객체에 접근할 수 있습니다.

4. 힙 메모리와 스택 메모리의 역할

예제 코드의 메모리 구조

Scanner scanner = new Scanner(System.in);
  • 스택(stack):
    • scanner라는 변수는 스택 메모리에 저장됩니다.
    • 이 변수는 힙에 생성된 Scanner 객체의 참조값을 저장합니다.
  • 힙(heap):
    • new Scanner(System.in)에 의해 힙 메모리에 Scanner 객체가 생성됩니다.
    • 이 객체는 키보드 입력을 처리할 수 있도록 초기화됩니다.

시각적 구조:

스택 메모리                     힙 메모리
+----------------+              +-----------------+
| scanner        | ----->       | Scanner 객체    |
+----------------+              +-----------------+

5. 객체가 사라지는 시점

가비지 컬렉션(Garbage Collection)

  • Java에서는 프로그래머가 직접 메모리를 관리하지 않고, **가비지 컬렉터(GC)**가 사용되지 않는 객체를 자동으로 제거합니다.
  • 참조 변수(scanner)가 더 이상 객체를 참조하지 않으면 해당 객체는 **가비지(garbage)**로 간주되고, 힙에서 제거됩니다.
scanner = null; // 참조를 끊음
// 이후 가비지 컬렉터가 힙 메모리에서 Scanner 객체를 제거

6. 비유로 이해

  • new는 공장에서 새 제품을 만드는 과정과 같습니다.
    1. 공장에서 새 제품(객체)을 만들면, 창고(힙 메모리)에 저장됩니다.
    2. 물류 센터(스택 메모리)는 이 제품의 위치(참조값)를 기억합니다.
    3. 프로그램이 끝나거나 더 이상 사용하지 않으면 청소부(가비지 컬렉터)가 창고에서 이 제품을 치웁니다.

7. 결론

new 키워드는:

  1. 힙 메모리에 새로운 객체를 생성합니다.
  2. 객체의 참조값(메모리 주소)을 반환합니다.
  3. 반환된 참조값은 참조 변수(예: scanner)에 저장되어 객체에 접근할 수 있게 합니다.