<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>micro_developer.log</title>
        <link>https://velog.io/</link>
        <description>Clarinetist.dev</description>
        <lastBuildDate>Fri, 11 Apr 2025 13:10:16 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>micro_developer.log</title>
            <url>https://velog.velcdn.com/images/homeless_snail/profile/e51cd226-18c6-4f4b-b7d3-468dc45a80ac/image.JPG</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. micro_developer.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/homeless_snail" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[Java] 기본형 vs 참조형]]></title>
            <link>https://velog.io/@homeless_snail/java-reference-type</link>
            <guid>https://velog.io/@homeless_snail/java-reference-type</guid>
            <pubDate>Fri, 11 Apr 2025 13:10:16 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>자바에서는 변수를 선언할 때 <strong>기본형(Primitive Type)</strong>과 <strong>참조형(Reference Type)</strong>으로 나눌 수 있다.</p>
</blockquote>
<h2 id="기본형primitive-type">기본형(Primitive Type)</h2>
<ul>
<li><p><code>int</code>, <code>long</code>, <code>double</code>, <code>boolean</code>, <code>char</code> 등</p>
</li>
<li><p>변수에 값 자체를 저장</p>
</li>
<li><p>연산 가능, <code>null</code> 사용 불가</p>
<pre><code class="language-java">int a = 10;
int b = a; // 값 10을 복사</code></pre>
</li>
<li><p><em>값을 복사했기 때문에 <code>a</code>와 <code>b</code>는 서로 영향을 주지 않는다.*</em></p>
</li>
</ul>
<h2 id="참조형reference-type">참조형(Reference Type)</h2>
<ul>
<li><p>클래스, 배열, 인터페이스 등</p>
</li>
<li><p>변수에 객체나 배열의 <strong>메모리 주소(참조값)</strong> 저장</p>
</li>
<li><p>연산 불가, null 사용 가능</p>
<pre><code class="language-java">Student s1 = new Student();
Student s2 = s1; // 참조값 복사</code></pre>
</li>
<li><p><em><code>s1</code>과 <code>s2</code>는 같은 객체를 가리킨다. 따라서 한 쪽에서 값을 바꾸면 다른 쪽에도 영향을 준다.*</em></p>
</li>
</ul>
<blockquote>
<p>기본형 변수에는 직접 사용할 수 있는 값이 들어있지만 참조형 변수에는 위치(참조값)가 들어가 있다. 
참조형 변수를 통해서 뭔가 하려면 결국 참조값을 통해 해당 위치로 이동해야 한다</p>
</blockquote>
<p>자바에서 <code>String</code>은 특별하다. <code>String</code>은 사실은 클래스이기 때문에 참조형이다.
그런데 기본형처럼 문자 값을 바로 대입할 수 있다.
문자열은 매우 자주 다루기 때문에 자바에서 특별하게 편의 기능을 제공한다.</p>
<hr>
<h2 id="메서드-호출-시-차이">메서드 호출 시 차이</h2>
<p>자바는 항상 값을 복사해서 전달한다.
하지만 전달되는 값이 &quot;실제 값&quot;인지 &quot;참조값&quot;인지에 따라 결과가 달라진다.</p>
<h3 id="기본형-전달">기본형 전달</h3>
<pre><code class="language-java">void change(int x) {
    x = 20;
}

int a = 10;
change(a);
System.out.println(a); // 10</code></pre>
<p>→ 값만 복사되므로 원본 <code>a</code>는 변경되지 않음</p>
<h3 id="참조형-전달">참조형 전달</h3>
<pre><code class="language-java">public class Student {
  String name;
  int age;
  int grade;
}</code></pre>
<pre><code class="language-java">void change(Student s) {
    s.grade = 100;
}

Student student = new Student();
student.grade = 90;
change(student);
System.out.println(student.grade); // 100</code></pre>
<p>→ 참조값이 복사되었기 때문에 같은 객체를 공유함. 내부 상태 변경 가능</p>
<h3 id="기본형과-참조형의-메서드-호출">기본형과 참조형의 메서드 호출</h3>
<p>자바에서 메서드의 매개변수(파라미터)는 항상 값에 의해 전달된다.
그러나 이 값이 실제 값이냐, 참조(메모리 주소)값이냐에 따라 동작이 달라진다.</p>
<ul>
<li><strong>기본형</strong>
메서드로 기본형 데이터를 전달하면, 해당 값이 복사되어 전달된다. 이 경우, 메서드 내부에서 매개변수(파라미터)의 값을 변경해도, 호출자의 변수 값에는 영향이 없다.</li>
<li><strong>참조형</strong>
메서드로 참조형 데이터를 전달하면, 참조값이 복사되어 전달된다. 이 경우, 메서드 내부에서 매개변수(파라미터)로 전달된 객체의 멤버 변수를 변경하면, 호출자의 객체도 변경된다.</li>
</ul>
<h3 id="메서드-호출-활용">메서드 호출 활용</h3>
<pre><code class="language-java">public static void main(String[] args) {
    Student student1 = createStudent(&quot;학생1&quot;, 15, 90);
    Student student2 = createStudent(&quot;학생2&quot;, 14, 95);

    printStudent(student1);
    printStudent(student2);
}

static void printStudent(Student student) {
    System.out.println(&quot;이름:&quot; + student.name + &quot; 나이:&quot; + student.age + &quot; 성적:&quot; + student.grade);
}

static Student createStudent(String name, int age, int grade) {
    Student student = new Student();
    student.name = name;
    student.age = age;
    student.grade = grade;

    return student;
}</code></pre>
<ul>
<li><code>createStudent()</code>라는 메서드를 만들고 객체를 생성하는 부분도 이 메서드안에 함께 포함했다.
이제 이 메서드 하나로 객체의 생성과 초기값 설정을 모두 처리한다.</li>
<li>그런데 메서드 안에서 객체를 생성했기 때문에 만들어진 객체를 메서드 밖에서 사용할 수 있게 돌려주어야 한다. 그래야 메서드 밖에서 이 객체를 사용할 수 있다.</li>
<li>메서드는 호출 결과를 반환(<code>return</code>)을 할 수 있다.
메서드의 반환 기능을 사용해서 만들어진 객체의 참조값을 메서드 밖으로 반환하면 된다</li>
</ul>
<hr>
<h2 id="변수의-초기화">변수의 초기화</h2>
<ul>
<li><strong>멤버 변수(필드)</strong>: 클래스에 선언</li>
<li><strong>지역 변수</strong>: 메서드에 선언, 매개변수도 지역 변수의 한 종류</li>
</ul>
<table>
<thead>
<tr>
<th>변수 종류</th>
<th align="center">자동 초기화</th>
<th>초기값 예시</th>
</tr>
</thead>
<tbody><tr>
<td>멤버 변수</td>
<td align="center">O</td>
<td>int=0, boolean=false, 참조형 = null</td>
</tr>
<tr>
<td>지역 변수</td>
<td align="center">X</td>
<td>반드시 직접 초기화 필요</td>
</tr>
</tbody></table>
<pre><code class="language-java">class Data {
    int x; // 자동 초기화: 0
    String str; // 자동 초기화: null
}

void method() {
    int y; // 초기화 안 하면 오류 발생
    System.out.println(y); // ❌
}</code></pre>
<hr>
<h2 id="참조형의-null과-nullpointerexception">참조형의 null과 NullPointerException</h2>
<p>참조형 변수는 <strong>아직 객체를 가리키지 않을 때 null</strong>로 초기화된다.</p>
<pre><code class="language-java">public class Data {
    int value;
}</code></pre>
<pre><code class="language-java">Data data = null;
data.value = 0; // ❌ NullPointerException</code></pre>
<p>→ <strong>null</strong>은 아무 객체도 가리키지 않기 때문에 <code>.name</code>과 같은 접근 시 예외 발생</p>
<hr>
<h2 id="gc-garbage-collection">GC (Garbage Collection)</h2>
<p>자바에서는 더 이상 사용하지 않는 객체를 <strong>자동으로 정리(삭제)</strong>해주는 기능이 있다.<br>이것을 <strong>GC(Garbage Collection, 가비지 컬렉션)</strong>이라고 부른다.</p>
<pre><code class="language-java">Data data = null;
System.out.println(&quot;1. data = &quot; + data);

data = new Data();
System.out.println(&quot;2. data = &quot; + data);

data = null;
System.out.println(&quot;3. data = &quot; + data);</code></pre>
<h3 id="실행-흐름-설명">실행 흐름 설명</h3>
<ol>
<li><code>data = null;</code></li>
</ol>
<ul>
<li><code>data</code> 변수는 <code>null</code>로 초기화되어 있어 아무 객체도 참조하지 않는 상태이다.</li>
<li>출력 결과: <code>1. data = null</code></li>
</ul>
<ol start="2">
<li><code>data = new Data();</code></li>
</ol>
<ul>
<li><code>new Data()</code>로 새로운 객체가 생성되고, 해당 객체의 참조값이 <code>data</code> 변수에 저장된다.</li>
<li>이 시점에서 메모리 어딘가에 <code>Data</code> 인스턴스가 존재하고, <code>data</code>가 그 위치를 참조한다.</li>
<li>출력 결과: <code>2. data = ref.Data@xxxxxx</code> (참조값)</li>
</ul>
<ol start="3">
<li><code>data = null;</code></li>
</ol>
<ul>
<li>다시 <code>data</code> 변수에 <code>null</code>을 할당하면, 기존에 참조하던 <code>Data</code> 객체와의 연결이 끊긴다.</li>
<li>이제 아무도 그 객체를 참조하지 않게 되며, 더 이상 접근할 방법이 없다.</li>
<li>출력 결과: <code>3. data = null</code></li>
</ul>
<p>이 시점에 메모리 내부에서는 Data 객체는 여전히 메모리에 존재하지만, 참조하는 변수(data)가 없기 때문에 쓸모 없는 객체가 된다.
이러한 객체를 자바에서는 <strong>Garbage(쓰레기)</strong>로 판단한다.
<strong>GC(Garbage Collector)</strong>는 이러한 객체를 주기적으로 감지하고 메모리에서 자동으로 제거한다.</p>
<h3 id="gcgarbage-collection의-특징">GC(Garbage Collection)의 특징</h3>
<ul>
<li><p>수동 삭제 불필요
개발자가 직접 <code>free()</code>나 <code>delete</code>를 호출할 필요 없음 (C/C++과의 차이점)</p>
</li>
<li><p>참조가 끊긴 객체만 제거
현재 어떤 변수도 참조하지 않는 객체만 GC 대상이 됨</p>
</li>
<li><p>언제 작동할지 모름
GC는 JVM이 알아서 적절한 시점에 실행함 (명시적 제어는 어려움)</p>
</li>
<li><p><code>null</code> 할당은 힌트일 뿐
변수에 <code>null</code>을 대입해도 GC가 바로 작동하진 않음</p>
</li>
</ul>
<h3 id="주의할-점">주의할 점</h3>
<ul>
<li><p>참조가 하나라도 남아 있으면 GC 대상이 아님</p>
</li>
<li><p>메모리 누수를 막기 위해 불필요한 참조는 <code>null</code>로 명시적으로 끊어주는 것이 좋을 때도 있음</p>
</li>
<li><p>단, <code>null</code>을 썼다고 해서 GC가 즉시 작동하는 것은 아니다</p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] 클래스]]></title>
            <link>https://velog.io/@homeless_snail/java-class</link>
            <guid>https://velog.io/@homeless_snail/java-class</guid>
            <pubDate>Fri, 11 Apr 2025 09:48:51 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>자바는 객체지향 프로그래밍 언어입니다. 그리고 그 중심에는 <code>클래스(class)</code>가 있습니다.
