첫날 학습의 성격
reference/javastudy/day0105/src/javaStudy에는 Study01.java부터 Study16.java까지 들어 있다. Java를 처음 배우는 날답게 내용은 화려하지 않다. 하지만 이 날 다룬 것들은 이후의 모든 Java 코드 위에 올라가는 바닥 공사에 해당한다.
첫날 실습 흐름을 크게 나누면 이렇다.
- Java 프로그램이 어떻게 출발하는지 본다.
- 변수에 값을 넣고 계산해 본다.
- 숫자를 여러 진법으로 표현해 본다.
- 정수형과 실수형, 문자형, 논리형을 각각 다뤄 본다.
- 서로 다른 타입끼리 값이 어떻게 바뀌는지 확인한다.
- 문자열을 숫자로 바꾸는 법까지 익힌다.
즉, 첫날은 “기초 문법 소개”가 아니라 “Java가 값을 다루는 방식 자체를 익히는 날”이었다.
1. Java 프로그램의 가장 기본 구조
Study01.java는 매우 짧다.
public class Study01 {
public static void main(String[] args) {
System.out.println("Java Study!!!");
}
}
이 코드는 단순 출력처럼 보이지만, Java 파일의 기본 구조가 모두 들어 있다.
class: 프로그램을 담는 기본 단위main: 프로그램 시작점System.out.println(): 콘솔 출력
처음에는 외우는 느낌이 강하지만, 중요한 건 main 메서드가 Java 프로그램의 출발점이라는 점이다. 이후 아무리 복잡한 애플리케이션을 만들더라도, 결국 실행 흐름은 어딘가의 진입점에서 시작한다.
2. 변수는 값을 저장하는 이름표다
Study02.java는 첫 번째 진짜 프로그래밍 실습이라고 볼 수 있다.
int x = 1;
int y = 2;
int result = x + y;
System.out.println(result);
여기서 배우는 핵심은 세 가지다.
- 변수는 값을 저장한다.
- 변수끼리 연산할 수 있다.
- 계산 결과도 다시 변수에 담을 수 있다.
왜 변수 이름이 중요한가
변수는 단순히 “숫자를 저장하는 상자”가 아니라, 그 값이 어떤 의미인지 설명하는 이름표 역할도 한다. x, y는 입문 예제라 괜찮지만, 실제 코드에서는 price, count, totalAmount처럼 의미가 드러나는 이름이 훨씬 좋다.
이날은 단순 덧셈이지만, 이후 프로그램에서 모든 계산은 결국 이런 변수 조합으로 이루어진다.
3. 초기화되지 않은 변수는 왜 쓸 수 없을까
Study03.java는 일부러 오류를 내는 형태의 예제다.
int value;
int result = value + 10;
이 코드는 컴파일되지 않는다. 이유는 value에 아직 어떤 값도 들어 있지 않기 때문이다.
이 규칙이 중요한 이유
Java는 지역 변수를 매우 엄격하게 다룬다. “아마 0이겠지”처럼 추측해서 처리하지 않는다. 값을 쓰기 전에 반드시 초기화해야 한다.
이 규칙은 귀찮아 보이지만 오히려 장점이다. 초기화되지 않은 값을 계산에 섞어 버리는 실수를 컴파일 단계에서 막아 주기 때문이다.
초반에 이 에러를 직접 보는 것은 의미가 있다. 나중에 조건문 안에서만 값이 설정되는 변수, 특정 경우에만 값이 들어가는 변수 때문에 생기는 문제를 이해하는 데 도움이 된다.
4. 변수 값 바꾸기: 임시 변수의 개념
Study04.java는 두 변수의 값을 서로 바꾸는 예제다.
int x = 10;
int y = 20;
int t = x;
x = y;
y = t;
겉보기엔 단순하지만, 이 예제를 통해 “값을 덮어쓰기 전에 잠깐 저장할 공간이 필요하다”는 감각을 익힌다.
왜 바로 바꾸면 안 될까?
x = y;
y = x;
이렇게 하면 첫 줄에서 이미 x의 원래 값이 사라진다. 그래서 중간 보관용 변수 t가 필요하다. 이 개념은 배열 값 교환, 정렬 알고리즘, 상태 관리 등에서 반복적으로 등장한다.
5. 숫자는 10진수만 있는 게 아니다
Study05.java에서는 같은 숫자라도 여러 방식으로 표현할 수 있다는 점을 배운다.
int var1 = 0b1011; // 2진수
int var2 = 0206; // 8진수
int var3 = 365; // 10진수
int var4 = 0xB3; // 16진수
이 부분은 처음엔 낯설지만, 컴퓨터가 내부적으로 숫자를 어떻게 이해하는지 감을 잡게 해 준다.
0b: 2진수- 앞에
0: 8진수 0x: 16진수
왜 이런 표현을 알아야 하나
일반적인 비즈니스 코드에서는 10진수를 주로 쓰지만, 색상 코드, 비트 마스크, 저수준 시스템 처리에서는 16진수나 2진수 표현을 자주 만난다. 초반에 한 번이라도 직접 써 보면 나중에 덜 낯설다.
6. 정수형: 범위가 다르면 저장 가능한 값도 다르다
Study06.java와 Study07.java는 정수형 자료형을 보여 준다.
byte
Study06.java에서는 byte 범위를 확인한다.
byte var1 = -128;
byte var5 = 127;
// byte var6 = 128; // 오류 발생
byte는 1바이트 크기이고, 저장 가능한 범위가 매우 작다. 그래서 범위를 넘는 값을 넣으려고 하면 컴파일 오류가 난다.
long
Study07.java에서는 long을 다룬다.
long var2 = 20L;
long var4 = 10000000000L;
여기서 중요한 포인트는 L 접미사다. 10000000000 같은 큰 수는 기본적으로 int 범위를 넘기 때문에, long 리터럴이라는 것을 명시해야 한다.
왜 범위를 알아야 하나
값이 작아 보일 때는 아무 타입이나 써도 문제 없어 보인다. 하지만 실제 프로그램에서는 사용자 수, 금액, 시간, 파일 크기처럼 큰 숫자를 다루는 순간 타입 선택이 중요해진다.
즉, 자료형은 단순 문법이 아니라 “어느 정도 크기의 값을 다룰 것인가”에 대한 설계 선택이다.
7. 문자형 char: 문자도 결국 숫자다
Study08.java는 char를 보여 준다.
char c1 = 'A';
char c2 = 66;
char c3 = '가';
char c4 = 44032;
이 예제의 핵심은 문자가 내부적으로 숫자 코드로 저장된다는 점이다. 'A'와 65, '가'와 특정 유니코드 값이 연결된다.
왜 중요한가
문자를 다루는 프로그램에서는 단순히 “글자”처럼 보여도 실제로는 숫자 코드 비교나 변환이 일어난다. 나중에 문자열 처리, 정렬, 인코딩 문제를 이해할 때 이 개념이 바탕이 된다.
8. 실수형 float와 double
Study09.java는 float와 double의 차이를 보여 준다.
float var1 = 3.1234567890123456789f;
double var2 = 3.1234567890123456789;
같은 값을 넣어도 float는 정밀도가 더 낮고, double은 더 많은 소수 자릿수를 보존한다.
왜 f를 붙일까
Java에서 실수 리터럴은 기본적으로 double로 인식된다. 그래서 float에 넣으려면 f 또는 F를 붙여야 한다.
float num = 3.14f;
이 규칙을 모르면 “왜 실수 하나 넣는데 오류가 나지?” 하고 당황하기 쉽다.
9. 논리형 boolean
Study10.java는 boolean 타입을 다룬다.
boolean stop = true;
if (stop) {
System.out.println("중지");
}
boolean은 true 또는 false 두 값만 가진다. 단순해 보이지만, 사실 조건문과 반복문의 중심이 되는 타입이다. 나중에 비교 연산자, 논리 연산자, 조건문을 배울 때 이 값이 계속 등장한다.
즉, boolean은 “참/거짓”을 저장하는 타입이 아니라 프로그램 흐름을 제어하는 핵심 타입이다.
10. 자동 형변환: 작은 타입은 큰 타입으로 자연스럽게 간다
Study11.java는 자동 형변환을 보여 준다.
byte byteValue = 10;
int intValue = byteValue;
char charValue = '가';
intValue = charValue;
이처럼 표현 범위가 더 작은 타입은 더 큰 타입으로 자동 변환될 수 있다.
byte -> intchar -> intint -> longfloat -> double
왜 자동 형변환이 가능한가
큰 그릇에 작은 값을 담는 것은 안전하기 때문이다. byte 값은 int 안에 충분히 들어간다. 반대로 큰 값을 작은 그릇에 넣는 것은 정보 손실이 생길 수 있으므로 자동으로 허용되지 않는다.
11. 강제 형변환: 큰 타입을 작은 타입에 넣으려면 책임이 따른다
Study12.java는 명시적 형변환, 즉 캐스팅을 보여 준다.
int var1 = 10;
byte var2 = (byte)var1;
long var3 = 300;
int var4 = (int)var3;
여기서는 개발자가 직접 “이 변환을 하겠다”고 표시해야 한다. 그래서 (byte), (int) 같은 표기를 쓴다.
왜 강제 형변환이 위험할 수 있나
큰 값을 작은 타입으로 바꾸면 값이 잘릴 수 있다. 예를 들어 int의 큰 수를 byte로 바꾸면 예상과 전혀 다른 결과가 나올 수 있다. 즉, 강제 형변환은 단순 문법이 아니라 결과를 스스로 책임지겠다는 선언에 가깝다.
12. 연산하면 왜 결과가 int가 될까
Study13.java는 연산 시 타입 승격 규칙을 보여 준다.
byte result1 = 10 + 20;
byte v1 = 10;
byte v2 = 20;
int result2 = v1 + v2;
여기서 초보자가 가장 헷갈리는 지점이 나온다.
10 + 20은 컴파일 시점에 계산 가능한 상수라서byte에 들어갈 수 있다.- 하지만 변수
v1 + v2는 연산 과정에서int로 승격된다.
즉, 겉으로는 둘 다 byte + byte처럼 보여도 자바가 처리하는 방식은 다르다.
왜 이런 규칙이 있을까
자바는 연산 과정에서 일관성을 유지하고, 작은 정수형에서 발생할 수 있는 예기치 않은 문제를 줄이기 위해 기본적으로 int 연산을 사용한다.
그래서 입문 단계에서는 다음 문장을 기억해 두면 좋다.
“정수 연산의 기본 결과는 int다.”
13. 문자열 결합과 숫자 계산은 다르다
Study14.java는 연산자 +가 숫자 계산에도 쓰이고 문자열 결합에도 쓰인다는 점을 보여 준다.
int result1 = 10 + 2 + 8;
String result2 = 10 + 2 + "8";
String result3 = "10" + 2 + 8;
결과는 각각 다르다.
10 + 2 + 8->2010 + 2 + "8"->128"10" + 2 + 8->1028
왜 결과가 달라질까
자바는 왼쪽부터 차례로 계산한다.
- 앞부분이 숫자끼리면 산술 연산
- 문자열이 등장한 순간부터는 문자열 결합
즉, + 기호 하나만 보고 같은 연산이라고 생각하면 안 된다. 현재 맥락이 숫자인지 문자열인지 함께 봐야 한다.
이 규칙은 콘솔 출력에서도 매우 중요하다.
System.out.println("합계: " + 10 + 20);
이 코드는 합계: 1020이 된다. 만약 30을 원한다면 괄호를 써야 한다.
System.out.println("합계: " + (10 + 20));
14. 문자열을 숫자로 바꾸기
Study15.java는 문자열을 숫자로 변환하는 실습이다.
int value1 = Integer.parseInt("10");
System.out.println(value1 + 5);
이 코드는 단순하지만 매우 중요하다. 사용자 입력, 파일 데이터, 웹 요청 값은 대부분 문자열로 들어온다. 그런데 계산을 하려면 결국 숫자로 바꿔야 한다.
자주 쓰는 변환 메서드
Integer.parseInt("10")Double.parseDouble("3.14")Long.parseLong("1000")
이날 parseInt()를 미리 다뤄 둔 덕분에 다음 날 Scanner 입력을 계산에 사용하는 과정이 자연스럽게 이어진다.
15. 변수의 생존 범위, 즉 스코프
Study16.java는 스코프 문제를 보여 주는 예제다.
int v1 = 15;
int v2 = 0;
if (v1 > 10) {
v2 = v1 - 10;
}
int v3 = v1 + v2 + 5;
이 코드에서 중요한 건 v2를 미리 선언하고 초기화해 두었다는 점이다. 만약 if 블록 안에서만 선언했다면, 블록 밖에서는 사용할 수 없다.
왜 스코프가 중요할까
변수는 선언된 위치에 따라 사용할 수 있는 범위가 정해진다. 이 개념을 이해하지 못하면 조건문, 반복문, 메서드 안팎에서 “왜 여기서는 이 변수가 안 보이지?” 같은 오류를 자주 만나게 된다.
첫날에 이 부분을 직접 본 것은 매우 좋았다. 나중에 훨씬 복잡한 로직에서도 결국 같은 문제가 반복되기 때문이다.
16. 첫날에 꼭 남겨야 할 핵심 정리
첫날 실습을 통해 얻은 핵심은 아래와 같다.
- Java는 자료형을 매우 엄격하게 본다.
- 변수는 사용 전에 반드시 초기화해야 한다.
- 숫자에도 타입과 범위가 있다.
- 문자도 내부적으로는 숫자 코드다.
- 연산 중에는 타입이 자동으로 바뀔 수 있다.
- 큰 타입에서 작은 타입으로 갈 때는 강제 형변환이 필요하다.
- 문자열과 숫자는 전혀 다르게 다뤄야 한다.
이 내용은 이후 모든 Java 학습의 기반이 된다. 클래스, 상속, JavaFX, 파일 입출력까지 가더라도 결국 데이터는 이런 기본 타입 위에서 움직인다.
오늘의 복습 질문
이 글만 읽고 아래 질문에 답할 수 있으면 day1 내용은 잘 정리된 것이다.
1. 왜 초기화되지 않은 지역 변수는 사용할 수 없을까?
지역 변수는 자동 기본값이 들어가지 않기 때문이다. Java는 쓰레기 값 사용을 막기 위해, 값을 넣기 전에는 지역 변수를 읽지 못하게 한다.
2. byte와 long은 어떤 상황에서 구분해서 써야 할까?
byte는 메모리를 아끼고 작은 범위의 정수만 다룰 때, long은 큰 범위의 수가 필요할 때 쓴다. 즉, 저장 범위와 용도가 다르다.
3. float에는 왜 f를 붙여야 할까?
실수 리터럴은 기본적으로 double로 해석되기 때문이다. float로 쓰겠다는 뜻을 컴파일러에 명확히 알려 주려면 f가 필요하다.
4. 자동 형변환과 강제 형변환의 차이는 무엇일까?
자동 형변환은 작은 범위 타입이 큰 범위 타입으로 안전하게 바뀌는 경우이고, 강제 형변환은 개발자가 직접 타입을 바꾸는 경우다. 강제 형변환은 값 손실 가능성을 함께 고려해야 한다.
5. 10 + 2 + "8"과 "10" + 2 + 8이 왜 다를까?
앞 식은 먼저 숫자 덧셈이 일어나 12가 되고, 그 뒤 문자열과 만나 "128"이 된다. 뒤 식은 처음부터 문자열 연결이 시작되어 "1028"이 된다.
6. 문자열 "10"을 숫자 10으로 바꾸려면 무엇을 써야 할까?
Integer.parseInt("10") 같은 파싱 메서드를 사용하면 된다. 타입에 따라 Double.parseDouble() 등도 함께 쓴다.
마무리
1월 5일은 결과물이 크지 않은 날이었다. 하지만 가장 중요한 날 중 하나였다. 이 날 익힌 변수, 자료형, 형변환, 문자열과 숫자의 차이를 제대로 이해하지 못하면 이후의 조건문, 반복문, 객체지향, GUI 학습도 계속 흔들린다.
즉, 첫날은 단순한 입문이 아니라 Java가 값을 바라보는 방식을 배우는 날이었다. 다음 학습일에는 여기에 Scanner, 연산자, 조건문, 반복문이 붙으면서 코드가 본격적으로 흐르기 시작한다.
Community
Comments
Comments appear immediately. Use report if something needs review.
No comments yet.