[TIL] 10. java 입출력, 반복문, String 과 static

MinseoKim·2026년 8월 12일
post-thumbnail

1. 오늘의 한 줄 요약

오늘은 Java의 String, 반복문, staticnon-static을 배웠다.

지난 수업에서 클래스와 객체를 배운 뒤라 그런지 오늘은 문법만 외우는 것보다 이 값은 누가 가지고 있는지, 이 객체는 매번 새로 만들어야 하는지, 반복은 어떤 기준으로 돌려야 하는지를 생각하면서 코드를 보게 됐다.

특히 문자열 비교에서 ==.equals()가 다른 이유와 static이 클래스 소유라는 개념이 기억에 남았다.

마지막에는 오늘 배운 반복문과 Scanner를 사용해서 1~100 사이 숫자를 맞추는 게임도 직접 만들었다.


2. 배운 내용

1) String

문자열 비교는 ==가 아니라 .equals()

오늘 가장 먼저 본 코드는 문자열 비교였다.

String str01 = new String("lg cns");
String str02 = new String("lg cns");

if(str01 == str02) {
    System.out.println("str01 == str02");
}else {
    System.out.println("str01 != str02");
}

if(str01.equals(str02)) {
    System.out.println("str01.equals(str02)");
}else {
    System.out.println("str01.!equals(str02)");
}

결과는 다음과 같다.

str01 != str02
str01.equals(str02)

str01str02에는 똑같이 "lg cns"가 들어있는데 ==false가 나온다.

이유는 두 비교 방식이 확인하는 대상이 다르기 때문이다.

str01 == str02

는 두 변수가 같은 객체를 가리키는지 비교한다.

반면

str01.equals(str02)

는 문자열 안의 내용이 같은지 비교한다.

그래서 문자열의 값을 비교할 때는 .equals()를 사용해야 한다.


문자열 리터럴과 new String()

문자열을 만드는 방법에 따라서도 차이가 있다.

String str01 = "lg cns";
String str02 = "lg cns";

문자열 리터럴을 사용하면 Java는 이미 같은 문자열이 존재하는지 확인하고 같은 값을 재사용할 수 있다.

반면:

String str01 = new String("lg cns");
String str02 = new String("lg cns");

처럼 new를 사용하면 각각 새로운 String 객체가 만들어진다.

그래서 내용은 같아도 서로 다른 객체가 된다.

정리하면:

비교 방식확인하는 것문자열 비교에 적합한가
==같은 객체인지X
.equals()같은 값인지O

String은 immutable

Stringimmutable이라는 특징을 가진다.

즉 한 번 만들어진 문자열 자체가 수정되는 것이 아니다.

String str = "mnseokim";
str = str + "!!";

위 코드를 보면 기존 "mnseokim""!!"가 붙는 것처럼 보인다.

하지만 실제로는:

"mnseokim"
↓
새 문자열 생성
↓
"mnseokim!!"

처럼 새로운 문자열이 만들어지고 str이 그 값을 다시 가리킨다.

문자열을 계속 수정해야 하는 경우에는 StringBufferStringBuilder를 사용할 수 있다.

오늘은 StringBuffer를 사용했다.

StringBuffer sb = new StringBuffer(str01);

sb.append("!!");
sb.append("!!");
sb.append("!!");
sb.append("!!");

String s = sb.toString();

append()로 문자열을 이어 붙이고 마지막에 toString()으로 다시 String으로 변환할 수 있다.


문자열은 배열이 아니다

Java의 문자열은 배열이 아니기 때문에:

str[0]

처럼 사용할 수 없다.

특정 위치의 문자를 가져오려면 .charAt()을 사용한다.

String name = "minseo";

char first = name.charAt(0);

System.out.println(first);

결과:

m

문자열을 문자 단위로 접근할 수는 있지만 실제 배열과 동일한 자료형은 아니다.


2) 반복문

오늘은 for, while, do-while을 배웠다.

셋 다 반복을 위한 문법이지만 사용하는 상황이 조금씩 다르다.

반복문조건 확인 시점최소 실행 횟수언제 사용하는가
for실행 전0번반복 횟수를 알고 있을 때
while실행 전0번조건을 기준으로 반복할 때
do-while실행 후최소 1번무조건 한 번은 실행해야 할 때

for

반복 횟수가 정해져 있을 때 사용하기 좋다.

for(int i = 1; i <= 10; i++){
    System.out.println(i);
}

흐름은:

i = 1
↓
i <= 10 확인
↓
코드 실행
↓
i++
↓
다시 조건 확인

숫자 맞추기 게임처럼 기회가 정확히 10번인 경우 for가 잘 맞는다.


while

while은 조건이 참인 동안 계속 반복한다.