클래스를 이해하면 객체를 만들고 다룰 수 있으며, 코드의 재사용성과 구조적 설계 능력을 갖출 수 있습니다.</p>
</blockquote>
<h2 id="클래스가-필요한-이유">클래스가 필요한 이유</h2>
<p>학생 2명의 이름, 나이, 성적을 출력하는 프로그램을 만들려면 아래와 같이 각각의 변수를 만들어야 한다.</p>
<pre><code class="language-java">String student1Name = &quot;학생1&quot;;
int student1Age = 15;
int student1Grade = 90;
String student2Name = &quot;학생2&quot;;
int student2Age = 16;
int student2Grade = 80;</code></pre>
<p><strong>문제점</strong></p>
<ul>
<li>학생 수가 늘어나면 변수도 함께 늘어남</li>
<li>출력 코드도 늘어나며 유지보수가 어려움</li>
</ul>
<p><strong>배열 도입 후 개선</strong></p>
<pre><code class="language-java">String[] names = {&quot;학생1&quot;, &quot;학생2&quot;};
int[] ages = {15, 16};
int[] grades = {90, 80};</code></pre>
<ul>
<li>반복문 사용 가능</li>
<li>하지만 이름, 나이, 성적이 각각 다른 배열로 나뉘어 있어 데이터 정합성 관리가 어려움</li>
</ul>
<p><strong>클래스 도입</strong></p>
<pre><code class="language-java">public class Student {
    String name;
    int age;
    int grade;
}</code></pre>
<pre><code class="language-java">Student student1 = new Student();
student1.name = &quot;학생1&quot;;
student1.age = 15;
student1.grade = 90;</code></pre>
<ul>
<li>학생이라는 하나의 단위로 데이터를 묶어 관리</li>
<li>코드 가독성과 유지보수성 향상</li>
</ul>
<hr>
<h2 id="클래스란">클래스란?</h2>
<ul>
<li>클래스는 객체를 만들기 위한 설계도</li>
<li>클래스는 객체가 가져야 할 <strong>속성(필드)</strong>과 <strong>기능(메서드)</strong>를 정의</li>
</ul>
<h2 id="클래스의-기본-구조">클래스의 기본 구조</h2>
<pre><code class="language-java">public class 클래스이름 {
    // 멤버 변수 (필드)
    // 생성자
    // 메서드
}</code></pre>
<table>
<thead>
<tr>
<th>구성요소</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>클래스 이름</td>
<td>클래스의 이름. 대문자로 시작하는 것이 관례</td>
</tr>
<tr>
<td>필드(변수)</td>
<td>객체의 속성 (예: 이름, 나이 등)</td>
</tr>
<tr>
<td>생성자</td>
<td>객체 생성 시 자동 호출되는 메서드</td>
</tr>
<tr>
<td>메서드</td>
<td>객체가 수행할 기능</td>
</tr>
</tbody></table>
<h2 id="객체object와-인스턴스instance">객체(Object)와 인스턴스(Instance)</h2>
<ul>
<li>객체(Object): 클래스에 따라 생성된 실체</li>
<li>인스턴스(Instance): 객체와 의미는 같지만, 특정 클래스에서 만들어졌다는 것을 강조할 때 사용<pre><code class="language-java">Student student1 = new Student(); // student1은 Student 클래스의 인스턴스</code></pre>
</li>
</ul>
<h2 id="객체-생성-과정">객체 생성 과정</h2>
<pre><code class="language-java">Student student1 = new Student();</code></pre>
<ol>
<li><p><code>new Student()</code> → 메모리에 Student 객체 생성 (예: x001)</p>
</li>
<li><p><code>student1</code> 변수에 참조값(x001) 저장</p>
</li>
<li><p><code>student1.name</code> → x001 객체의 name 필드에 접근</p>
</li>
</ol>
<blockquote>
<p>자바는 객체 자체가 아니라 객체 <strong>참조값(주소)</strong>을 저장한다.</p>
</blockquote>
<h2 id="클래스와-필드-사용">클래스와 필드 사용</h2>
<pre><code class="language-java">Student student = new Student();
student.name = &quot;학생1&quot;;
student.age = 15;
student.grade = 90;</code></pre>
<ul>
<li><code>student.name</code>처럼 <code>.</code>(dot)으로 객체의 필드에 접근</li>
</ul>
<pre><code class="language-java">System.out.println(student.name);</code></pre>
<ul>
<li>참조값을 통해 실제 객체의 데이터에 접근해 출력함</li>
</ul>
<h2 id="배열과-클래스-결합">배열과 클래스 결합</h2>
<p>학생이 많아질 경우, Student 객체를 배열로 관리할 수 있다.</p>
<pre><code class="language-java">Student[] students = new Student[2];
students[0] = student1;
students[1] = student2;</code></pre>
<p>출력 예시:</p>
<pre><code class="language-java">for (Student s : students) {
    String result = String.format(&quot;이름: %s, 나이: %d, 성적: %d&quot;, s.name, s.age, s.grade);
    System.out.println(result);
}</code></pre>
<hr>
<h2 id="마무리">마무리</h2>
<p>지금까지 클래스를 도입하는 이유와 객체 생성 방식, 그리고 배열과 결합하여 데이터를 어떻게 구조화할 수 있는지 배웠습니다.<br>클래스를 통해 현실 세계의 개념을 코드로 표현할 수 있다는 점에서, 객체지향 프로그래밍의 첫걸음을 떼었다고 할 수 있습니다.</p>
<blockquote>
<p>다음 글에서는 객체를 생성할 때 자동으로 호출되는 <strong>생성자(Constructor)</strong>와  
객체의 동작을 정의하는 <strong>메서드(Method)</strong>에 대해 자세히 알아보겠습니다.</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[메모리 구조와 가상 메모리]]></title>
            <link>https://velog.io/@homeless_snail/memory</link>
            <guid>https://velog.io/@homeless_snail/memory</guid>
            <pubDate>Fri, 11 Apr 2025 08:04:45 GMT</pubDate>
            <description><![CDATA[<h2 id="1-프로그램의-메모리-구조">1. 프로그램의 메모리 구조</h2>
<p>운영체제는 프로그램을 실행할 때 메모리를 여러 영역으로 나누어 관리한다.
대표적인 구조는 다음과 같다.</p>
<ul>
<li><strong>코드(Code) 영역</strong>
실행할 프로그램의 기계어 코드가 저장되는 영역
주로 읽기 전용이며, 실행 중 변경되지 않는다.</li>
<li><strong>데이터(Data) 영역</strong>
전역 변수나 static 변수처럼 프로그램 전체에서 공유되는 데이터가 저장되는 공간</li>
<li><strong>힙(Heap) 영역</strong>
동적으로 할당되는 메모리 공간
<code>new</code>, <code>malloc()</code> 등을 통해 할당하며, 명시적으로 해제해줘야 합니다.</li>
<li><strong>스택(Stack) 영역</strong>
함수 호출 시 지역 변수와 리턴 주소 등을 저장하는 공간
함수가 끝나면 자동으로 메모리가 해제된다.</li>
</ul>
<blockquote>
<p>힙은 위쪽으로, 스택은 아래쪽으로 자라며, 중간에서 만나면 <strong>메모리 부족(overflow)</strong> 이 발생할 수 있다.</p>
</blockquote>
<hr>
<h2 id="2-가상-메모리virtual-memory">2. 가상 메모리(Virtual Memory)</h2>
<p><strong>가상 메모리</strong>는 실제 메모리(RAM)보다 더 큰 메모리를 사용하는 것처럼 보이게 하는 운영체제의 기법이다.</p>
<ul>
<li><strong>프로세스마다 독립된 메모리 공간</strong>을 제공하여 안정성과 보안을 보장</li>
<li>실제 필요한 메모리만 물리 메모리에 올려두고, 나머지는 <strong>디스크(보조기억장치)</strong> 에 저장한다.</li>
</ul>
<hr>
<h2 id="3-페이지와-페이지-폴트">3. 페이지와 페이지 폴트</h2>
<p>가상 메모리는 <strong>페이지(Page)</strong> 단위로 관리된다.</p>
<ul>
<li>가상 주소 공간과 물리 주소 공간을 같은 크기의 페이지로 나눕니다.</li>
<li>필요한 페이지만 물리 메모리에 올려 사용합니다.</li>
</ul>
<blockquote>
<p><strong>페이지 폴트(Page Fault)</strong>는 접근하려는 페이지가 물리 메모리에 없을 때 발생하는 인터럽트이다.
이 경우 운영체제가 해당 페이지를 디스크에서 불러와 물리 메모리에 적재한다.</p>
</blockquote>
<hr>
<h2 id="4-스와핑swapping">4. 스와핑(Swapping)</h2>
<p><strong>스와핑</strong>은 프로세스의 일부나 전체를 디스크와 메모리 사이에서 교체하는 것을 말한다.</p>
<ul>
<li>메모리가 부족할 경우, 덜 사용되는 데이터를 디스크로 내보내고(active한 프로세스에게 메모리를 할당) 필요할 때 다시 불러온다.</li>
<li>이 과정은 <strong>느리지만 메모리를 효율적으로 사용</strong>할 수 있게 해준다.</li>
</ul>
<hr>
<h2 id="5-가상-메모리의-동작-과정-요약">5. 가상 메모리의 동작 과정 요약</h2>
<ol>
<li>프로세스는 가상 주소를 사용해 메모리에 접근</li>
<li>MMU(메모리 관리 유닛)가 페이지 테이블을 참조해 물리 주소로 변환</li>
<li>물리 메모리에 해당 페이지가 없으면 → 페이지 폴트 발생</li>
<li>운영체제가 디스크에서 페이지를 읽어와 물리 메모리에 적재</li>
<li>프로세스는 다시 해당 데이터에 접근 가능</li>
</ol>
<hr>
<h2 id="정리">정리</h2>
<table>
<thead>
<tr>
<th>용어</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>코드 영역</td>
<td>실행 코드 저장, 읽기 전용</td>
</tr>
<tr>
<td>데이터 영역</td>
<td>전역/정적 변수 저장</td>
</tr>
<tr>
<td>힙</td>
<td>동적 메모리, 명시적 할당/해제</td>
</tr>
<tr>
<td>스택</td>
<td>함수 호출, 지역 변수 저장</td>
</tr>
<tr>
<td>가상 메모리</td>
<td>물리 메모리보다 큰 주소 공간 제공</td>
</tr>
<tr>
<td>페이지</td>
<td>가상/물리 메모리의 단위</td>
</tr>
<tr>
<td>페이지 폴트</td>
<td>필요한 페이지가 없을 때 발생</td>
</tr>
<tr>
<td>스와핑</td>
<td>메모리-디스크 간 데이터 교체</td>
</tr>
</tbody></table>
]]></description>
        </item>
        <item>
            <title><![CDATA[멀티프로세스와 멀티스레드]]></title>
            <link>https://velog.io/@homeless_snail/multiprocess-multithread</link>
            <guid>https://velog.io/@homeless_snail/multiprocess-multithread</guid>
            <pubDate>Fri, 11 Apr 2025 06:48:46 GMT</pubDate>
            <description><![CDATA[<h2 id="멀티프로세스multi-process란">멀티프로세스(Multi-Process)란?</h2>
<blockquote>
<p>하나의 프로그램이 <strong>여러 개의 프로세스를 생성</strong>하여 병렬로 실행하는 구조</p>
</blockquote>
<ul>
<li>각 프로세스는 <strong>독립된 메모리 공간</strong>을 가짐</li>
<li>프로세스 간 통신은 <strong>IPC(Inter-Process Communication)</strong>을 통해 수행됨 (예: 파이프, 소켓 등)</li>
<li>하나가 죽어도 다른 프로세스에 영향이 적음</li>
</ul>
<h3 id="예시">예시</h3>
<ul>
<li>웹 브라우저(크롬): 탭마다 별도 프로세스로 실행 → 한 탭이 다운되어도 다른 탭은 영향 없음</li>
<li>서버: 클라이언트 요청마다 별도 프로세스로 처리</li>
</ul>
<hr>
<h2 id="멀티스레드multi-thread란">멀티스레드(Multi-Thread)란?</h2>
<blockquote>
<p>하나의 프로세스 안에서 <strong>여러 개의 스레드가 동시 실행</strong>되는 구조</p>
</blockquote>
<ul>
<li>스레드는 코드, 데이터, 힙을 공유하고 <strong>스택만 독립적</strong></li>
<li>같은 프로세스 내에서 <strong>빠르게 통신하고 협업</strong> 가능</li>
<li>하지만 하나의 스레드 오류가 전체 프로세스에 영향을 줄 수 있음</li>
</ul>
<h3 id="예시-1">예시</h3>
<ul>
<li>게임 클라이언트: 렌더링, 사운드, 네트워크를 각각 다른 스레드에서 처리</li>
<li>웹 서버: 요청 처리, 로깅, DB 저장 등을 스레드로 병렬화</li>
</ul>
<hr>
<h2 id="구조-비교">구조 비교</h2>
<table>
<thead>
<tr>
<th>항목</th>
<th>멀티프로세스</th>
<th>멀티스레드</th>
</tr>
</thead>
<tbody><tr>
<td>실행 단위</td>
<td>독립된 프로세스</td>
<td>프로세스 내 스레드</td>
</tr>
<tr>
<td>메모리</td>
<td>완전히 분리됨</td>
<td>코드/데이터/힙 공유, 스택만 분리</td>
</tr>
<tr>
<td>통신 속도</td>
<td>느림 (IPC 필요)</td>
<td>빠름 (메모리 직접 접근)</td>
</tr>
<tr>
<td>안정성</td>
<td>하나 죽어도 영향 적음</td>
<td>하나 오류 시 전체 영향 가능성 있음</td>
</tr>
<tr>
<td>생성 비용</td>
<td>큼 (무거움)</td>
<td>작음 (가벼움)</td>
</tr>
<tr>
<td>활용 예시</td>
<td>브라우저, 데몬 프로세스</td>
<td>게임, 웹 서버, 실시간 처리</td>
</tr>
</tbody></table>
<hr>
<h2 id="장단점-요약">장단점 요약</h2>
<h3 id="멀티프로세스">멀티프로세스</h3>
<ul>
<li><strong>장점</strong><ul>
<li>안정성 높음 (독립적 구조)</li>
<li>문제 발생 시 확산 방지</li>
</ul>
</li>
<li><strong>단점</strong><ul>
<li>메모리 사용량 많음</li>
<li>프로세스 간 통신이 복잡하고 느림</li>
</ul>
</li>
</ul>
<h3 id="멀티스레드">멀티스레드</h3>
<ul>
<li><strong>장점</strong><ul>
<li>메모리 효율적 (공유 구조)</li>
<li>통신 및 협업 빠름</li>
</ul>
</li>
<li><strong>단점</strong><ul>
<li>스레드 간 동기화 필요 (race condition 발생 가능)</li>
<li>하나의 스레드가 전체를 멈출 수 있음</li>
</ul>
</li>
</ul>
<hr>
<h2 id="선택-기준은">선택 기준은?</h2>
<table>
<thead>
<tr>
<th>상황</th>
<th>적합한 구조</th>
</tr>
</thead>
<tbody><tr>
<td>안정성과 격리가 중요한 경우</td>
<td>멀티프로세스</td>
</tr>
<tr>
<td>속도와 협업이 중요한 경우</td>
<td>멀티스레드</td>
</tr>
</tbody></table>
<p><strong>예시</strong></p>
<ul>
<li><strong>브라우저</strong>는 탭마다 격리가 필요해 멀티프로세스</li>
<li><strong>게임, 실시간 서버</strong>는 빠른 반응이 필요해 멀티스레드</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[프로세스와 스레드]]></title>
            <link>https://velog.io/@homeless_snail/process-thread</link>
            <guid>https://velog.io/@homeless_snail/process-thread</guid>
            <pubDate>Fri, 11 Apr 2025 06:38:53 GMT</pubDate>
            <description><![CDATA[<h2 id="프로세스process란">프로세스(Process)란?</h2>
<blockquote>
<p>프로세스는 <strong>실행 중인 프로그램의 인스턴스</strong>이다.</p>
</blockquote>
<p>하나의 실행 파일(.exe, .py 등)을 더블 클릭하면, 운영체제는 그 파일을 메모리에 로딩하고 독립적인 실행 환경을 구성하며, 이때 만들어지는 것이 바로 <strong>프로세스</strong>이다.</p>
<ul>
<li><p>고유한 메모리 공간을 가짐 (코드, 데이터, 스택, 힙)</p>
<ul>
<li>Code : 코드 자체를 구성하는 메모리 영역 (프로그램 명령)</li>
<li>Data : 전역 변수, 정적 변수, 배열 등
초기화된 데이터는 Data 영역에 저장
초기화되지 않은 데이터는 BSS 영역에 저장</li>
<li>Heap : 동적 할당 시 사용 (new(), malloc() 등)</li>
<li>Stack : 지역 변수, 매개 변수, 리턴 값 (임시 메모리 영역)</li>
</ul>
</li>
<li><p>운영체제에서 PID(Process ID)를 부여</p>
</li>
<li><p>서로 독립적이기 때문에 다른 프로세스와 직접 메모리를 공유하지 않음</p>
</li>
</ul>
<hr>
<h2 id="스레드thread란">스레드(Thread)란?</h2>
<blockquote>
<p>스레드는 <strong>프로세스 내에서 실행되는 작업의 최소 단위</strong>이다.</p>
</blockquote>
<p>모든 프로세스는 최소한 하나의 스레드를 가지고 시작하며, 필요에 따라 여러 개의 스레드를 가질 수 있다.
같은 프로세스 내 스레드들은 <strong>메모리 공간을 공유</strong>하기 때문에 협업이 빠르고 효율적이다.</p>
<ul>
<li><p>스레드는 Stack만 따로 할당받고 나머지 영역은 공유한다.</p>
<ul>
<li>코드, 데이터, 힙 영역은 공유</li>
<li>스택은 스레드마다 별도로 존재</li>
</ul>
</li>
<li><p>스레드는 독립적인 동작을 수행하기 위해 존재 (독립적으로 함수를 호출할 수 있어야 함)</p>
</li>
<li><p>함수의 매개 변수, 지역 변수 등을 저장하는 Stack 영역은 독립적으로 할당받아야 함  </p>
</li>
<li><p>경량화된 실행 단위로, 생성/소멸 비용이 적음</p>
</li>
</ul>
<hr>
<h2 id="프로세스-vs-스레드-비교표">프로세스 vs 스레드 비교표</h2>
<table>
<thead>
<tr>
<th>항목</th>
<th>프로세스</th>
<th>스레드</th>
</tr>
</thead>
<tbody><tr>
<td>정의</td>
<td>실행 중인 프로그램</td>
<td>프로세스 내의 실행 단위</td>
</tr>
<tr>
<td>메모리</td>
<td>독립된 공간 사용</td>
<td>메모리 공유 (스택만 분리)</td>
</tr>
<tr>
<td>통신 방식</td>
<td>IPC 필요 (느림)</td>
<td>메모리 공유로 빠름</td>
</tr>
<tr>
<td>안정성</td>
<td>충돌에 강함</td>
<td>하나가 죽으면 전체 영향 가능</td>
</tr>
<tr>
<td>생성 비용</td>
<td>상대적으로 큼</td>
<td>가벼움, 빠름</td>
</tr>
<tr>
<td>예시</td>
<td>크롬 창 2개</td>
<td>탭 5개는 각각 스레드</td>
</tr>
</tbody></table>
<hr>
<h2 id="메모리-구조-관점에서의-차이">메모리 구조 관점에서의 차이</h2>
<h3 id="1-운영체제의-기본-메모리-영역-구조">1. 운영체제의 기본 메모리 영역 구조</h3>
<ul>
<li>프로그램이 실행되면 메모리에 다음과 같은 영역들이 할당된다.<pre><code>┌─────────────┐ ← 높은 주소
│ 스택 (Stack) │ ◀ 함수 호출, 지역 변수
├─────────────┤
│ 힙 (Heap)    │ ◀ 동적 메모리 (new, malloc 등)
├─────────────┤
│ 데이터 영역    │ ◀ 전역 변수, static 변수
├─────────────┤
│ 코드 영역     │ ◀ 실행 명령어 (기계어)
└─────────────┘ ← 낮은 주소</code></pre><h3 id="2-프로세스의-메모리-구조">2. 프로세스의 메모리 구조</h3>
</li>
<li>각 프로세스는 위 구조 전체를 독립적으로 가지고 있음</li>
<li>다른 프로세스와 코드/데이터/스택/힙 모두 분리됨</li>
<li>하나의 프로세스가 죽거나 메모리를 잘못 써도 다른 프로세스에 영향 없음<pre><code>[프로세스 A]
┌ 코드 영역     ┐
│ 데이터 영역    │
│ 힙 영역       │
│ 스택 영역     │
</code></pre></li>
</ul>
<p>[프로세스 B]
┌ 코드 영역     ┐
│ 데이터 영역    │
│ 힙 영역       │
│ 스택 영역     │</p>
<pre><code>
**장점**: 안정성 높음
**단점**: 프로세스 간 통신이 느림 (공유 X → IPC 필요)


### 3. 스레드의 메모리 구조
- 스레드는 같은 프로세스 내부에서 실행되는 작업 단위
- 따라서, 코드 / 데이터 / 힙 영역은 공유하고, 스택만 개별로 가짐</code></pre><p>[프로세스 A] (2개의 스레드)
┌ 코드 영역       ┐ ← 공유
│ 데이터 영역      │ ← 공유
│ 힙 영역         │ ← 공유
├───────────────┤
│ 스택 (스레드 1)  │ ← 개별
├───────────────┤
│ 스택 (스레드 2)  │ ← 개별
└───────────────┘</p>
<p>```
<strong>장점</strong>: 데이터 공유 빠름, 스레드 간 협업에 유리
<strong>단점</strong>: 한 스레드가 힙/데이터를 잘못 건드리면 전체가 충돌 가능 (동기화 이슈)</p>
<p>이러한 구조 덕분에 스레드는 협업이 빠르지만, 잘못된 접근 시 <strong>동기화 문제</strong>나 <strong>데이터 충돌</strong>이 발생할 수 있다.</p>
<h4 id="왜-스택은-공유하지-않을까">왜 스택은 공유하지 않을까?</h4>
<ul>
<li>스택은 함수 호출, 지역 변수 등을 저장하는 영역</li>
<li>스레드마다 콜스택이 다르므로 반드시 분리되어야 함</li>
<li>분리되지 않으면 A 스레드 함수가 B 스레드의 변수에 영향을 줄 수 있어 심각한 오류 발생 가능</li>
</ul>
<hr>
<h2 id="실제-예시">실제 예시</h2>
<ul>
<li><p><strong>크롬 브라우저</strong>  </p>
<ul>
<li>크롬은 탭마다 <strong>독립된 프로세스</strong>를 실행한다. </li>
<li>탭 내에서는 렌더링, 자바스크립트, 네트워크 등 역할을 하는 <strong>스레드들이 함께 동작</strong>한다.<br>→ 탭이 다운되어도 다른 탭에 영향이 없는 이유이다.</li>
</ul>
</li>
<li><p><strong>게임 클라이언트</strong>  </p>
<ul>
<li>하나의 프로세스 안에 렌더링 스레드, 사운드 스레드, 네트워크 스레드 등 <strong>다수의 스레드가 병렬로 실행</strong>된다.
→ 빠른 반응성과 실시간 처리에 유리하다.</li>
</ul>
</li>
<li><p><strong>웹 서버 (예: Node.js)</strong>  </p>
<ul>
<li>단일 프로세스에서 <strong>이벤트 루프 기반 스레드 모델</strong>을 사용해 I/O 작업을 비동기 처리한다.</li>
<li>고성능 처리를 위해 클러스터링으로 멀티프로세스를 병행하기도 한다.</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[운영체제의 역할과 구조]]></title>
            <link>https://velog.io/@homeless_snail/os</link>
            <guid>https://velog.io/@homeless_snail/os</guid>
            <pubDate>Fri, 11 Apr 2025 06:08:35 GMT</pubDate>
            <description><![CDATA[<h2 id="운영체제의-주요-역할">운영체제의 주요 역할</h2>
<blockquote>
<p>운영체제는 하드웨어와 소프트웨어 사이의 중간 관리자 역할을 하며, 시스템 자원을 효율적으로 관리한다.</p>
</blockquote>
<table>
<thead>
<tr>
<th>역할</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><strong>프로세스 관리</strong></td>
<td>프로그램의 실행 단위인 <strong>프로세스</strong>를 생성, 스케줄링, 종료</td>
</tr>
<tr>
<td><strong>메모리 관리</strong></td>
<td>RAM을 효율적으로 나누어 사용하고, 접근을 보호</td>
</tr>
<tr>
<td><strong>파일 시스템 관리</strong></td>
<td>파일의 저장, 읽기/쓰기, 디렉토리 관리 등</td>
</tr>
<tr>
<td><strong>입출력(I/O) 장치 제어</strong></td>
<td>마우스, 키보드, 디스크, 네트워크 등의 I/O 요청 처리</td>
</tr>
<tr>
<td><strong>보안과 권한 관리</strong></td>
<td>사용자 간 자원 접근 제한, 암호화, 권한 검사 등</td>
</tr>
</tbody></table>
<hr>
<h2 id="운영체제의-구조">운영체제의 구조</h2>
<h3 id="1-커널kernel">1. 커널(Kernel)</h3>
<p>운영체제의 핵심
하드웨어와 직접 소통하며, 메모리, CPU, 파일 시스템, 장치 등을 제어한다.</p>
<ul>
<li><strong>커널 모드</strong>에서만 실행되며, 사용자 프로그램은 직접 하드웨어를 접근할 수 없다.</li>
<li>대표 예시: Linux Kernel, Windows NT Kernel</li>
</ul>
<hr>
<h3 id="2-시스템-콜system-call">2. 시스템 콜(System Call)</h3>
<p>사용자 프로그램이 OS 기능을 사용할 수 있도록 제공하는 인터페이스</p>
<ul>
<li>예: <code>read()</code>, <code>write()</code>, <code>fork()</code>, <code>exec()</code>, <code>open()</code></li>
<li>하드웨어 접근은 반드시 시스템 콜을 통해 커널에 요청해야 한다.</li>
</ul>
<hr>
<h2 id="프로세스와-스레드">프로세스와 스레드</h2>
<table>
<thead>
<tr>
<th>구분</th>
<th>프로세스</th>
<th>스레드</th>
</tr>
</thead>
<tbody><tr>
<td>단위</td>
<td>실행 중인 프로그램</td>
<td>프로세스 내 작업 단위</td>
</tr>
<tr>
<td>메모리</td>
<td>독립된 메모리 공간</td>
<td>메모리 공유</td>
</tr>
<tr>
<td>특징</td>
<td>독립적, 충돌 방지</td>
<td>가볍고 빠름, 충돌 가능성</td>
</tr>
<tr>
<td>예시</td>
<td>크롬 창 2개</td>
<td>각 탭은 하나의 스레드</td>
</tr>
</tbody></table>
<ul>
<li>운영체제는 각 프로세스를 별도로 관리하고, 스레드 간에는 자원 공유를 허용하기도 한다.</li>
</ul>
<hr>
<h2 id="메모리-관리">메모리 관리</h2>
<p>운영체제는 RAM을 효율적으로 분배하고, 충돌을 방지한다.<br>프로세스마다 아래와 같은 메모리 구조가 존재한다.</p>
<ul>
<li><strong>코드 영역</strong>: 프로그램 실행 코드  </li>
<li><strong>데이터 영역</strong>: 전역 변수, static 변수  </li>
<li><strong>힙 영역</strong>: 동적 메모리 할당 공간  </li>
<li><strong>스택 영역</strong>: 함수 호출, 지역 변수 저장</li>
</ul>
<p>운영체제는 각 프로세스의 메모리 공간을 <strong>분리</strong>하여 안정성을 확보합니다.</p>
<hr>
<h2 id="파일-시스템">파일 시스템</h2>
<p>운영체제는 디스크 상의 파일을 논리적으로 관리한다.</p>
<ul>
<li>파일 이름, 위치, 크기, 권한 등의 <strong>메타데이터</strong> 관리</li>
<li>디렉토리 구조 생성 및 탐색</li>
<li>대표 파일 시스템 포맷: FAT32, NTFS, ext4 등</li>
</ul>
<hr>
<h2 id="입출력-장치-관리-io">입출력 장치 관리 (I/O)</h2>
<ul>
<li>디스크, 마우스, 키보드, 네트워크 장치 등은 모두 I/O 장치</li>
<li>운영체제는 I/O 요청을 받아 <strong>장치 드라이버</strong>를 통해 처리한다.</li>
<li>사용자 프로그램은 시스템 콜을 통해만 접근 가능</li>
</ul>
<hr>
<h2 id="서버-운영체제에-리눅스가-많은-이유">서버 운영체제에 리눅스가 많은 이유</h2>
<h3 id="1-비용-효율성"><strong>1. 비용 효율성</strong></h3>
<ul>
<li><strong>오픈소스</strong> : 리눅스는 무료로 사용할 수 있는 오픈소스 운영 체제입니다. 서버를 대량으로 운영하는 기업이나 데이터센터 입장에서, 상용 운영 체제(예: Windows Server) 대신 리눅스를 선택하면 <strong>라이선스 비용을 절감</strong>할 수 있음</li>
<li><strong>유연한 커스터마이징</strong>: 필요에 따라 소스 코드를 수정해 최적화할 수 있기 때문에 특정 하드웨어나 애플리케이션에 맞춘 서버 환경 구축이 용이</li>
</ul>
<h3 id="2-안정성과-신뢰성"><strong>2. 안정성과 신뢰성</strong></h3>
<ul>
<li>대부분의 리눅스 배포판(Ubuntu Server, CentOS, Red Hat 등)은 <strong>24/7(항상 가동)</strong>을 목표로 설계되었고, 다운타임이 적음</li>
<li>커널 패치와 업데이트가 활발히 이루어져 <strong>장기적인 안정성</strong>이 보장</li>
<li>금융, 클라우드 서비스, 인터넷 기업 등 <strong>대규모 트래픽</strong>을 처리하는 시스템에서 안정성이 중요한데, 리눅스는 이에 적합</li>
</ul>
<h3 id="3-보안"><strong>3. 보안</strong></h3>
<ul>
<li><strong>사용자 권한 체계</strong>와 파일 시스템 보안이 강력</li>
<li>오픈소스 특성 덕분에 보안 취약점이 빠르게 발견되고 수정</li>
<li>서버 관리자가 방화벽, 접근 제어, 암호화와 같은 고급 보안 기능을 자유롭게 설정</li>
</ul>
<h3 id="4-유연성과-확장성"><strong>4. 유연성과 확장성</strong></h3>
<ul>
<li>리눅스는 <strong>다양한 서버 환경에 적응가능</strong></li>
<li>웹 서버(Apache, Nginx), 데이터베이스 서버(MySQL, PostgreSQL), 파일 서버 등 모든 서버 역할을 수행할 수 있는 범용성.</li>
<li>다양한 하드웨어(고성능 서버부터 저성능 IoT 디바이스까지)를 지원하여 확장성이 높음</li>
</ul>
<h3 id="5-커뮤니티와-생태계"><strong>5. 커뮤니티와 생태계</strong></h3>
<ul>
<li>전 세계 개발자와 서버 관리자가 참여해, 문제 해결과 최적화를 돕는 방대한 자료와 문서를 제공</li>
<li>리눅스를 기반으로 한 다양한 서버용 배포판(예: CentOS, Ubuntu Server, Debian, Red Hat)이 존재해, 용도에 맞는 선택이 가능</li>
</ul>
<h3 id="6-서버-및-클라우드-환경에서의-점유율"><strong>6. 서버 및 클라우드 환경에서의 점유율</strong></h3>
<ul>
<li>리눅스는 클라우드 서버와 호환성이 뛰어나며, AWS, Google Cloud, Microsoft Azure 같은 주요 클라우드 서비스도 리눅스를 기반으로 운영</li>
<li>서버의 약 96%가 리눅스 기반이며, 이는 기업과 데이터센터에서의 선호도가 높음을 알 수 있음</li>
</ul>
<h3 id="7-오픈소스-소프트웨어와의-호환성"><strong>7. 오픈소스 소프트웨어와의 호환성</strong></h3>
<ul>
<li>리눅스는 많은 오픈소스 서버 소프트웨어와 <strong>완벽한 호환성</strong>을 제공</li>
</ul>
<h3 id="8-성능-최적화"><strong>8. 성능 최적화</strong></h3>
<ul>
<li>리눅스는 가벼운 커널 구조와 프로세스 관리 방식을 통해 서버 하드웨어를 최대한 효율적으로 활용</li>
<li>메모리 사용량이 적고, CPU 자원을 효율적으로 배분</li>
<li>불필요한 서비스와 GUI를 제거해 <strong>서버 전용으로 최적화</strong>된 환경을 구축 가능</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[프로그램 실행 시 내부동작]]></title>
            <link>https://velog.io/@homeless_snail/program-operation-sequence</link>
            <guid>https://velog.io/@homeless_snail/program-operation-sequence</guid>
            <pubDate>Fri, 11 Apr 2025 05:39:31 GMT</pubDate>
            <description><![CDATA[<h2 id="1-실행-요청-더블-클릭-또는-명령어-입력">1. 실행 요청 (더블 클릭 또는 명령어 입력)</h2>
<p>사용자가 실행 파일(예: <code>.exe</code>, <code>.java</code>, <code>.py</code>)을 실행하면, 운영체제는 해당 파일의 위치, 속성, 권한 등을 확인하고 실행 가능한지 판단을 한다.</p>
<h2 id="2-운영체제가-메모리에-프로그램-로딩">2. 운영체제가 메모리에 프로그램 로딩</h2>
<p>운영체제(OS)는 실행 파일을 <strong>RAM(주기억장치)</strong>에 올려서 실행할 준비를 한다.
이때 코드, 전역 변수, 실행 환경 등을 메모리에 배치하고, 새로운 <strong>프로세스(Process)</strong>를 생성한다.</p>
<ul>
<li>각 프로세스는 고유한 PID(프로세스 ID)를 가짐</li>
<li>스택, 힙, 코드 영역 등이 메모리에 구성됨</li>
</ul>
<h2 id="3-cpu가-명령어를-하나씩-실행">3. CPU가 명령어를 하나씩 실행</h2>
<p>메모리에 올라간 명령어들은 CPU가 읽고 실행한다.
이때 CPU는 내부의 레지스터, 연산장치(ALU)를 활용해 계산, 판단, 제어를 수행한다.</p>
<ul>
<li>Program Counter는 현재 실행할 명령어 위치를 추적함</li>
<li>연산은 ALU에서 수행되고, 중간 결과는 레지스터/메모리에 저장됨</li>
</ul>
<h2 id="4-메모리-공간-관리-스택-힙">4. 메모리 공간 관리 (스택, 힙)</h2>
<p>실행 중인 프로그램은 메모리 내에서 여러 공간을 사용한다.</p>
<ul>
<li>스택(Stack): 함수 호출, 지역 변수 저장</li>
<li>힙(Heap): 동적 메모리 할당 (new, malloc 등)</li>
</ul>
<p>운영체제는 각 프로세스의 메모리를 분리해 충돌을 방지합니다.</p>
<h2 id="5-입출력-작업은-운영체제가-처리">5. 입출력 작업은 운영체제가 처리</h2>
<p>파일 열기, 마우스 클릭, 키보드 입력, 네트워크 통신 등은 <strong>시스템 콜(System Call)</strong>을 통해 운영체제가 하드웨어와 직접 소통하며 처리한다.</p>
<h2 id="6-멀티태스킹과-cpu-스케줄링">6. 멀티태스킹과 CPU 스케줄링</h2>
<p>컴퓨터는 동시에 여러 프로그램이 실행되는 것처럼 보이지만, 실제로는 운영체제가 CPU 시간을 분할하여 각 프로세스에 할당하고 빠르게 전환(Context Switching)한다.</p>
<p>이 덕분에 사용자 입장에서는 여러 앱이 동시에 작동하는 것처럼 느껴진다.</p>
<h2 id="7-프로그램-종료와-자원-회수">7. 프로그램 종료와 자원 회수</h2>
<p>프로그램이 종료되면 운영체제는 해당 프로세스가 사용하던 메모리, 파일 핸들, 네트워크 연결 등을 정리하고 시스템 자원을 회수한다.</p>
<h2 id="예시-메모장-실행-시-내부-동작">예시: 메모장 실행 시 내부 동작</h2>
<ol>
<li><p>사용자가 메모장 아이콘을 더블 클릭</p>
</li>
<li><p><code>notepad.exe</code>가 RAM에 로딩되고 프로세스가 생성됨</p>
</li>
<li><p>CPU가 명령어를 순차적으로 실행하며 메모장 화면이 나타남</p>
</li>
<li><p>파일 열기 시, OS가 디스크에서 파일을 읽어 메모리에 올림</p>
</li>
<li><p>작업 완료 후 프로그램 종료 → 자원 해제, 프로세스 종료</p>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[컴퓨터 하드웨어의 기본개념과 구성 요소]]></title>
            <link>https://velog.io/@homeless_snail/computer-hardware-basic</link>
            <guid>https://velog.io/@homeless_snail/computer-hardware-basic</guid>
            <pubDate>Fri, 11 Apr 2025 05:17:08 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>컴퓨터는 소프트웨어와 하드웨어로 구성되어 있으며, 이 중 <strong>하드웨어</strong>는 우리가 눈으로 볼 수 있는 <strong>물리적인 부품들</strong>을 의미합니다.
이 글에서는 컴퓨터 하드웨어의 구조와 각 구성 요소의 역할에 대해 쉽게 설명해보겠습니다.</p>
</blockquote>
<h2 id="1-cpu-central-processing-unit-중앙처리장치">1. CPU (Central Processing Unit, 중앙처리장치)</h2>
<p><strong>CPU</strong>는 컴퓨터의 두뇌라고 불리며, 모든 연산과 명령 처리를 담당
사용자나 프로그램이 내리는 명령을 해석하고 실행하는 역할</p>
<ul>
<li><strong>주요 구성</strong><ul>
<li>연산장치(ALU): 계산 담당</li>
<li>제어장치(CU): 명령어 순서대로 실행</li>
</ul>
</li>
</ul>
<ul>
<li><strong>단위</strong>: GHz (속도), 코어 수 (병렬 처리 능력)</li>
</ul>
<hr>
<h2 id="2-메인-메모리-ram-vs-rom">2. 메인 메모리 (RAM vs ROM)</h2>
<p>컴퓨터에서 가장 기본적인 메모리로는 <strong>RAM</strong>과 <strong>ROM</strong>이 있다.
이 둘은 모두 메모리지만, 성격과 역할이 다르다.</p>
<h3 id="ram-random-access-memory">RAM (Random Access Memory)</h3>
<p><strong>RAM</strong>: 컴퓨터에서 현재 실행 중인 프로그램이나 데이터를 <strong>임시로 저장</strong>하는 장치
휘발성이기 때문에 전원을 끄면 저장된 내용은 사라진다.</p>
<ul>
<li>프로그램 실행 중 데이터를 임시 저장</li>
<li>속도는 빠르지만 전원을 끄면 모두 사라짐 (휘발성)</li>
<li>용량이 크면 한 번에 여러 작업 가능 (예: 8GB, 16GB 등)</li>
<li>실행 속도와 멀티태스킹 성능에 큰 영향</li>
</ul>
<h3 id="rom-read-only-memory">ROM (Read Only Memory)</h3>
<p><strong>ROM</strong>: 이름처럼 데이터를 <strong>읽기 전용으로 저장</strong>하는 비휘발성 메모리
컴퓨터가 켜질 때 가장 먼저 사용하는 <strong>부팅용 펌웨어(BIOS/UEFI)</strong>가 저장된 공간</p>
<ul>
<li>전원을 꺼도 데이터가 <strong>유지됨</strong> (비휘발성)  </li>
<li>사용자가 직접 수정할 수 없음 (특수 환경 제외)  </li>
<li>하드웨어가 기본적으로 필요한 정보(펌웨어, 부트로더 등)를 저장  </li>
<li>읽기만 가능하며, 내용은 제조 시점에 고정되거나 제한적으로 수정 가능</li>
</ul>
<h3 id="ram-vs-rom-요약-비교">RAM vs ROM 요약 비교</h3>
<table>
<thead>
<tr>
<th>항목</th>
<th>RAM</th>
<th>ROM</th>
</tr>
</thead>
<tbody><tr>
<td>용도</td>
<td>실행 중인 데이터 임시 저장</td>
<td>부팅 정보 등 영구 저장</td>
</tr>
<tr>
<td>휘발성</td>
<td>O (전원 끄면 사라짐)</td>
<td>X (전원 꺼도 유지됨)</td>
</tr>
<tr>
<td>수정 가능</td>
<td>O (계속 변경됨)</td>
<td>X (수정 불가 또는 제한적)</td>
</tr>
<tr>
<td>속도</td>
<td>빠름</td>
<td>느림</td>
</tr>
<tr>
<td>예시</td>
<td>프로그램 실행 중 메모리</td>
<td>BIOS, UEFI, 펌웨어</td>
</tr>
</tbody></table>
<hr>
<h2 id="3-저장-장치-hdd--ssd">3. 저장 장치 (HDD / SSD)</h2>
<p>운영체제, 애플리케이션, 사용자 데이터 등을 <strong>영구적으로 저장</strong>하는 장치</p>
<ul>
<li>파일, 앱, OS 등 영구 저장</li>
<li><strong>HDD</strong>: 느리지만 저렴, 기계식</li>
<li><strong>SSD</strong>: 빠르고 조용, 반도체 방식</li>
</ul>
<hr>
<h2 id="4-메인보드-motherboard">4. 메인보드 (Motherboard)</h2>
<p>모든 하드웨어 부품이 연결되는 <strong>중심 회로판</strong>
CPU, RAM, 저장 장치, 전원 등 모든 부품들이 이 보드를 통해 서로 통신</p>
<ul>
<li>모든 부품이 꽂히는 중심 회로판</li>
<li>전원 공급 및 데이터 전달 통로 역할</li>
<li>칩셋, 슬롯, 포트 등 다양한 회로와 단자가 포함</li>
</ul>
<hr>
<h2 id="5-gpu-그래픽카드">5. GPU (그래픽카드)</h2>
<p><strong>GPU</strong>는 화면 출력, 3D 렌더링, 영상 처리 등 그래픽 연산을 담당하는 장치
최근에는 인공지능 연산용으로도 사용</p>
<ul>
<li><strong>내장 GPU</strong>: CPU나 메인보드에 포함</li>
<li><strong>외장 GPU</strong>: 별도로 장착, 고성능 게임 및 작업에 유리</li>
<li>CPU보다 더 많은 연산 코어를 가지고 있음 (병렬 연산에 특화)</li>
<li>복잡한 그래픽 연산을 CPU 대신 처리해서 전체 성능을 높여줌</li>
</ul>
<hr>
<h2 id="6-입출력-장치-io-devices">6. 입출력 장치 (I/O Devices)</h2>
<p>사용자가 컴퓨터와 상호작용할 수 있도록 돕는 장치</p>
<ul>
<li><strong>입력 장치</strong>: 키보드, 마우스, 마이크, 스캐너 등  </li>
<li><strong>출력 장치</strong>: 모니터, 스피커, 프린터 등</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[데이터베이스 성능 최적화의 핵심 INDEX]]></title>
            <link>https://velog.io/@homeless_snail/rdbms-index</link>
            <guid>https://velog.io/@homeless_snail/rdbms-index</guid>
            <pubDate>Thu, 10 Apr 2025 07:30:58 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>데이터베이스에서 대량의 데이터를 빠르게 검색하려면 어떻게 해야 할까?
바로 <strong>인덱스(Index)</strong>를 사용하는 것이다.</p>
</blockquote>
<hr>
<h2 id="인덱스란">인덱스란?</h2>
<ul>
<li>인덱스는 <strong>데이터베이스 테이블의 데이터를 빠르게 조회하기 위한 자료구조</strong>이다.</li>
<li>도서관의 책 색인처럼, 원하는 데이터를 효율적으로 찾을 수 있도록 도와주는 역할을 한다.</li>
</ul>
<p>예를 들어, 아래와 같은 쿼리를 실행한다고 가정해본다면</p>
<pre><code class="language-sql">SELECT * FROM users WHERE user_id = 123;</code></pre>
<ul>
<li>user_id에 인덱스가 없다면 → 모든 데이터를 Full Scan</li>
<li>user_id에 인덱스가 있다면 → 인덱스를 통해 바로 해당 위치 조회</li>
</ul>
<hr>
<h3 id="인덱스의-자료구조">인덱스의 자료구조</h3>
<table>
<thead>
<tr>
<th align="center">인덱스 종류</th>
<th align="center">특징</th>
</tr>
</thead>
<tbody><tr>
<td align="center">B-Tree 인덱스</td>
<td align="center">범위 검색, 정렬 등 다양한 검색에 적합</td>
</tr>
<tr>
<td align="center">Hash 인덱스</td>
<td align="center">equal(=) 비교에 빠름, 범위 검색에는 부적합</td>
</tr>
<tr>
<td align="center">Bitmap 인덱스</td>
<td align="center">중복값이 많은 컬럼에 적합 (예: 성별)</td>
</tr>
<tr>
<td align="center">Full-Text 인덱스</td>
<td align="center">텍스트 검색에 특화 (검색엔진 등)</td>
</tr>
</tbody></table>
<h4 id="b-트리-인덱스-b-tree-index">B-트리 인덱스 (B-Tree Index)</h4>
<blockquote>
<p>B-트리는 정렬된 데이터를 트리 형태로 저장하는 자료구조
대부분의 관계형 데이터베이스(MySQL, PostgreSQL 등)에서 기본 인덱스로 사용됨
검색, 삽입, 삭제 연산을 평균적으로 $O(log n)$에 수행할 수 있다.</p>
</blockquote>
<h4 id="구조예시">구조예시</h4>
<pre><code>                  [30]
                /      \
           [10, 20]   [40, 50]
          /   |   \    /   |   \
       [5] [15] [25] [35] [45] [55]</code></pre><ul>
<li>루트 노드: [30]</li>
<li>내부 노드: [10, 20], [40, 50]</li>
<li>리프 노드: [5], [15], ..., [55]</li>
<li>모든 리프 노드는 같은 깊이에 있음 → 균형 트리</li>
</ul>
<h4 id="검색-동작">검색 동작</h4>
<p>예: <code>WHERE age = 45</code>
→ 루트에서 시작 → 45는 30보다 크므로 오른쪽
→ [40, 50] 에서 45는 40보다 크고 50보다 작으므로 중간 자식으로 이동
→ 리프 노드 [45] 도달 → 검색 성공</p>
<hr>
<h3 id="인덱스-생성-예시">인덱스 생성 예시</h3>
<pre><code class="language-sql">-- 단일 인덱스
CREATE INDEX idx_users_userid ON users(user_id);

-- 복합 인덱스
CREATE INDEX idx_users_name_email ON users(name, email);</code></pre>
<hr>
<h3 id="인덱스의-장점">인덱스의 장점</h3>
<ul>
<li><p>검색 속도 향상: WHERE, JOIN, ORDER BY 절의 성능 향상</p>
</li>
<li><p>정렬 최적화: 정렬이 빠르게 처리됨</p>
</li>
<li><p>조인 성능 향상: 키 기반 검색 속도 증가</p>
</li>
</ul>
<h3 id="인덱스의-단점">인덱스의 단점</h3>
<ul>
<li><p>쓰기 성능 저하: INSERT/UPDATE/DELETE 시 인덱스도 갱신 필요</p>
</li>
<li><p>디스크 공간 추가 사용: 인덱스를 저장할 공간 필요</p>
</li>
<li><p>인덱스 남용 주의: 너무 많은 인덱스는 오히려 성능 저하</p>
</li>
</ul>
<hr>
<h3 id="언제-인덱스를-사용해야-할까">언제 인덱스를 사용해야 할까?</h3>
<table>
<thead>
<tr>
<th align="center">상황</th>
<th align="center">인덱스 사용 여부</th>
</tr>
</thead>
<tbody><tr>
<td align="center">WHERE 조건에 자주 사용되는 컬럼</td>
<td align="center">권장</td>
</tr>
<tr>
<td align="center">JOIN에 사용되는 컬럼</td>
<td align="center">권장</td>
</tr>
<tr>
<td align="center">ORDER BY 또는 GROUP BY 컬럼</td>
<td align="center">권장</td>
</tr>
<tr>
<td align="center">자주 수정되는 컬럼</td>
<td align="center">주의</td>
</tr>
<tr>
<td align="center">데이터 분포가 고르지 않은 컬럼</td>
<td align="center">조건부 권장</td>
</tr>
</tbody></table>
<h3 id="인덱스-조회-계획-확인">인덱스 조회 계획 확인</h3>
<ul>
<li>인덱스가 실제로 사용되고 있는지 확인하려면 EXPLAIN을 사용<pre><code class="language-sql">EXPLAIN SELECT * FROM users WHERE user_id = 123;</code></pre>
</li>
</ul>
<h3 id="인덱스-종류-요약">인덱스 종류 요약</h3>
<table>
<thead>
<tr>
<th>인덱스 종류</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>기본 인덱스 (PK)</td>
<td>자동 생성, 유일값 보장</td>
</tr>
<tr>
<td>유니크 인덱스 (UNIQUE)</td>
<td>중복 방지 목적</td>
</tr>
<tr>
<td>보조 인덱스</td>
<td>일반 인덱스</td>
</tr>
<tr>
<td>복합 인덱스</td>
<td>여러 컬럼 조합으로 생성된 인덱스</td>
</tr>
<tr>
<td>함수 기반 인덱스</td>
<td>함수 결과에 대한 인덱스</td>
</tr>
<tr>
<td>파셜 인덱스 (PostgreSQL)</td>
<td>특정 조건을 만족하는 값만 인덱싱</td>
</tr>
</tbody></table>
]]></description>
        </item>
        <item>
            <title><![CDATA[RDBMS 정규화]]></title>
            <link>https://velog.io/@homeless_snail/rdbms-normalization</link>
            <guid>https://velog.io/@homeless_snail/rdbms-normalization</guid>
            <pubDate>Thu, 10 Apr 2025 07:01:49 GMT</pubDate>
            <description><![CDATA[<h2 id="1-정규화란">1. 정규화란?</h2>
<blockquote>
<p>관계형 데이터베이스(RDBMS)에서 <strong>정규화</strong>는 데이터의 <strong>중복을 제거하고</strong>,
<strong>데이터 무결성</strong>을 유지하기 위해 테이블 구조를 체계적으로 설계하는 기법</p>
</blockquote>
<hr>
<h2 id="2-정규화의-목적">2. 정규화의 목적</h2>
<ul>
<li><strong>중복 제거</strong>: 같은 정보가 여러 곳에 반복 저장되지 않도록</li>
<li><strong>이상 현상 방지</strong>: 삽입/삭제/수정 시 데이터 불일치 방지</li>
<li><strong>무결성 유지</strong>: 일관성 있는 데이터 저장</li>
<li><strong>재사용성 향상</strong>: 여러 테이블을 효율적으로 연결 가능</li>
</ul>
<hr>
<h2 id="3-이상현상이란">3. 이상현상이란?</h2>
<p>이상현상은 테이블 설계가 잘못됐을 때 발생하는 비정상적인 현상</p>
<table>
<thead>
<tr>
<th>종류</th>
<th>설명</th>
<th>예시</th>
</tr>
</thead>
<tbody><tr>
<td>삽입 이상</td>
<td>일부 정보만으로는 삽입 불가</td>
<td>고객이 주문해야 등록 가능</td>
</tr>
<tr>
<td>삭제 이상</td>
<td>하나의 삭제가 다른 정보도 삭제</td>
<td>마지막 주문 삭제 시 고객 정보도 삭제</td>
</tr>
<tr>
<td>갱신 이상</td>
<td>중복 데이터 중 일부만 수정되어 불일치 발생</td>
<td>고객 주소가 여러 행에 있을 때 일부만 변경</td>
</tr>
</tbody></table>
<hr>
<h2 id="4-정규화-단계">4. 정규화 단계</h2>
<h3 id="4-1-제1정규형-1nf--원자값atomic-value">4-1. 제1정규형 (1NF) – <strong>원자값(Atomic Value)</strong></h3>
<ul>
<li>컬럼에 반복되거나 집합적인 값이 존재하면 안 됨</li>
<li>각 필드는 <strong>더 이상 나눌 수 없는 단일값</strong>만 저장</li>
</ul>
<h4 id="비정규화-테이블-예시">비정규화 테이블 예시</h4>
<table>
<thead>
<tr>
<th align="center">학번(StudentID)</th>
<th align="center">과목명(Subject)</th>
</tr>
</thead>
<tbody><tr>
<td align="center">101</td>
<td align="center">DB, C#</td>
</tr>
<tr>
<td align="center">102</td>
<td align="center">DB</td>
</tr>
</tbody></table>
<h4 id="1nf-적용">1NF 적용</h4>
<table>
<thead>
<tr>
<th align="center">학번(StudentID)</th>
<th align="center">과목명(Subject)</th>
</tr>
</thead>
<tbody><tr>
<td align="center">101</td>
<td align="center">DB</td>
</tr>
<tr>
<td align="center">101</td>
<td align="center">C#</td>
</tr>
<tr>
<td align="center">102</td>
<td align="center">DB</td>
</tr>
</tbody></table>
<hr>
<h3 id="4-2-제2정규형-2nf---부분-함수-종속-제거">4-2. 제2정규형 (2NF) - 부분 함수 종속 제거</h3>
<ul>
<li><strong>제1정규화(1NF)</strong>를 만족해야 하며,</li>
<li><strong>기본키의 일부분에만 종속되는 속성(부분 함수 종속)</strong>이 없어야 한다.</li>
</ul>
<p>즉, 모든 비프라이머리 속성(기본키가 아닌 속성)은 기본키 전체에 대해 완전 함수 종속이어야 함.</p>
<h4 id="비정규화-예시">비정규화 예시</h4>
<ul>
<li>제1정규형까지만 적용된 테이블</li>
</ul>
<table>
<thead>
<tr>
<th align="center">학번(StudentID)</th>
<th align="center">과목명(Subject)</th>
<th align="center">교수명(Professor)</th>
</tr>
</thead>
<tbody><tr>
<td align="center">101</td>
<td align="center">DB</td>
<td align="center">홍길동</td>
</tr>
<tr>
<td align="center">101</td>
<td align="center">C#</td>
<td align="center">김철수</td>
</tr>
<tr>
<td align="center">102</td>
<td align="center">DB</td>
<td align="center">홍길동</td>
</tr>
</tbody></table>
<ul>
<li>기본키: <code>(학번, 과목명)</code> → 복합키</li>
<li><code>교수명</code>은 <code>과목명</code>에만 종속됨 → 부분 함수 종속 발생</li>
</ul>
<p>문제점</p>
<ul>
<li>과목과 교수의 관계는 중복됨 (수학=김교수)</li>
<li>과목명이 바뀌거나 교수가 변경되면 다수의 행을 수정해야 함 → 이상 발생 가능</li>
</ul>
<p>→ 교수명은 과목에만 종속되어 있으므로 과목 테이블로 분리</p>
<h4 id="2nf-적용">2NF 적용</h4>
<ul>
<li>학생-수강 테이블 (Student_Subject)</li>
</ul>
<table>
<thead>
<tr>
<th align="center">학번(StudentID)</th>
<th align="center">과목명(Subject)</th>
</tr>
</thead>
<tbody><tr>
<td align="center">101</td>
<td align="center">DB</td>
</tr>
<tr>
<td align="center">101</td>
<td align="center">C#</td>
</tr>
<tr>
<td align="center">102</td>
<td align="center">DB</td>
</tr>
<tr>
<td align="center">- 과목-교수 테이블 (Subject_Professor)</td>
<td align="center"></td>
</tr>
</tbody></table>
<table>
<thead>
<tr>
<th align="center">과목명(Subject)</th>
<th align="center">교수명(Professor)</th>
</tr>
</thead>
<tbody><tr>
<td align="center">DB</td>
<td align="center">홍길동</td>
</tr>
<tr>
<td align="center">C#</td>
<td align="center">김철수</td>
</tr>
<tr>
<td align="center">DB</td>
<td align="center">홍길동</td>
</tr>
<tr>
<td align="center">→ 교수명이 과목명에만 종속된 부분 종속 제거 완료</td>
<td align="center"></td>
</tr>
<tr>
<td align="center">→ 각 테이블은 단일 기본키에만 의존하도록 분해됨</td>
<td align="center"></td>
</tr>
</tbody></table>
<hr>
<h3 id="4-3-제3정규형-3nf---이행-함수-종속-제거">4-3. 제3정규형 (3NF) - 이행 함수 종속 제거</h3>
<ul>
<li><strong>제2정규화(2NF)</strong>를 만족해야 하며</li>
<li><strong>이행적 함수 종속(Transitive Dependency)</strong>을 제거해야 한다</li>
</ul>
<h4 id="이행적-함수-종속transitive-dependency">이행적 함수 종속(Transitive Dependency):</h4>
<ul>
<li>A → B, B → C가 존재할 때, A → C도 성립하는 관계</li>
<li>여기서 C는 A에 직접적으로 종속된 게 아니라, B를 거쳐 종속됨</li>
</ul>
<p>즉, 기본키가 아닌 다른 컬럼에 종속된 속성이 존재하는 경우!</p>
<h4 id="비정규화-예시-1">비정규화 예시</h4>
<ul>
<li>제2정규화까지만 적용된 테이블</li>
</ul>
<table>
<thead>
<tr>
<th align="center">학번</th>
<th align="center">학과코드(DeptCode)</th>
<th align="center">학과명(DeptName)</th>
</tr>
</thead>
<tbody><tr>
<td align="center">101</td>
<td align="center">CS</td>
<td align="center">컴퓨터공학과</td>
</tr>
<tr>
<td align="center">102</td>
<td align="center">EE</td>
<td align="center">전자공학과</td>
</tr>
<tr>
<td align="center">103</td>
<td align="center">CS</td>
<td align="center">컴퓨터공학과</td>
</tr>
</tbody></table>
<ul>
<li>기본키: <code>학번(StudentID)</code></li>
<li><code>학과명(DeptName)</code>은 <code>학과코드(DeptCode)</code>에 종속</li>
<li><code>학과코드</code>는 <code>학번</code>에 종속
→ 따라서 <code>학과명</code>은 <strong>학번에 이행적 종속</strong>됨</li>
</ul>
<p>문제점</p>
<ul>
<li>학과명이 바뀌면 여러 행을 수정해야 함</li>
<li>데이터 중복으로 인해 갱신 이상(Anomaly) 발생 가능</li>
</ul>
<h4 id="3nf-적용">3NF 적용</h4>
<ul>
<li>학생 테이블 (Student)</li>
</ul>
<table>
<thead>
<tr>
<th align="center">학번(StudentID)</th>
<th align="center">학과코드(DeptCode)</th>
</tr>
</thead>
<tbody><tr>
<td align="center">101</td>
<td align="center">CS</td>
</tr>
<tr>
<td align="center">102</td>
<td align="center">EE</td>
</tr>
<tr>
<td align="center">103</td>
<td align="center">CS</td>
</tr>
<tr>
<td align="center">- 학과 테이블 (Department)</td>
<td align="center"></td>
</tr>
</tbody></table>
<table>
<thead>
<tr>
<th align="center">학과코드(DeptCode)</th>
<th align="center">학과명(DeptName)</th>
</tr>
</thead>
<tbody><tr>
<td align="center">CS</td>
<td align="center">컴퓨터공학과</td>
</tr>
<tr>
<td align="center">EE</td>
<td align="center">전자공학과</td>
</tr>
<tr>
<td align="center">→ 이행적 종속 제거 완료</td>
<td align="center"></td>
</tr>
<tr>
<td align="center">→ <strong>DeptName</strong>은 더 이상 <strong>Student</strong> 테이블에 존재하지 않음</td>
<td align="center"></td>
</tr>
</tbody></table>
<hr>
<h2 id="5-정규화-vs-비정규화">5. 정규화 vs 비정규화</h2>
<table>
<thead>
<tr>
<th>항목</th>
<th>정규화</th>
<th>비정규화</th>
</tr>
</thead>
<tbody><tr>
<td><strong>정의</strong></td>
<td>중복 제거 및 이상현상 방지를 위해 테이블을 분해</td>
<td>성능 향상을 위해 테이블을 병합하거나 중복 허용</td>
</tr>
<tr>
<td><strong>목적</strong></td>
<td>무결성과 일관성 유지</td>
<td>조회 속도 향상 및 쿼리 단순화</td>
</tr>
<tr>
<td><strong>데이터 중복</strong></td>
<td>최소화</td>
<td>일부 허용 (조회 속도 우선)</td>
</tr>
<tr>
<td><strong>무결성</strong></td>
<td>유지하기 용이</td>
<td>유지하기 어려움</td>
</tr>
<tr>
<td><strong>설계 복잡도</strong></td>
<td>구조가 정교하고 복잡</td>
<td>구조가 단순화됨</td>
</tr>
<tr>
<td><strong>속도 최적화</strong></td>
<td>쓰기(INSERT/UPDATE) 최적화</td>
<td>읽기(SELECT) 최적화</td>
</tr>
<tr>
<td><strong>사용 시점</strong></td>
<td>설계 초기, 정합성이 중요한 시스템</td>
<td>성능이 중요한 상황, 조회가 많은 시스템</td>
</tr>
</tbody></table>
<h3 id="언제-정규화를-사용할까">언제 정규화를 사용할까?</h3>
<ul>
<li>데이터 <strong>무결성</strong>이 중요할 때</li>
<li>데이터 <strong>중복 최소화</strong>가 필요할 때</li>
<li><strong>업데이트, 삭제 이상</strong>을 방지하고 싶을 때</li>
</ul>
<h3 id="언제-비정규화를-사용할까">언제 비정규화를 사용할까?</h3>
<ul>
<li><strong>조회 속도</strong>가 중요한 시스템 (예: 분석, 검색 위주)</li>
<li><strong>복잡한 조인</strong>이 시스템 성능에 영향을 줄 때</li>
<li><strong>캐싱</strong>이나 <strong>요약 데이터</strong>가 필요한 경우</li>
</ul>
<blockquote>
<p>정규화는 데이터의 일관성을 보장하고 유지 관리가 용이하다는 장점이 있지만,
때로는 성능상 이유로 비정규화가 필요할 수도 있다.</p>
<p><strong>&quot;설계 초기엔 정규화, 성능 최적화 시 비정규화&quot;</strong>가 일반적인 접근</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[알고리즘] 분할정복]]></title>
            <link>https://velog.io/@homeless_snail/divide-and-conquer</link>
            <guid>https://velog.io/@homeless_snail/divide-and-conquer</guid>
            <pubDate>Thu, 10 Apr 2025 03:48:18 GMT</pubDate>
            <description><![CDATA[<h1 id="분할-정복divide-and-conquer이란">분할 정복(Divide and Conquer)이란?</h1>
<blockquote>
<p>분할 정복(Divide and Conquer)은 복잡한 문제를 <strong>작은 부분 문제로 나누어 해결한 뒤</strong>,  
이를 다시 합쳐 원래 문제의 해답을 얻는 알고리즘 설계 기법이다.</p>
</blockquote>
<p>쉽게 말해,  <strong>&quot;문제를 작게 나누고, 각 문제를 해결한 뒤, 그 결과를 합쳐서 큰 문제를 해결하는 방식&quot;</strong></p>
<hr>
<h2 id="1-분할-정복의-동작-과정">1. 분할 정복의 동작 과정</h2>
<p>분할 정복 알고리즘은 보통 다음 세 단계로 구성된다.</p>
<ol>
<li><strong>분할(Divide)</strong>: 큰 문제를 더 작은 부분 문제로 나눈다.</li>
<li><strong>정복(Conquer)</strong>: 각각의 작은 부분 문제를 재귀적으로 해결한다.</li>
<li><strong>병합(Combine)</strong>: 작은 문제들의 결과를 합쳐서 원래 문제의 해답을 얻는다.</li>
</ol>
<hr>
<h2 id="2-분할-정복의-특징-및-장점">2. 분할 정복의 특징 및 장점</h2>
<ul>
<li>문제를 작은 단위로 나누어 <strong>복잡도를 낮추는 데 효과적</strong>이다.</li>
<li>작은 부분 문제들이 서로 <strong>독립적</strong>으로 해결 가능하기 때문에 병렬 처리에 유리하다.</li>
<li>재귀적 방법을 자주 사용하며, 간결하고 효율적인 코드 작성이 가능하다.</li>
</ul>
<hr>
<h2 id="3-분할-정복을-사용하는-대표적인-알고리즘들">3. 분할 정복을 사용하는 대표적인 알고리즘들</h2>
<table>
<thead>
<tr>
<th>알고리즘</th>
<th>설명</th>
<th>시간복잡도</th>
</tr>
</thead>
<tbody><tr>
<td>병합 정렬 (Merge Sort)</td>
<td>배열을 반씩 나누어 정렬하고 병합하는 알고리즘</td>
<td><strong>$O(N log N)$</strong></td>
</tr>
<tr>
<td>퀵 정렬 (Quick Sort)</td>
<td>피벗을 기준으로 나누어 정렬하는 알고리즘</td>
<td>평균 <strong>$O(N log N)$</strong>, 최악 <strong>$O(N^2)$</strong></td>
</tr>
<tr>
<td>이진 탐색 (Binary Search)</td>
<td>정렬된 데이터에서 값을 빠르게 찾는 알고리즘</td>
<td><strong>$O(log N)$</strong></td>
</tr>
<tr>
<td>거듭제곱 (Fast Power)</td>
<td>빠르게 제곱수를 계산하는 알고리즘</td>
<td><strong>$O(log N)$</strong></td>
</tr>
<tr>
<td>스트라센 알고리즘</td>
<td>행렬 곱셈을 더 빠르게 계산하는 알고리즘</td>
<td>약 <strong>$O(N^{2.81})$</strong></td>
</tr>
</tbody></table>
<hr>
<h2 id="4-분할-정복의-시간복잡도-분석">4. 분할 정복의 시간복잡도 분석</h2>
<p>분할 정복 알고리즘의 일반적인 시간 복잡도는 다음과 같이 표현된다.
$$ 
T(n) = aT(n/b) + O(n^d)
$$</p>
<ul>
<li>$a$ : 재귀 호출 횟수</li>
<li>$n/b$ : 문제의 크기가 얼마나 작아지는지</li>
<li>$O(n^d)$ : 분할 및 병합에 걸리는 시간</li>
</ul>
<p>병합 정렬의 경우</p>
<ul>
<li>$T(n) = 2T(n/2) + O(n) = O(n log n)$</li>
</ul>
<hr>
<h2 id="5-분할-정복-예시">5. 분할 정복 예시</h2>
<h3 id="5-1-거듭제곱fast-power">5-1 거듭제곱(Fast Power)</h3>
<p>거듭제곱은 단순히 <code>a^n</code>을 반복 곱셈으로 구하면 <strong>$O(n)$</strong>의 시간이 걸린다.<br>하지만 분할 정복을 사용하면 <strong>$O(log n)$</strong> 시간에 빠르게 계산할 수 있다.</p>
<h4 id="아이디어">아이디어</h4>
<ul>
<li>짝수 지수
<strong>$a^n = (a^{n/2})^2$</strong></li>
<li>홀수 지수
<strong>$a^n = a \times (a^{\lfloor n/2 \rfloor})^2$</strong></li>
</ul>
<h4 id="예시-코드">예시 코드</h4>
<pre><code class="language-python">def fast_power(a, n):
    if n == 0:
        return 1
    half = fast_power(a, n // 2)
    if n % 2 == 0:
        return half * half
    else:
        return a * half * half

# 예시: 2^10 = 1024
print(fast_power(2, 10))  # 출력: 1024</code></pre>
<h4 id="시간-복잡도">시간 복잡도</h4>
<ul>
<li><strong>$O(log n)$</strong> → 재귀 호출이 n을 절반씩 줄이기 때문에 매우 빠름</li>
</ul>
<hr>
<h3 id="5-2-모듈러modular-거듭제곱">5-2 모듈러(modular) 거듭제곱</h3>
<p>큰 수를 계산할 때는 <strong>중간에 모듈러 연산을 적용</strong>해 오버플로우를 방지하고 효율적으로 계산할 수 있다.</p>
<h4 id="아이디어-1">아이디어</h4>
<ul>
<li>짝수 지수
<strong>$a^n \bmod m = ( a^{n/2} \bmod m )^2 \bmod m$</strong></li>
<li>홀수 지수
<strong>$a^n \bmod m = a \times ( a^{\lfloor n/2 \rfloor} \bmod m )^2 \bmod m$</strong></li>
</ul>
<h4 id="예시-코드-1">예시 코드</h4>
<pre><code class="language-python">def fast_power_mod(a, n, mod):
    if n == 0:
        return 1
    half = fast_power_mod(a, n // 2, mod)
    result = (half * half) % mod
    if n % 2 == 1:
        result = (result * a) % mod
    return result

# 예시: 2^10 % 1000 = 24
print(fast_power_mod(2, 10, 1000))  # 출력: 24</code></pre>
<h4 id="파이썬-내장-함수와-비교">파이썬 내장 함수와 비교</h4>
<pre><code class="language-python">import time

# 비교용 큰 수
a = 987654321
n = 10**9
mod = 1_000_000_007

# 사용자 정의 함수 시간 측정
start = time.time()
custom_result = fast_power_mod(a, n, mod)
end = time.time()
print(f&quot;Custom fast_power_mod result: {custom_result}&quot;)
print(f&quot;Custom function time: {end - start:.6f} seconds&quot;)

# 내장 함수 pow 시간 측정
start = time.time()
builtin_result = pow(a, n, mod)
end = time.time()
print(f&quot;Built-in pow result: {builtin_result}&quot;)
print(f&quot;Built-in pow time: {end - start:.6f} seconds&quot;)</code></pre>
<pre><code># 결과
Custom fast_power_mod result: 69424128
Custom function time: 0.000118 seconds
Built-in pow result: 69424128
Built-in pow time: 0.000005 seconds</code></pre><ul>
<li><p><strong>내장 함수 <code>pow(a, b, mod)</code></strong>는 C로 작성되어 있고 파이썬 인터프리터 수준에서 최적화되어 있기 때문에 매우 빠르다.</p>
</li>
<li><p>반면, <code>fast_power_mod</code>는 Python으로 작성된 재귀 함수이므로 약간의 오버헤드가 있지만, 그럼에도 불구하고 충분히 빠른 속도를 보여준다.</p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[알고리즘] 정렬 알고리즘]]></title>
            <link>https://velog.io/@homeless_snail/sorting-algorithms</link>
            <guid>https://velog.io/@homeless_snail/sorting-algorithms</guid>
            <pubDate>Wed, 09 Apr 2025 12:46:34 GMT</pubDate>
            <description><![CDATA[<h1 id="정렬-알고리즘sorting-algorithms이란">정렬 알고리즘(Sorting Algorithms)이란?</h1>
<blockquote>
<p>정렬 알고리즘은 데이터를 특정 기준에 따라 순서를 맞추어 나열하는 알고리즘이다.
주로 숫자나 문자를 오름차순 또는 내림차순으로 정렬할 때 사용 됨
자료구조와 알고리즘 분야에서 기초적이면서도 매우 중요한 개념</p>
</blockquote>
<hr>
<h2 id="1-버블-정렬bubble-sort">1. 버블 정렬(Bubble Sort)</h2>
<p>가장 간단한 정렬 방법 중 하나로, 인접한 두 원소를 비교하며 큰 값(또는 작은 값)을 계속 뒤로 보내면서 정렬</p>
<ul>
<li><strong>시간 복잡도</strong>: 최선 <strong>$O(N)$</strong>, 평균 및 최악 <strong>$O(N^2)$</strong></li>
<li><strong>공간 복잡도</strong>: <strong>$O(1)$</strong></li>
<li><strong>특징</strong>: 이해하기 쉽지만 성능이 좋지 않아 실제로는 거의 사용되지 않음</li>
</ul>
<h3 id="동작-과정">동작 과정</h3>
<ul>
<li>인접한 원소 두 개씩 비교하여 순서를 바꿈</li>
<li>배열 끝까지 반복하면 가장 큰(또는 작은) 원소가 맨 뒤로 이동</li>
<li>위 과정을 반복해 정렬을 완료<pre><code class="language-python">def bubble_sort(arr):
  n = len(arr)
  for i in range(n):
      swapped = False
      for j in range(n - 1 - i):
          if arr[j] &gt; arr[j + 1]:
              arr[j], arr[j + 1] = arr[j + 1], arr[j]
              swapped = True
      if not swapped:
          break
  return arr
</code></pre>
</li>
</ul>
<p>print(bubble_sort([4, 3, 5, 1, 2]))</p>
<pre><code>
---

## 2. 선택 정렬(Selection Sort)

매번 가장 작은(또는 가장 큰) 원소를 찾아 맨 앞으로 보내는 방식으로 정렬

- **시간 복잡도**: 최선, 평균, 최악 모두 **$O(N^2)$**
- **공간 복잡도**: **$O(1)$**
- **특징**: 간단하지만 비효율적

### 동작 과정
- 전체 배열에서 가장 작은 원소를 찾아 첫 번째 위치와 교환
- 두 번째 위치부터 이 과정을 반복하여 전체를 정렬
```python
def selection_sort(arr):
    n = len(arr)
    for i in range(n):
        min_idx = i
        for j in range(i + 1, n):
            if arr[min_idx] &gt; arr[j]:
                min_idx = j
        arr[i], arr[min_idx] = arr[min_idx], arr[i]
    return arr

print(selection_sort([4, 3, 5, 1, 2]))</code></pre><hr>
<h2 id="3-삽입-정렬insertion-sort">3. 삽입 정렬(Insertion Sort)</h2>
<p>배열의 각 원소를 이미 정렬된 부분에 삽입하는 방식</p>
<ul>
<li><strong>시간 복잡도</strong>: 최선 <strong>$O(N)$</strong>, 평균 및 최악 <strong>$O(N^2)$</strong></li>
<li><strong>공간 복잡도</strong>: <strong>$O(1)$</strong></li>
<li><strong>특징</strong>: 데이터가 어느 정도 정렬되어 있을 때 매우 효율적</li>
</ul>
<h3 id="동작-과정-1">동작 과정</h3>
<ul>
<li>첫 번째 원소를 정렬된 부분으로 간주</li>
<li>두 번째 원소부터 정렬된 부분 내 적절한 위치를 찾아 삽입</li>
<li>전체 원소를 대상으로 반복<pre><code class="language-python">def insertion_sort(arr):
  n = len(arr)
  for i in range(1, n):
      key = arr[i]
      j = i - 1
      while j &gt;= 0 and arr[j] &gt; key:
          arr[j + 1] = arr[j]
          j -= 1
      arr[j + 1] = key
  return arr
</code></pre>
</li>
</ul>
<p>print(insertion_sort([4, 3, 5, 1, 2]))</p>
<pre><code>
---

## 4. 병합 정렬(Merge Sort)

배열을 절반씩 나누어 각각 정렬한 후 병합하는 방식으로, 분할 정복(Divide and Conquer)을 사용합니다.

- **시간 복잡도**: 최선, 평균, 최악 모두 **$O(N log N)$**
- **공간 복잡도**: **$O(N)$**
- **특징**: 안정적이며 성능이 일관적

### 동작 과정
- 배열을 절반씩 나누어 최소 단위로 쪼갬
- 각 단위를 정렬하며 병합하여 다시 큰 배열로 합침
- 전체 배열이 정렬될 때까지 반복
```python
def merge_sort(arr):
    if len(arr) &lt;= 1:
        return arr
    mid = len(arr) // 2
    left = merge_sort(arr[:mid])
    right = merge_sort(arr[mid:])
    return merge(left, right)

def merge(left, right):
    result = []
    i = j = 0
    while i &lt; len(left) and j &lt; len(right):
        if left[i] &lt;= right[j]:
            result.append(left[i])
            i += 1
        else:
            result.append(right[j])
            j += 1
    result.extend(left[i:])
    result.extend(right[j:])
    return result

print(merge_sort([4, 3, 5, 1, 2]))</code></pre><hr>
<h2 id="5-퀵-정렬quick-sort">5. 퀵 정렬(Quick Sort)</h2>
<p>기준점(pivot)을 정해 기준보다 작은 값과 큰 값을 나누어 정렬하는 방법</p>
<ul>
<li><strong>시간 복잡도</strong>: 최선, 평균 <strong>$O(N log N)$</strong>, 최악 <strong>$O(N^2)$</strong></li>
<li><strong>공간 복잡도</strong>: <strong>$O(log N)$</strong></li>
<li><strong>특징</strong>: 일반적으로 매우 빠르지만 피벗 선택에 따라 성능이 달라진다.</li>
</ul>
<h3 id="동작-과정-2">동작 과정</h3>
<ul>
<li>배열에서 피벗을 선정(첫 번째, 마지막, 중앙값 등)</li>
<li>피벗 기준으로 작은 값은 왼쪽, 큰 값은 오른쪽에 배치</li>
<li>나뉜 부분에 대해 반복하여 정렬을 완료<pre><code class="language-python">def quick_sort(arr):
  if len(arr) &lt;= 1:
      return arr
  pivot = arr[len(arr) // 2]
  left = [x for x in arr if x &lt; pivot]
  middle = [x for x in arr if x == pivot]
  right = [x for x in arr if x &gt; pivot]
  return quick_sort(left) + middle + quick_sort(right)
</code></pre>
</li>
</ul>
<p>print(quick_sort([4, 3, 5, 1, 2]))</p>
<pre><code>
---

## 6. 힙 정렬(Heap Sort)

힙 자료구조를 이용하여 정렬하는 알고리즘

- **시간 복잡도**: 최선, 평균, 최악 모두 **$O(N log N)$**
- **공간 복잡도**: **$O(1)$**
- **특징**: 성능이 안정적이며 추가 메모리 공간을 거의 사용하지 않음

### 동작 과정
- 배열을 힙(heap) 형태로 구성(heapify)
- 힙에서 루트 원소(최대 또는 최소)를 하나씩 꺼내어 배열 뒤에서부터 채움
- 힙을 재구성하며 반복적으로 진행
```python
import heapq

def heap_sort(arr):
    heapq.heapify(arr)
    return [heapq.heappop(arr) for _ in range(len(arr))]

print(heap_sort([4, 3, 5, 1, 2]))</code></pre><pre><code class="language-python"># 힙 정렬(Heap Sort) 내부 동작 코드 예시

def heapify(arr, n, i):
    largest = i       # 현재 노드를 가장 큰 값으로 가정
    left = 2 * i + 1  # 왼쪽 자식 인덱스
    right = 2 * i + 2 # 오른쪽 자식 인덱스

    # 왼쪽 자식이 루트보다 크면 업데이트
    if left &lt; n and arr[left] &gt; arr[largest]:
        largest = left

    # 오른쪽 자식이 현재까지의 최대값보다 크면 업데이트
    if right &lt; n and arr[right] &gt; arr[largest]:
        largest = right

    # 루트가 최대가 아니라면 교환 후 하위 트리 heapify
    if largest != i:
        arr[i], arr[largest] = arr[largest], arr[i]
        print(f&quot;heapify: swapped {arr[i]} and {arr[largest]}, array: {arr}&quot;)
        heapify(arr, n, largest)

def heap_sort(arr):
    n = len(arr)

    # 최대 힙(max heap) 만들기
    for i in range(n // 2 - 1, -1, -1):
        heapify(arr, n, i)
        print(f&quot;build max-heap step: {arr}&quot;)

    print(f&quot;Max heap constructed: {arr}&quot;)

    # 힙에서 요소를 하나씩 추출하며 정렬
    for i in range(n - 1, 0, -1):
        # 현재 루트(최대값)와 마지막 원소 교환
        arr[0], arr[i] = arr[i], arr[0]
        print(f&quot;Swap root with index {i}: {arr}&quot;)

        # 힙 크기를 줄이고 다시 heapify
        heapify(arr, i, 0)
        print(f&quot;Heap after removing max element: {arr}&quot;)

    return arr

# 테스트 코드
arr = [4, 3, 5, 1, 2]
sorted_arr = heap_sort(arr)
print(f&quot;Sorted array: {sorted_arr}&quot;)</code></pre>
<hr>
<h2 id="정렬-알고리즘-특징-비교">정렬 알고리즘 특징 비교</h2>
<table>
<thead>
<tr>
<th>알고리즘</th>
<th>최선</th>
<th>평균</th>
<th>최악</th>
<th>공간복잡도</th>
</tr>
</thead>
<tbody><tr>
<td>버블 정렬</td>
<td>$O(N)$</td>
<td>$O(N^2)$</td>
<td>$O(N^2)$</td>
<td>$O(1)$</td>
</tr>
<tr>
<td>선택 정렬</td>
<td>$O(N^2)$</td>
<td>$O(N^2)$</td>
<td>$O(N^2)$</td>
<td>$O(1)$</td>
</tr>
<tr>
<td>삽입 정렬</td>
<td>$O(N)$</td>
<td>$O(N^2)$</td>
<td>$O(N^2)$</td>
<td>$O(1)$</td>
</tr>
<tr>
<td>병합 정렬</td>
<td>$O(N log N)$</td>
<td>$O(N log N)$</td>
<td>$O(N log N)$</td>
<td>$O(N)$</td>
</tr>
<tr>
<td>퀵 정렬</td>
<td>$O(N log N)$</td>
<td>$O(N log N)$</td>
<td>$O(N^2)$</td>
<td>$O(log N)$</td>
</tr>
<tr>
<td>힙 정렬</td>
<td>$O(N log N)$</td>
<td>$O(N log N)$</td>
<td>$O(N log N)$</td>
<td>$O(1)$</td>
</tr>
</tbody></table>
<hr>
<h2 id="정리">정리</h2>
<p>정렬 알고리즘은 각각의 상황과 데이터 특성에 따라 선택하는 것이 중요하다.</p>
<ul>
<li>데이터가 거의 정렬되어 있으면 삽입 정렬이 효율적</li>
<li>일반적인 경우 빠른 속도를 원하면 퀵 정렬을 고려</li>
<li>안정적이고 일관된 성능이 필요하면 병합 정렬이나 힙 정렬이 적합</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] 메서드]]></title>
            <link>https://velog.io/@homeless_snail/java-method</link>
            <guid>https://velog.io/@homeless_snail/java-method</guid>
            <pubDate>Sun, 06 Apr 2025 12:36:18 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>자주 반복되는 작업을 하나의 코드 블록으로 정의해 재사용할 수 있게 해주는 <strong>메서드(method)</strong>는 가독성과 유지보수를 높이는 핵심 도구이다.</p>
</blockquote>
<h2 id="메서드가-필요한-이유">메서드가 필요한 이유</h2>
<pre><code class="language-java">int a = 1, b = 2;
System.out.println(a + &quot;+&quot; + b + &quot; 연산 수행&quot;);
int sum1 = a + b;

int x = 10, y = 20;
System.out.println(x + &quot;+&quot; + y + &quot; 연산 수행&quot;);
int sum2 = x + y;</code></pre>
<ul>
<li>위처럼 같은 연산을 반복해야 할 때, 코드 중복이 많고 유지보수가 어렵다</li>
</ul>
<hr>
<h2 id="메서드의-기본-구조">메서드의 기본 구조</h2>
<pre><code class="language-java">public static int add(int a, int b) {
    int sum = a + b;
    return sum;
}</code></pre>
<ul>
<li><code>public static</code>: 제어자</li>
<li><code>int</code>: 반환 타입 (리턴값의 타입)</li>
<li><code>add</code>: 메서드 이름 (호출 시 사용)</li>
<li><code>(int a, int b)</code>: 매개변수(파라미터) – 메서드에 전달하는 값</li>
<li><code>{ ... }</code>: 메서드 본문 – 실제 동작을 수행하는 코드 블록</li>
</ul>
<h3 id="사용-예시">사용 예시</h3>
<pre><code class="language-java">int sum1 = add(5, 10);  // 결과: 15
int sum2 = add(15, 20); // 결과: 35</code></pre>
<ul>
<li><code>add(5, 10)</code> 호출 → 메서드 내부 실행 → 결과 15 반환 → 변수에 저장</li>
<li>메서드는 호출하는 쪽에서는 내부 동작을 몰라도 사용 가능 (블랙박스)</li>
</ul>
<hr>
<h2 id="메서드와-형변환-형이-다른-값을-메서드에-넘길-때">메서드와 형변환 (형이 다른 값을 메서드에 넘길 때)</h2>
<p>자바에서는 메서드를 호출할 때, 전달하는 값(인수)의 타입이 <strong>메서드가 정의한 매개변수 타입과 다를 수 있음</strong>
이때 자바는 형변환(casting)을 자동 또는 명시적으로 처리해야 한다.</p>
<h3 id="자동-형변환-묵시적-형변환">자동 형변환 (묵시적 형변환)</h3>
<p><strong>작은 타입 → 큰 타입</strong>으로 넘길 때는 자바가 자동으로 형을 맞춰준다.</p>
<pre><code class="language-java">public static void printDouble(double value) {
    System.out.println(&quot;실수: &quot; + value);
}

int i = 10;
printDouble(i);  // int → double 자동 형변환</code></pre>
<ul>
<li><code>int</code>는 <code>double</code>보다 작은 타입</li>
<li>자바가 자동으로 <code>10</code>을 <code>10.0</code>으로 변환해서 넘겨줌</li>
</ul>
<h3 id="명시적-형변환-강제-형변환">명시적 형변환 (강제 형변환)</h3>
<p>큰 타입 → 작은 타입으로 넘기면 컴파일 에러 발생!
이 경우 개발자가 명시적으로 형변환을 해줘야 한다.</p>
<pre><code class="language-java">public static void printInt(int value) {
    System.out.println(&quot;정수: &quot; + value);
}

double d = 3.14;
printInt((int) d); // 명시적 형변환 필요 → 결과: 3</code></pre>
<ul>
<li>실수형 <code>3.14는</code> 정수형보다 크므로 자동 변환 불가능</li>
<li><code>(int)</code>를 붙여서 강제로 정수로 변환해야 함</li>
<li>소수점은 잘려서 정수 부분만 남음</li>
</ul>
<pre><code class="language-java">printInt(3.14); // ❌ 컴파일 오류!</code></pre>
<ul>
<li>손실 가능성이 있으므로 자동 변환을 허용하지 않음</li>
</ul>
<hr>
<h2 id="메서드-오버로딩-overloading">메서드 오버로딩 (Overloading)</h2>
<blockquote>
<p>같은 이름의 메서드라도, 매개변수의 타입이나 개수가 다르면 여러 개 만들 수 있다.
이를 <strong>오버로딩(overloading)</strong>이라고 한다.</p>
</blockquote>
<h3 id="오버로딩-예제">오버로딩 예제</h3>
<ul>
<li>이름은 모두 <code>add</code>지만, 매개변수 개수 또는 매개변수 타입이 다르기 때문에 각각 별개의 메서드로 인식됨<pre><code class="language-java">public static int add(int a, int b) {
  return a + b;
}
</code></pre>
</li>
</ul>
<p>public static double add(double a, double b) {
    return a + b;
}</p>
<p>public static int add(int a, int b, int c) {
    return a + b + c;
}</p>
<p>System.out.println(add(1, 2));        // int 버전 호출
System.out.println(add(1.0, 2.0));    // double 버전 호출
System.out.println(add(1, 2, 3));     // 파라미터 3개짜리 버전 호출</p>
<pre><code>### ⚠️ 주의: 반환값만 다르면 오버로딩이 안 된다!
```java
public static int test() {
    return 1;
}

// 아래 메서드는 에러 발생!
public static double test() {
    return 1.0;
}</code></pre><ul>
<li>컴파일러는 메서드 이름과 매개변수 시그니처만 보고 구분</li>
<li>반환값은 오버로딩 판별 기준이 아니기 때문에 위 코드는 중복 정의 오류가 발생</li>
</ul>
<h3 id="오버로딩이-왜-필요할까">오버로딩이 왜 필요할까?</h3>
<ul>
<li><p>같은 동작이지만 입력 방식이 다를 때
<code>print(String)</code> vs <code>print(int)</code>처럼 다양한 타입을 처리 가능</p>
</li>
<li><p>확장성 향상
같은 이름으로 처리 가능하므로 메서드 이름을 외우기 쉬움</p>
</li>
<li><p>코드 가독성 증가
의미 있는 메서드 이름을 일관되게 사용할 수 있음</p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] 배열]]></title>
            <link>https://velog.io/@homeless_snail/java-array</link>
            <guid>https://velog.io/@homeless_snail/java-array</guid>
            <pubDate>Fri, 04 Apr 2025 14:30:58 GMT</pubDate>
            <description><![CDATA[<h2 id="배열이-필요한-이유">배열이 필요한 이유</h2>
<blockquote>
<p>많은 양의 데이터를 효율적으로 다루기 위해 <strong>배열(Array)</strong>을 사용</p>
</blockquote>
<p>예를 들어 학생 5명의 점수를 관리한다고 할 때, 배열이 없다면 이렇게 작성해야 한다.</p>
<pre><code class="language-java">int student1 = 90;
int student2 = 80;
int student3 = 70;
int student4 = 60;
int student5 = 50;</code></pre>
<ul>
<li>학생 수가 많아질수록 코드가 <strong>선언 + 출력</strong> 모두 비효율적</li>
<li><strong>비슷한 변수 이름 반복</strong>, <strong>반복문 적용 불가</strong> → 유지보수 어려움</li>
</ul>
<hr>
<h2 id="배열의-선언과-생성">배열의 선언과 생성</h2>
<pre><code class="language-java">int[] students;             // 배열 변수 선언
students = new int[5];      // 배열 생성</code></pre>
<ul>
<li><code>int[]</code> → int형 배열을 의미</li>
<li><code>new int[5]</code> → int 5개짜리 배열 생성</li>
<li>배열 생성 시 자바가 자동으로 초기화해준다.<ul>
<li>숫자는 <code>0</code>, boolean은 <code>false</code>, String(문자열)은 <code>null</code>로 초기화 된다.</li>
</ul>
</li>
</ul>
<hr>
<h2 id="배열-참조의-개념">배열 참조의 개념</h2>
<blockquote>
<p>배열은 참조형(reference type)이다.
즉, 변수는 배열이 저장된 <strong>메모리 주소(참조값)</strong>를 가지고 있다.</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/homeless_snail/post/ae116b01-9b70-486f-ac44-e406d0dbcee7/image.png" alt=""></p>
<pre><code class="language-java">int[] students = new int[5]; //1. 배열 생성
int[] students = x001; //2. new int[5]의 결과로 x001 참조값 반환
students = x001 //3. 최종 결과</code></pre>
<p>→ <code>x001</code>은 배열의 주소이고, 이를 통해 배열에 접근한다.</p>
<ul>
<li>실제 배열의 참조값을 출력하면 다음과 같이 나온다.<pre><code class="language-java">System.out.println(students);
//출력 결과: `[I@16f65612` (int형 배열의 참조값)</code></pre>
<code>[I@4617c264</code> @앞의 <code>[I</code>는 int형 배열을 뜻한다. @뒤에 16진수는 참조값을 뜻한다.</li>
</ul>
<hr>
<h2 id="인덱스">인덱스</h2>
<ul>
<li>배열은 변수와 사용법이 비슷한데, 차이점이 있다면 다음과 같이  <code>[]</code>사이에 숫자 번호를 넣어주면 된다.</li>
<li>배열의 위치를 나타내는 숫자를 인덱스(index)라 한다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/homeless_snail/post/bc2a6371-f593-48ee-8bf3-435fcd4c6e38/image.png" alt=""></p>
<pre><code class="language-java">//변수 값 대입
students[0] = 90;
students[1] = 80;
//변수 값 사용
System.out.println(&quot;학생1 점수: &quot; + students[0]);
System.out.println(&quot;학생2 점수: &quot; + students[1]);</code></pre>
<p><strong>배열은 0부터 시작한다</strong></p>
<ul>
<li><code>new int[5]</code>와 같이 5개의 요소를 가지는  <code>int</code>형 배열을 만들었다면 인덱스는  <code>0,1,2,3,4</code>가 존재한다.</li>
<li>여기서 주의해야 할 점이 있는데 인덱스는 0부터 시작한다는 것이다. 배열의 요소를 5개로 생성했지만, 인덱스는 0부터 시작한다.</li>
<li>따라서 사용 가능한 인덱스의 범위는  <code>0 ~ (n-1)</code>이 된다. 그래서  <code>students[4]</code>가 배열의 마지막 요소이
다.</li>
<li>만약  <code>students[5]</code>와 같이 접근 가능한 배열의 인덱스 범위를 넘어가면 오류가 발생한다.</li>
</ul>
<hr>
<h2 id="배열-초기화">배열 초기화</h2>
<ul>
<li>앞서 배열을 생성하면 자바가 자동으로 초기화해준다고 소개를 했다.</li>
<li>배열 생성 후 값을 대입하려면 아래와 같이 해야한다.
이 경우 코드가 늘어나는 단점이 생긴다.<pre><code class="language-java">int[] students;             // 배열 변수 선언
students = new int[5];      // 배열 생성
// 초기화된 배열: {0, 0, 0, 0, 0}
</code></pre>
</li>
</ul>
<p>// 배열에 값 대입
students[0] = 90;
students[1] = 80;
students[2] = 70;
students[3] = 60;
students[4] = 50;</p>
<pre><code>- 생성과 동시에 값을 대입해보자
```java
int[] student; // 배열 선언
students = new int[]{90, 80, 70, 60, 50}; // 배열 생성과 초기화</code></pre><ul>
<li>선언과 동시에 생성 및 초기화도 가능<pre><code class="language-java">int[] students = new int[]{90, 80, 70, 60, 50};
// 또는
int[] students = {90, 80, 70, 60, 50};</code></pre>
</li>
</ul>
<hr>
<h2 id="2차원-배열">2차원 배열</h2>
<blockquote>
<p>2차원 배열은 <strong>행(row)과 열(column)</strong>로 구성된 배열</p>
</blockquote>
<ul>
<li><p>2차원 배열 선언과 생성</p>
<pre><code class="language-java">int[][] arr = new int[2][3];
arr[0][0] = 1;  // 1행 1열</code></pre>
</li>
<li><p>2차원 배열 초기화</p>
<pre><code class="language-java">int[][] arr = {
  {1,2,3},
  {4,5,6}
}; //행2, 열3</code></pre>
</li>
<li><p>2차원 배열 출력</p>
<pre><code class="language-java">for (int row = 0; row &lt; arr.length; row++) {
  for (int column = 0; column &lt; arr[row].length; column++) {
      System.out.print(arr[row][column] + &quot; &quot;);
  }
  System.out.println(); //한 행이 끝나면 라인을 변경
}</code></pre>
</li>
</ul>
<hr>
<h2 id="enhanced-for-loop">Enhanced For Loop</h2>
<blockquote>
<p>배열 요소를 처음부터 끝까지 순회할 때 사용
각각의 요소를 탐색한다는 의미로 for-each문이라고도 많이 부른다.</p>
</blockquote>
<h3 id="향상된-for문-정의">향상된 for문 정의</h3>
<pre><code class="language-java">for (변수 : 배열 또는 컬렉션) {
  // 배열 또는 컬렉션의 요소를 순회하면서 수행할 작업
}</code></pre>
<h3 id="예제">예제</h3>
<pre><code class="language-java">// 일반 for문
for(int i = 0; i &lt; numbers.length; ++i) {
    int number = numbers[i];
    System.out.println(number);
}

// Enhanced For 문, for-each문
for (int number : numbers) {
    System.out.println(number);
}</code></pre>
<ul>
<li>인덱스가 필요 없는 경우에 코드가 훨씬 깔끔해짐</li>
<li>인덱스를 활용해야 할 경우에는 일반 for문을 사용해야 함</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] Scanner]]></title>
            <link>https://velog.io/@homeless_snail/java-scanner</link>
            <guid>https://velog.io/@homeless_snail/java-scanner</guid>
            <pubDate>Fri, 04 Apr 2025 11:28:25 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>자바에서 사용자로부터 키보드 입력을 받을 때는 <code>Scanner</code> 클래스를 가장 많이 사용한다.
