회고록 블로그

[공부 필기] Java 기본 공부하기 (11) 본문

2. 프로그래밍 언어 공부/Java

[공부 필기] Java 기본 공부하기 (11)

김간장 2021. 10. 27. 20:29

공부 중인 강의 : 윤성우 선생님, 윤성우의 열혈 Java 프로그래밍 강의.

링크 : https://cafe.naver.com/cstudyjava

 

윤성우의 프로그래밍 스터디그룹 [C/... : 네이버 카페

윤성우의 스터디 공간입니다. C와 JAVA를 공부하시는 분들은 모두 들어오세요. ^^

cafe.naver.com

 

Java 강의 자체는 노잼이지만, 윤성우 선생님은 정말 잘 가르쳐 주시는 듯 하다.

 


1. 콘솔 출력

- 콘솔(console)?

   간단하게 컴퓨터의 입출력을 담당하는 장치들 (키보드, 모니터 등)이라고 해석할 수 있을 것 같음

- 관련 메소드로는 System.out.print 등이 있음

 

1.1. [출력] println메소드(또는 print 메소드)에 대해서 알아둘 사실 한가지!

   → 두 코드는 같은 결과를 출력함

...
public static void main(String args[]) {
	StringBuilder school = new StringBuilder("University");
	school.insert(0, "Seoul");
		
	System.out.println(school.toString());	// 1번. 출력결과 SeoulUniversity
	System.out.println(school);		// 2번. 출력결과 SeoulUniversity
...

   → 이러한 결과가 출력 가능한 이유는 println이 StringBuilder 인스턴스의 참조값을 바탕으로 toString 메소드를 호출해오기 때문

         * StringBuilder 인스턴스의 참조변수는 school (참조변수에는 '참조값'이 저장되어 있음)

         * 2번 코드에서는 참조변수 school을 println 메소드의 인자값으로 전달해주었음

         * 즉, println은 StringBuilder 인스턴스의 참조값을 인자로 받은 상태임

         * 이때 println 메소드는 이 전달받은 참조값을 바탕으로 해당 StringBuilder 인스턴스의 toString 메소드를 호출함

            (println은 StringBuilder의 수많은 메소드 중에서도 굳이 toString 메소드를 기본적으로 호출해옴)

 

1.2. [출력] StringBuilder 인스턴스만 해당되는 이야기일까?

- 아님

- 개발자가 직접 클래스를 만들고, 그 안에 toString 메소드를 정의해도 결과는 마찬가지

public class Quote {
	private String sentence;
	
	Quote(String sentence) {
		this.sentence = sentence;
	}
	public String toString() {
		return this.sentence;
	}
}
public class MainMethod {
	public static void main(String args[]) {
		Quote q = new Quote("늦었다고 생각할 때가 진짜 너무 늦었다");
		
		System.out.println(q.toString());
		System.out.println(q);
	}
}

- 여기에서 print(혹은 println) 메소드는 객체(참조값)를 인자로 받았을 때, 기본적으로 인스턴스의 toString을 호출해온다는 것을

   알 수 있음 (자동으로 toString을 호출해오기로 약속되어 있음)

- 참고로 위의 코드는 toString 메소드를 재정의한 것임

 

1.3. [출력] 만약 toString 메소드가 정의되어 있지 않다면?

- 개발자가 클래스를 만드는데 안에 toString 메소드를 정의하지 않았거나

   toString 메소드가 명시적으로 정의되어 있지 않는 인스턴스를 생성했다면?

public class Quote {
	private String sentence;
	
	Quote(String sentence) {
		this.sentence = sentence;
	}
	/* public String toString() {
		return this.sentence;
	} */
    // toString 메소드를 주석처리해봄
}
public class MainMethod {
	public static void main(String args[]) {
		Quote q = new Quote("늦었다고 생각할 때가 진짜 너무 늦었다");
		
		System.out.println(q.toString());
		System.out.println(q);
	}
}

- 에러는 발생하지 않음

   → 보통 메소드가 정의되어 있지 않으면, not defined 에러가 발생할텐데

         toString 메소드는 (명시적으로) 정의되지 않았어도 에러가 발생하지 않았음

   → 다만 기대했던 결과(문장)가 출력되지는 않음 (그 이유는 바로 아래에서 설명)

실행결과

- 이는 모든 클래스에는 toString이 기본적으로 정의되어 있기 때문에 가능한 결과

   → 나중에 "상속" 단원에서 배우게 됨

        * 간단히 설명하면 Java의 클래스들에게는 최상위 부모가 있음

        * 그 부모의 이름은 Object 클래스

        * 이 최상위 부모에게는 toString 이라는 메소드가 기본적으로 정의되어 있는데

           자식들(자식 클래스)은 자신의 내부에 toString 메소드가 별도로 정의되어 있지 않다면(= 재정의 되지 않았다면)

           최상위 부모가 가진 toString 메소드를 호출해옴

최상위 부모인 Object 클래스 내부에 있는 toString 메소드

          * 아까 위의 코드에서 기대했던 결과(문장)가 출력되지 않았던 이유는

             최상위 부모 클래스에 정의되어 있는 toString 메소드가 "클래스의 이름 + 해시코드"를 출력하도록 정의되어 있기 때문

어쨌든 여기에서 중요한 사실은
1) print/println 메소드는 자신의 인자값으로 인스턴스(참조값)를 받으면
     해당 인스턴스 안에 정의되어 있는 toString 메소드를 자동으로 호출해와서 출력해주며

2) 클래스 내부에 toString 메소드가 정의되어 있지 않다면
    (그들의 부모인) 최상위 부모 클래스(Object)에 정의되어 있는 toString 메소드를 호출해온다는 사실

 