int data = 1;

while (data <= nan) {
    result += data;
    data++;
}

data <= nan이 참인 동안 실행된다.

조건이 처음부터 거짓이라면 한 번도 실행되지 않을 수 있다.


do-while

do-while은 코드를 먼저 실행한 뒤 조건을 확인한다.

do {
    result += data;
    data++;
} while(data <= nan);

그래서 조건이 처음부터 거짓이어도 최소 한 번은 실행된다.

일단 지금은 이렇게 기억하려고 한다.

while
→ 조건부터 확인

do-while
→ 일단 한 번 실행하고 조건 확인

3) Static vs Non-Static

오늘 가장 많이 생각했던 개념이다.

실습 코드는 다음과 같다.

public class StaticDemo {
    
    public String message = "인스턴스 소유의 변수";

    public static String staticMessage = "클래스 소유의 변수";

    public static final double PI = 3.14;
    
    public StaticDemo(){
        
    }
}

사용하는 쪽에서는:

public static void main(String[] args) {

    StaticDemo demo = new StaticDemo();

    System.out.println(demo.message);

    // StaticDemo.message;
    // error

    System.out.println(StaticDemo.staticMessage);
}

가장 중요한 차이는 누가 이 값을 가지고 있는가였다.


Non-Static

public String message = "인스턴스 소유의 변수";

static이 붙지 않은 값은 각 객체가 가지고 있다.

그래서 먼저 객체를 만든다.

StaticDemo demo = new StaticDemo();

그리고:

demo.message

처럼 접근한다.

즉:

클래스
↓
new
↓
객체 생성
↓
객체가 자신의 값 보유

이다.


Static

public static String staticMessage = "클래스 소유의 변수";

static이 붙으면 객체가 아니라 클래스가 가지고 있는 값이다.

그래서 객체를 만들지 않고:

StaticDemo.staticMessage

처럼 클래스 이름으로 바로 접근할 수 있다.

정리하면:

non-static
→ 객체 소유

static
→ 클래스 소유

왜 static에서는 instance에 바로 접근할 수 없을까?

static은 객체를 만들기 전에도 사용할 수 있다.

하지만 instance 멤버는 실제 객체가 생성돼야 존재한다.

new StaticDemo();

가 실행되기 전에는 어떤 message를 가리켜야 하는지 정할 수 없다.

반대로 객체가 만들어진 시점에는 static 멤버가 이미 존재하므로 instance에서 static에 접근하는 것은 가능하다.

지금은 이렇게 이해했다.

static
→ 먼저 존재 가능

instance
→ new 이후 존재

그래서:

instance → static
가능

static → instance
바로 접근 불가능

이다.


static final

public static final double PI = 3.14;

staticfinal은 서로 다른 의미다.

static
→ 누구 소유인가?

final
→ 값을 다시 바꿀 수 있는가?

둘을 같이 사용하면 클래스 전체에서 하나만 존재하고 값도 다시 바꿀 수 없는 상수가 된다.

상수는 보통 대문자로 작성한다.

PI
MAX_SIZE
DEFAULT_VALUE

3. 실습 (과제 코드 리뷰)

오늘 배운 내용을 이용해서 숫자 맞추기 게임을 만들었다.

조건은 다음과 같다.

1~100 사이 난수 생성

기회는 총 10번

입력한 값이 정답보다 크면
→ down

작으면
→ up

정답이면
→ "x번째 정답을 맞췄습니다"

10번 모두 실패하면
→ "10번의 기회를 모두 사용하였습니다."

GuessGameApp.java

import features.game.GuessGame;

public class GuessGameApp {

    public static void main(String[] args) {

        GuessGame game = new GuessGame();

        String result = game.gameFor();

        System.out.println(result);
    }
}

지난번에 배운 객체 개념도 자연스럽게 다시 사용했다.

GuessGame game = new GuessGame();

GuessGame 객체를 만들고:

game.gameFor();

객체가 가진 gameFor() 메서드를 호출한다.

반환 타입이 String이기 때문에:

String result = game.gameFor();

로 결과를 받을 수 있다.


GuessGame.java

package features.game;

import java.util.Scanner;

public class GuessGame {

    public GuessGame(){

    }

    public String gameFor(){

        int answer = (int)(Math.random()*100) + 1;

        Scanner sc = new Scanner(System.in);

        String msg = "";

        for (int i = 1; i <= 10; i++){

            System.out.print(">>>> 생각하는 숫자를 입력하세요!");

            int guess = sc.nextInt();

            int num = i;

            if(guess > answer){

                System.out.println("down");

            }else if(guess < answer){

                System.out.println("up");

            }else{

                msg = String.format(
                    "%d번째 정답을 맞췄습니다",
                    num
                );

                break;
            }

            if(num == 10){

                msg = "10번의 기회를 모두 사용하였습니다.";
            }
        }

        return msg;
    }