<code>System.in</code>을 활용해서 다양한 타입의 값을 간단하게 입력받을 수 있다.</p>
</blockquote>
<h2 id="scanner-사용-기본-구조">Scanner 사용 기본 구조</h2>
<pre><code class="language-java">Scanner scanner = new Scanner(System.in);</code></pre>
<ul>
<li><code>System.in</code> : 표준 입력 (키보드)</li>
<li><code>new Scanner(...)</code> : 입력 도구 생성</li>
</ul>
<hr>
<h2 id="scanner-주요-메서드-정리">Scanner 주요 메서드 정리</h2>
<table>
<thead>
<tr>
<th>메서드</th>
<th>설명</th>
<th>입력 예시</th>
<th>결과 값</th>
<th>결과 타입</th>
</tr>
</thead>
<tbody><tr>
<td><code>nextLine()</code></td>
<td>한 줄 전체 입력</td>
<td>hello world</td>
<td>hello world</td>
<td>String</td>
</tr>
<tr>
<td><code>next()</code></td>
<td>단어 하나 (공백 기준)</td>
<td>hello world</td>
<td>hello</td>
<td>String</td>
</tr>
<tr>
<td><code>nextInt()</code></td>
<td>정수 입력</td>
<td>10</td>
<td>10</td>
<td>int</td>
</tr>
<tr>
<td><code>nextDouble()</code></td>
<td>실수 입력</td>
<td>3.14</td>
<td>3.14</td>
<td>double</td>
</tr>
<tr>
<td><code>nextBoolean()</code></td>
<td>true / false 입력</td>
<td>true</td>
<td>true</td>
<td>boolean</td>
</tr>
</tbody></table>
<ul>
<li>입력예제<pre><code class="language-java">Scanner scanner = new Scanner(System.in);
System.out.print(&quot;이름을 입력하세요: &quot;);
String name = scanner.nextLine();
System.out.println(&quot;안녕하세요, &quot; + name + &quot;님!&quot;);</code></pre>
</li>
</ul>
<hr>
<h2 id="scanner-사용-시-주의점">Scanner 사용 시 주의점</h2>
<ul>
<li><code>nextInt()</code> 등 숫자 입력 후 <code>nextLine()</code>을 바로 쓰면 버퍼 문제로 줄바꿈이 넘어감</li>
</ul>
<pre><code class="language-java">int age = scanner.nextInt();
String name = scanner.nextLine(); // ← 여기서 빈 문자열이 들어올 수 있음</code></pre>
<p>→ 해결법: <code>nextLine()</code>을 한 번 더 써서 줄바꿈 제거</p>
<ul>
<li><code>Scanner</code>는 보통 프로그램 끝나기 전에 닫지 않아도 큰 문제는 없지만, 자바에서는 리소스 정리를 위해 <code>scanner.close();</code>를 호출하는 습관이 좋음</li>
</ul>
<h3 id="예시">예시</h3>
<pre><code class="language-java">Scanner scanner = new Scanner(System.in);

