[Java] Java 01 Hello, Java!
- Period 1 — JDK 21 • IntelliJ • Claude Code • HelloWorld
- Period 2 — public class • main • System.out.println
- Period 3 — declare • assign • reassign • naming
- primitive types • String • casting
- Period 5 — 연산자와 사용자 입력
- Period 6 — JVM 구조와 실행 흐름
- Period 7 — JVM 메모리
Period 1 — JDK 21 • IntelliJ • Claude Code • HelloWorld
자바는 어떤 언어인가?
- 플랫폼 독립성 (Write Once, Run Anyware)
- 한 번 작성한 코드가 Windows • macOS • Linux • Android 어디서든 똑같이 동작. JVM이 OS 차이를 흡수.
- 객체지향 (Object-Oriented)
- 현실 세계의 사물(자동차 • 학생 • 은행계좌)을 클래스로 모델링. 큰 시스템을 부품 단위로 만들고 조립하는 방식.
- 강타입 안전성 (Strongly Typed)
- 변수에 담을 데이터 종류를 미리 정해야 하고, 컴파일러가 타입 실수를 사전에 잡아줌. 운영 중 사고를 예방.
“안전하고, 어디서든 돌아가고, 체계적인 언어” — 그래서 자바는 금융/통신/대기업 시스템의 1순위로 쓰임
WORA — Write Once, Run Anyware
같은 .class 파일이 모든 OS에서 동작함
OS마다 JVM을 만들어 두면 같은
.class가 그대로 돌아감
- Android 앱
- 전 세계 모바일의 70%가 Android — 자바/코틀린 기반
- Google • Samsung
- 대규모 서버
- 수천만 사용자를 처리하는 백엔드 — Spring Framework
- Netflix • 네이버
- 금융 시스템
- 은행 • 증권 • 결제 — 1원도 틀리면 안 되는 시스템
- 카카오뱅크 • 토스
- 빅데이터
- Hadoop • Spark • Kafka — 데이터 처리 엔진의 핵심
- Apache 생태계
Period 2 — public class • main • System.out.println
5줄 코드를 4부위로 나눠보기
public class Main {
public static void main(String[] args) {
System.out.println("Hello, Java!");
}
}
public class Main {}클래스 선언 — 코드를 담는 상자- 자바의 모든 코드는
class안에 들어감. 파일명과 클래스명은 같아야 함 - (
Main.java↔class Main)
- 자바의 모든 코드는
- main 메서드 — 시작점
- 프로그램을 실행하면 JVM이 제일 먼저 부르는 메서드. 형태가 정확히
public static void main(String[] args)여야 함.
- 프로그램을 실행하면 JVM이 제일 먼저 부르는 메서드. 형태가 정확히
- 실제 동작 — 콘솔 출력
- 사람이 시키고 싶은 일은 이 안에 씀. 여기선
"Hello, Java!"를 출력 (println: print line)
- 사람이 시키고 싶은 일은 이 안에 씀. 여기선
- 중괄호 닫기 — 범위 종료
- 메서드의 끝 (
})과 클래스의 끝 (}). 여는 괄호가 있으면 반드시 닫는 괄호도 있어야 함.
- 메서드의 끝 (
public class Main — 코드를 담는 상자
- 클래스 = 코드 상자
자바는 함수 하나도 클래스 안에 넣어야 함 클래스는 코드를 담는 기본 단위 — 다른 언어처럼 “그냥 코드 한 줄”만은 쓸 수 없음
- 파일명 = 클래스명
public이 붙은 클래스는 파일명과 정확히 같아야 함. 대소문자도 구분 — Main과 main은 다른 이름
- { } = 범위 표시
중괄호 안이 이 클래스에 속한 코드. 여는 {가 있으면 반드시 닫는 }가 짝으로 있어야 함 IntelliJ가 자동으로 짝을 맞춰줌.
main 메서드 — 프로그램의 시작점
public static void main (String[] args) { ... }
public— 어디서든 접근- JVM이외부에서 이 메서드를 부를 수 있어야 하므로 public 고정
static— 객체 없이 실행- 아직 만들어진 객체가 없을 때 JVM이 바로 호출 — static 필수
void— 반환값 없음- main은 끝나면 그냥 종료 — 결과를 돌려주지 않으니 void
main— 고정된 이름- JVM은 “main”이라는 이름의 메서드만 시작점으로 인식 — 오타 금지
String[] args— 실행 인자- 터미널에서
java Main hello처럼 넘긴 값이 args에 담김
- 터미널에서
System.out.println — 콘솔로 한 줄 출력
System.out.println("Hello, Java!");
// "시스템 -> 출력 통로 -> 한 줄 찍기 (이 문자열)"로 읽으면 자연스러움
// 마지막 세미콜론(;)은 문장의 끝을 의미
System시스템 클래스
JVM이 제공하는 표준 클래스. 시스템 자원(입출력 • 환경변수 • 시간 등)에 접근할 때 사용함
.out표준 출력 통로
System 안에 있는 출력 스트림 보통은 콘솔 화면 리다이렉트하면 파일로 보낼 수 있음
.println()한 줄 출력 + 줄바꿈
“print line”의 줄임말. 괄호 안 값을 찍고 끝에 자동으로 \n(줄바꿈)을 추가함
"Hello, Java!"문자열 인자
실제로 출력할 내용. 자바에서 문자열은 큰따옴표 “ ”로 감쌈 작은따옴표는 문자 한 개용
3가지 출력문 — println • print • printf
println()한 줄씩 — 가장 흔함
System.out.println("안녕!");
System.out.println("자바!");
출력
안녕
자바!
줄바꿈 자동. 한 줄에 하나씩 출력하고 다음 줄로 — 일반적인 출력은 거의 다 이걸로 충분
print()붙여 쓰기 — 줄바꿈 없음
System.out.print("안녕!");
System.out.print("자바!");
출력
안녕자바!
한 줄에 이어 쓰고 싶을 때. 직접 \n을 붙이면 줄바꿈도 가능 — print(”안녕\n”)
printf()서식 출력 — 값 끼워넣기
// %s=문자열, %d=정수, %n=줄바꿈
System.out.printf("%s는 %d살%n", "민수", 25);
출력
민수는 25살
값을 자리에 끼워 출력. C의 printf와 동일. 변수 여러 개 섞을 때 편리 — 자릿수 • 소수점 제어도 가능함.
주석 — 컴파일러는 무시, 사람은 읽는다
//한 줄 주석- 가장 자주 쓰는 형태. // 부터 그 줄 끝까지가 주석. 코드 한 줄에 대한 짧은 설명에 적합
/* ... */여러 줄 주석- 여러 줄을 한 번에. /* 로 시작해 */로 끝. 코드 블록 전체를 일시적으로 비활성화활 때도 유용.
/** ... */문서 주석(Javadoc)- API문서 자동 생성용. javadoc 명령으로 HTML 문서 추출. 메서드 • 클래스 설명용 — 일반 코드 주석은 아님.
Period 3 — declare • assign • reassign • naming
변수 = 메모리 한 칸에 붙인 이름표
변수의 4가지 핵심 속성
- 이름 (Name)
- 사람이 부르는 식별자. age, userName 같은 영문 단어. 의미가 드러나야 좋은 이름.
- 타입 (Type)
- 어떤 종류의 값을 담을지 미리 정함. int, double, String 등. 한번 정하면 못 바꿈.
- 값 (Value)
- 실제로 담겨 있는 데이터. 25, “민수” 같은 구체적인 값. 프로그램 실행 중 바뀔 수 있음.
- 주소 (Address)
- 메모리에서 차지하는 실제 위치 — JVM이 관리하므로 우리가 직접 다룰 일은 거의 없습니다. 이름으로 충분.
변수 선언과 값 할당
- 📝 변수 선언 (Variable Declaration):
- 컴퓨터 메모리에 데이터를 저장할 공간을 확보하고 공간에 이름을 붙이는 과정.
- 자바에서는 저장할 데이터의 종류에 맞는 데이터 타입(형)을 반드시 먼저 지정해야 함.
- 예시:
int age;(정수를 저장할 수 있는age라는 메모리 공간을 확보함)
- 📥 값 할당 (Value Assignment):
- 선언된 변수(메모리 공간)에 실제 데이터를 집어넣는 과정.
- 대입 연산자
=를 사용하여 우변의 값을 좌변의 변수에 저장. - 예시:
age = 25;(age공간에 25라는 값을 저장함)
- ⚡ 초기화 (Initialization):
- 변수를 선언함과 동시에 최초로 값을 할당하는 것을 의미함.
- 예시:
int age = 25;(선언과 할당을 한 줄로 처리함)
값은 바꿔도, 타입은 못 바꾼다
- 🔄 값의 재할당 (Reassignment):
- 이미 선언된 변수에 새로운 값을 다시 집어넣는 행위.
- 동일한 데이터 타입 내에서는 몇 번이든 값을 자유롭게 바꿀 수 있음.
- 값을 새로 할당하면 기존에 메모리 공간에 있던 이전 데이터는 사라지고 가장 최근에 할당된 값만 남게 됨.
- 예시:
int age = 25; age = 30;(정수형 내에서 25를 30으로 바꾸는 것은 문제없음)
- 🚫 타입 변경 불가 (Type Immutability):
- 자바는 정적 타이핑(Static Typing)을 지원하는 언어이므로, 한 번 선언한 변수의 데이터 타입은 프로그램이 끝날 때까지 절대 바꿀 수 없음.
- 변수를 선언할 때 지정한 타입과 맞지 않는 종류의 데이터를 강제로 넣으려고 하면 컴파일 에러가 발생.
- 예시:
int score = 100; score = "A";(정수형 변수int에 문자열"A"를 넣는 행위는 불가능함)
변수 이름 짓기 (Variable Naming Rules)
- 필수 규칙 (반드시 지켜야 함 - 위반 시 컴파일 에러 발생):
- 대소문자 구분: 자바는 대소문자를 엄격하게 구분함 (예:
age와Age는 완전히 다른 변수). - 숫자 사용 제한: 숫자로 시작할 수 없으며 문자 뒤나 중간에만 올 수 있음 (예:
1st는 불가,top1은 가능). - 특수문자 제한: 특수문자는 오직
_(밑줄)와$(달러 표시) 두 가지만 허용 (예:my_name,$price). - 예약어 사용 금지: 자바 언어 자체에서 이미 고유한 기능으로 예약해 둔 키워드(예:
int,class,public,if등)는 변수 이름으로 사용할 수 없음.
- 대소문자 구분: 자바는 대소문자를 엄격하게 구분함 (예:
- 권장 관례 (개발자 간의 약속 - 가독성을 위해 권장):
- 카멜 케이스 (Camel Case) 사용: 소문자로 시작하되, 여러 단어가 이어질 경우 두 번째 단어의 첫 글자를 대문자로 작성.
- 예시:
studentAge,totalDeliveryPrice
- 예시:
- 의미 있는 이름 부여: 단순히
a,b,x같은 무의미한 알파벳보다는 변수의 역할과 목적이 명확히 드러나는 단어를 선택.- 예시:
userEmail(O) /e(X)
- 예시:
- 한글 변수명 지양: 자바에서 한글 변수명을 지원은 하나, 호환성과 협업 관례를 위해 무조건 영문으로 작성하는 것이 원칙.
- 카멜 케이스 (Camel Case) 사용: 소문자로 시작하되, 여러 단어가 이어질 경우 두 번째 단어의 첫 글자를 대문자로 작성.
변수 3대 활용 패턴
- 🔄 1. 값의 단순 재할당 (Value Replacement):
- 변수에 기존 값 대신 새로운 값을 덮어써서 상태를 업데이트하는 패턴.
- 이전의 데이터는 완전히 지워지고 가장 마지막에 대입한 값만 메모리에 남게 됨.
- 예시:
x = 10; x = 20;(변수x는 최종적으로 20이 됨)
- ➕ 2. 자기 자신을 참조하여 누적하기 (Accumulation):
- 변수의 현재 값에 특정 연산을 수행한 후, 그 결과를 다시 자기 자신에게 할당하는 패턴.
- 주로 합계나 카운트를 누적할 때 필수적으로 사용.
- 예시:
sum = sum + score;또는count = count + 1;
- 🔀 3. 두 변수의 값 맞바꾸기 (Value Swapping):
- 두 변수에 담긴 값을 서로 교환하는 패턴.
- 자바에서는 두 변수의 값을 곧바로 바꿀 수 없기 때문에, 값을 임시로 보관할 제3의 변수(Temp)가 반드시 필요.
- 과정:
- 임시 상자(
temp)에a의 값을 복사해 둠 (temp = a;). - 비어있는
a에b의 값을 넣음 (a = b;). b에 임시 상자 에 두었던 기존a의 값을 넣음 (b = temp;).
- 임시 상자(
실습 — 자기소개 프로그램 작성
public class Main {
public static void main(String[] args) {
// 1. 변수 3개 선언 + 초기화
String name = "Lian Choi";
int age = 25;
String city = "경기도";
// 2. 출력 -- 문자열 연결(+) 사용
System.out.println("안녕하세요!");
System.out.println("이름: " + name);
System.out.println("나이: " + age);
System.out.println(city + "에 살고 있어요.");
}
}
안녕하세요!
이름: 최리안
나이: 25
경기도에 살고 있어요.
primitive types • String • casting
자바 자료형 (Data Types)
- 📦 기본 자료형 (Primitive Type):
- 실제 데이터 값 자체를 메모리에 직접 저장하는 가장 기본적인 자료형.
- 자바에서 총 8개가 제공되며, 각각 정해진 메모리 크기를 가짐.
- 종류:
- 정수형:
byte(1바이트),short(2바이트),int(4바이트, 기본 정수형),long(8바이트) - 실수형:
float(4바이트),double(8바이트, 기본 실수형) - 문자형:
char(2바이트, 단 하나의 글자만 저장) - 논리형:
boolean(1바이트,true또는false만 저장)
- 정수형:
- 🔗 참조 자료형 (Reference Type):
- 실제 데이터 값이 아닌, 데이터가 저장되어 있는 메모리의 주소(참조값)를 저장하는 자료형.
- 기본 자료형 8개를 제외한 모든 자료형(클래스, 배열, 인터페이스 등)이 이에 해당.
- 대표적 예시:
String(문자열을 다루는 클래스 타입)
- 💡 핵심 차이점 요약:
- 기본 자료형: 상자(변수) 안에 실제 데이터 값이 들어있음.
- 참조 자료형: 상자(변수) 안에 실제 데이터가 위치한 메모리 주소(이정표)가 들어있음.
정수형 4가지 — int를 기본으로
- 📉 byte (1 바이트 / 8 비트):
- 표현 범위: $-128$ ~ $127$
- 아주 작은 범위의 정수를 저장할 때 사용하며, 메모리를 극도로 아껴야 하는 파일 전송이나 이미지 데이터 처리 등에 주로 쓰임.
- 📉 short (2 바이트 / 16 비트):
- 표현 범위: $-32,768$ ~ $32,767$
- C/C++ 언어와의 호환성을 위해 주로 사용되며, 현업 자바 프로그래밍에서는 거의 사용되지 않음.
- 👑 int (4 바이트 / 32 비트) — 연산의 기본 타입:
- 표현 범위: 약 $-21$억 ~ 약 $21$억
- 자바에서 정수 연산을 처리하는 기본(Default) 자료형임.
- 컴퓨터 CPU가 정수를 연산할 때 가장 효율적으로 처리하는 크기이므로, 일반적인 숫자는 대부분
int를 사용함.
- 🚀 long (8 바이트 / 64 비트):
- 표현 범위: 약 $-922$경 ~ 약 $922$경 (우주적인 규모의 숫자 표현 가능)
- 은행 잔고, 전 세계 인구수, 대형 서비스의 회원 번호(ID), 시간 측정(밀리초) 등
int범위를 넘어가는 큰 데이터를 다룰 때 사용함. - 주의 사항: 리터럴 뒤에 대문자
L(또는 소문자l)을 반드시 접미사로 붙여서 컴파일러에게long타입임을 알려줘야 함.- 예시:
long heavyValue = 3000000000L;
- 예시:
실수형 (Floating-Point Types) — 무조건 double
- 📉 float (4 바이트 / 32 비트):
- 정밀도: 소수점 아래 약 7자리까지 정밀하게 표현 가능함.
- 특징: 메모리를 적게 차지하지만 정밀도가 낮아 오차가 발생하기 쉬움.
- 주의 사항: 리터럴 뒤에 대문자
F(또는 소문자f)를 반드시 접미사로 붙여야 함. 접미사가 없으면 컴파일러가double로 인식하여 에러가 발생함.- 예시:
float pi = 3.14F;
- 예시:
- 👑 double (8 바이트 / 64 비트) — 실수의 기본 타입:
- 정밀도: 소수점 아래 약 15자리까지 정밀하게 표현 가능함 (float보다 2배 정밀함).
- 특징: 자바에서 실수 연산을 처리하는 기본(Default) 자료형임. 값 뒤에 접미사를 붙이지 않아도 기본적으로
double로 처리됨. - 높은 정밀도가 요구되는 일반적인 실수는 모두
double을 사용하는 것이 원칙임.- 예시:
double rate = 0.05;
- 예시:
char(문자 하나) • boolean(참/거짓)
- 🔤 문자형 char (2 바이트 / 16 비트):
- 단 하나의 문자만 저장할 수 있는 자료형임.
- 값을 표기할 때 반드시 작은따옴표(
' ')를 사용해야 함 (큰따옴표는 문자열String으로 인식하므로 컴파일 에러 발생).- 예시:
char grade = 'A';
- 예시:
- 컴퓨터 내부 동작 방식 (유니코드):
- 컴퓨터는 문자를 직접 저장할 수 없기 때문에 세계 모든 문자를 특정 숫자 코드로 매핑한 유니코드(Unicode) 체계를 사용함.
- 따라서
char형 변수에 문자를 넣으면 실제로는 그 문자에 해당하는 정수(유니코드 숫자)가 메모리에 기록됨. - 예시:
'A'를 저장하면 내부적으로는 정수65가 저장되며, 이를 활용해char변수에 정수를 직접 대입하거나 산술 연산을 수행하는 것도 가능함.
- ⚖️ 논리형 boolean (1 바이트):
- 오직 참을 뜻하는
true와 거짓을 뜻하는false두 가지 값만 가질 수 있는 자료형임. - 조건문(
if,while)의 흐름을 제어하거나, 어떤 상태의 성공/실패 여부를 판별할 때 필수적으로 사용됨. - 다른 프로그래밍 언어(C/C++ 등)와 달리, 자바에서는 숫자를
boolean대신 사용할 수 없음 (예:0은false,1은true같은 자동 변환이 불가능함).- 예시:
boolean isPassed = true;
- 예시:
- 오직 참을 뜻하는
String — 사실은 클래스, 하지만 가장 기본
- 🧵 문자열 String의 개념:
- 단 하나의 문자만 저장하는
char와 달리, 여러 개의 문자(텍스트)를 한꺼번에 묶어서 다룰 수 있는 자료형임. - 값을 표기할 때 반드시 큰따옴표(
" ")를 사용해야 함.- 예시:
String name = "Java";
- 예시:
- 단 하나의 문자만 저장하는
- 🔗 참조 자료형 (Reference Type):
- 앞서 배운 8가지 기본 자료형(int, double, char 등)과 달리,
String은 자바가 제공하는 클래스(Class) 기반의 참조 자료형임. - 변수 상자 안에 실제 텍스트 데이터가 직접 들어가는 것이 아니라, 실제 문자열이 저장된 메모리 공간의 주소값(참조값)을 가리키는 이정표가 저장됨.
- 앞서 배운 8가지 기본 자료형(int, double, char 등)과 달리,
- ➕ 문자열 연결 연산 (String Concatenation):
- 덧셈 연산자(
+)를 사용하여 문자열과 문자열, 혹은 문자열과 다른 자료형을 하나로 이어 붙일 수 있음. - 연산 규칙: 덧셈 연산식에 문자열이 단 하나라도 포함되어 있으면, 다른 피연산자들도 모두 자동으로 문자열로 변환(Type Promotion)된 후 결합됨.
- 예시 1:
"Hello " + "World"➡️"Hello World" - 예시 2:
"Age: " + 25➡️"Age: 25"(int형 25가 문자열"25"로 바뀌어 결합됨)
- 예시 1:
- 덧셈 연산자(
형변환 (Type Casting) - 작은 것은 자동, 큰 것은 강제
- 🔄 형변환의 개념:
- 변수나 리터럴의 데이터 타입을 다른 타입으로 변환하는 행위임.
- 자바에서는 연산을 수행할 때 피연산자들의 데이터 타입이 서로 일치해야 하므로, 타입이 다를 경우 형변환이 필수적으로 발생함.
- 📈 1. 자동 형변환 (묵시적 형변환 / Type Promotion):
- 개발자가 직접 명시하지 않아도 컴파일러가 자동으로 타입을 바꾸어 주는 현상임.
- 원칙: 표현 범위가 작은 자료형에서 큰 자료형으로 값이 이동할 때 발생함 (데이터 손실 위험이 없기 때문임).
- 방향:
byte➡️short➡️int➡️long➡️float➡️double - 예시:
int num = 10; double dNum = num;(int형 10이double형 10.0으로 자동 변환되어 저장됨)
- 📉 2. 강제 형변환 (명시적 형변환 / Type Casting):
- 표현 범위가 큰 자료형에서 작은 자료형으로 값을 강제로 쑤셔 넣을 때 사용하는 방법임.
- 방법: 값 앞에 바꾸고자 하는 타입을 괄호
( )안에 명시함 (캐스팅 연산자 사용).- 예시:
double pi = 3.14; int intPi = (int)pi;
- 예시:
실습 — 가격 계산기 (자료형 + 형변환)
public class PriceCalculator {
public static void main(String[] args) {
// 1. Input
String item = "노트북";
int price = 1_200_000; // 원
int qty = 3;
double taxRate = 0.1; // 10%
double discount = 0.05; // 5% 할인
// 2. 계산 (int * double = double -- 자동)
double subtotal = price * qty;
double tax = subtotal * taxRate;
double total = subtotal + tax - (subtotal * discount);
// 3. 결제 금액은 정수(원)로 -- 강제 형변환
int finalAmount = (int) total;
// 4. 영수증 출력
System.out.println("==== 영수증 ====");
System.out.printf("%s x %d = %.0f원%n", item, qty, subtotal);
System.out.printf("결제: %,d원%n", finalAmount);
}
}
==== 영수증 ====
노트북 x 3 = 3600000원
결제: 3,780,000원
Period 5 — 연산자와 사용자 입력
산술 연산자 5가지 + 대입 축약
- ➕ 산술 연산자 5가지 (Arithmetic Operators):
- 수학적 계산을 수행하는 가장 기본적인 연산자들임.
+(더하기): 두 값을 더함.-(빼기): 앞의 값에서 뒤의 값을 뺌.*(곱하기): 두 값을 곱함./(나누기): 앞의 값을 뒤의 값으로 나눈 몫을 구함.
%(나머지 / Modulo): 앞의 값을 뒤의 값으로 나눈 후 남은 나머지 값을 구함.- 홀수/짝수 판별(
num % 2 == 0이면 짝수)이나 배수 검사, 주기적 순환 값을 계산할 때 자주 쓰임.
- 홀수/짝수 판별(
- 📉 대입 축약 연산자 (복합 대입 연산자 / Compound Assignment):
- 산술 연산과 대입 연산을 하나로 묶어서 코드를 더 간결하게 작성하는 표현식임.
- 변수 자기 자신을 참조하여 값을 변경하고 다시 누적할 때 결합하여 사용함.
- 종류 및 예시:
a += b➡️a = a + b(기존a에b를 더해서 다시a에 저장)a -= b➡️a = a - ba *= b➡️a = a * ba /= b➡️a = a / ba %= b➡️a = a % b
비교 연산자 (Comparison Operators) — 결과는 항상 boolean
- ⚖️ 비교 연산자의 개념:
- 두 피연산자의 값을 서로 비교하여 크고 작음이나 같고 다름을 판별하는 연산자임.
- 비교 연산의 결과는 오직 참(
true) 또는 거짓(false)을 뜻하는boolean자료형으로만 반환됨. - 조건문(
if)이나 반복문(while)의 실행 흐름을 제어하는 조건식을 만들 때 필수적으로 활용됨.
- 🔍 비교 연산자 6가지 종류:
>(크다 / 초과): 좌변이 우변보다 크면true임.<(작다 / 미만): 좌변이 우변보다 작으면true임.>=(크거나 같다 / 이상): 좌변이 우변보다 크거나 같으면true임.
<=(작거나 같다 / 이하): 좌변이 우변보다 작거나 같으면true임.
==(같다): 좌변과 우변의 값이 서로 같으면true임.
!=(같지 않다 / 다르다): 좌변과 우변의 값이 서로 다르면true임.
- 🚨 문자열(String) 비교 시 주의 사항:
- 자바에서 기본 자료형(int, double 등)은
==를 사용하여 값을 직접 비교할 수 있음. - 하지만 참조 자료형인 문자열(
String)의 텍스트 내용이 같은지 비교할 때는==를 사용하면 안 됨. ==는 메모리 상의 주소값(참조값)을 비교하기 때문에, 글자가 같아도 메모리 위치가 다르면false가 나올 수 있음.- 따라서 문자열의 순수 텍스트 내용을 비교할 때는 반드시
.equals()메서드를 사용해야 함.- 예시:
str1.equals(str2)
- 예시:
- 자바에서 기본 자료형(int, double 등)은
논리 연산자 (Logical Operators)
- 🧠 논리 연산자의 개념:
- 주어진 복수의 조건식(또는 참/거짓 값)들을 결합하여 하나의 거대한 논리적 판단을 수행하는 연산자임.
- 비교 연산자와 마찬가지로 연산 결과는 오직
true또는false의boolean자료형으로만 반환됨. - 복잡한 조건 제어(예: “나이가 20세 이상이면서 면허가 있는가?”)를 구현할 때 필수적으로 활용됨.
- 🔍 논리 연산자 3가지 종류:
&&(AND 연산자 / 논리곱):- 두 조건이 모두 참(
true)일 때만 최종 결과가true가 됨. - 하나라도
false가 섞여 있으면 무조건false임. - 예시:
(age >= 20) && (hasLicense == true)➡️ 성인이면서 면허도 있어야 함.
- 두 조건이 모두 참(
||(OR 연산자 / 논리합):- 두 조건 중 어느 하나라도 참(
true)이면 최종 결과가true가 됨. - 두 조건이 모두
false일 때만false를 반환함. - 예시:
(isWeekend == true) || (isHoliday == true)➡️ 주말이거나 공휴일이면 쉼.
- 두 조건 중 어느 하나라도 참(
!(NOT 연산자 / 논리부정):- 단항 연산자로, 현재의 참/거짓 상태를 반대로 뒤집는 역할을 함.
true앞에 붙이면false가 되고,false앞에 붙이면true가 됨.- 예시:
!isPassed➡️ 합격이 아닌 경우(불합격)를 뜻함.
- ⚡ 단락 평가 (Short-Circuit Evaluation) 기능:
- 자바의
&&와||연산자는 효율성을 위해 앞의 조건만 보고도 결과를 확정할 수 있으면 뒤의 조건은 아예 실행(평가)하지 않고 연산을 끝내 버림. &&연산: 앞의 조건이false이면 뒤의 조건이 무엇이든 결과는 무조건false이므로, 뒤쪽 연산식은 패스함.||연산: 앞의 조건이true이면 뒤의 조건이 무엇이든 결과는 무조건true이므로, 뒤쪽 연산식은 패스함.
- 자바의
Scanner (화면 입력) — 콘솔에서 값 입력 받기
- 📥 Scanner 클래스의 개념:
- 키보드나 시스템 등 다양한 입력 소스로부터 사용자가 직접 입력한 데이터를 읽어오기 위해 자바에서 기본적으로 제공하는 유틸리티 클래스임.
- 콘솔창(화면)에 사용자가 텍스트나 숫자를 타이핑하고 엔터(Enter)를 누르면 그 값을 프로그램 안으로 안전하게 가져오는 다리 역할을 수행함.
- 🛠️ Scanner 사용을 위한 3단계:
- 클래스 패키지 임포트(Import):
Scanner는 기본 패키지(java.lang)에 포함되어 있지 않으므로 코드 최상단에 패키지 위치를 반드시 선언해 줘야 함.- 코드:
import java.util.Scanner;
- 객체 생성:
- 표준 입력 스트림(키보드)을 뜻하는
System.in을 연결하여 입력을 받아들이는 상자(인스턴스)를 메모리에 만듦. - 코드:
Scanner sc = new Scanner(System.in);
- 표준 입력 스트림(키보드)을 뜻하는
- 메서드를 활용한 데이터 읽기:
- 사용자가 입력하는 데이터의 종류(타입)에 맞춰 알맞은 전용 메서드를 호출함.
- 클래스 패키지 임포트(Import):
- 🔍 자주 사용하는 주요 입력 메서드:
sc.next(): 공백(스페이스바, 탭, 엔터)을 기준으로 하나의 단어(문자열) 단위만 끊어서 읽어옴.sc.nextLine(): 공백과 상관없이 사용자가 치고 엔터를 누르기 전까지의 한 줄 전체(문자열)를 통째로 읽어옴.sc.nextInt(): 입력된 문자열을 해석하여 정수형(int) 데이터로 변환해 가져옴.sc.nextDouble(): 입력된 데이터를 실수형(double) 데이터로 변환해 가져옴.
실습 1 — 두 수 입력받아 더하기
import java.util.Scanner;
public class Adder {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.print("첫 번째 수: ");
int a = sc.nextInt();
System.out.print("두 번째 수: ");
int b = sc.nextInt();
int sum = a + b;
System.out.printf("%d + %d = %d%n", a, b, sum);
sc.close();
}
}
첫 번째 수: 123456
두 번째 수: 789456
123456 + 789456 = 912912
실습 2 — BMI 계산기
import java.util.Scanner;
public class BMICalculator {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
// 1. 사용자 입력
System.out.print("이름: ");
String name = sc.next();
System.out.print("키(cm): ");
double heightCm = sc.nextDouble();
System.out.print("몸무게(kg): ");
double weight = sc.nextDouble();
// 2. BMI = 몸무게(kg) / (키(m))**2
double heightM = heightCm / 100;
double bmi = weight / (heightM * heightM);
// 4. 분류 출력
if (bmi < 18.5) {
System.out.println("저체중");
} else if (bmi < 23) {
System.out.println("정상");
} else if (bmi < 25) {
System.out.println("과체중");
} else { System.out.println("비만"); }
}
}
이름: 리안
키(cm): 177
몸무게(kg): 81
비만
Period 6 — JVM 구조와 실행 흐름
자바 코드의 일생 (Lifecycle of Java Code)
- 🏗️ 1. 소스 코드 작성 (.java):
- 개발자가 텍스트 에디터나 IDE(Eclipse, IntelliJ 등)를 사용하여 사람이 이해할 수 있는 자바 문법으로 코드를 작성하는 단계임.
- 이 파일은 사람이 읽을 수 있는 텍스트 형태의
.java확장자를 가지며, 컴퓨터는 이 상태의 코드를 직접 해석할 수 없음.
- 🔍 2. 문법 검사 (Syntax Check):
- 개발자가 작성을 마친 코드를 자바 컴파일러(
javac)가 가장 먼저 샅샅이 뜯어보며 규칙에 맞게 작성되었는지 검증하는 단계임. - 오타, 세미콜론(
;) 누락, 잘못된 변수 타입 사용 등 자바 언어의 대원칙을 위반한 문법 오류(Syntax Error)를 이 과정에서 전부 잡아내며, 오류가 발견되면 다음 단계인 컴파일을 중단하고 개발자에게 에러를 뿜어냄.
- 개발자가 작성을 마친 코드를 자바 컴파일러(
- ⚙️ 3. 컴파일 (Compile — .class 생성):
- 문법 검사를 완벽히 통과한 안전한 소스 코드를 컴파일러(
javac)가 컴퓨터 계열이 이해할 수 있는 중간 단계의 언어인 자바 바이트코드(Bytecode)로 최종 번역하는 과정임. - 번역이 성공적으로 완료되면 컴퓨터 내부 메모리나 디스크 상에 바이너리 형태의
.class파일이 결과물로 생성됨.
- 문법 검사를 완벽히 통과한 안전한 소스 코드를 컴파일러(
- 🚀 4. 실행 (Run — JVM의 동작):
- 컴파일된 바이트코드(
.class) 파일을 자바 가상 머신(JVM, Java Virtual Machine)이 읽어 들여 실제 컴퓨터의 OS가 이해할 수 있는 기계어로 실시간 재번역하며 프로그램을 구동함. - JVM 내부의 인터프리터와 JIT 컴파일러(Just-In-Time Compiler)가 협력하여 바이트코드를 고속으로 실행 파일화함.
- 컴파일된 바이트코드(
javac — 터미널에서 직접 컴파일하기
- 🛠️ javac의 정의:
- JDK(Java Development Kit)에 기본적으로 포함되어 있는 자바 표준 컴파일러 프로그램.
- 터미널이나 콘솔창에서 명령어로 직접 호출하여 사용할 수 있으며, 사람이 읽을 수 있는 소스 코드를 기계 진영(JVM)이 실행할 수 있는 특수한 형태의 문서로 번역 및 생산하는 총지휘관 역할을 맡음.
- 🔄 핵심 명령어와 파일 변환 과정:
- 실행 명령:
javac 파일이름.java - 변환 구조: 사람이 텍스트로 타이핑한 고수준 언어 파일인
.java파일을 입력받아, 컴퓨터 가상 환경이 즉각 실행할 수 있는 최적의 명령어 세트인 바이트코드(Bytecode)가 포함된.class파일로 새로 뽑아냄.
- 실행 명령:
- 🧱 주요 내부 동작 메커니즘:
- 규격 검사기: 무작정 기계어로 번역하기 전에, 변수 선언 방식의 유효성, 데이터 타입 적합성, 블록 구조 매칭, 세미콜론 누락 등을 꼼꼼하게 따져 원칙을 지키지 않은 에러 코드를 사전에 철저하게 걸러내는 파수꾼 역할을 수행함.
- 중간 최적화 기술: 단순히 글자만 바꾸는 것이 아니라, JVM이 코드를 가장 빠르고 안정적으로 가동할 수 있도록 전체 구조를 파싱(Parsing)하여 효율적인 상수의 배치 및 컴팩트한 명령어 흐름(Opcode)으로 가공하는 정밀 가공 처리를 함께 진행함.
javap — .class 안에는 뭐가 들어있나?
- 🛠️ javap의 정의:
- JDK(Java Development Kit)에서 제공하는 자바 클래스 파일 디스어셈블러(Disassembler) 프로그램.
- 사람이 도저히 알아볼 수 없는 이진수(바이너리) 형태로 꽉 막혀 있는
.class파일(바이트코드)을 다시 사람이 해독할 수 있는 최소한의 형태인 클래스 구조와 JVM 명령어 흐름으로 쪼개서 보여주는 역공학 분석 도구.
- 🔄 핵심 명령어와 역추적 과정:
- 실행 명령:
javap 클래스이름(또는 내부 바이트코드 흐름까지 상세히 보려면javap -c 클래스이름) - 추적 구조: 번역이 끝나 실행 대기 중인
.class파일을 입력받아, 내부에 어떤 변수가 있고 어떤 메서드가 포함되어 있는지 원본 코드의 설계도를 역으로 추적하여 화면(콘솔)에 텍스트 형태로 다시 뱉어냄.
- 실행 명령:
- 🧱 주요 활용 목적 및 장점:
- 컴파일 결과물 검증: 소스 코드 없이
.class파일만 덜렁 있을 때 해당 클래스가 어떤 public/protected 필드와 메서드로 구성되어 있는지 내부 사정을 빠르게 파악할 수 있음. - 자바 가상 머신의 동작 이해: 내부가 어떻게 최적화되었는지, 스택 기반 연산이 어떻게 일어나는지 내부 바이트코드 단위(Opcode)까지 출력하여 눈으로 확인하고 코드의 실질적인 효율성을 뜯어볼 수 있음.
- 컴파일 결과물 검증: 소스 코드 없이
java 명령어 — JVM이 .class를 실행한다
- 🛠️ java 명령어의 정의:
- JDK(Java Development Kit) 및 JRE(Java Runtime Environment)에 기본 포함된 자바 프로그램 실행 명령(Launcher)임.
javac를 통해 컴파일이 완료된 바이트코드(.class) 파일을 구동하여 프로그램이 실제 컴퓨터 위에서 살아 움직이도록 만드는 최종 실행관 역할을 수행함.
- 🔄 핵심 명령어와 실행 과정:
- 실행 명령:
java 클래스이름(확장자인.class는 절대 붙이지 않고 클래스명만 입력해야 함). - 동작 구조:
.class파일을 메모리에 로드한 후, 자바 프로그램의 시작점인main메서드(public static void main(String[] args))를 찾아내어 그 내부의 코드를 순차적으로 실행함.
- 실행 명령:
- 🧱 주요 내부 동작 메커니즘:
- 가상 가동 환경 제공 (JVM 부팅): 명령어가 실행되는 순간 OS 위에 독립적인 가상 컴퓨터 환경(JVM)을 즉각 구축하고 구동하는 하이퍼바이저 역할을 수행함.
- 실시간 번역 및 실행: JVM 내부의 클래스 로더를 통해 바이트코드를 가져온 뒤, 인터프리터와 JIT 컴파일러를 작동시켜 해당 OS가 이해할 수 있는 이진 기계어로 완전히 바꾸어 가며 연산을 처리함.
실행 순수 — 5 스텝
- JVM이 시작 — Class Loader가
Main.class를 찾아 로드 - Class Loader가 바이트코드를 검증 (안전한지 확인)
- Memory에 Main 클래스 배치, main 메서드를 찾음
- Execution Engine이 main()의 바이트코드를 한 줄씩 실행
- main이 끝나면 JVM 종료 → exit code 반환
JIT 컴파일러 (Just-In-Time Compiler) — 자바는 왜 빠른가?
- 🛠️ JIT 컴파일러의 정의:
- JVM(자바 가상 머신)의 실행 엔진 내부에 탑재되어 프로그램 실행 성능을 폭발적으로 끌어올리는 동적 컴파일러임.
- 처음부터 끝까지 한 줄씩 읽어가며 느리게 실행하는 일반적인 인터프리터 방식의 단점을 완전히 보완하기 위해 도입된 핵심 기술임.
- 🔄 하이브리드 실행 구조 (인터프리터와의 협력):
- 초기 단계 (인터프리터 운용): 자바 애플리케이션이 처음 스타트를 끊을 때는 인터프리터가 바이트코드(
.class)를 한 행씩 빠르게 읽어가며 즉각적으로 실행을 시작함. - 감지 및 전환 (JIT 컴파일러 개입): 프로그램이 돌고 있는 와중에 특정 메서드나 반복문이 계속해서 중복 실행되는 현상을 JVM이 프로파일링(추적)함. 기준치를 넘어 자주 쓰이는 영역을 포착하면 JIT 컴파일러가 출동함.
- 초기 단계 (인터프리터 운용): 자바 애플리케이션이 처음 스타트를 끊을 때는 인터프리터가 바이트코드(
- 🧱 핵심 동작 메커니즘:
- 핫스팟(HotSpot) 디텍팅: 반복 호출되어 온도가 “뜨거워진” 코드 영역(Hot Code)을 실시간으로 찾아내는 기법임.
- 네이티브 기계어 번역 및 캐싱: 핫스팟으로 지정된 바이트코드 덩어리를 통째로 긁어와서 해당 컴퓨터 OS가 다이렉트로 이해할 수 있는 최적화된 네이티브 기계어(Native Code)로 한 번에 구워버림. 번역된 기계어는 JVM 내부의 코드 캐시(Code Cache) 메모리 영역에 안전하게 저장됨.
- 고속 직행 실행: 다음번 연산 과정에서 동일한 메서드나 코드가 호출되면, 인터프리터가 구구절절 번역기를 돌리지 않고 캐시에 저장된 기계어를 즉시 CPU로 밀어 넣어 실행하므로 속도가 네이티브 C언어급으로 빨라짐.
Period 7 — JVM 메모리
JVM 메모리 구조 — Static • Stack • Heap
- 🏗️ JVM 메모리(Runtime Data Area)의 개념:
- 자바 프로그램이 실행될 때 OS로부터 할당받는 자바 전용 메모리 공간임.
- 용도와 데이터의 특성에 따라 크게 메서드 영역, 힙 영역, 스택 영역으로 쪼개어 체계적으로 관리함.
- 📂 1. 메서드 영역 (Method Area) — 클래스 정보 보관소:
- 공유 범위: 프로그램 내부의 모든 스레드가 공통으로 공유하는 영역임.
- 저장 데이터: JVM이 바이트코드(
.class)를 읽어 들일 때, 클래스별 설계도(클래스 구조, 메서드 코드, 생성자 코드, 인터페이스 정보 등)와static변수(클래스 변수)를 이곳에 올려두고 상시 참조함. - 수명: 프로그램이 시작될 때 메모리에 로드되어, 프로그램이 완전히 종료될 때까지 유지됨.
- 📦 2. 힙 영역 (Heap Area) — 인스턴스 생성 공간:
- 공유 범위: 메서드 영역과 마찬가지로 모든 스레드가 공유함.
- 저장 데이터: 자바에서
new연산자를 통해 동적으로 생성된 모든 객체(인스턴스)와 배열이 저장되는 공간임. - 특징: 스택 영역의 변수들이 이 힙 영역에 생성된 실제 객체의 메모리 주소(참조값)를 이정표 삼아 가리키게 됨.
- 수명: 더 이상 자신을 가리키는(참조하는) 변수가 없어지면, 쓰레기 수집기(GC, Garbage Collector)가 주기적으로 방문하여 메모리에서 자동으로 쓸어 담아 소멸시킴.
- 🧵 3. 스택 영역 (Stack Area) — 스레드별 실행 제어소:
- 공유 범위: 스레드별로 독립적으로 할당되며, 서로 다른 스레드는 절대 침범할 수 없음.
- 저장 데이터: 메서드가 호출될 때마다 해당 메서드 전용 임시 상자인 스택 프레임(Stack Frame)이 한 층씩 쌓임. 프레임 내부에는 메서드 안에서 선언된 지역 변수(Local Variable)와 매개 변수(Parameter), 연산 중간 결과 등이 저장됨.
- 특징: 후입선출(LIFO) 구조로 동작하여, 메서드 실행이 끝나면 해당 스택 프레임과 그 안의 변수들이 메모리에서 흔적도 없이 자동으로 즉각 파괴됨. 기본 자료형 변수는 실제 값이 스택에 직접 들어있고, 참조 자료형 변수는 힙 영역 객체의 주소값이 들어있음.
기본형 복사 vs 참조형 복사 — 결정적 차이
- 📈 1. 기본형 복사 (Value Copy):
- 변수 상자 안에 실제 데이터 값 자체를 복사하여 넘겨주는 방식.
- 복사본 변수를 새로 만들면 원본과 복사본은 메모리 공간(스택 프레임) 상에서 서로 완전히 독립된 별개의 상자로 존재하게 됨.
- 특징: 복사 이후에 복사본 변수의 값을 아무리 수정하고 지고 볶아도, 원본 변수 상자 안의 값에는 그 어떤 영향도 주지 않음.
- 예시:
int a = 10; int b = a; b = 20;하더라도 원본a는 여전히10으로 안전하게 보존됨.
- 🔗 2. 참조형 복사 (Reference Copy):
- 변수 상자 안에 들어있는 실제 객체의 데이터가 아니라, 객체가 위치한 힙 영역의 메모리 주소값(참조값)을 복사해 주는 방식.
- 이 과정을 거치면 서로 다른 두 변수 상자가 메모리 상에서 결국 동일한 하나의 객체를 똑같이 가리키는(바라보는) 형태가 됨.
- 특징: 한쪽 변수를 통해 객체의 내부 데이터를 수정하면, 동일한 주소를 공유하는 다른 쪽 변수에서 조회했을 때도 바뀐 데이터가 그대로 반영되어 나타남. 두 변수가 한 몸처럼 연결되어 움직이는 격임.
- 예시:
int[] arr1 = {1, 2}; int[] arr2 = arr1; arr2[0] = 99;수행 시, 원본인arr1[0]을 확인해 봐도99로 똑같이 바뀌어 있음.
Garbage Collection — Heap의 청소부
- 🛠️ 가비지 컬렉션(GC)의 정의:
- JVM(자바 가상 머신)의 실행 엔진 내부에 탑재되어 시스템 메모리를 자동으로 관리해 주는 핵심 기능임.
- 개발자가 직접 메모리를 해제할 필요 없이, 더 이상 사용되지 않는 객체를 추적하여 메모리에서 깔끔하게 쓸어 담아 소멸시키는 역할을 수행함.
- 🔄 핵심 가동 원리 (참조 끊기):
- 대상 선정: 스택 영역의 지역 변수나 다른 활성화된 객체들로부터 어떠한 연결 고리(참조 주소값)도 남지 않아 고립된 힙 영역의 객체들을 ‘쓰레기(Garbage)’로 판단함.
- 동작 프로세스: 변수가 스택 프레임에서 파괴되거나 다른 값을 가리키게 되어 주소 링크가 끊어지면, GC가 주기적으로 힙 영역을 감시하다가 유효하지 않은 메모리 공간을 회수하여 OS에 반환하거나 재사용할 수 있도록 비워둠.
- 예시:
int[] arr = {1, 2}; arr = null;처럼 참조 변수에null을 대입하여 연결을 끊어버리면, 원래 힙에 있던 배열 객체는 쓰레기가 되어 GC의 수집 대상이 됨.
- 🧱 가비지 컬렉션의 장단점:
- 장점: C/C++ 언어처럼 개발자가 일일이 메모리 해제 코드(
free(),delete)를 작성하지 않아도 되므로 메모리 누수(Memory Leak) 위험에서 자유롭고 생산성이 극대화됨. - 단점: GC가 언제 정확히 구동될지 제어할 수 없으며, 가비지를 수집하는 동안 JVM이 애플리케이션의 실행을 잠시 멈추는 STW(Stop-The-World) 현상이 발생하여 미세한 성능 저하나 버벅임이 유발될 수 있음.
- 장점: C/C++ 언어처럼 개발자가 일일이 메모리 해제 코드(