    public String gameWhile(){

        // 미완

        return null;
    }

    public String gameDoWhile(){

        // 미완

        return null;
    }
}

난수 생성

int answer = (int)(Math.random()*100) + 1;

Math.random()을 사용해서 1~100 사이의 값을 만들었다.

현재는 이런 형태로 기억하려고 한다.

(int)(Math.random() * 범위) + 시작값

Scanner는 반복문 밖에 한 번만 생성

Scanner sc = new Scanner(System.in);

처음에는 입력을 받을 때마다 Scanner를 새로 만들어야 하나 싶었는데 역할이 달랐다.

new Scanner(System.in)

은 입력을 받을 통로를 만드는 것이다.

실제 입력은:

sc.nextInt();

로 받는다.

그래서:

Scanner sc = new Scanner(System.in);

for (...) {
    int guess = sc.nextInt();
}

처럼 한 번 만든 Scanner를 계속 사용하면 된다.

앞으로 객체를 반복문 안에 둘지 밖에 둘지 고민될 때는:

이 객체를 매 반복마다 새로 만들 이유가 있는가?

를 먼저 생각해볼 것 같다.


String.format()

몇 번째 시도에서 정답을 맞혔는지 문자열로 만들기 위해 사용했다.

msg = String.format(
    "%d번째 정답을 맞췄습니다",
    num
);

예를 들어 num3이면:

3번째 정답을 맞췄습니다

가 된다.

%d를 문자열에 그냥 넣는다고 값이 자동으로 들어가는 것은 아니고 String.format()을 사용해야 한다.


break

정답을 맞히면 더 이상 반복할 이유가 없다.

}else{

    msg = String.format(
        "%d번째 정답을 맞췄습니다",
        num
    );

    break;
}

break가 실행되면 현재 반복문을 바로 빠져나간다.

출력 결과


4. 개념 요약

오늘 배운 내용을 짧게 다시 정리하면 다음과 같다.

String 비교

str01.equals(str02);

문자열의 내용을 비교할 때는 .equals()를 사용한다.


String은 immutable

String str = "hello";
str = str + "!";

기존 문자열을 수정하는 것이 아니라 새로운 문자열이 만들어진다.

수정이 많다면 StringBufferStringBuilder를 사용할 수 있다.


문자 접근

str.charAt(0);

Java의 문자열은 배열이 아니기 때문에 str[0]을 사용할 수 없다.


반복문

for
→ 반복 횟수를 알 때

while
→ 조건을 기준으로 반복할 때

do-while
→ 무조건 한 번은 실행해야 할 때

Non-Static

demo.message

객체가 가지고 있는 값이다.


Static

StaticDemo.staticMessage

클래스가 가지고 있는 값이다.


Static Final

public static final double PI = 3.14;

클래스 소유이면서 값이 바뀌지 않는 상수다.


Scanner

Scanner sc = new Scanner(System.in);
int guess = sc.nextInt();

Scanner 객체는 한 번 만들고 입력 메서드는 반복해서 호출할 수 있다.


객체 생성 위치

매번 새로 만들 이유가 없다
→ 반복문 밖

매 반복마다 새로운 객체가 필요하다
→ 반복문 안

이 기준을 기억해두려고 한다.


5. 다음 해야 할 일

다음에는 오늘 만든 숫자 맞추기 게임을 그대로 두고 반복문만 바꿔서 다시 구현해볼 예정이다.

public String gameWhile(){

    // while 버전 구현

    return null;
}
public String gameDoWhile(){

    // do-while 버전 구현

    return null;
}

같은 기능을 for, while, do-while로 각각 작성해보면서 세 반복문의 차이를 코드로 익히고 싶다.

그리고 반복문은 문법만 봐서는 익숙해지기 어려운 것 같아서 간단한 코딩테스트 문제도 반복해서 풀어볼 생각이다.

특히 우선 익숙해지고 싶은 것은:

  • for로 범위 순회하기
  • 누적합 구하기
  • 조건에 맞는 값 세기
  • 최댓값 / 최솟값 찾기
  • while을 이용한 조건 반복
  • break, continue 사용하기
  • 중첩 반복문 읽고 작성하기

오늘은 새로운 문법이 많았지만 지난번에 배운 객체 개념이 ScannerGuessGame에서도 계속 등장한다는 게 조금씩 보이기 시작했다.

다음에는 반복문을 직접 여러 번 작성하면서 코드를 봤을 때 어떤 반복문을 써야 할지 바로 판단할 수 있을 정도로 익숙해지는 것을 목표로 해야겠다.

0개의 댓글