System.out.print(&quot;나이를 입력하세요: &quot;);
int age = scanner.nextInt();  // 여기서 숫자 입력

System.out.print(&quot;이름을 입력하세요: &quot;);
String name = scanner.nextLine();  // 이름 입력?
System.out.println(&quot;입력된 이름: &quot; + name);</code></pre>
<p><strong>실행</strong></p>
<ul>
<li>입력<pre><code>나이를 입력하세요: 20
이름을 입력하세요: </code></pre></li>
<li>결과<pre><code>입력된 이름: </code></pre>사용자 입장에서는 분명 숫자 <code>20</code>을 입력하고 엔터를 쳤는데,
다음 <code>nextLine()</code>에서 <strong>입력을 건너뛰고 바로 빈 문자열(&quot;&quot;)</strong>이 들어가 버린다.</li>
</ul>
<h3 id="왜-이런-일이-발생할까">왜 이런 일이 발생할까?</h3>
<ul>
<li><code>nextInt()</code>는 숫자만 읽고, 사용자가 누른 엔터(줄바꿈 문자 <code>\n</code>)는 버퍼에 남겨둔다.</li>
<li>이후 <code>nextLine()</code>이 호출되면, 그 남아 있던 <code>\n</code>만 읽고 끝난다.</li>
<li>결과적으로 <strong>입력 없이 넘어간 것처럼 보이는 것</strong>이다.</li>
</ul>
<h3 id="해결-방법">해결 방법</h3>
<ul>
<li>숫자 입력 후 버퍼를 비워주는 <code>nextLine()</code>을 한 번 더 호출하면 된다.<pre><code class="language-java">Scanner scanner = new Scanner(System.in);
</code></pre>
</li>
</ul>
<p>System.out.print(&quot;나이를 입력하세요: &quot;);
int age = scanner.nextInt();
scanner.nextLine();  // ★ 여기서 엔터 제거!</p>
<p>System.out.print(&quot;이름을 입력하세요: &quot;);
String name = scanner.nextLine();</p>
<p>System.out.println(&quot;입력된 이름: &quot; + name);</p>
<p>```</p>
<blockquote>
<p>정수나 실수 입력 후 문자열 입력이 바로 이어진다면, 반드시 <code>nextLine()</code>으로 버퍼를 비워줘야 한다!</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] 스코프(Scope)와 형변환(Casting)]]></title>
            <link>https://velog.io/@homeless_snail/java-scopecasting</link>
            <guid>https://velog.io/@homeless_snail/java-scopecasting</guid>
            <pubDate>Fri, 04 Apr 2025 05:06:38 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>자바에서 변수는 선언된 <strong>범위(스코프)</strong> 안에서만 유효하며,
서로 다른 <strong>타입 간 대입</strong>에는 <strong>형변환</strong>이 필요하다. 이번 글에서는 이 두 개념을 정리한다.</p>
</blockquote>
<hr>
<h2 id="1-스코프-scope">1. 스코프 (Scope)</h2>
<h3 id="1-1-지역-변수의-생존-범위">1-1. 지역 변수의 생존 범위</h3>
<ul>
<li>변수는 선언된 <code>{}</code> 블록 안에서만 유효하다. 해당 블록을 벗어나면 변수는 제거되고 접근할 수 없다.</li>
</ul>
<pre><code class="language-java">public static void main(String[] args) {
    int m = 10; // main 전체에서 유효

    if (true) {
        int x = 20; // if 블록 내부에서만 유효
        System.out.println(m); // 가능
        System.out.println(x); // 가능
    }

    // System.out.println(x); // 오류: x는 스코프 밖
    System.out.println(m); // 가능
}</code></pre>
<h3 id="1-2-for-문과-스코프">1-2. for 문과 스코프</h3>
<ul>
<li>for문 안에서 선언한 변수는 해당 for 블록 안에서만 사용 가능하다.<pre><code class="language-java">for (int i = 0; i &lt; 3; i++) {
  System.out.println(i); // 가능
}
// System.out.println(i); // 오류: i는 for문 밖</code></pre>
</li>
</ul>
<hr>
<h3 id="왜-스코프가-필요할까">왜 스코프가 필요할까?</h3>
<ul>
<li>메모리 낭비 줄임</li>
<li>코드 가독성 향상</li>
<li>유지보수에 유리</li>
</ul>
<p><strong>변수는 꼭 필요한 범위 내에서만 사용하는 것이 좋다.</strong></p>
<ul>
<li>❌ 잘못된 예<pre><code class="language-java">int temp = 0;
</code></pre>
</li>
</ul>
<p>if (m &gt; 0) {
    temp = m * 2;
}</p>
<pre><code>
- ✅ 좋은 예
```java
if (m &gt; 0) {
    int temp = m * 2;
}</code></pre><hr>
<h2 id="2-형변환-casting">2. 형변환 (Casting)</h2>
<h3 id="2-1-묵시적자동-형변환">2-1. 묵시적(자동) 형변환</h3>
<ul>
<li>작은 타입 → 큰 타입으로 변환은 자동으로 처리된다.<pre><code class="language-java">int intValue = 10;
long longValue = intValue;
double doubleValue = intValue;</code></pre>
</li>
<li><code>int → long → double</code> 은 값의 손실이 없기 때문에 자동으로 변환된다.</li>
<li>이처럼 <strong>묵시적 형변환은 컴파일 시점에 처리되며</strong>,  <code>.class</code> 파일에는 해당 형변환 정보가 <strong>명확하게 기록된다.</strong></li>
</ul>
<p>즉, 자바 컴파일러가 소스 코드를 바이트코드로 변환할 때 <strong>형변환을 JVM이 인식할 수 있도록 명확하게 삽입</strong>한다.</p>
<h3 id="2-2-명시적강제-형변환">2-2. 명시적(강제) 형변환</h3>
<ul>
<li>큰 타입 → 작은 타입으로 변환하려면 명시적으로 변환해야 한다.</li>
</ul>
<pre><code class="language-java">double d = 1.5;
int i = (int) d;  // 소수점 버려짐 → i = 1</code></pre>
<hr>
<h3 id="형변환과-오버플로우">형변환과 오버플로우</h3>
<blockquote>
<p>형변환을 할 때 만약 작은 숫자가 표현할 수 있는 범위를 넘어서면 어떻게 될까?</p>
</blockquote>
<pre><code class="language-java">long big = 2147483648L;  // int 최대값 초과
int small = (int) big;