1.4. 더 많은 출력 메소드

- 다양한 출력 메소드는 java.io.PrintStream 클래스를 확인해보기

PrintStream 메소드 내부 (메소드 오버로딩이 엄청난 것 같다)

 

2. 콘솔 입력

- 사용자(키보드 등)로부터 어떤 값을 입력받기 위해 필요한 클래스가 Scanner

- Scanner 클래스의 생성자를 보면 어떻게 쓰는지 알 수 있음

   → 파일(file)을 읽어올 수도 있고

   → 입력 스트림을 읽어올 수도 있고

   → 코드 안에 있는 String을 읽어올 수도 있음

 

참고 URL : https://docs.oracle.com/en/java/javase/16/docs/api/java.base/java/util/Scanner.html

 

Scanner (Java SE 16 & JDK 16)

All Implemented Interfaces: Closeable, AutoCloseable, Iterator A simple text scanner which can parse primitive types and strings using regular expressions. A Scanner breaks its input into tokens using a delimiter pattern, which by default matches whitespac

docs.oracle.com

 

2.1. [입력] Scanner는 기본적으로 "whitespace(여백)"를 기준으로 입력의 처음과 끝을 정함

- Java 공식 문서를 보면 알 수 있음

출처 : JDK 16버전 API Documentation

- 즉, "apple banana cinnamon"이라는 값을 입력 받으면 apple, banana, cinnamon 이라는 세개의 단어가 입력 받아지는 것

String word = "apple banana cinnamon";

java.util.Scanner scan = new java.util.Scanner(word); // String을 인자로 전달
System.out.println(scan.next()); // 출력결과 apple
System.out.println(scan.next()); // 출력결과 banana
System.out.println(scan.next()); // 출력결과 cinnamon

 

