Chapter 3: 변수
3.1 선언과 초기화
변수를 선언하고 초기화하는 건 이렇게 한다.
// 선언만 하기
int number;
// 초기화하기
number = 10;
// 선언하고 초기화하기
int number = 10;
3.2 primitive types
// 논리형
boolean isStudnet = true;
// 문자형
char grade = 'A';
// 정수형
byte b = 127; // -128 ~ 127 (1byte)
short s = 32767; // -32,768 ~ 32,767 (2byte)
int i = 2147483647; // 약 ±21억 (4byte) ★가장 많이 사용
long l = 9223372036854775807L; // 매우 큰 정수 (8byte, L 접미사)
// 실수형
float f = 3.14f; // 소수점 약 7자리 (4byte, f 접미사)
double d = 3.141592653589; // 소수점 약 15자리 (8byte) ★기본형
3.3 상수와 리터럴
상수는 값이 변하지 않는 상수로 final 키워드와 함께 쓴다.
final double PI = 3.14159;
final int MAX_SIZE = 100;
그리고 왠지 상수 변수들은 모두 대문자로 사용하는듯?
상수로 선언된 변수에 다시 값을 할당하려고 하면 컴파일 에러가 난다.
리터럴은 소스코드에 직접 작성된 값을 의미한다.
int num = 100;
double d = 3.14;
String s = "hello";
질문: 왜 리터럴 문자열만 String으로 선언하는지? 위에는 char이라고 했잖아
<추가된 답변="">
char와 String은 서로 다른 타입입니다:
- char: 단일 문자 하나만 저장 (작은따옴표 사용)
```java
char c = 'A'; // OK
char c = 'AB'; // 에러! 한 글자만 가능
```
- String: 문자열 (여러 문자 또는 문자 없음도 가능, 큰따옴표 사용)
```java
String s = "Hello"; // OK
String s = "A"; // OK (한 글자도 가능)
String s = ""; // OK (빈 문자열도 가능)
```
char는 기본형(primitive type)이고, String은 참조형(reference type)입니다.
리터럴에서 "hello"처럼 여러 문자를 담으려면 반드시 String을 써야 합니다.
</추가된 답변>
printf 쓸때
%s -> string
%d -> double
%f -> float
### 질문: 맨 뒤에 %n을 붙이는데 이건 뭐야?
<추가된 답변="">
%n은 줄바꿈(newline)을 의미합니다.
- \n도 줄바꿈이지만 운영체제마다 다를 수 있습니다
- Windows: \r\n
- Unix/Linux/Mac: \n
- %n은 플랫폼 독립적인 줄바꿈입니다
- printf에서 사용하면 현재 운영체제에 맞는 줄바꿈 문자를 자동으로 선택
따라서 printf를 사용할 때는 \n보다 %n을 쓰는 것이 더 안전합니다!
```java
System.out.printf("첫 줄%n두 번째 줄%n"); // 권장
System.out.printf("첫 줄\n두 번째 줄\n"); // 동작하지만 비권장
```
</추가된 답변>
```java
public class PrintfExample {
public static void main(String[] args) {
String name = "김철수";
int age = 20;
double score = 95.5;
// printf: 형식 지정 출력 (줄바꿈 없음)
System.out.printf("이름: %s%n", name); // %s: 문자열
System.out.printf("나이: %d세%n", age); // %d: 정수
System.out.printf("점수: %.1f점%n", score); // %.1f: 소수점 1자리
System.out.printf("합격률: %d%%%n", 85); // %%: % 출력
// 여러 값 동시 출력
System.out.printf("%s님은 %d세이고, 점수는 %.2f입니다.%n",
name, age, score);
}
}
```
여러 변수를 쓸 수도 있고 불러온 변수 뒤에 문자를 그대로 쓸 수도 있다. % 같은 특수문자를 쓸 때도 그냥 붙이면 됨.
### 질문: 큰따옴표랑 작은따옴표 사이에 차이가 있나?
<추가된 답변="">
네, 명확한 차이가 있습니다:
- 작은따옴표 (''): char 타입, 단일 문자만
```java
char c = 'A'; // OK
char c = '한'; // OK
char c = 'AB'; // 에러!
```
- 큰따옴표 (""): String 타입, 문자열
```java
String s = "Hello"; // OK
String s = "A"; // OK (한 글자도 문자열)
String s = ""; // OK (빈 문자열)
```
헷갈리지 않으려면:
- 한 글자 → 작은따옴표
- 여러 글자 또는 문자열 → 큰따옴표
</추가된 답변>
| 지정자 | 설명 | 예시 |
|--------|------|------|
| `%d` | 10진수 정수 | `123` |
| `%f` | 실수 (기본 소수점 6자리) | `3.140000` |
| `%.2f` | 실수 (소수점 2자리) | `3.14` |
| `%s` | 문자열 | `"Hello"` |
| `%c` | 문자 | `'A'` |
| `%n` | 줄바꿈 | |
| `%5d` | 5자리 확보 (우측 정렬) | ` 123` |
| `%-5d` | 5자리 확보 (좌측 정렬) | `123 ` |
3.4 scanner로 입력받기
동일한 프로젝트에서 여러 소스 코드를 당연히 넣을 수 있다. 다른 역할을 하더라도.
처음에 프로젝트와 동일한 이름의 클래스를 만들라고 했던 건 내가 잘못 이해한 거고
파일명과 public 클래스명이 대소문자까지 일치해야 한다는 규칙이다.
### 질문: 왜 이런 규칙이 있을까?
<추가된 답변="">
이유 1. 클래스 찾기를 쉽게 하려고
자바 컴파일러나 자바 가상머신이 클래스를 로드할 때, 클래스 이름으로 파일을 찾는다. 파일명과 클래스명이 다르면 모든 파일을 각각 열어봐야 해 비효율적이다.
그러면 이름이 다르면 파일을 못 찾나? → 못 찾는 게 아니라 컴파일러가 컴파일하지 않는다. 규칙 위반이라서!
이유 2. 개발자도 찾기 쉽게 하려고
코드를 읽을 때 클래스명만 보고 어느 파일에 있는지 바로 알 수 있다.
이유 3. 하나의 파일 = 하나의 책임
파일 하나에 public 클래스 하나만 허용해서 코드를 명확하게 분리하도록 유도한 철학이다.
따라서 public이 아닌 클래스는 파일명과 클래스명이 달라도 된다.
</추가된 답변>
**Scanner 주요 메서드:**
| 메서드 | 반환 타입 | 설명 |
|--------|----------|------|
| `nextLine()` | String | 한 줄 전체 |
| `next()` | String | 공백 전까지 |
| `nextInt()` | int | 정수 |
| `nextDouble()` | double | 실수 |
| `nextBoolean()` | boolean | true/false |
암튼 이렇게 해서 계산하는 클래스를 만들었다.
### 질문: 미리 계산 결과를 지정해서 print 찍어야 하는지?
<추가된 답변="">
궁금했고 예제에서는 미리 지정하라고 했는데 해보니까 지정 안 해도 잘 나왔다. 파이썬이랑 똑같다.
두 방법 모두 가능합니다:
```java
// 방법 1: 미리 변수에 저장
int sum = num1 + num2;
System.out.println(sum);
// 방법 2: 직접 계산
System.out.println(num1 + num2);
```
차이점:
- 방법 1: 값을 재사용할 때 편리, 디버깅 시 변수 확인 가능
- 방법 2: 간결함, 일회성 계산에 적합
예제에서 미리 지정하라고 한 이유는 학습 목적(변수 연습)과 코드 가독성 때문입니다.
</추가된 답변>
3.5 형변환
type casting
자동 형변환은 작은 타입에서 큰 타입으로 따로 변경하지 않고 변수 선언만 해도 된다
큰 타입에서 작은 타입으로의 변환은 강제로 해줘야 한다.
### 질문: double -> int로의 변환은 바로 되는데 왜 double을 String으로 변환하는 건 에러가 날까?
에러 메시지:
```
incompatible types: double cannot be converted to java.lang.String
```
<추가된 답변="">
type casting은 같은 계열의 기본형끼리만 가능하다.
- 숫자 기본형: byte, short, int, long, float, double
- 이들끼리는 형변환 가능
```java
double d = 3.14;
int i = (int) d; // OK
```
- String은 문자 참조형
- 기본형과는 전혀 다른 타입
- type casting으로 변환 불가능
- 형변환 메서드를 사용해야 함
```java
double d = 3.14;
String s = String.valueOf(d); // OK
String s = Double.toString(d); // OK
String s = "" + d; // OK (문자열 연결)
```
반대로 String → double도 마찬가지:
```java
String s = "3.14";
double d = Double.parseDouble(s); // OK
```
</추가된 답변>
## Chapter 3 실습
### 추가 연습 문제
1. 온도 변환기: 섭씨를 입력받아 화씨로 변환 (공식: F = C × 9/5 + 32)
2. 윤년 판별기: 연도를 입력받아 윤년인지 판별 (4의 배수이면서 100의 배수가 아니거나, 400의 배수)
힌트: 윤년 조건
```java
boolean isLeapYear = (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
```
### 질문: 왜 이렇게 출력하면 안 돼?
```java
import java.util.Scanner;
public class Test2 {
// 윤년 판별기
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("연도를 입력해주세요.");
int yr = sc.nextInt();
boolean isLeapYear = (yr % 4 == 0 && yr % 100 != 0) || (yr % 400 == 0);
if (isLeapYear == true) ? System.out.printf("%d 년은 윤년입니다.", yr) : System.out.printf("%d 년은 윤년이 아닙니다.", yr);
}
}
```
<추가된 답변="">
문제 1: 삼항 연산자와 if를 섞어서 문제가 생겼다.
문제 2: 그냥 삼항 연산자만 써도 안 되던데?
```java
(isLeapYear == true) ? System.out.printf("%d 년은 윤년입니다.", yr) : System.out.printf("%d 년은 윤년이 아닙니다.", yr);
```
이렇게 쓰면 안 되는 이유: Java에서 한 줄의 코드로 인정되는 문장(statement)의 종류가 정해져 있다.
삼항 연산자는 표현식(expression)이지 문장(statement)이 아닙니다. 따라서 결과값을 어딘가에 할당해야 합니다.
</추가된 답변>
Java에서 한 줄의 코드로 인정되는 문장(statement)의 종류:
1. 변수의 선언
```java
int x = 5;
String name = "서우";
final double PI = 3.14;
```
2. 표현식 문장
- 대입 연산
- 증감 연산
- 메서드 호출
- 객체 생성
3. 제어문
- 조건문 (if, switch)
- 반복문 (for, while)
- 분기문 (break, continue)
4. 기타
- 빈 문장: `;`
- 블록: `{ int a = 1; int b = 2; }`
- 라벨: `myLabel: for (...) { }`
- try-catch: `try { } catch (Exception e) { }`
- throw: `throw new RuntimeException();`
- synchronized: `synchronized (lock) { }`
- assert: `assert x > 0;`
그래서 삼항 연산자를 사용하려면 이 연산으로 얻은 결과를 어떤 변수에 써야 한다.
올바른 사용 예시:
```java
// 방법 1: 문자열 변수에 할당
String message = (isLeapYear == true) ?
String.format("%d 년은 윤년입니다.", yr) :
String.format("%d 년은 윤년이 아닙니다.", yr);
System.out.println(message);
// 방법 2: PrintStream에 할당 (고급 기법, 비추천)
PrintStream out = (isLeapYear == true) ?
System.out.printf("%d 년은 윤년입니다.%n", yr) :
System.out.printf("%d 년은 윤년이 아닙니다.%n", yr);
```
그럼 삼항 연산자를 안 쓰고 if를 쓰고 싶은 경우에는? 조건문 챕터에서 배우겠다.
올바른 if문 사용:
```java
if (isLeapYear) {
System.out.printf("%d 년은 윤년입니다.%n", yr);
} else {
System.out.printf("%d 년은 윤년이 아닙니다.%n", yr);
}
```
추가된>추가된>추가된>추가된>추가된>추가된>추가된>