System.out.println(small);  // 출력: -2147483648</code></pre>
<ul>
<li>2147483648은 int 범위를 넘는 값 → 형변환 시 비트 앞쪽(부호비트 포함)이 잘려 나감</li>
<li>그 결과 <strong>int의 최소값(-2,147,483,648)</strong> 이 된다</li>
</ul>
<h4 id="왜-이런-일이-생길까">왜 이런 일이 생길까?</h4>
<ul>
<li>컴퓨터는 메모리 공간이 고정되어 있으므로,
큰 타입에서 작은 타입으로 변환할 경우 <strong>비트 수가 줄어들면서 앞쪽 비트들이 손실</strong>된다.<br>이는 <strong>2의 보수 표현 방식</strong>에 의해 음수로 해석될 수 있다.</li>
</ul>
<h4 id="오버플로우가-발생해도-컴파일-에러는-없다">오버플로우가 발생해도 컴파일 에러는 없다</h4>
<ul>
<li>형변환 자체는 문제가 없기 때문에 컴파일러는 에러를 내지 않는다.<br>하지만 결과는 예기치 않게 나올 수 있으므로, 반드시 값을 확인하거나 조건을 체크해야 한다.</li>
</ul>
<p><strong>오버플로우는 눈에 보이지 않고, 경고 없이 발생하기 때문에 항상 주의해야 한다!</strong></p>
<hr>
<h2 id="3-계산-시-형변환">3. 계산 시 형변환</h2>
<ul>
<li>계산 과정에서도 자동 형변환이 발생할 수 있다.</li>
<li>같은 타입끼리 계산 → 결과도 같은 타입</li>
<li>다른 타입끼리 계산 → 큰 타입으로 자동 형변환</li>
</ul>
<pre><code class="language-java">int div1 = 3 / 2;
System.out.println(&quot;div1 = &quot; + div1); //1

