[Java] Java 01 Hello, Java!


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!");
	}
}
  1. public class Main {} 클래스 선언 — 코드를 담는 상자
    • 자바의 모든 코드는 class 안에 들어감. 파일명과 클래스명은 같아야 함
    • (Main.javaclass Main)
  2. main 메서드 — 시작점
    • 프로그램을 실행하면 JVM이 제일 먼저 부르는 메서드. 형태가 정확히 public static void main(String[] args) 여야 함.
  3. 실제 동작 — 콘솔 출력
    • 사람이 시키고 싶은 일은 이 안에 씀. 여기선 "Hello, Java!"를 출력 (println: print line)
  4. 중괄호 닫기 — 범위 종료
    • 메서드의 끝 (})과 클래스의 끝 (}). 여는 괄호가 있으면 반드시 닫는 괄호도 있어야 함.

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가지 핵심 속성

  1. 이름 (Name)
    • 사람이 부르는 식별자. age, userName 같은 영문 단어. 의미가 드러나야 좋은 이름.
  2. 타입 (Type)
    • 어떤 종류의 값을 담을지 미리 정함. int, double, String 등. 한번 정하면 못 바꿈.
  3. 값 (Value)
    • 실제로 담겨 있는 데이터. 25, “민수” 같은 구체적인 값. 프로그램 실행 중 바뀔 수 있음.
  4. 주소 (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)

  • 필수 규칙 (반드시 지켜야 함 - 위반 시 컴파일 에러 발생):
    • 대소문자 구분: 자바는 대소문자를 엄격하게 구분함 (예: ageAge는 완전히 다른 변수).
    • 숫자 사용 제한: 숫자로 시작할 수 없으며 문자 뒤나 중간에만 올 수 있음 (예: 1st는 불가, top1은 가능).
    • 특수문자 제한: 특수문자는 오직 _ (밑줄)와 $ (달러 표시) 두 가지만 허용 (예: my_name, $price).
    • 예약어 사용 금지: 자바 언어 자체에서 이미 고유한 기능으로 예약해 둔 키워드(예: int, class, public, if 등)는 변수 이름으로 사용할 수 없음.
  • 권장 관례 (개발자 간의 약속 - 가독성을 위해 권장):
    • 카멜 케이스 (Camel Case) 사용: 소문자로 시작하되, 여러 단어가 이어질 경우 두 번째 단어의 첫 글자를 대문자로 작성.
      • 예시: studentAge, totalDeliveryPrice
    • 의미 있는 이름 부여: 단순히 a, b, x 같은 무의미한 알파벳보다는 변수의 역할과 목적이 명확히 드러나는 단어를 선택.
      • 예시: userEmail (O) / e (X)
    • 한글 변수명 지양: 자바에서 한글 변수명을 지원은 하나, 호환성과 협업 관례를 위해 무조건 영문으로 작성하는 것이 원칙.

변수 3대 활용 패턴

  • 🔄 1. 값의 단순 재할당 (Value Replacement):
    • 변수에 기존 값 대신 새로운 값을 덮어써서 상태를 업데이트하는 패턴.
    • 이전의 데이터는 완전히 지워지고 가장 마지막에 대입한 값만 메모리에 남게 됨.
    • 예시: x = 10; x = 20; (변수 x는 최종적으로 20이 됨)
  • ➕ 2. 자기 자신을 참조하여 누적하기 (Accumulation):
    • 변수의 현재 값에 특정 연산을 수행한 후, 그 결과를 다시 자기 자신에게 할당하는 패턴.
    • 주로 합계나 카운트를 누적할 때 필수적으로 사용.
    • 예시: sum = sum + score; 또는 count = count + 1;
  • 🔀 3. 두 변수의 값 맞바꾸기 (Value Swapping):
    • 두 변수에 담긴 값을 서로 교환하는 패턴.
    • 자바에서는 두 변수의 값을 곧바로 바꿀 수 없기 때문에, 값을 임시로 보관할 제3의 변수(Temp)가 반드시 필요.
    • 과정:
      1. 임시 상자(temp)에 a의 값을 복사해 둠 (temp = a;).
      2. 비어있는 ab의 값을 넣음 (a = b;).
      3. 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 대신 사용할 수 없음 (예: 0false, 1true 같은 자동 변환이 불가능함).
      • 예시: boolean isPassed = true;