※ 참고로 위에서는 문자열을 하나씩 가져오고 싶어서 next 메소드를 사용했는데 nextInt, nextDouble 등 메소드도 있음

   → 처음에는 StringBuilder처럼 입력한 문자열을 toString 메소드로 가져올 수 있을 것이라 생각했지만 불가능했음

         * delimPattern, position, matchValid 등 정보를 출력해줌

   → 이러한 결과가 나오는 이유는 Scanner 클래스의 toString 메소드는 아래와 같이 정의되어 있기 때문에..

   → 또한 객체(위의 그림에서는 scan이 이에 해당함)를 println의 인자값으로 주면 scan.toString() 과 동일한 결과가 출력됨

         * 이는 위의 [출력]에서 배운 print/println 메소드가 인스턴스(참조값)를 인자로 받으면 toString 메소드를 자동 호출하는 특징 때문임

 

- 문자열의 처음과 끝을 "whitespace(여백)"이 아니라 다른 것으로 할 수도 있음

   → 이때 사용하는 메소드가 useDelimiter임

   → 더 정보가 필요하다면 Java API Documentation을 읽어보기를 추천(정말 공식 문서에는 다 있음)

delimiters가 \s*end\s* 로 바뀐 것을 알 수 있음

 

※ 참고사항. Scanner 인스턴스로 받은 문자열/입력값은 버퍼에 저장이 됨

   → java.util.Scanner 소스파일을 찾아서 생성자를 확인해보면 알 수 있음

        * Scanner의 생성자를 확인해보면, "source"라는 멤버 변수에 문자열/입력값을 대입하는 것을 알 수 있음

        * 이 "source"라는 멤버변수는 데이터 타입이 "Readable"임

        * java.lang.Readable 소스파일을 찾아보면 알 수 있지만, 이는 Chracter Buffer(문자 버퍼)임

 

2.2. [입력] 키보드로 값을 입력받고 싶을 때?

- 키보드로 값을 입력받고 싶을 때는 "System.in"을 사용함

   → System.in은 키보드 정보를 가지고 있음

   → 정확하게는 여기에서 "in"은 참조변수이고, 참조변수 "in"이 가리키고 있는 인스턴스에는 키보드 정보가 있음

   → 즉, Scanner 인스턴스가 키보드와 연결을 시도해서 연결을 성공하고 키보드로 입력된 값을 가져오는 것

변수 in은 InputStream 인스턴스의 참조변수임

- next* 메소드는 입력된 값을 가져옴

   → next 메소드는 입력된 값을 반환해주는 메소드임

   → next 메소드가 값을 반환하기 위해서는 입력이 먼저 완료되어야 함

   → 따라서, next 메소드가 두개라는 것은 String 입력을 두번 받겠다는 의미이기도 함

- 키보드는 미리 문자열이 저장되어 있지 않음

   → 실시간으로 사용자가 값을 입력해야함

   → 그렇기 때문에 키보드로 값이 입력이 안된 상태이면, 입력될 때까지 대기상태가 됨

Scanner scan = new Scanner(System.in); // Scanner 인스턴스 생성

String value1 = scan.next(); // 키보드로 값이 입력될 때까지(Enter 누를 때까지) 여기에서 대기상태가 됨
String value2 = scan.next();
// next 메소드가 두개 이므로, 값이 두개 모두 입력될 때까지 대기 상태가 됨

System.out.println(value1);
System.out.println(value2);

- 결론적으로 정리를 하자면 아래와 같은 과정으로 값을 입력받고 출력해줌

   → 여백을 기준으로 총 두개의 데이터가 입력되면 됨        * 즉, 입력할 때 "apple[한칸 띄어쓰기 하고]banana"로 해도 되고 "apple[Ente키 누름]banana[Enter키 누름]"으로 해도 됨

정리

 

2.3. [입력] 파일에 들어있는 내용을 읽어오고 싶다면?

- next 메소드를 이용해서 입력된 값을 가져오는 것은 동일함

- Scanner 인스턴스를 생성하는 것도 동일함

- 다른 점이 있다면, Scanner 인스턴스의 인자값으로 "파일명"을 전달하느냐, "System.in"을 전달하느냐.

Comments