double div2 = 3 / 2;
System.out.println(&quot;div2 = &quot; + div2); //1.0

double div3 = 3.0 / 2;
System.out.println(&quot;div3 = &quot; + div3); //1.5

double div4 = (double) 3 / 2;
System.out.println(&quot;div4 = &quot; + div4); //1.5

int a = 3;
int b = 2;
double result = (double) a / b;
System.out.println(&quot;result = &quot; + result); //1.5
</code></pre>
<table>
<thead>
<tr>
<th>구분</th>
<th>설명</th>
<th>예시</th>
</tr>
</thead>
<tbody><tr>
<td>자동 형변환</td>
<td>작은 타입 → 큰 타입, 문제 없음</td>
<td>int → long → double</td>
</tr>
<tr>
<td>명시적 형변환</td>
<td>큰 타입 → 작은 타입, <strong>개발자 책임</strong></td>
<td>(int) 1.5 → 1 (소수 손실)</td>
</tr>
</tbody></table>
<blockquote>
<p>작은 컵에서 큰 컵은 OK, 큰 컵에서 작은 컵은 흘러넘칠 수 있다!</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] 반복문]]></title>
            <link>https://velog.io/@homeless_snail/java-loop</link>
            <guid>https://velog.io/@homeless_snail/java-loop</guid>
            <pubDate>Fri, 04 Apr 2025 04:35:51 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><strong>반복문</strong>은 특정 코드를 여러 번 반복 실행하고 싶을 때 사용한다.</p>