String — 사실은 클래스, 하지만 가장 기본

  • 🧵 문자열 String의 개념:
    • 단 하나의 문자만 저장하는 char와 달리, 여러 개의 문자(텍스트)를 한꺼번에 묶어서 다룰 수 있는 자료형임.
    • 값을 표기할 때 반드시 큰따옴표(" ")를 사용해야 함.
      • 예시: String name = "Java";
  • 🔗 참조 자료형 (Reference Type):
    • 앞서 배운 8가지 기본 자료형(int, double, char 등)과 달리, String은 자바가 제공하는 클래스(Class) 기반의 참조 자료형임.
    • 변수 상자 안에 실제 텍스트 데이터가 직접 들어가는 것이 아니라, 실제 문자열이 저장된 메모리 공간의 주소값(참조값)을 가리키는 이정표가 저장됨.
  • ➕ 문자열 연결 연산 (String Concatenation):
    • 덧셈 연산자(+)를 사용하여 문자열과 문자열, 혹은 문자열과 다른 자료형을 하나로 이어 붙일 수 있음.
    • 연산 규칙: 덧셈 연산식에 문자열이 단 하나라도 포함되어 있으면, 다른 피연산자들도 모두 자동으로 문자열로 변환(Type Promotion)된 후 결합됨.
      • 예시 1: "Hello " + "World" ➡️ "Hello World"
      • 예시 2: "Age: " + 25 ➡️ "Age: 25" (int형 25가 문자열 "25"로 바뀌어 결합됨)

형변환 (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 (기존 ab를 더해서 다시 a에 저장)
      • a -= b ➡️ a = a - b
      • a *= b ➡️ a = a * b
      • a /= b ➡️ a = a / b
      • a %= 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)

논리 연산자 (Logical Operators)

  • 🧠 논리 연산자의 개념:
    • 주어진 복수의 조건식(또는 참/거짓 값)들을 결합하여 하나의 거대한 논리적 판단을 수행하는 연산자임.
    • 비교 연산자와 마찬가지로 연산 결과는 오직 true 또는 falseboolean 자료형으로만 반환됨.
    • 복잡한 조건 제어(예: “나이가 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단계:
    1. 클래스 패키지 임포트(Import):
      • Scanner는 기본 패키지(java.lang)에 포함되어 있지 않으므로 코드 최상단에 패키지 위치를 반드시 선언해 줘야 함.
      • 코드: import java.util.Scanner;
    2. 객체 생성:
      • 표준 입력 스트림(키보드)을 뜻하는 System.in을 연결하여 입력을 받아들이는 상자(인스턴스)를 메모리에 만듦.
      • 코드: Scanner sc = new Scanner(System.in);
    3. 메서드를 활용한 데이터 읽기:
      • 사용자가 입력하는 데이터의 종류(타입)에 맞춰 알맞은 전용 메서드를 호출함.
  • 🔍 자주 사용하는 주요 입력 메서드:
    • 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 스텝

  1. JVM이 시작 — Class LoaderMain.class를 찾아 로드
  2. Class Loader가 바이트코드를 검증 (안전한지 확인)
  3. Memory에 Main 클래스 배치, main 메서드를 찾음
  4. Execution Engine이 main()의 바이트코드를 한 줄씩 실행
  5. 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) 현상이 발생하여 미세한 성능 저하나 버벅임이 유발될 수 있음.





© 2017. by isme2n

Powered by aiden