</blockquote>
<h2 id="1-while-문">1. <code>while</code> 문</h2>
<ul>
<li>조건이 참인 동안 반복 실행한다.
조건식이 false가 되면 반복이 종료된다.</li>
</ul>
<h3 id="기본구조">기본구조</h3>
<pre><code class="language-java">while (조건식) {
    // 반복할 코드
}</code></pre>
<ul>
<li>예제<pre><code class="language-java">int count = 0;
while (count &lt; 3) {
  count++;
  System.out.println(&quot;현재 숫자는: &quot; + count);
}</code></pre>
</li>
</ul>
<hr>
<h2 id="2-do-while문">2. <code>do-while</code>문</h2>
<ul>
<li>조건과 상관없이 최소 1회는 실행된다.
조건이 거짓이라도 코드 블럭은 최소 한 번은 실행됨</li>
</ul>
<h3 id="기본구조-1">기본구조</h3>
<pre><code class="language-java">do {
    // 반복할 코드
} while (조건식);</code></pre>
<ul>
<li>예제<pre><code class="language-java">int i = 10;
do {
  System.out.println(&quot;현재 숫자는: &quot; + i);
  i++;
} while (i &lt; 3);</code></pre>
</li>
</ul>
<hr>
<h2 id="3-for-문">3. <code>for</code> 문</h2>
<ul>
<li>초기식, 조건식, 증감식을 한 줄에 모아 작성할 수 있어 가독성이 좋다.<h3 id="기본구조-2">기본구조</h3>
<pre><code class="language-java">for (초기식; 조건식; 증감식) {
  // 반복할 코드
}</code></pre>
</li>
<li>예제<pre><code class="language-java">for (int i = 1; i &lt;= 3; i++) {
  System.out.println(&quot;i = &quot; + i);
}</code></pre>
</li>
</ul>
<hr>
<h2 id="4-break와-continue">4. <code>break</code>와 <code>continue</code></h2>
<blockquote>
<p><code>break</code>: 반복문을 <strong>즉시 종료</strong>
<code>continue</code>: 현재 반복을 건너뛰고 <strong>다음 반복으로 진행</strong></p>
</blockquote>
<ul>
<li><code>break</code> 예제<pre><code class="language-java">int sum = 0;
int i = 1;
</code></pre>
</li>
</ul>
<p>while (true) {
    sum += i;
    if (sum &gt; 10) {
        break;
    }
    i++;
}
// 출력: 1 2 4 5</p>
<pre><code>- `continue` 예제
```java
for (int i = 1; i &lt;= 5; i++) {
    if (i == 3) continue;
    System.out.println(i);
}</code></pre><hr>
<h2 id="5-중첩-반복문">5. 중첩 반복문</h2>
<ul>
<li>반복문 안에 또 다른 반복문을 넣을 수 있다.<pre><code class="language-java">for (int i = 1; i &lt;= 9; i++) {
  for (int j = 1; j &lt;= 9; j++) {
      System.out.println(i + &quot; * &quot; + j + &quot; = &quot; + (i * j));
  }
}
</code></pre>
</li>
</ul>
<h2 id="">```</h2>
<h2 id="6-for-vs-while-비교">6. for vs while 비교</h2>
<table>
<thead>
<tr>
<th>구분</th>
<th><code>for</code>문 특징</th>
<th><code>while</code>문 특징</th>
</tr>
</thead>
<tbody><tr>
<td>사용 목적</td>
<td>반복 횟수가 <strong>명확할 때</strong> 사용</td>
<td>조건 기반 반복이 <strong>필요할 때</strong> 사용</td>
</tr>
<tr>
<td>가독성</td>
<td>초기식, 조건식, 증감식을 <strong>한 줄로 표현</strong> → 명확함</td>
<td>조건과 반복 흐름이 <strong>코드에 분산됨</strong></td>
</tr>
<tr>
<td>변수 범위</td>
<td>루프 변수(<code>i</code> 등)가 <strong>for문 블록 안에서만 유효</strong></td>
<td>루프 변수의 범위가 넓어 <strong>실수로 변경될 위험</strong></td>
</tr>
</tbody></table>
<blockquote>
<p>정해진 횟수 반복 → <code>for문</code>
조건 만족할 때까지 반복 → <code>while문</code></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] 조건문]]></title>
            <link>https://velog.io/@homeless_snail/java-condition</link>
            <guid>https://velog.io/@homeless_snail/java-condition</guid>
            <pubDate>Fri, 04 Apr 2025 03:45:48 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>조건문은 특정 <strong>조건에 따라 실행 흐름을 제어</strong>할 수 있게 해준다.  </p>
</blockquote>
<h2 id="1-if문">1. <code>if</code>문</h2>
<h3 id="기본-구조">기본 구조</h3>
<pre><code class="language-java">if (조건) {
    // 조건이 참일 때 실행
} else if (다른 조건) {
    // 위 조건이 거짓이고, 이 조건이 참일 때 실행
} else {
    // 모든 조건이 거짓일 때 실행
}</code></pre>
<ul>
<li>예제<pre><code class="language-java">int age = 20;
</code></pre>
</li>
</ul>
<p>if (age &gt;= 18) {
    System.out.println(&quot;성인입니다.&quot;);
} else {
    System.out.println(&quot;미성년자입니다.&quot;);
}</p>
<pre><code>- `else if`를 활용한 다중 조건 분기
```java
int age = 14;

if (age &lt;= 7) {
    System.out.println(&quot;미취학&quot;);
} else if (age &lt;= 13) {
    System.out.println(&quot;초등학생&quot;);
} else if (age &lt;= 16) {
    System.out.println(&quot;중학생&quot;);
} else if (age &lt;= 19) {
    System.out.println(&quot;고등학생&quot;);
} else {
    System.out.println(&quot;성인&quot;);
}</code></pre><hr>
<h2 id="2-switch-문">2. <code>switch</code> 문</h2>
<ul>
<li><code>switch</code>는 특정 값에 따라 코드를 분기할 때 사용한다.<pre><code class="language-java">int grade = 2;
int coupon;
</code></pre>
</li>
</ul>
<p>switch (grade) {
    case 1:
        coupon = 1000;
        break;
    case 2:
        coupon = 2000;
        break;
    case 3:
        coupon = 3000;
        break;
    default:
        coupon = 500;
}</p>
<p>System.out.println(&quot;발급받은 쿠폰 &quot; + coupon);</p>
<pre><code>- Java 14 이후 새로운 `switch`
  - `-&gt;` 화살표 문법
  - 값을 반환할 수 있음
  - `break` 생략
```java
int grade = 2;

int coupon = switch (grade) {
    case 1 -&gt; 1000;
    case 2 -&gt; 2000;
    case 3 -&gt; 3000;
    default -&gt; 500;
};</code></pre><hr>
<h2 id="3-삼항-연산자">3. 삼항 연산자</h2>
<h3 id="기본구조">기본구조</h3>
<pre><code>(조건) ? 참_값 : 거짓_값</code></pre><ul>
<li>단순한 분기를 표현할 때 <code>if</code>보다 코드가 짧고 간결함<pre><code class="language-java">int age = 18;
String status = (age &gt;= 18) ? &quot;성인&quot; : &quot;미성년자&quot;;
System.out.println(status);</code></pre>
</li>
</ul>
<hr>
<h2 id="조건문-종류-요약표">조건문 종류 요약표</h2>
<table>
<thead>
<tr>
<th>종류</th>
<th>특징</th>
<th>사용 예시</th>
</tr>
</thead>
<tbody><tr>
<td><code>if</code></td>
<td>기본 조건문</td>
<td><code>if (조건) { ... }</code></td>
</tr>
<tr>
<td><code>if - else</code></td>
<td>조건이 거짓일 때 다른 코드 실행</td>
<td><code>if (...) { ... } else { ... }</code></td>
</tr>
<tr>
<td><code>else if</code></td>
<td>다중 조건 분기</td>
<td>여러 조건 중 하나 선택</td>
</tr>
<tr>
<td><code>switch</code></td>
<td>값에 따라 분기</td>
<td><code>switch (변수) { case ... }</code></td>
</tr>
<tr>
<td>삼항 연산자</td>
<td>간단한 조건값 선택</td>
<td><code>(조건) ? 값1 : 값2</code></td>
</tr>
</tbody></table>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] 비트 연산자]]></title>
            <link>https://velog.io/@homeless_snail/java-bit-operator</link>
            <guid>https://velog.io/@homeless_snail/java-bit-operator</guid>
            <pubDate>Fri, 04 Apr 2025 03:18:39 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>비트 연산자는 정수를 <strong>2진수 비트 단위로 직접 조작</strong>할 수 있게 해주는 연산자다.
평소에는 자주 쓰이지 않지만, <strong>알고리즘 문제</strong>, <strong>성능 최적화</strong>, <strong>비트 마스킹</strong> 등에 매우 유용하다.</p>
</blockquote>
<hr>
<h3 id="주요-비트-연산자">주요 비트 연산자</h3>
<table>
<thead>
<tr>
<th>연산자</th>
<th>이름</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><code>&amp;</code></td>
<td>AND</td>
<td>두 비트가 모두 1이면 1, 아니면 0</td>
</tr>
<tr>
<td>|</td>
<td>OR</td>
<td>두 비트 중 하나라도 1이면 1</td>
</tr>
<tr>
<td><code>^</code></td>
<td>XOR</td>
<td>두 비트가 다르면 1, 같으면 0</td>
</tr>
<tr>
<td><code>~</code></td>
<td>NOT</td>
<td>비트를 반전 (1 → 0, 0 → 1)</td>
</tr>
<tr>
<td><code>&lt;&lt;</code></td>
<td>왼쪽 시프트</td>
<td>비트를 왼쪽으로 이동, 빈 자리는 0으로 채움</td>
</tr>
<tr>
<td><code>&gt;&gt;</code></td>
<td>오른쪽 시프트</td>
<td>부호 유지하며 오른쪽으로 이동 (음수는 1 유지)</td>
</tr>
<tr>
<td><code>&gt;&gt;&gt;</code></td>
<td>논리적 시프트</td>
<td>부호 무시하고 오른쪽으로 이동, 빈 자리는 0</td>
</tr>
</tbody></table>
<hr>
<h3 id="비트-연산-예제">비트 연산 예제</h3>
<pre><code class="language-java">int a = 5; // 00000101
int b = 3; // 00000011

System.out.println(a &amp; b);  // 1  (00000001)
System.out.println(a | b);  // 7  (00000111)
System.out.println(a ^ b);  // 6  (00000110)
System.out.println(~a);     // -6 (11111010) 2의 보수</code></pre>
<h3 id="시프트-연산자-예제">시프트 연산자 예제</h3>
<pre><code class="language-java">int n = 8; // 00001000

System.out.println(n &lt;&lt; 1); // 16 (00010000) → 왼쪽 시프트: *2
System.out.println(n &gt;&gt; 1); // 4  (00000100) → 오른쪽 시프트: /2</code></pre>
<hr>
<h3 id="활용-예시">활용 예시</h3>
<ul>
<li>짝수 / 홀수 판별<pre><code class="language-java">int x = 7;
</code></pre>
</li>
</ul>
<p>if ((x &amp; 1) == 1) {
    System.out.println(&quot;홀수&quot;);
} else {
    System.out.println(&quot;짝수&quot;);
}</p>
<pre><code>- 값을 2배 또는 반으로 만들기
```java
int x = 4;

System.out.println(x &lt;&lt; 1); // 8 (곱하기 2)
System.out.println(x &gt;&gt; 1); // 2 (나누기 2)</code></pre><ul>
<li>비트 마스크 예시 (권한 체크)<pre><code class="language-java">int READ = 1;      // 0001
int WRITE = 2;     // 0010
int EXECUTE = 4;   // 0100
</code></pre>
</li>
</ul>
<p>int permission = READ | WRITE; // 0011</p>
<p>// 권한 확인
boolean canWrite = (permission &amp; WRITE) != 0;
System.out.println(canWrite); // true</p>
<pre><code>---

### &#39;`&gt;&gt;`&#39; vs &#39;`&gt;&gt;&gt;`&#39; 차이점


| 연산자 | 이름               | 설명                                  |
|--------|--------------------|---------------------------------------|
| `&gt;&gt;`   | 산술 시프트         | 부호 비트 유지하며 오른쪽 이동 (음수 유지) |
| `&gt;&gt;&gt;`  | 논리 시프트         | **부호 무시**, 비어있는 자리를 0으로 채움 |

#### &#39;`&gt;&gt;&gt;`&#39; 예제

```java
int a = -8; // 11111111 11111111 11111111 11111000 (32bit)

System.out.println(a &gt;&gt; 2);   // -2
System.out.println(a &gt;&gt;&gt; 2);  // 1073741822</code></pre><ul>
<li>a &gt;&gt; 2: 산술 시프트 → 부호 유지 → 여전히 음수</li>
<li>a &gt;&gt;&gt; 2: 부호 무시, 왼쪽에 0을 채움 → 매우 큰 양수로 나옴</li>
<li><code>&gt;&gt;&gt;</code>는 부호 없는 시프트를 하기 때문에, 음수를 양수로 바꿀 수도 있다.</li>
</ul>
<table>
<thead>
<tr>
<th>표현</th>
<th>비트값 (상위 비트 예시)</th>
<th>결과 값</th>
</tr>
</thead>
<tbody><tr>
<td><code>a = -8</code></td>
<td><code>11111111 11111111 11111111 11111000</code></td>
<td>-8</td>
</tr>
<tr>
<td><code>a &gt;&gt; 2</code></td>
<td><code>11111111 11111111 11111111 11111110</code></td>
<td>-2  <em>(부호 유지)</em></td>
</tr>
<tr>
<td><code>a &gt;&gt;&gt; 2</code></td>
<td><code>00111111 11111111 11111111 11111110</code></td>
<td>1073741822 <em>(부호 제거)</em></td>
</tr>
</tbody></table>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] 자바 문자열 비교 시 주의사항]]></title>
            <link>https://velog.io/@homeless_snail/java-string-compare</link>
            <guid>https://velog.io/@homeless_snail/java-string-compare</guid>
            <pubDate>Fri, 04 Apr 2025 02:52:47 GMT</pubDate>
            <description><![CDATA[<h2 id="자바에서-문자열-비교할-때-을-사용하면-안-되는-이유">자바에서 문자열 비교할 때 <code>==</code>을 사용하면 안 되는 이유</h2>
<blockquote>
<p>Java에서 문자열(String)을 비교할 때 흔히 실수하는 부분 중 하나는 <code>==</code> 연산자를 사용하는 것이다.
하지만 <code>==</code>은 문자열을 비교할 때 <strong>내용이 아닌 주소(참조값)</strong> 를 비교하므로 <strong>정확한 비교가 되지 않는다.</strong></p>
</blockquote>
<hr>
<h3 id="-vs-equals-차이">&#39;<code>==</code>&#39; vs &#39;<code>.equals()</code>&#39; 차이</h3>
<table>
<thead>
<tr>
<th>연산자</th>
<th>비교 대상</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><code>==</code></td>
<td>참조(주소)</td>
<td>두 객체가 <strong>같은 메모리 주소</strong>를 가리키는지 비교</td>
</tr>
<tr>
<td><code>.equals()</code></td>
<td>실제 값(내용)</td>
<td>두 객체의 <strong>내용이 같은지</strong> 비교</td>
</tr>
</tbody></table>
<hr>
<h3 id="예제-1-리터럴-비교-같은-주소">예제 1: 리터럴 비교 (같은 주소)</h3>
<ul>
<li>문자열 리터럴은 String Pool에 저장되므로 동일한 <code>&quot;hello&quot;</code>를 참조함.<pre><code class="language-java">String a = &quot;hello&quot;;
String b = &quot;hello&quot;;
</code></pre>
</li>
</ul>
<p>System.out.println(a == b);       // true (같은 리터럴을 참조)
System.out.println(a.equals(b));  // true</p>
<pre><code>
---

### 예제 2: new 키워드 사용 (다른 주소)
- `new String()`은 새로운 객체를 생성하므로 같은 `&quot;hello&quot;`라도 주소가 다르다.

```java
String a = new String(&quot;hello&quot;);
String b = new String(&quot;hello&quot;);

System.out.println(a == b);       // false (주소 다름)
System.out.println(a.equals(b));  // true (내용 같음)</code></pre><hr>
<h3 id="⚠️-반드시-equals-사용해야-하는-이유">⚠️ 반드시 .equals() 사용해야 하는 이유</h3>
<ul>
<li><code>==</code>은 주소 비교 → 값이 같아도 다른 객체면 <code>false</code></li>
<li><code>.equals()</code>는 값 비교 → 실제 문자열이 같으면 <code>true</code><pre><code class="language-java">String a = &quot;abc&quot;;
String b = &quot;abc&quot;;
System.out.println(a == b);         // true
System.out.println(a.equals(b));    // true
</code></pre>
</li>
</ul>
<p>String c = new String(&quot;abc&quot;);
System.out.println(a == c);         // false
System.out.println(a.equals(c));    // true</p>
<pre><code>---

### 널(null) 안전한 비교 방법
- `.equals()`를 사용할 때는 NPE(NullPointerException) 에 주의해야 한다.
- 문자열이 `null`일 가능성이 있으면 `&quot;문자열&quot;.equals(변수)` 형태로 비교

```java
String str = null;

// 안전한 방법
&quot;hello&quot;.equals(str); // false (null이어도 안전)

// 위험한 방법
str.equals(&quot;hello&quot;); // ❌ NullPointerException 발생 가능</code></pre>]]></description>
        </item>
    </channel>
</rss>