<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>아니, 근데 그게</title>
        <link>https://velog.io/</link>
        <description>안녕나를소개하지이름은HaBu직업은Programer취미는tai chi meditation</description>
        <lastBuildDate>Mon, 29 Jul 2024 07:47:53 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>아니, 근데 그게</title>
            <url>https://velog.velcdn.com/images/ha_bu/profile/20c4c336-d869-49e2-9093-f4b97460c6a6/social_profile.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. 아니, 근데 그게. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/ha_bu" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[제네릭]]></title>
            <link>https://velog.io/@ha_bu/%EC%A0%9C%EB%84%A4%EB%A6%AD</link>
            <guid>https://velog.io/@ha_bu/%EC%A0%9C%EB%84%A4%EB%A6%AD</guid>
            <pubDate>Mon, 29 Jul 2024 07:47:53 GMT</pubDate>
            <description><![CDATA[<h2 id="목표">목표</h2>
<blockquote>
<p>Java의 제네릭에 대해 학습</p>
</blockquote>
<h3 id="목차">목차</h3>
<p><a href="#1-%EC%A0%9C%EB%84%A4%EB%A6%AD-%EC%82%AC%EC%9A%A9%EB%B2%95">1. 제네릭 사용법</a>
<a href="#2-%EC%A0%9C%EB%84%A4%EB%A6%AD-%EC%A3%BC%EC%9A%94-%EA%B0%9C%EB%85%90">2. 제네릭 주요 개념</a>
<a href="#3-%EC%A0%9C%EB%84%A4%EB%A6%AD-%EB%A9%94%EC%86%8C%EB%93%9C-%EB%A7%8C%EB%93%A4%EA%B8%B0">3. 제네릭 메소드 만들기</a>
<a href="#4-erasure">4. Erasure</a></p>
<br>

<h2 id="1-제네릭-사용법">1. 제네릭 사용법</h2>
<blockquote>
<p>Java의 제네릭(Generics)은 <strong>컴파일 시 타입을 검사하고, 코드 재사용성을 높이는데 매우 유용한 기능</strong>입니다. 제네릭을 사용하면 클래스나 메서드를 작성할 때 타입을 파라미터로 사용할 수 있어 <strong>타입 안전성을 보장할 수 있습니다.</strong></p>
</blockquote>
<br>

<h3 id="1-1-제네릭-클래스">1-1) 제네릭 클래스</h3>
<p>&amp;nbsp 제네릭 클래스는 클래스 선언에서 타입 파라미터를 사용하는 클래스입니다. 타입 파라미터는 보통 대문자 <strong>T(Type), E(Element), K(Key), V(Value)</strong> 등을 사용합니다.</p>
<pre><code class="language-java">public class Box&lt;T&gt; {
    private T item;

    public void setItem(T item) {
        this.item = item;
    }

    public T getItem() {
        return item;
    }

    public static void main(String[] args) {
        Box&lt;String&gt; stringBox = new Box&lt;&gt;();
        stringBox.setItem(&quot;Hello, Generics&quot;);
        System.out.println(stringBox.getItem());

        Box&lt;Integer&gt; integerBox = new Box&lt;&gt;();
        integerBox.setItem(123);
        System.out.println(integerBox.getItem());
    }
}</code></pre>
<p>&amp;nbsp 위의 예시에서 <code>Box</code> 클래스는 타입 파라미터 <code>T</code>를 사용하여 저장할 항목의 타입을 지정합니다. <code>Box&lt;String&gt;</code> 인스턴스는 문자열을, <code>Box&lt;Integer&gt;</code>인스턴스는 정수를 저장할 수 있습니다.</p>
<br>

<h3 id="1-2-제네릭-메서드">1-2) 제네릭 메서드</h3>
<p>&amp;nbsp 제네릭 메서드는 <strong>메서드 선언에서 타입 파라미터를 사용하는 메서드입니다.</strong> 메서드 선언에서 타입 파라미터를 사용하려면 리턴 타입 앞에 타입 파라미터를 지정합니다.</p>
<pre><code class="language-java">public class GenericMethodExample {
    public static &lt;T&gt; void printArray(T[] array) {
        for (T element : array) {
            System.out.print(element + &quot; &quot;);
        }
        System.out.println();
    }

    public static void main(String[] args) {
        Integer[] intArray = {1, 2, 3, 4, 5};
        String[] strArray = {&quot;Hello&quot;, &quot;Generics&quot;};

        printArray(intArray);
        printArray(strArray);
    }
}</code></pre>
<p>&amp;nbsp 위 예시에서 <code>printArray</code> 메서드는 타입 파라미터 <code>T</code>를 사용하여 배열의 요소를 출력합니다. <code>Integer</code> 배열과 <code>String</code> 배열을 모두 처리할 수 있습니다.</p>
<br>

<h3 id="1-3-제네릭-인터페이스">1-3) 제네릭 인터페이스</h3>
<p>&amp;nbsp 제네릭 인터페이스는 인터페이스 선언에서 타입 파라미터를 사용하는 인터페이스 입니다.</p>
<pre><code class="language-java">public interface Pair&lt;K, V&gt; {
    K getKey();
    V getValue();
}

public class OrderedPair&lt;K, V&gt; implements Pair&lt;K, V&gt; {
    private K key;
    private V value;

    public OrderedPair(K key, V value) {
        this.key = key;
        this.value = value;
    }

    @Override
    public K getKey() {
        return key;
    }

    @Override
    public V getValue() {
        return value;
    }

    public static void main(String[] args) {
        Pair&lt;String, Integer&gt; pair = new OrderedPair&lt;&gt;(&quot;One&quot;, 1);
        System.out.println(&quot;Key: &quot; + pair.getKey() + &quot;, Value: &quot; + pair.getValue());
    }
}</code></pre>
<p>&amp;nbsp 위 예제에서 <code>Pair</code> 인터페이스는 두 개의 타입 파라미터 <code>K</code>와 <code>V</code>를 사용합니다. <code>Orderedpair</code> 클래스는 <code>Pair</code> 인터페이스를 구현하며, 타입 파라미터 <code>K</code>와 <code>V</code>를 사용합니다.</p>
<br>

<h3 id="요약">요약</h3>
<ul>
<li><p><strong>제네릭 클래스</strong>
클래스 선언에서 타입 파라미터를 사용하여 타입 안전성을 보장하고 코드 재사용성을 높입니다.</p>
</li>
<li><p><strong>제네릭 메서드</strong>
메서드 선언에서 타입 파라미터를 사용하여 다양한 타입의 데이터를 처리할 수 있습니다.</p>
</li>
<li><p><strong>제네릭 인터페이스</strong>
인터페이스 선언에서 타입 파라미터를 사용하여 타입 안전성을 보장하고 코드 재사용성을 높입니다.</p>
</li>
</ul>
<p><br><br></p>
<h2 id="2-제네릭-주요-개념">2. 제네릭 주요 개념</h2>
<blockquote>
<p>여기서는 <strong>Bounded types</strong>와 <strong>Wildcards</strong>에 대해 설명하겠습니다.</p>
</blockquote>
<br>

<h3 id="2-1-바운디드-타입bounded-types">2-1) 바운디드 타입(Bounded Types)</h3>
<p>&amp;nbsp 바운디드 타입은 <strong>타입 파라미터가 특정 클래스나 인터페이스의 서브타입 또는 슈퍼타입이어야 한다는 제약을 추가하는 기능</strong>입니다. 이를 통해 타입 파라미터에 대해 더 구체적인 제약을 걸 수 있습니다.</p>
<br>

<h4 id="2-1-1-상한-바운드upper-bound">2-1-1) 상한 바운드(Upper Bound)</h4>
<p>&amp;nbsp 상한 바운드는 타입 파라미터가 특정 클래스나 인터페이스의 서브타입이어야 한다는 제약입니다. <code>extends</code> 키워드를 사용합니다.</p>
<pre><code class="language-java">public class BoundedTypeExample {
    public static &lt;T extends Number&gt; void printDoubleValue(T number) {
        System.out.println(number.doubleValue() * 2);
    }

    public static void main(String[] args) {
        printDoubleValue(10);       // Integer 타입
        printDoubleValue(10.5);     // Double 타입
        printDoubleValue(5.75f);    // Float 타입
    }
}</code></pre>
<p>&amp;nbsp 위 예시에서 <code>printDoubleValue</code> 메서드는 타입 파라미터 <code>T</code>가 <code>Number</code>의 서브 타입이어야 한다고 제한합니다. 따라서 <code>Integer</code>, <code>Double</code>, <code>Float</code> 타입만 사용할 수 있습니다. </p>
<br>

<h4 id="2-1-2-하한-바운드lower-bound">2-1-2) 하한 바운드(Lower Bound)</h4>
<p>&amp;nbsp 하한 바운드는 타입 파라미터가 특정 클래스나 인터페이스의 슈퍼타입이어야 한다는 제약입니다. <code>super</code> 키워드를 사용합니다. 이는 주로 와일드카드와 함께 사용됩니다.</p>
<pre><code class="language-java">import java.util.List;
import java.util.ArrayList;

public class LowerBoundExample {
    public static void addNumbers(List&lt;? super Integer&gt; list) {
        list.add(1);
        list.add(2);
        list.add(3);
    }

    public static void main(String[] args) {
        List&lt;Number&gt; numList = new ArrayList&lt;&gt;();
        addNumbers(numList);
        System.out.println(numList);
    }
}</code></pre>
<p>&amp;nbsp 위 예시에서 <code>addNumbers</code> 메서드는 타입 파라미터가 <code>Integer</code>의 슈퍼타입이어야 한다는 제약을 겁니다. 따라서 <code>Number</code>나 <code>Object</code> 타입의 리스트에 <code>Integer</code> 값을 추가할 수 있습니다.</p>
<p><br><br></p>
<h3 id="2-2-와일드카드-wildcards">2-2) 와일드카드 (Wildcards)</h3>
<p>&amp;nbsp 와일드카드는 제네릭 타입을 사용할 때 불특정 타입을 나타내기 위해 사용됩니다. 세 가지 종류의 와일드카드가 있습니다.</p>
<br>

<h4 id="2-2-1-불특정-와일드카드unbounded-wildcard">2-2-1) 불특정 와일드카드(Unbounded Wildcard)</h4>
<p>&amp;nbsp 불특정 와일드카드는<code>?</code>를 사용하여 어떤 타입이든 받아들일 수 있습니다.</p>
<pre><code class="language-java">import java.util.List;

public class UnboundedWildcardExample {
    public static void printList(List&lt;?&gt; list) {
        for (Object element : list) {
            System.out.print(element + &quot; &quot;);
        }
        System.out.println();
    }

    public static void main(String[] args) {
        List&lt;Integer&gt; intList = List.of(1, 2, 3);
        List&lt;String&gt; strList = List.of(&quot;Hello&quot;, &quot;Generics&quot;);
        printList(intList);
        printList(strList);
    }
}</code></pre>
<p>&amp;nbsp 위 예시에서 <code>printList</code> 메서드는 어떤 타입의 리스트든 받아들일 수 있습니다.</p>
<br>

<h4 id="2-2-2-상한-와일드카드-upper-bounded-wildcard">2-2-2) 상한 와일드카드 (Upper Bounded Wildcard)</h4>
<p>&amp;nbsp 상한 와일드카드는 <code>&lt;? extends T&gt;</code> 형태로 사용하며, 특정 타입의 서브타입만 받아들일 수 있습니다.</p>
<pre><code class="language-java">import java.util.List;
import java.util.ArrayList;

public class UpperBoundedWildcardExample {
    public static double sumOfList(List&lt;? extends Number&gt; list) {
        double sum = 0.0;
        for (Number num : list) {
            sum += num.doubleValue();
        }
        return sum;
    }

    public static void main(String[] args) {
        List&lt;Integer&gt; intList = List.of(1, 2, 3);
        List&lt;Double&gt; doubleList = List.of(1.1, 2.2, 3.3);
        System.out.println(&quot;Sum of intList: &quot; + sumOfList(intList));
        System.out.println(&quot;Sum of doubleList: &quot; + sumOfList(doubleList));
    }
}</code></pre>
<p>&amp;nbsp 위 예시에서 <code>sumOfList</code> 메서드는 <code>Number</code>의 서브타입을 받아들입니다.</p>
<br>

<h4 id="2-2-3-하한-와일드-카드lower-bounded-wildcard">2-2-3) 하한 와일드 카드(Lower Bounded Wildcard)</h4>
<p>&amp;nbsp 하한 와일드카드는 <code>&lt;? super T&gt;</code> 형태로 사용하며, 특정 타입의 슈퍼타입만 받아들일 수 있습니다.</p>
<pre><code class="language-java">import java.util.List;
import java.util.ArrayList;

public class LowerBoundedWildcardExample {
    public static void addNumbers(List&lt;? super Integer&gt; list) {
        list.add(1);
        list.add(2);
        list.add(3);
    }

    public static void main(String[] args) {
        List&lt;Number&gt; numList = new ArrayList&lt;&gt;();
        addNumbers(numList);
        System.out.println(numList);
    }
}</code></pre>
<p>&amp;nbsp 위 예시에서 <code>addNumber</code> 메서드는 <code>Integer</code>의 슈퍼타입을 받아들입니다.</p>
<br>

<h3 id="2-3-제네릭-타입의-제한-사항">2-3) 제네릭 타입의 제한 사항</h3>
<p><strong>1. 프리미티브 타입 사용 불가</strong>
제네릭 타입 파라미터에는 프리미티브 타입을 사용할 수 없습니다. 대신 박싱된 타입을 사용해야합니다.</p>
<pre><code class="language-java">// 불가능
// List&lt;int&gt; list = new ArrayList&lt;&gt;();

// 가능
List&lt;Integer&gt; list = new ArrayList&lt;&gt;();</code></pre>
<br>

<p><strong>2. 정적 컨텍스트에서 사용 제한</strong>
제네릭 타입 파라미터는 정적 변수나 정적 메서드에서 사용할 수 없습니다.</p>
<pre><code class="language-java">public class GenericClass&lt;T&gt; {
    // 불가능
    // private static T instance;

    // 가능
    private T instance;

    public static &lt;T&gt; void staticMethod(T param) {
        // 제네릭 타입 파라미터는 메서드 수준에서만 사용 가능
    }
}</code></pre>
<br>

<p><strong>3. 런타임 시 타입 소거(Type Erasure)</strong>
자바의 제네릭은 컴파일 타임에 타입 체크를 하고, 런타임에는 타입 정보가 소거됩니다. 따라서 런타임에 타입 파라미터의 실제 타입을 알 수 없습니다.</p>
<pre><code class="language-java">public class GenericClass&lt;T&gt; {
    public void printClassName() {
        // 런타임 시에는 타입 정보를 알 수 없음
        System.out.println(T.class.getName());  // 컴파일 오류
    }
}</code></pre>
<p><a href="#4-erasure">Erasure</a>는 아래에서 다시한번 자세히 설명하겠습니다.</p>
<br>

<h3 id="요약-1">요약</h3>
<ul>
<li><p><strong>바운디드 타입</strong>
타입 파라미터에 상한(<code>extends</code>) 또는 하한(<code>super</code>) 제한을 걸어 특정 타입 게층 내에서만 사용할 수 있도록 합니다.</p>
</li>
<li><p><strong>와일드 카드</strong>
<code>?</code>를 사용하여 제네릭 타입을 불특정 타입으로 나타내며, <code>extends</code>와 <code>super</code>를 사용하여 상한 및 하한을 지정할 수 있습니다.</p>
</li>
<li><p><strong>제네릭 메서드</strong>
메서드 선언에서 타입 파라미터를 사용하여 다양한 타입의 데이터를 처리할 수 있습니다.</p>
</li>
<li><p><strong>제네릭 타입의 제한 사항</strong>
프리미티브 타입 사용 불가, 정적 컨텍스트에서 사용 제한, 런타임 시 타입 소거 등의 제한이 있습니다.</p>
</li>
</ul>
<p><br><br></p>
<h2 id="3-제네릭-메소드-만들기">3. 제네릭 메소드 만들기</h2>
<blockquote>
<p>제네릭 메서드는 메서드 선언에서 타입 파라미터를 사용하는 메서드입니다. 이는 메서드가 호출될 때 타입을 명시할 수 있게 하여 다양한 타입의 데이터를 처리할 수 있게 합니다.</p>
</blockquote>
<br>

<h3 id="3-1-제네릭-메서드-선언">3-1) 제네릭 메서드 선언</h3>
<p>&amp;nbsp 제네릭 메서드를 선언할 때는 메서드의 리턴 타입 파라미터를 선언합니다. 이는 메서드의 인수와 리턴 타입에서 사용할 수있습니다.</p>
<p><strong>기본형태</strong></p>
<pre><code class="language-java">public &lt;T&gt; void methodName(T param) {
    // 메서드 구현
}</code></pre>
<h4 id="예제-1-제네릭-메서드">예제 1: 제네릭 메서드</h4>
<p>&amp;nbsp 배열의 요소를 출력하는 제네릭 메서드의 예제 입니다.</p>
<pre><code class="language-java">public class GenericMethodExample {
    public static &lt;T&gt; void printArray(T[] array) {
        for (T element : array) {
            System.out.print(element + &quot; &quot;);
        }
        System.out.println();
    }

    public static void main(String[] args) {
        Integer[] intArray = {1, 2, 3, 4, 5};
        String[] strArray = {&quot;Hello&quot;, &quot;Generics&quot;};

        printArray(intArray);  // 제네릭 메서드 호출
        printArray(strArray);  // 제네릭 메서드 호출
    }
}</code></pre>
<br>

<h4 id="예제-2-제네릭-메서드와-타입-변환">예제 2: 제네릭 메서드와 타입 변환</h4>
<p>&amp;nbsp 제네릭 메서드는 반환 타입에서도 제네릭을 사용할 수 있습니다. 다음은 두 개의 인수를 비교하여 큰 값을 반환하는 제네릭 메서드의 예제입니다.</p>
<pre><code class="language-java">public class GenericMethodExample {
    public static &lt;T extends Comparable&lt;T&gt;&gt; T findMax(T a, T b) {
        return a.compareTo(b) &gt; 0 ? a : b;
    }

    public static void main(String[] args) {
        System.out.println(findMax(3, 5));           // 정수 비교
        System.out.println(findMax(&quot;apple&quot;, &quot;pear&quot;)); // 문자열 비교
    }
}</code></pre>
<br>

<h3 id="3-2-제네릭-메서드의-타입-파라미터-제한">3-2) 제네릭 메서드의 타입 파라미터 제한</h3>
<p>&amp;nbsp 앞서 설명한 바운디드 타입을 통해 파라미터의 타입을 제한할 수있습니다. 특정 클래스나 인터페이스의 서브타입으로 제한될 수 있습니다.</p>
<pre><code class="language-java">public class BoundedGenericMethodExample {
    public static &lt;T extends Number&gt; void printDoubleValue(T number) {
        System.out.println(number.doubleValue() * 2);
    }

    public static void main(String[] args) {
        printDoubleValue(10);        // Integer 타입
        printDoubleValue(10.5);      // Double 타입
        printDoubleValue(5.75f);     // Float 타입
    }
}</code></pre>
<p>&amp;nbsp 위 예시에서 <code>printDoubleValue</code> 메서드는 타입 파라미터 <code>T</code>가 <code>Number</code>의 서브 타입이도록 제한하고 있습니다.</p>
<br>

<h3 id="3-3-여러-개의-타입-파라미터">3-3) 여러 개의 타입 파라미터</h3>
<p>&amp;nbsp 제네릭 메서드는 여러 개의 타입 파라미터를 가질 수 있습니다. 이는 타입 파라미터를 쉼표로 구분하여 선언합니다.</p>
<pre><code class="language-java">public class MultiGenericMethodExample {
    public static &lt;K, V&gt; void printKeyValue(K key, V value) {
        System.out.println(&quot;Key: &quot; + key + &quot;, Value: &quot; + value);
    }

    public static void main(String[] args) {
        printKeyValue(&quot;One&quot;, 1);
        printKeyValue(&quot;Apple&quot;, &quot;Fruit&quot;);
    }
}</code></pre>
<p>&amp;nbsp 위 예시에서 <code>printkeyValue</code> 메서드는 두 개의 타입 파라미터 <code>K</code>와 <code>V</code>를 가집니다.</p>
<br>

<h3 id="3-4-제네릭-메서드의-호출">3-4) 제네릭 메서드의 호출</h3>
<p>&amp;nbsp 제네릭 메서드는 메서드 호출 시 타입을 명시적으로 지정하지 않아도 컴파일러가 타입을 추론해줍니다. 하지만 명시적으로 타입을 지정해 주는 방법도 있습니다.</p>
<pre><code class="language-java">public class ExplicitTypeGenericMethodExample {
    public static &lt;T&gt; void printElement(T element) {
        System.out.println(&quot;Element: &quot; + element);
    }

    public static void main(String[] args) {
        // 컴파일러가 타입을 추론
        printElement(123);
        printElement(&quot;Hello&quot;);

        // 명시적으로 타입 지정
        ExplicitTypeGenericMethodExample.&lt;String&gt;printElement(&quot;Generics&quot;);
    }
}</code></pre>
<br>

<h3 id="요약-2">요약</h3>
<ul>
<li><p><strong>제네릭 메서드 선언</strong>
리턴 타입 앞에 타입 파라미터를 선언합니다.</p>
</li>
<li><p><strong>타입 파라미터 제한</strong>
<code>extends</code> 키워드를 사용하여 타입 파라미터를 특정 클래스나 인터페이스의 서브타입으로 제한할 수 있습니다.</p>
</li>
<li><p><strong>여러 개의 타입 파라미터</strong>
쉼표로 구분하여 여러 개의 타입 파라미터를 선언할 수 있습니다.</p>
</li>
<li><p><strong>제네릭 메서드 호출</strong>
컴파일러가 타입을 추론하지만, 필요에 따라 명시적으로 타입을 지정할 수도 있습니다.</p>
</li>
</ul>
<p><br><br></p>
<h2 id="4-erasure">4. Erasure</h2>
<blockquote>
<p><code>제네릭 타입 소거(Erasure)</code>는 Java의 제네릭이 컴파일 타임에만 검사를 수행하고, 런타임에는 제네릭 타입 정보를 제거하는 과정입니다.</p>
<p>이 개념은 자바의 제네릭 구현 방식의 핵심으로, 호환성과 성능 측면에서 중요한 역할을 합니다.</p>
</blockquote>
<br>


<h3 id="제네릭-타입-소거erasure란">제네릭 타입 소거(Erasure)란?</h3>
<p>&amp;nbsp 제네릭 타입 소거는 자바 컴파일러가 제네릭 타입을 처리하는 방법입니다. 제네릭 코드가 컴파일되면 모든 제네릭 타입 정보는 제거(소거)되고, 제네릭 타입을 사용한 코드는 타입 안전성을 보장하는 기본형 코드로 변환됩니다.</p>
<p>&amp;nbsp 즉, <strong>제네릭 타입 파라미터는 제거되고, 필요에 따라 해당 타입은</strong> <code>Object</code><strong>나 바운드로 대체됩니다.</strong></p>
<p><br><br></p>
<h3 id="왜-타입-소거가-필요한가">왜 타입 소거가 필요한가?</h3>
<p>&amp;nbsp 타입 소거는 자바의 제네릭이 Java5 에서 도입되었을 때, <U>이전 버전과의 하위 호환성을 유지하기 위해 도입되었습니다.</U></p>
<p>&amp;nbsp 기존의 Java 코드와 새로운 제네릭 코드가 함께 동작할 수 있도록 하기 위해, <strong>제네릭 타입 정보는 컴파일 타임에만 사용되고 런타임에는 제거됩니다.</strong> 이를 통해 제네릭 도입 이전에 작성된 코드와 제네릭 코드가 동일한 바이트코드를 공유할 수 있었습니다.</p>
<p><br><br></p>
<h3 id="타입-소거의-작동방식">타입 소거의 작동방식</h3>
<p>&amp;nbsp 타입 소거는 다음과 같은 방식으로 작동합니다.</p>
<p><strong>1. 제네릭 타입 파라미터 제거</strong>
모든 제네릭 타입 파라미터가 제거되고, 필요에 따라 <code>Object</code> 또는 <code>Upper Bound</code>로 대체됩니다.</p>
<p><strong>2. 타입 검사 및 캐스팅 추가</strong>
타입 안정성을 보장하기 위해 컴파일러는 필요한 곳에 강제 캐시팅을 추가합니다.</p>
<p><strong>3. 바운드 적용</strong>
타입 파라미터가 바운드(<code>extends</code> 키워드)로 제한된 경우, 제네릭 타입은 해당 바운드 타입으로 대체됩니다.</p>
<h4 id="예제-타입-소거-전후">예제: 타입 소거 전후</h4>
<p><strong>제네릭 코드</strong></p>
<pre><code class="language-java">public class Box&lt;T&gt; {
    private T item;

    public void setItem(T item) {
        this.item = item;
    }

    public T getItem() {
        return item;
    }
}</code></pre>
<p><strong>타입 소거 후 코드</strong></p>
<pre><code class="language-java">public class Box {
    private Object item;

    public void setItem(Object item) {
        this.item = item;
    }

    public Object getItem() {
        return item;
    }
}</code></pre>
<p>&amp;nbsp 보시는 바와 같이 제네릭 타입 파라미터 <code>T</code>는 <code>Object</code>로 대체되게 됩니다.</p>
<br>

<h4 id="예제-바운드-타입-소거">예제: 바운드 타입 소거</h4>
<p><strong>제네릭 코드</strong></p>
<pre><code class="language-java">public class Box&lt;T extends Number&gt; {
    private T item;

    public void setItem(T item) {
        this.item = item;
    }

    public T getItem() {
        return item;
    }
}</code></pre>
<p><strong>타입 소거 후 코드</strong></p>
<pre><code class="language-java">public class Box {
    private Number item;

    public void setItem(Number item) {
        this.item = item;
    }

    public Number getItem() {
        return item;
    }
}</code></pre>
<p>&amp;nbsp 여기서는 <code>T extends Number</code>가 <code>Number</code>로 대체됩니다.</p>
<br>

<h3 id="타입-소거의-영향">타입 소거의 영향</h3>
<p>&amp;nbsp 타입 소거는 제네릭 타입을 런타임에 사용할 수 없게 만듭니다. 이는 몇 가지 제약을 발생시킵니다.</p>
<p><strong>1. 런타임 타입 검사 불가</strong>
제네릭 타입 파라미터의 런타임 타입 정보를 알 수 없습니다.</p>
<pre><code class="language-java">public &lt;T&gt; void checkType(T item) {
    if (item instanceof T) {  // 컴파일 오류
        // ...
    }
}</code></pre>
<p><strong>2. 제네릭 배열 생성 불가</strong>
제네릭 타입 파라미터를 사용해 배열을 생성할 수 없습니다.</p>
<pre><code class="language-java">public &lt;T&gt; void createArray() {
    T[] array = new T[10];  // 컴파일 오류
}</code></pre>
<p><strong>3. 강제 캐스팅 필요</strong>
타입 소거로 인해 제네릭 타입 정보가 제거되므로, 종종 강제 캐스팅이 필요하게 됩니다.</p>
<pre><code class="language-java">Box&lt;String&gt; stringBox = new Box&lt;&gt;();
Box rawBox = stringBox;
String item = (String) rawBox.getItem();  // 강제 캐스팅 필요</code></pre>
<br>

<h3 id="와일드카드와-타입-소거">와일드카드와 타입 소거</h3>
<p>&amp;nbsp 와일드카드(<code>?</code>), 상한 바운드(<code>? extends T</code>), 하한 바운드(<code>? super T</code>)도 타입 소거의 영향을 받습니다. 컴파일 타임에 타입 검사가 이루어지고, 런타임에는 와일드카드 정보가 소거됩니다.</p>
<br>

<h3 id="요약-3">요약</h3>
<ul>
<li><p><strong>타입소거</strong>는 제네릭 타입 정보를 컴파일 타임에만 사용하고, 런타임에는 제거하는 과정입니다.</p>
</li>
<li><p><strong>하위 호환성</strong>을 유지하기 위해 자바에서 도입된 방식입니다.</p>
</li>
<li><p><strong>타입 파라미터</strong>는 <code>Object</code> 또는 바운드 타입으로 대체됩니다.</p>
</li>
<li><p><strong>제약사항</strong> : 런타임 타입 검사 불가, 제네릭 배열 생성 불가, 강제 캐스팅 필요</p>
</li>
</ul>
<p><br><br></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Java의 I/O]]></title>
            <link>https://velog.io/@ha_bu/Java%EC%9D%98-IO</link>
            <guid>https://velog.io/@ha_bu/Java%EC%9D%98-IO</guid>
            <pubDate>Mon, 15 Jul 2024 08:31:40 GMT</pubDate>
            <description><![CDATA[<h2 id="목표">목표</h2>
<blockquote>
<p>Java의 Input과 Output에대해 학습</p>
</blockquote>
<h3 id="목차">목차</h3>
<p><a href="#1-stream--buffer--channel-%EA%B8%B0%EB%B0%98%EC%9D%98-io">1. Stream / Buffer / Channel 기반의 I/O</a>
<a href="#2-inputstream%EA%B3%BC-outputstream">2. InputStream과 OutputStream</a>
<a href="#3-byte%EC%99%80-character-%EC%8A%A4%ED%8A%B8%EB%A6%BC">3. Byte와 Character 스트림</a>
<a href="#4-%ED%91%9C%EC%A4%80-%EC%8A%A4%ED%8A%B8%EB%A6%BC">4. 표준 스트림</a>
<a href="#5-%ED%8C%8C%EC%9D%BC-%EC%9D%BD%EA%B3%A0-%EC%93%B0%EA%B8%B0">5. 파일 읽고 쓰기</a></p>
<br>

<h2 id="1-stream--buffer--channel-기반의-io">1. Stream / Buffer / Channel 기반의 I/O</h2>
<blockquote>
<p>Java에서 I/O(Input/Output) 작업을 처리하는 방법중 Stream, Buffer, Channel에 대해 알아보겠습니다.</p>
</blockquote>
<br>

<h3 id="1-1-stream기반의-io">1-1 Stream기반의 I/O</h3>
<blockquote>
<p>Stream은 자바에서 I/O 작업을 처리하는 가장 기본적인 방법입니다. Stream은 데이터를 순차적으로 읽고 쓰는 통로를 의미합니다. </p>
</blockquote>
<p>자바의 Stream은 다음과 같이 두 가지 유형으로 나뉩니다.</p>
<ul>
<li><p><strong>InputStream</strong> : 입력 데이터를 읽기 위한 스트림
( Ex: FileInputStream, ByteArrayInputStream )</p>
</li>
<li><p><strong>OutputStream</strong> : 출력 데이터를 쓰기 위한 스트림
( Ex: FileOutputStream, ByteArrayOutputStream )</p>
</li>
</ul>
<br>

<p>&amp;nbsp 스트림은 바이트 단위로 데이터를 처리하며, 이러한 스트림은 데이터를 한 바이트씩 읽거나 쓸 수 있습니다. 이를 통해 파일, 네트워크 소켓 등의 다양한 I/O 소스를 처리할 수 있습니다.</p>
<br>

<h4 id="reader와-writer">Reader와 Writer</h4>
<p>&amp;nbsp 스트림은 기본적으로 바이트 단위로 데이터를 처리하지만, 문자 데이터를 효율적으로 처리하기 위해 자바는 <code>Reader</code>와 <code>Writer</code> 클래스를 제공합니다. 이들은 문자 단위로 데이터를 읽고 씁니다.</p>
<ul>
<li><strong>Reader</strong> : 입력을 위한 문자 스트림입니다.</li>
<li><strong>Writer</strong> : 출력을 위한 문자 스트림입니다.</li>
</ul>
<br>

<p>&amp;nbsp 스트림 기반 I/O는 단순하고 직관적이지만, <strong>데이터를 한 바이트씩 처리하기 때문에 성능 면에서 비효율적일 수 있습니다.</strong> 이를 보완하기 위해 버퍼를 사용합니다.</p>
<br>


<h3 id="1-2-buffer-기반의-io">1-2 Buffer 기반의 I/O</h3>
<blockquote>
<p><strong>Buffer</strong>는 데이터 입출력 성능을 향상시키기 위해 사용되는 메모리의 특정 영역입니다. <strong>버퍼는 데이터를 일시적으로 저장하여, 한 번에 많은 데이터를 읽거나 쓸 수 있도록 도와줍니다.</strong> 이는 <strong>디스크나 네트워크와의 I/O 작업에서</strong> 특히 유용합니다.</p>
</blockquote>
<br>

<h4 id="bufferd-stream">Bufferd Stream</h4>
<p>&amp;nbsp 자바에서 버퍼링을 사용하기 위해 <code>BufferedInputStream</code>과 <code>BufferedOutputStream</code> 클래스를 제공합니다. 이 클래스들은 내부적으로 버퍼를 사용하여 데이터를 한 번에 더 많이 읽거나 씁니다.</p>
<ul>
<li><p><strong>BufferedInputStream</strong> : 입력을 위한 버퍼링된 바이트 스트림</p>
</li>
<li><p><strong>BufferedOutputStream</strong> : 출력을 위한 버퍼링된 바이트 스트림</p>
</li>
</ul>
<br>

<h4 id="buffered-reader와-writer">Buffered Reader와 Writer</h4>
<p>문자 스트림에도 버퍼링이 가능합니다. 이를 위해 <code>BufferedReader</code>와 <code>BufferedWriter</code> 클래스를 사용합니다.</p>
<ul>
<li><strong>BufferedReader</strong> : 입력을 위한 버퍼링된 문자 스트림</li>
<li><strong>BufferedWriter</strong> : 출력을 위한 버퍼링된 문자 스트림</li>
</ul>
<br>

<p>&amp;nbsp 버퍼링된 스트림을 사용하면 성능이 크게 향상될 수 있습니다. 이는 특히 <strong>대량의 데이터를 처리할 때 유용합니다.</strong></p>
<br>

<h3 id="1-3-channel-기반의-io">1-3 Channel 기반의 I/O</h3>
<blockquote>
<p><strong>Channel</strong>은 Java NIO (New I/O)패키지에서 도입된 개념으로, 스트림보다 더 유연하고 강력한 I/O 처리를 제공합니다. 채널은 양방향 통신을 지원하며, 비동기 I/O 및 버퍼와 함께 사용됩니다. </p>
</blockquote>
<p>주요 채널 클래스는 아래와 같습니다.</p>
<ul>
<li><strong>FileChannel</strong> : 파일 I/O를 위한 채널</li>
<li><strong>SocketChannel</strong> : 소켓 I/O를 위한 채널</li>
<li><strong>ServerSocketChannel</strong> : 서버 소켓 I/O를 위한 채널</li>
<li><strong>DatagramChannel</strong> : UDP 소컷 I/O를 위한 채널</li>
</ul>
<br>

<h4 id="버퍼와-채널의-조합">버퍼와 채널의 조합</h4>
<p>&amp;nbsp 채널은 데이터를 직접 일고 쓰지 않고, 항상 버퍼를 통해 데이터를 처리합니다. 이는 효율적인 데이터 전송과 처리를 가능하게 합니다.</p>
<p>&amp;nbsp 예를 들어, <code>FileChannel</code>을 사용하여 파일에서 데이터를 읽는 과정은 아래와 같습니다.</p>
<br>

<p>*<em>1. 파일 채널 열기 *</em></p>
<pre><code class="language-java">FileChannel fileChannel = 
FileChannel.open(Paths.get(&quot;file.txt&quot;), StandardOpenOption.READ);</code></pre>
<p>*<em>2. 버퍼 생성 *</em></p>
<pre><code class="language-java">ByteBuffer buffer = ByteBuffer.allocate(1024);</code></pre>
<p><strong>3. 채널에서 버퍼로 데이터 읽기</strong></p>
<pre><code class="language-java">int bytesRead = fileChannel.read(buffer);</code></pre>
<p><strong>4. 채널에서 버퍼로 데이터 읽기</strong></p>
<pre><code class="language-java">int bytesRead = fileChannel.read(buffer);</code></pre>
<p>*<em>5. 채널 닫기 *</em></p>
<pre><code class="language-java">fileChannel.close();</code></pre>
<h3 id="요약">요약</h3>
<ul>
<li><p><strong>Stream</strong> : 단순하고 사용하기 쉬우며, 단방향I/O를 지원하지만, 성능이 떨어질 수 있습니다.</p>
</li>
<li><p><strong>Buffer</strong> : 성능을 향상시키기 위해 데이터를 일시적으로 저장하여 한 번에 읽고 쓰는 방식입니다.</p>
</li>
<li><p><strong>Channel</strong> : 양방향 I/O와 비동기 처리를 지원하며, 버퍼와 함께 사용하여 효율적인 데이터 처리를 가능하게 합니다.</p>
</li>
</ul>
<p><br><br></p>
<h2 id="2-inputstream과-outputstream">2. InputStream과 OutputStream</h2>
<blockquote>
<p><strong>InputStream</strong>과 <strong>OutputStream</strong>은 자바에서 기본적인 I/O 처리를 위한 추상 클래스입니다. </p>
<p>이 두 클래스는 바이트 단위로 데이터를 읽고 쓰는데 사용됩니다. 이들은 I/O의 핵심이며, 다양한 서브클래스를 통해 파일, 네트워크 소켓, 메모리 등 여러 소스와 목적지로부터 데이터를 처리할 수 있습니다.</p>
</blockquote>
<h3 id="inputstream">InputStream</h3>
<p>&amp;nbsp <strong>InputStream</strong>은 바이트 단위로 데이터를 읽기 위한 추상 클래스입니다. 주로 데이터를 읽는 작업에 사용되며, 주요 서브클래스와 함께 사용됩니다.</p>
<h4 id="주요-메서드">주요 메서드</h4>
<ul>
<li><p><code>int read()</code>
입력 스트림에서 다음 바이트 데이터를 읽습니다. 바이트 값을 0~255 사이의 정수로 반환하며, 더 이상 읽을 데이터가 없으면 -1을 반환합니다.</p>
</li>
<li><p><code>int read(byre[] b)</code>
입력 스트림에서 바이트 배열 <code>b</code>의 길이만큼 데이터를 읽습니다. 읽은 바이트 수를 반환하며, 더 이상 읽을 데이터가 없으면 -1을 반환합니다.</p>
</li>
<li><p><code>int read(byte[] b, int off, int len)</code>
입력 스트림에서 최대 <code>len</code> 바이트를 읽고, 이를 바이트 배열 <code>b</code>의 <code>off</code> 위치에서 시작하여 저장합니다.</p>
</li>
<li><p><code>void close()</code>
스트림을 닫고, 자원을 해제합니다.</p>
</li>
<li><p><code>int available()</code>
스트림에서 읽을 수 있는 바이트 수를 반환합니다.</p>
</li>
</ul>
<br>

<h4 id="주요-서브-클래스">주요 서브 클래스</h4>
<ul>
<li><p><code>FileInputStream</code>
파일로부터 바이트 입력을 읽기 위한 스트림입니다.</p>
</li>
<li><p><code>ByteArrayInputStream</code>
바이트 배열로부터 바이트 입력을 읽기 위한 스트림 입니다.</p>
</li>
<li><p><code>BufferedInputStream</code>
다른 입력 스트림에 버퍼링 기능을 추가하여 입력 성능을 향상시킵니다.</p>
</li>
<li><p><code>DataInputStream</code>
기본 데이터 타입 (int, float 등)을 입력 스트림에서 읽을 수 있습니다.</p>
</li>
</ul>
<br>

<h4 id="예시">예시</h4>
<pre><code class="language-java">import java.io.FileInputStream;
import java.io.IOException;

public class InputStreamExample {
    public static void main(String[] args) {
        try (FileInputStream fis = new FileInputStream(&quot;input.txt&quot;)) {
            int data;
            while ((data = fis.read()) != -1) {
                System.out.print((char) data);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}</code></pre>
<br>

<h3 id="outputstream">OutputStream</h3>
<p>&amp;nbsp <strong>OutputStream</strong>은 바이트 단위로 데이터를 쓰기 위한 추상 클래스입니다. 주로 데이터를 쓰는 작업에 사용되며, 주요 서브클래스와 함께 사용됩니다.</p>
<h4 id="주요-메서드-1">주요 메서드</h4>
<ul>
<li><p><code>void write(int b)</code>
출력 스트림에 주어진 바이트 데이터를 씁니다.</p>
</li>
<li><p><code>void write(byte[] b)</code>
바이트 배열 <code>b</code>의 모든 바이트 데이터를 출력 스트림에 씁니다.</p>
</li>
<li><p><code>void write(byte[] b, int off, int len)</code>
바이트 배열 <code>b</code>의 <code>off</code> 위치에서 시작하여 <code>len</code> 바이트 데이터를 출력 스트림에 씁니다.</p>
</li>
<li><p><code>void flush()</code>
출력 스트림을 비우고, 모든 버퍼된 출력 바이트를 실제 출력 대상에 씁니다.</p>
</li>
<li><p><code>void close()</code>
스트림을 닫고, 자원을 해제합니다.</p>
</li>
</ul>
<br>

<h4 id="주요-서브-클래스-1">주요 서브 클래스</h4>
<ul>
<li><p><code>FileOutputStream</code>
파일에 바이트 출력을 쓰기 위한 스트림입니다.</p>
</li>
<li><p><code>ByteArrayoutputStream</code>
바이트 배열에 바이트 출력을 쓰기 위한 스트림입니다.</p>
</li>
<li><p><code>BufferedOutputStream</code>
다른 출력 스트림에 버퍼링 기능을 추가하여 출력 성능을 향상시킵니다.</p>
</li>
<li><p><code>DataOutputStream</code>
기본 데이터 타입 (int, float 등)을 출력 스트림에 쓸 수 있습니다.</p>
</li>
</ul>
<br>

<h4 id="예시-1">예시</h4>
<pre><code class="language-java">import java.io.FileOutputStream;
import java.io.IOException;

public class OutputStreamExample {
    public static void main(String[] args) {
        try (FileOutputStream fos = new FileOutputStream(&quot;output.txt&quot;)) {
            String data = &quot;Hello, World!&quot;;
            fos.write(data.getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}</code></pre>
<br>

<p><strong>결합 사용 예시</strong>
InputStream과 OutputStream을 결합하여 파일 복사를 할 수 있습니다.</p>
<pre><code class="language-java">import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class CopyFileExample {
    public static void main(String[] args) {
        try (FileInputStream fis = new FileInputStream(&quot;input.txt&quot;);
             FileOutputStream fos = new FileOutputStream(&quot;output.txt&quot;)) {

            byte[] buffer = new byte[1024];
            int bytesRead;

            while ((bytesRead = fis.read(buffer)) != -1) {
                fos.write(buffer, 0, bytesRead);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}</code></pre>
<h3 id="요약-1">요약</h3>
<ul>
<li><p><strong>InputStream</strong>과 <strong>OutputStream</strong>은 자바에서 바이트 단위 I/O를 처리하기 위한 기본 추상 클래스입니다.</p>
</li>
<li><p><strong>InputStream</strong>은 데이터를 읽고, <strong>OutputStream</strong>은 데이터를 씁니다.</p>
</li>
<li><p>이들 클래스는 다양한 서브클래스를 통해 파일, 네트워크 소켓, 메모리 등 여러 소스와 목적지로부터 데이터를 처리할 수 있습니다.</p>
</li>
<li><p>버퍼링 클래스(<code>BufferedInputStream</code>, <code>BufferedOutputStream</code>)를 사용하면 성능이 향상될 수 있습니다.</p>
</li>
<li><p>스트림을 사용할 때는 항상 자원을 해제하기 위해 <code>close()</code> 메서드를 호출해야 하며, 이를 위해 try-with-resources 구문을 사용하는 것이 권장됩니다.</p>
</li>
</ul>
<p><br><br></p>
<h2 id="3-byte와-character-스트림">3. Byte와 Character 스트림</h2>
<blockquote>
<p>Java의 I/O 시스템은 데이터를 바이트 단위로 처리하는 바이트 스트림과, 문자를 처리하는 캐릭터 스트림으로 나뉩니다. 각각의 스트림은 특정 용도와 데이터 형식에 맞춰 설계되었으며, 효율적인 데이터 처리를 위해 다양한 클래스가 제공됩니다.</p>
</blockquote>
<h3 id="byte-스트림">Byte 스트림</h3>
<p><strong>Byte</strong> 스트림은 바이트 단위로 데이터를 읽고 쓰는 스트림입니다. 주로 바이너리 데이터를 처리하는 데 사용됩니다. 예를 들어, 이미지 파일, 오디오 파일, 비디오 파일 등은 바이트 스트림을 사용하여 처리할 수 있습니다.</p>
<h4 id="주요-클래스">주요 클래스</h4>
<p><strong>InputStream</strong></p>
<ul>
<li><strong>FileInputStream</strong>
파일로부터 바이트 단위로 데이터를 읽습니다.</li>
<li><strong>ByteArrayInputStream</strong>
메모리 내의 바이트 배열로부터 데이터를 읽습니다.</li>
<li><strong>BufferedInputStream</strong>
다른 InputStream에 버퍼링 기능을 추가하여 성능을 향상시킵니다.</li>
<li><strong>DataInputStream</strong>
기본 데이터 타입(int, float 등)을 읽기 위한 기능을 제공합니다.</li>
</ul>
<br>

<p><strong>OutputStream</strong></p>
<ul>
<li><strong>FileOutputStream</strong>
파일에 바이트 단위로 데이터를 씁니다.</li>
<li><strong>ByteArrayOutputStream</strong>
메모리 내의 바이트 배열에 데이터를 씁니다.</li>
<li><strong>BufferedOutputStream</strong>
다른 OutputStream에 버퍼링 기능을 추가하여 성능을 향상시킵니다.</li>
<li><strong>DataOutputStream</strong>
디본 데이터 타입(int, float 등)을 쓰기 위한 기능을 제공합니다.</li>
</ul>
<h4 id="예제">예제</h4>
<pre><code class="language-java">import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class ByteStreamExample {
    public static void main(String[] args) {
        // 파일에 데이터 쓰기
        try (FileOutputStream fos = new FileOutputStream(&quot;byte_output.txt&quot;)) {
            String data = &quot;Hello, Byte Stream!&quot;;
            fos.write(data.getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        }

        // 파일로부터 데이터 읽기
        try (FileInputStream fis = new FileInputStream(&quot;byte_output.txt&quot;)) {
            int byteData;
            while ((byteData = fis.read()) != -1) {
                System.out.print((char) byteData);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}</code></pre>
<br>

<h3 id="character-스트림">Character 스트림</h3>
<p>&amp;nbsp <strong>Character</strong> 스트림은 문자 단위로 데이터를 읽고 쓰는 스트림입니다. <strong>주로 텍스트 데이터를 처리하는 데 사용됩니다.</strong> Java에서 문자는 2바이트 유니코드로 처리되므로, 캐릭터 스트림은 국제화된 텍스트 데이터를 처리하는 데 적합합니다.</p>
<h4 id="주요-클래스-1">주요 클래스</h4>
<p><strong>Reader</strong></p>
<ul>
<li><strong>FileReader</strong>
파일로부터 문자 데이터를 읽습니다.</li>
<li><strong>CharArrayReader</strong>
메모리 내의 문자 배열로부터 데이터를 읽습니다.</li>
<li><strong>BufferedReader</strong>
다른 Reader에 버퍼링 기능을 추가하여 성능을 향상시킵니다. 또한 <code>readLine()</code> 메서드를 제공하여 한 줄씩 읽을 수 있습니다.</li>
<li><strong>InputStreamReader</strong>
바이트 스트림을 문자 스트림으로 변환합니다.</li>
</ul>
<p><strong>Writer</strong></p>
<ul>
<li><strong>FileWriter</strong>
파일에 문자 데이터를 씁니다.</li>
<li><strong>CharArrayWriter</strong>
메모리 내의 문자 배열에 데이터를 씁니다.</li>
<li><strong>BufferedWriter</strong>
다른 Writer에 버퍼링 기능을 추가하여 성능을 향상시킵니다.</li>
<li><strong>OutpufStreamWriter</strong>
바이트 스트림을 문자 스트림으로 변환합니다.</li>
</ul>
<h4 id="예제-1">예제</h4>
<pre><code class="language-java">import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class CharacterStreamExample {
    public static void main(String[] args) {
        // 파일에 문자 데이터 쓰기
        try (FileWriter fw = new FileWriter(&quot;char_output.txt&quot;)) {
            String data = &quot;Hello, Character Stream!&quot;;
            fw.write(data);
        } catch (IOException e) {
            e.printStackTrace();
        }

        // 파일로부터 문자 데이터 읽기
        try (FileReader fr = new FileReader(&quot;char_output.txt&quot;)) {
            int charData;
            while ((charData = fr.read()) != -1) {
                System.out.print((char) charData);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}</code></pre>
<h3 id="byte-스트림과-character-스트림-비교">Byte 스트림과 Character 스트림 비교</h3>
<ul>
<li><p><strong>데이터 단위</strong>
바이트 스트림은 바이트 단위로 데이터를 처리하며, 캐릭터 스트림은 문자 다누이로 데이터를 처리합니다.</p>
</li>
<li><p><strong>용도</strong>
바이트 스트림은 바이너리 데이터를 처리하는 데 적합하고, 캐릭터 스트림은 텍스트 데이터를 처리하는데 적합합니다.</p>
</li>
<li><p><strong>유니코드 지원</strong>
캐릭터 스트림은 유니코드 문자를 지원하여 국제화된 텍스트 데이터를 처리할 수 있습니다.</p>
</li>
<li><p><strong>버퍼링</strong>
두 스트림 모두 버퍼링된 클래스를 제공하여 성능을 향상시킬 수 있습니다.</p>
</li>
</ul>
<br>

<h3 id="요약-2">요약</h3>
<ul>
<li><p><strong>Byte</strong> 스트림
바이트 단위로 데이터를 읽고 쓰며, 바이너리 데이터를 처리하는데 사용됩니다. 주요 클래스는 <code>InputStream</code>과 <code>OutputStream</code>입니다.</p>
</li>
<li><p><strong>Character</strong> 스트림
문자 단위로 데이터를 읽고 쓰며, 텍스트 데이터를 처리하는 데 사용됩니다. 주요 클래스는 <code>Reader</code>와 <code>Writer</code>입니다.</p>
</li>
</ul>
<p><br><br></p>
<h2 id="4-표준-스트림">4. 표준 스트림</h2>
<blockquote>
<p>표준 스트림은 자바 프로그램이 실행될 때 기본적으로 사용할 수 있는 세 가지 스트림을 의미합니다. 이 스트림들은 프로그램과 사용자 간의 기본적인 입출력을 처리하기 위해 저공됩니다. <strong>표준 스트림에는 표준 입력 스트림, 표준 출력 스트림, 표준 오류 스트림이 있습니다.</strong></p>
</blockquote>
<br>

<h3 id="표준-입력-스트림standard-input-stream">표준 입력 스트림(Standard Input Stream)</h3>
<p>&amp;nbsp표준 입력 스트림은 기본적으로 키보드로부터 입력을 받는 스트림입니다. Java에서는 <code>System.in</code> 객체로 제공됩니다. 이 스트림은 <code>InputStream</code> 타입이며, 주로 콘솔에서 사용자 입력을 읽는 데 사용됩니다.</p>
<pre><code class="language-java">import java.io.InputStreamReader;
import java.io.BufferedReader;
import java.io.IOException;

public class StandardInputExample {
    public static void main(String[] args) {
        System.out.println(&quot;Enter some text:&quot;);

        try (BufferedReader reader = new BufferedReader(new InputStreamReader(System.in))) {
            String input = reader.readLine();
            System.out.println(&quot;You entered: &quot; + input);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}</code></pre>
<br>

<h3 id="표준-출력-스트림standard-output-stream">표준 출력 스트림(Standard Output Stream)</h3>
<p>&amp;nbsp표준 출력 스트림은 기본적으로 콘솔에 출력을 보내는 스트림입니다. Java에서는 <code>System.out</code> 객체로 제공됩니다. 이 스트림은 <code>PrintStream</code> 타입이며, 프로그램의 출력을 사용자에게 보여주는 데 사용됩니다.</p>
<pre><code class="language-java">public class StandardOutputExample {
    public static void main(String[] args) {
        System.out.println(&quot;Hello, World!&quot;);
        System.out.println(&quot;This is an example of standard output.&quot;);
    }
}</code></pre>
<br>

<h3 id="표준-오류-스트림standard-error-stream">표준 오류 스트림(Standard Error Stream)</h3>
<p>&amp;nbsp표준 오류 스트림은 기본적으로 오류 메시지를 콘솔에 출력하는 스트림입니다. Java에서는 <code>System.err</code> 객체로 제공됩니다. 이 스트림도 <code>PrintStream</code> 타입이며, 오류 메시지나 예외 정보를 출력하는 데 사용됩니다.</p>
<pre><code class="language-java">public class StandardErrorExample {
    public static void main(String[] args) {
        System.err.println(&quot;An error occurred!&quot;);
        System.err.println(&quot;This is an example of standard error output.&quot;);
    }
}</code></pre>
<br>

<h3 id="표준-스트림의-리디렉션">표준 스트림의 리디렉션</h3>
<p>&amp;nbsp Java에서는 <strong>표준 스트림을 다른 스트림으로 리디렉션 할 수 있습니다.</strong> 예를 들어, 파일로 출력을 리디렉션하거나 입력을 파일로부터 받을 수 있습니다. 이는 <code>System.setIn()</code>, <code>System.setOut()</code>, <code>System.setErr()</code> 메서드를 사용하여 가능합니다.</p>
<h4 id="표준-출력-스트림-리디렉션">표준 출력 스트림 리디렉션</h4>
<pre><code class="language-java">import java.io.FileOutputStream;
import java.io.PrintStream;
import java.io.IOException;

public class RedirectOutputExample {
    public static void main(String[] args) {
        try (PrintStream out = new PrintStream(new FileOutputStream(&quot;output.txt&quot;))) {
            System.setOut(out);
            System.out.println(&quot;This will be written to the file instead of the console.&quot;);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}</code></pre>
<br>

<h4 id="표준-입력-스트림-리디렉션">표준 입력 스트림 리디렉션</h4>
<pre><code class="language-java">import java.io.FileInputStream;
import java.io.IOException;

public class RedirectInputExample {
    public static void main(String[] args) {
        try (FileInputStream fis = new FileInputStream(&quot;input.txt&quot;)) {
            System.setIn(fis);
            BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println(&quot;Read from file: &quot; + line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}</code></pre>
<h3 id="요약-3">요약</h3>
<ul>
<li><p><strong>표준 입력 스트림(<code>System.in</code>)</strong>
기본적으로 키보드로부터 입력을 받는 스트림입니다. <code>InputStream</code> 타입이며, 주로 <code>BufferedReader</code>와 함께 사용하여 문자열 입력을 처리합니다.</p>
</li>
<li><p><strong>표준 출력 스트림(<code>System.out</code>)</strong>
기본적으로 콘솔에 출력을 보내는 스트림입니다. <code>PrintStream</code>타입이며, <code>println</code> 메서드를 사용하여 텍스트를 출력합니다.</p>
</li>
<li><p><strong>표준 오류 스트림(<code>System.err</code>)</strong>
기본적으로 콘솔에 오류 메시지를 보내는 스트림입니다. <code>PrintStream</code> 타입이며, 오류나 예외 정보를 출력합니다.</p>
</li>
<li><p><strong>리디렉션</strong>
표준 스트림을 다른 스트림으로 리디렉션하여 입력을 파일에서 받거나 출력을 파일로 보낼 수 있습니다.</p>
</li>
</ul>
<p><br><br></p>
<h2 id="5-파일-읽고-쓰기">5. 파일 읽고 쓰기</h2>
<blockquote>
<p>파일 읽고 쓰기를 위해 Java는 다양한 클래스를 제공합니다. 파일 I/O는 크게 바이트 스트림과 문자 스트림의로 나뉘며, 각각의 스트림을 사용하여 파일을 읽고 쓸 수 있습니다.</p>
</blockquote>
<br>

<h3 id="바이트-스트림을-이용한-파일-읽기와-쓰기">바이트 스트림을 이용한 파일 읽기와 쓰기</h3>
<p>&amp;nbsp 바이트 스트림은 파일의 데이터를 바이트 단위로 읽고 쓰는데 사용됩니다. 바이트 스트림은 바이너리 파일(이미지, 비디오, 오디오 파일 등)을 처리하는 데 적합합니다.</p>
<h4 id="파일-읽기fileinputstream">파일 읽기(FileInputStream)</h4>
<p><code>FileInputStream</code> 클래스를 사용하여 파일을 바이트 단위로 읽을 수 있습니다.</p>
<pre><code class="language-java">import java.io.FileInputStream;
import java.io.IOException;

public class FileInputStreamExample {
    public static void main(String[] args) {
        try (FileInputStream fis = new FileInputStream(&quot;input.txt&quot;)) {
            int data;
            while ((data = fis.read()) != -1) {
                System.out.print((char) data);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}</code></pre>
<p><br><br></p>
<h4 id="파일-쓰기fileoutputstream">파일 쓰기(FileOutputStream)</h4>
<p><code>FileOutputStream</code> 클래스를 사용하여 파일에 바이트 단위로 데이터를 쓸 수 있습니다.</p>
<pre><code class="language-java">import java.io.FileOutputStream;
import java.io.IOException;

public class FileOutputStreamExample {
    public static void main(String[] args) {
        try (FileOutputStream fos = new FileOutputStream(&quot;output.txt&quot;)) {
            String data = &quot;Hello, World!&quot;;
            fos.write(data.getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}</code></pre>
<p><br><br></p>
<h3 id="문자-스트림을-이용한-파일-읽기와-쓰기">문자 스트림을 이용한 파일 읽기와 쓰기</h3>
<p>&amp;nbsp 문자 스트림은 파일의 데이터를 문자 단위로 읽고 쓰는 데 사용됩니다. 문자 스트림은 텍스트 파일(<code>.txt</code>, <code>.csv</code>, <code>.html</code> 등)을 처리하는데 적합합니다.</p>
<h4 id="파일-읽기filereader">파일 읽기(FileReader)</h4>
<p><code>FileReader</code> 클래스를 사용하여 파일을 문자 단위로 읽을 수 있습니다.</p>
<pre><code class="language-java">import java.io.FileReader;
import java.io.IOException;

public class FileReaderExample {
    public static void main(String[] args) {
        try (FileReader fr = new FileReader(&quot;input.txt&quot;)) {
            int data;
            while ((data = fr.read()) != -1) {
                System.out.print((char) data);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}</code></pre>
<p><br><br></p>
<h4 id="파일-쓰기filewriter">파일 쓰기(FileWriter)</h4>
<p><code>FileWriter</code> 클래스를 사용하여 파일에 문자 단위로 데이터를 쓸 수 있습니다.</p>
<pre><code class="language-java">import java.io.FileWriter;
import java.io.IOException;

public class FileWriterExample {
    public static void main(String[] args) {
        try (FileWriter fw = new FileWriter(&quot;output.txt&quot;)) {
            String data = &quot;Hello, World!&quot;;
            fw.write(data);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}</code></pre>
<p><br><br></p>
<h3 id="버퍼링된-스트림을-이용한-파일-읽기와-쓰기">버퍼링된 스트림을 이용한 파일 읽기와 쓰기</h3>
<p>&amp;nbsp 버퍼링된 스트림은 데이터의 입출력 성능을 향상시키기 위해 사용됩니다. 버퍼를 사용하여 데이터를 한 번에 더 많이 읽거나 쓸 수 있습니다.</p>
<br>

<h4 id="파일-읽기bufferedreader">파일 읽기(BufferedReader)</h4>
<p><code>BufferedReader</code> 클래스를 사용하여 파일을 효율적으로 읽을 수 있습니다.</p>
<pre><code class="language-java">import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class BufferedReaderExample {
    public static void main(String[] args) {
        try (BufferedReader br = new BufferedReader(new FileReader(&quot;input.txt&quot;))) {
            String line;
            while ((line = br.readLine()) != null) {
                System.out.println(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}</code></pre>
<p><br><br></p>
<h4 id="파일-쓰기bufferedwriter">파일 쓰기(BufferedWriter)</h4>
<p><code>BufferedWriter</code> 클래스를 사용하여 파일에 효율적으로 데이터를 쓸 수 있습니다.</p>
<pre><code class="language-java">import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;

public class BufferedWriterExample {
    public static void main(String[] args) {
        try (BufferedWriter bw = new BufferedWriter(new FileWriter(&quot;output.txt&quot;))) {
            String data = &quot;Hello, World!&quot;;
            bw.write(data);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}</code></pre>
<p><br><br></p>
<h3 id="데이터-스트림을-이용한-파일-읽기와-쓰기">데이터 스트림을 이용한 파일 읽기와 쓰기</h3>
<p>데이터 스트림은 기본 데이터 타입(int, float, double 등)을 입출력하는 데 사용됩니다.</p>
<br>

<h4 id="파일-쓰기dataoutputstream">파일 쓰기(DataOutputStream)</h4>
<p><code>DataOutputStream</code> 클래스를 사용하여 파일에 기본 데이터 타입을 쓸 수 있습니다.</p>
<pre><code class="language-java">import java.io.DataOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class DataOutputStreamExample {
    public static void main(String[] args) {
        try (DataOutputStream dos = new DataOutputStream(new FileOutputStream(&quot;data.bin&quot;))) {
            dos.writeInt(123);
            dos.writeFloat(4.56f);
            dos.writeUTF(&quot;Hello, World!&quot;);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}</code></pre>
<p><br><br></p>
<h4 id="파일-읽기datainputstream">파일 읽기(DataInputStream)</h4>
<p><code>DataInputStream</code> 클래스를 사용하여 파일로부터 기본 데이터 타입을 읽을 수 있습니다.</p>
<pre><code class="language-java">import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.IOException;

public class DataInputStreamExample {
    public static void main(String[] args) {
        try (DataInputStream dis = new DataInputStream(new FileInputStream(&quot;data.bin&quot;))) {
            int intValue = dis.readInt();
            float floatValue = dis.readFloat();
            String strValue = dis.readUTF();
            System.out.println(&quot;Read values: &quot; + intValue + &quot;, &quot; + floatValue + &quot;, &quot; + strValue);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}</code></pre>
<p><br><br></p>
<h3 id="파일-복사-예제">파일 복사 예제</h3>
<pre><code class="language-java">import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class FileCopyExample {
    public static void main(String[] args) {
        try (FileInputStream fis = new FileInputStream(&quot;source.txt&quot;);
             FileOutputStream fos = new FileOutputStream(&quot;destination.txt&quot;)) {

            byte[] buffer = new byte[1024];
            int bytesRead;

            while ((bytesRead = fis.read(buffer)) != -1) {
                fos.write(buffer, 0, bytesRead);
            }

            System.out.println(&quot;File copied successfully.&quot;);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}</code></pre>
<p><br><br></p>
<h3 id="요약-4">요약</h3>
<ul>
<li><p><strong>바이트 스트림</strong>
<code>FileInputStream</code>과 <code>FileOutputStream</code>을 사용하여 파일의 데이터를 바이트 단위로 읽고 씁니다.</p>
</li>
<li><p><strong>문자 스트림</strong>
<code>FileReader</code>와 <code>FileWriter</code>를 사용하여 파일의 데이터를 문자 단위로 읽고 씁니다.</p>
</li>
<li><p><strong>버퍼링된 스트림</strong>
<code>BufferedReader</code>와 <code>BufferedWriter</code>를 사용하여 효율적으로 파일을 읽고 씁니다.</p>
</li>
<li><p><strong>데이터 스트림</strong>
<code>DataInputStream</code>과 <code>DataOutputStream</code>을 사용하여 기본 데이터 타입을 파일로부터 읽고 씁니다.</p>
</li>
</ul>
<p><br><br></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[어노테이션]]></title>
            <link>https://velog.io/@ha_bu/%EC%96%B4%EB%85%B8%ED%85%8C%EC%9D%B4%EC%85%98</link>
            <guid>https://velog.io/@ha_bu/%EC%96%B4%EB%85%B8%ED%85%8C%EC%9D%B4%EC%85%98</guid>
            <pubDate>Wed, 03 Jul 2024 09:56:10 GMT</pubDate>
            <description><![CDATA[<h3 id="목표">목표</h3>
<blockquote>
<p>자바의 어노테이션에 대해 학습</p>
</blockquote>
<h3 id="목차">목차</h3>
<p><a href="#1-%EC%96%B4%EB%85%B8%ED%85%8C%EC%9D%B4%EC%85%98-%EC%A0%95%EC%9D%98%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95">1. 어노테이션 정의하는 방법</a>
<a href="#2-retention">2. @retention</a>
<a href="#3-target">3. @target</a>
<a href="#4-documented">4. @documented</a>
<a href="#5-%EC%96%B4%EB%85%B8%ED%85%8C%EC%9D%B4%EC%85%98-%ED%94%84%EB%A1%9C%EC%84%B8%EC%84%9C">5. 어노테이션 프로세서</a></p>
<br>

<h3 id="1-어노테이션-정의하는-방법">1. 어노테이션 정의하는 방법</h3>
<blockquote>
<p>Java에서 어노테이션(Annotation)은 메타데이터를 제공하는 특별한 종류의 인터페이스입니다. 어노테이션은 <strong>코드에 대한 추가 정보를 제공하며, 주로 컴파일러 지시자, 런타임 정보 제공, 또는 코드 분석 도구에서 사용</strong>됩니다.</p>
</blockquote>
<br>

<h4 id="1-1-어노테이션-정의하기">1-1 어노테이션 정의하기</h4>
<ol>
<li><p>어노테이션 인터페이스 생성
<code>@interface</code> 키워드를 사용하여 어노테이션을 정의합니다.</p>
</li>
<li><p>요소 정의
어노테이션 내에 요소(Element)를 정의할 수 있습니다. 요소는 기본값을 가질 수 있습니다.</p>
</li>
</ol>
<p>** 예제 **</p>
<pre><code class="language-java">// 어노테이션 정의
public @interface MyAnnotation {
    String value();
    int number() default 0;
}

// 어노테이션 사용
@MyAnnotation(value = &quot;Hello&quot;, number = 5)
public class MyClass {
    // 클래스 내용
}</code></pre>
<br>

<h4 id="1-2-어노테이션-요소의-기본값-설정">1-2 어노테이션 요소의 기본값 설정</h4>
<p>어노테이션 요소에 기본값을 설정할 수 있습니다. 기본값을 설정하면 어노테이션을 사용할 때 해당 요소를 생략할 수 있습니다.</p>
<pre><code class="language-java">// 어노테이션 정의
public @interface MyAnnotation {
    String value() default &quot;default value&quot;;
    int number() default 42;
}

@MyAnnotation
public class MyClass {
    // 클래스 내용
    // 기본값을 설정해 두었기때문에, 요소를 생략할 수 있습니다.
}</code></pre>
<br>

<h4 id="1-3-어노테이션의-메타-어노테이션">1-3 어노테이션의 메타-어노테이션</h4>
<p>&amp;nbsp 어노테이션도 다른 어노테이션으로 설명할 수 있습니다. 이를 메타-어노테이션(Meta-Annotation)이라고 합니다. Java에서는 여러 가지 메타-어노테이션이 있습니다.</p>
<ul>
<li><code>@Retention</code> : 어노테이션의 유지 정책을 정의합니다.</li>
<li><code>@Target</code> : 어노테이션이 적용될 수 있는 위치를 정의합니다.</li>
<li><code>@Documented</code> : 어노테이션이 Javadoc에 포함되도록 합니다.</li>
<li><code>@Inherited</code> : 어노테이션이 하위 클래스에 상속되도록 합니다.</li>
</ul>
<p>** 예제 **</p>
<pre><code class="language-java">import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

// 어노테이션 정의
@Retention(RetentionPolicy.RUNTIME) // 런타임까지 어노테이션 유지
@Target(ElementType.METHOD) // 메서드에만 적용 가능
public @interface MyAnnotation {
    String value() default &quot;default value&quot;;
    int number() default 42;
}</code></pre>
<p><br><br></p>
<h3 id="2-retention">2. @Retention</h3>
<blockquote>
<p><code>@Retention</code> 어노테이션은 Java에서 어노테이션이 얼마나 오래 유지될지를 지정하는 메타-어노테이션입니다. 이를 통해 어노테이션이 소스 코드, 클래스 파일, 런타임 중 <strong>어느 단계까지 유지될지를 결정할 수 있습니다.</strong></p>
</blockquote>
<br>

<h4 id="2-1-retention-사용-방법">2-1 @Retention 사용 방법</h4>
<p><code>@Retention</code> 어노테이션을 사용하여 어노테이션의 유지 정책을 설정할 수 있습니다. 유지 정책은 <code>java.lang.annotation.RetentionPolicy</code> 열거형을 통해 지정됩니다. <code>RetentionPolicy</code>는 다음과 같은 세 가지 값을 가질 수 있습니다.</p>
<br>

<p><strong>1. RetentionPolicy.SOURCE</strong>
어노테이션이 소스코드에만 유지되고, 컴파일 과정에서 제거됩니다. 이는 주로 컴파일러에 대한 힌트로 사용됩니다.</p>
<p><strong>2. RetentionPolicy.CLASS</strong>
어노테이션이 컴파일된 클래스 파일에 포함되지만, JVM에서 실행될 때는 사용할 수 없습니다. 이는 기본값입니다.</p>
<p><strong>3. RetentionPolicy.RUNTIME</strong>
어노테이션이 런타임까지 유지되며, 리플렉션을 사용하여 런타임에 접근할 수 있습니다. 런타임 시에 동적으로 어노테이션 정보를 필요로 하는 경우에 사용됩니다.</p>
<br>

<p><strong>예제</strong></p>
<pre><code class="language-java">import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface MyRuntimeAnnotation {
    String value();
}

// ----------------------------------------------------------

public class MyClass {
    @MyRuntimeAnnotation(value = &quot;Example&quot;)
    public void myMethod() {
        // 메서드 내용
    }

    public static void main(String[] args) {
        MyClass obj = new MyClass();
        // 런타임에 어노테이션 정보 읽기
        MyRuntimeAnnotation annotation 
        = obj.getClass().getMethod(&quot;myMethod&quot;)
        .getAnnotation(MyRuntimeAnnotation.class);

        System.out.println(annotation.value()); 
        // &quot;Example&quot; 출력
    }
}</code></pre>
<br>

<h4 id="2-2-요약">2-2 요약</h4>
<ul>
<li><p><code>@Retention</code> 어노테이션은 어노테이션의 유지 정책을 결정합니다.</p>
</li>
<li><p><code>RetentionPolicy.SOURCE</code> : 컴파일 후 어노테이션 제거</p>
</li>
<li><p><code>RetentionPolicy.CLASS</code> : 컴파일된 클래스 파일에 어노테이션 유지</p>
</li>
<li><p><code>RetentionPolicy.RUNTIME</code> : 런타임까지 어노테이션 유지</p>
</li>
</ul>
<p><br><br></p>
<h3 id="3-target">3. @Target</h3>
<blockquote>
<p><code>@Target</code> 어노테이션은 Java에서 <strong>어노테이션이 적용될 수 있는 프로그램 요소를 지정</strong>하는 메타-어노테이션입니다. 이 어노테이션을 어디에 적용할 수 있는지 제한할 수 있습니다.</p>
</blockquote>
<br>

<h4 id="3-1-target-사용-방법">3-1 @Target 사용 방법</h4>
<p>&amp;nbsp <code>@Target</code> 어노테이션은 <code>java.lang.annotation.ElementType</code> 열거형을 인수로 받습니다. <code>ElementType</code>은 어노테이션이 적용될 수 있는 프로그램 요소를 정의하는 여러 상수를 제공합니다. 주요 <code>ElemetType</code> 값은 다음과 같습니다.</p>
<br>

<p><strong>1. ElementType.Type</strong>
클래스, 인터페이스(어노테이션 유형 포함), 열거형에 적용됩니다.</p>
<p><strong>2. ElementType.FIELD</strong>
필드(인스턴스 변수 포함)에 적용됩니다.</p>
<p><strong>3. ElementType.METHOD</strong>
메서드에 적용됩니다.</p>
<p><strong>4. ElementType.PARAMETER</strong>
메서드의 매개변수에 적용됩니다.</p>
<p><strong>5. ElementType.CONSTRUCTOR</strong>
생성자에 적용됩니다.</p>
<p><strong>6. ElementType.LOCAL_VARIABLE</strong>
지역 변수에 적용됩니다.</p>
<p><strong>7. ElementType.ANNOTATION_TYPE</strong>
다른 어노테이션에 적용됩니다.</p>
<p><strong>8. ElementType.PACKAGE</strong>
패키지 선언에 적용됩니다.</p>
<p><strong>9. ElementType.TYPE_PARAMETER</strong>
제네릭 타입 매개변수에 적용됩니다.</p>
<p>*<em>10. ElementType.TYPE_USE *</em>
타입 사용에 적용됩니다.</p>
<br>

<h4 id="3-2-target-예제">3-2 @Target 예제</h4>
<p>&amp;nbsp 다음은 <code>@Target</code> 어노테이션을 사용하여 어노테이션이 메서드에만 적용되도록 하는 예제입니다.</p>
<pre><code class="language-java">import java.lang.annotation.ElementType;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
public @interface MethodOnlyAnnotation {
    String value();
}

//-----------------------------------------------
public class MyClass {
    @MethodOnlyAnnotation(value = &quot;This is a method&quot;)
    public void myMethod() {
        // 메서드 내용
    }

    // 잘못된 사용 - 컴파일 오류 발생
    // @MethodOnlyAnnotation(value = &quot;This is a field&quot;)
    // private String myField;
}</code></pre>
<br>

<p><code>@Target</code> 어노테이션은 배열 형태로 여러 <code>ElementType</code> 값을 지정할 수 있습니다.</p>
<pre><code class="language-java">import java.lang.annotation.ElementType;
import java.lang.annotation.Target;

@Target({ElementType.TYPE, ElementType.METHOD})
public @interface TypeAndMethodAnnotation {
    String value();
}

//-----------------------------------------------

@TypeAndMethodAnnotation(value = &quot;This is a class&quot;)
public class MyClass {
    @TypeAndMethodAnnotation(value = &quot;This is a method&quot;)
    public void myMethod() {
        // 메서드 내용
    }
}</code></pre>
<br>

<h4 id="3-3-요약">3-3 요약</h4>
<ul>
<li><p><code>@Target</code> 어노테이션은 어노테이션이 적용될 수 있는 프로그램 요소를 지정합니다.</p>
</li>
<li><p>주요 <code>ElementType</code> 값은 클래스, 메서드, 필드, 생성자, 매개변수 등 다양한 프로그램 요소를 포함합니다.</p>
</li>
<li><p>여러 <code>ElementType</code> 값을 배열 형태로 지정할 수있습니다.</p>
</li>
</ul>
<p><br><br></p>
<h3 id="4-documented">4. @Documented</h3>
<blockquote>
<p><code>@Documented</code> 어노테이션은 Java에서 메타-어노테이션 중 하나로, 어노테이션이 <strong>Javadoc 문서에 포함되도록 지정하는 데 사용됩니다.</strong> 이를 통해 어노테이션이 문서화되고, Javadoc 도구를 사용하여 생성된 API 문서에 어노테이션의 존재와 설명이 포함됩니다.</p>
</blockquote>
<br>

<h4 id="4-1-documented-사용방법">4-1 @Documented 사용방법</h4>
<p>&amp;nbsp <code>@Documented</code> 어노테이션은 단순히 어노테이션 타입에 적용하여 Javadoc에 포함되도록 하는 역할을 합니다. 이는 주로 라이브러리나 API를 작성할 때 유용하며, 사용자가 어노테이션의 의미와 사용 방법을 문서에서 쉽게 확인할 수 있게 합니다.</p>
<p><strong>예제</strong></p>
<pre><code class="language-java">import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyDocumentedAnnotation {
    String value();
}

// -----------------------------------------------

public class MyClass {
    /**
     * 이 메서드는 예제 메서드입니다.
     *
     * @param param 예제 매개변수
     */
    @MyDocumentedAnnotation(value = &quot;Example annotation&quot;)
    public void myMethod(String param) {
        // 메서드 내용
    }
}

</code></pre>
<p>&amp;nbsp 이제 Javadoc 도구를 사용하여 문서를 생성하면 <code>myMethod</code> 메서드에 <code>@MyDocumentedAnnotation</code> 어노테이션이 포함된다는 내용이 문서화됩니다.</p>
<pre><code class="language-html">/**
 * 이 메서드는 예제 메서드입니다.
 *
 * @param param 예제 매개변수
 * @MyDocumentedAnnotation(value = &quot;Example annotation&quot;)
 */
public void myMethod(String param) {
    // 메서드 내용
}</code></pre>
<br>

<h4 id="4-2-요약">4-2 요약</h4>
<ul>
<li><p><code>@Documented</code> 어노테이션은 어노테이션이 Javadoc 문서에 포함되도록 지정합니다.</p>
</li>
<li><p>이는 API 문서를 작성할 때 어노테이션의 의미와 사용 방법을 문서에 포함시켜 사용자에게 제공하는 데 유용합니다.</p>
</li>
</ul>
<p><br><br></p>
<h3 id="5-어노테이션-프로세서">5. 어노테이션 프로세서</h3>
<blockquote>
<p>Java 어노테이션 프로세서(Annotation Processor)는 컴파일러가 소스 코드를 컴파일하는 동안 어노테이션을 처리할 수 있는 도구입니다. </p>
<p>어노테이션 프로세서를 사용하면 컴파일 타임에 어노테이션을 분석하고, 소스코드를 생성하거나 검증 작업을 수행할 수 있습니다. 이를 통해 코드의 유지보수성과 생산성을 높일 수 있습니다.</p>
</blockquote>
<h4 id="5-1-어노테이션-프로세서의-동작-원리">5-1 어노테이션 프로세서의 동작 원리</h4>
<p>&amp;nbsp 어노테이션 프로세서는 컴파일러 API를 사용하여 특정 어노테이션이 적용된 코드를 분석하고, 이에 따라 추가적인 작업을 수행합니다. 주요 단계는 아래와 같습니다.</p>
<br>

<p><strong>1. 어노테이션 프로세서 정의</strong>
어노테이션 프로세서 클래스를 정의하고 <code>javax.annotation.processing.Processor</code> 인터페이스를 구현합니다.</p>
<p><strong>2. 어노티이션 프로세서 등록</strong>
<code>META-INF/service/javax.annotation.processing.Processor</code> 파일에 어노테이션 프로레서 클래스 이름을 등록합니다.</p>
<p><strong>3. 어노테이션 프로세서 실행</strong>
컴파일 시 컴파일러가 어노테이션 프로세서를 자동으로 실행하여 어노테이션을 처리합니다.</p>
<br>

<h4 id="5-2-어노테이션-프로레서-구현-예제">5-2 어노테이션 프로레서 구현 예제</h4>
<p>&amp;nbsp 이 예제에서는 <code>@MyAnnotation</code> 어노테이션이 적용된 클래스의 정보를 출력하는 어노테이션 프로세서를 작성합니다.</p>
<br>

<p>*<em>어노테이션 정의 *</em>
먼저, <code>@MyAnnotation</code> 어노테이션을 정의합니다.</p>
<pre><code class="language-java">import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.SOURCE)
public @interface MyAnnotation {
    String value();
}</code></pre>
<br>

<p><strong>어노테이션 프로세서 구현</strong>
다음으로, <code>@MyAnnotation</code> 어노테이션을 처리하는 어노테이션 프로세서를 구현합니다.</p>
<pre><code class="language-java">import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import java.util.Set;

@SupportedAnnotationTypes(&quot;MyAnnotation&quot;)
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class MyAnnotationProcessor extends AbstractProcessor {

    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        super.init(processingEnv);
    }

    @Override
    public boolean process(Set&lt;? extends TypeElement&gt; annotations, RoundEnvironment roundEnv) {
        for (Element element : roundEnv.getElementsAnnotatedWith(MyAnnotation.class)) {
            MyAnnotation annotation = element.getAnnotation(MyAnnotation.class);
            System.out.println(&quot;Found @MyAnnotation with value: &quot; + annotation.value());
        }
        return true; // 어노테이션이 처리되었음을 표시
    }
}</code></pre>
<br>

<p><strong>어노테이션 프로세서 등록</strong>
<code>META-INF/services/javax.annotation.processing.Processor</code>파일을 생성하고, 어노테이션 프로세서 클래 이름 등록을 합니다.</p>
<pre><code class="language-text">MyAnnotationProcessor</code></pre>
<br>

<p><strong>어노테이션 프로세서 사용</strong>
이제 <code>@MyAnnotation</code> 어노테이션을 사용하여 클래스를 작성하고 컴파일하면 어노테이션 프로세서가 실행됩니다.</p>
<pre><code class="language-java">@MyAnnotation(value = &quot;Hello, World!&quot;)
public class MyClass {
    public static void main(String[] args) {
        // 메인 메서드 내용
    }
}</code></pre>
<h4 id="5-3-주요-클래스와-인터페이스">5-3 주요 클래스와 인터페이스</h4>
<ul>
<li><p><strong>AbstractProcessor</strong>
<code>Processor</code> 인터페이스의 기본 구현을 제공하는 추상 클래스입니다. 어노테이션 프로세서를 작성할 때 주로 이 클래스를 확장합니다.</p>
</li>
<li><p><strong>ProcessingEnvironment</strong>
어노테이션 프로세서 환경을 제공하는 인터페이스로, 필수 유틸리티 메서드와 메시지 출력을 지원합니다.</p>
</li>
<li><p><strong>RoundEnvironment</strong>
현재 프로세스 라운드에 대한 정보를 제공하는 인터페이스로, 어노테이션이 적용된 요소들을 탐색할 수 있습니다.</p>
</li>
</ul>
<br>

<h4 id="5-4-요약">5-4 요약</h4>
<ul>
<li><p>어노테이션 프로세서는 컴파일 타임에 어노테이션을 처리하여 추가적인 작업을 수행합니다.</p>
</li>
<li><p>어노테이션 프로세서를 정의하려면 <code>AbstractProcessor</code> 클래스를 확장하고, 필요한 메서드를 구현해야 합니다.</p>
</li>
<li><p>어노테이션 프로세서를 등록하려면 <code>META-INF/services/javax.annotation.processing.Processor</code> 파일에 프로세러 클래스를 등록해야 합니다.</p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Enum]]></title>
            <link>https://velog.io/@ha_bu/Enum</link>
            <guid>https://velog.io/@ha_bu/Enum</guid>
            <pubDate>Wed, 26 Jun 2024 13:34:01 GMT</pubDate>
            <description><![CDATA[<h3 id="목표">목표</h3>
<blockquote>
<p>Java의 열거형에 대해 학습</p>
</blockquote>
<h3 id="목차">목차</h3>
<p><a href="#1-enum-%EC%A0%95%EC%9D%98%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95">1. enum 정의하는 방법</a>
<a href="#2-enum%EC%9D%B4-%EC%A0%9C%EA%B3%B5%ED%95%98%EB%8A%94-%EB%A9%94%EC%86%8C%EB%93%9Cvalues%EC%99%80-valueof">2. enum이 제공하는 메소드(values()와 valueOf())</a>
<a href="#3-javalangenum">3. java.lang.Enum</a>
<a href="#4-enumset">4. EnumSet</a></p>
<br>

<h3 id="1-enum-정의하는-방법">1. enum 정의하는 방법</h3>
<blockquote>
<p>Java에서 <code>enum</code>(열거형)은 상수의 집합을 정의하는 특수한 데이터 타입입니다. <code>enum</code>을 사용하면 코드의 가독성을 높이고, 특정 값들만 사용할 수 있도록 제한할 수있습니다.</p>
</blockquote>
<br>

<h4 id="1-1-기본적인-enum의-정의">1-1 기본적인 enum의 정의</h4>
<p>바로 코드를 통해 알아보겠습니다.</p>
<pre><code class="language-java">public enum Day {
    SUNDAY,
    MONDAY,
    TUESDAY,
    WEDNESDAY,
    THURSDAY,
    FRIDAY,
    SATURDAY
}

public class Main {
    public static void main(String[] args) {
        Day today = Day.MONDAY;
        System.out.println(&quot;오늘은: &quot; + today);

        switch (today) {
            case MONDAY:
                System.out.println(&quot;월요일입니다.&quot;);
                break;
            case TUESDAY:
                System.out.println(&quot;화요일입니다.&quot;);
                break;
            // 다른 요일에 대한 처리...
            default:
                System.out.println(&quot;다른 요일입니다.&quot;);
                break;
        }
    }
}</code></pre>
<p>&amp;nbsp 이렇게 정의된 <code>enum</code>을 사용할 때는 위와 같이 사용할 수 있습니다.</p>
<p><br><br></p>
<h4 id="1-2-enum에-멤버-변수와-메서드-추가">1-2 enum에 멤버 변수와 메서드 추가</h4>
<p>&amp;nbsp <code>enum</code>은 단순히 상수 값만 가질 수 있는 것이 아니라, 멤버 변수와 메서드도 추가할 수 있습니다. 예를 들어 각 요일에 대한 간단한 설명을 추가해 보겠습니다.</p>
<pre><code class="language-java">public enum Day {
    SUNDAY(&quot;휴일&quot;),
    MONDAY(&quot;평일&quot;),
    TUESDAY(&quot;평일&quot;),
    WEDNESDAY(&quot;평일&quot;),
    THURSDAY(&quot;평일&quot;),
    FRIDAY(&quot;평일&quot;),
    SATURDAY(&quot;휴일&quot;);

    private String description;

    Day(String description) {
        this.description = description;
    }

    public String getDescription() {
        return description;
    }
}

public class Main {
    public static void main(String[] args) {
        Day today = Day.SUNDAY;
        System.out.println(&quot;오늘은: &quot; + today);
        System.out.println(&quot;설명: &quot; + today.getDescription());
    }
}</code></pre>
<p><br><br></p>
<h4 id="1-3-enum에-추상-메서드-추가">1-3 enum에 추상 메서드 추가</h4>
<p>&amp;nbsp <code>enum</code>에 추상 메서드를 추가하고 각 열거형 값에서 이를 구현할 수 있습니다. 예를 들어 각 요일에 따라 다른 행동을 정의해보겠습니다.</p>
<pre><code class="language-java">public enum Day {
    SUNDAY {
        @Override
        public void action() {
            System.out.println(&quot;휴식을 취합니다.&quot;);
        }
    },
    MONDAY {
        @Override
        public void action() {
            System.out.println(&quot;일을 합니다.&quot;);
        }
    },
    TUESDAY {
        @Override
        public void action() {
            System.out.println(&quot;일을 합니다.&quot;);
        }
    },
    WEDNESDAY {
        @Override
        public void action() {
            System.out.println(&quot;일을 합니다.&quot;);
        }
    },
    THURSDAY {
        @Override
        public void action() {
            System.out.println(&quot;일을 합니다.&quot;);
        }
    },
    FRIDAY {
        @Override
        public void action() {
            System.out.println(&quot;일을 합니다.&quot;);
        }
    },
    SATURDAY {
        @Override
        public void action() {
            System.out.println(&quot;휴식을 취합니다.&quot;);
        }
    };

    public abstract void action();
}

public class Main {
    public static void main(String[] args) {
        Day today = Day.FRIDAY;
        today.action();  // &quot;일을 합니다.&quot; 출력
    }
}</code></pre>
<h4 id="요약">요약</h4>
<ul>
<li><code>enum</code>은 상수의 집합을 정의하는 특수한 데이터 타입입니다.</li>
<li><code>enum</code>에 멤버 변수와 메서드를 추가할 수 있습니다.</li>
<li><code>enum</code>에 추상 메서드를 추가하고 각 열거형 값에서 이를 구현할 수 있습니다.</li>
</ul>
<p><br><br></p>
<h3 id="2-enum이-제공하는-메소드values와-valueof">2. enum이 제공하는 메소드(values()와 valueOf())</h3>
<blockquote>
<p><code>enum</code>은 자동으로 <code>valuse()</code>와 <code>valueOf(String name)</code> 메서드를 제공합니다.</p>
</blockquote>
<br>

<h4 id="2-1-values-메서드">2-1 values() 메서드</h4>
<p>&amp;nbsp <code>values()</code> 메서드는 해당 <code>enum</code> 타입의 모든 열거형 상수들을 배열로 반환합니다. 이 메서드는 컴파일러가 자동으로 추가하는 메서드로, 모든 <code>enum</code> 타입에서 사용할 수 있습니다.</p>
<br>

<pre><code class="language-java">public enum Day {
    SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY
}

public class Main {
    public static void main(String[] args) {
        Day[] days = Day.values();

        for (Day day : days) {
            System.out.println(day);
        }
    }
}

// 출력
// SUNDAY
// MONDAY
// TUESDAY
// WEDNESDAY
// THURSDAY
// FRIDAY
// SATURDAY</code></pre>
<p>&amp;nbsp 위 예제를 보면 알 수 있듯이, <code>Day.values()</code>는 <code>Day</code> 열거형 타입의 모든 상수를 배열로 반환합니다. 이 배열을 반복하여 모든 상수를 출력할 수 있습니다.</p>
<p><br><br></p>
<h4 id="2-2-valueofstring-name-메서드">2-2 valueOf(String name) 메서드</h4>
<p>&amp;nbsp <code>valueOf(String name)</code> 메서드는 주어진 문자열과 일치하는 <code>enum</code> 상수를 반환합니다. 이 메서드는 <code>java.lang.Enum</code> 클래스에 정의되어 있으며, 문자열이 일치하는 <code>enum</code> 상수가 없으면 <code>IllegalArgumentException</code>을 던집니다. <strong>문자열은 대소문자를 구분합니다.</strong></p>
<br>

<pre><code class="language-java">public enum Day {
    SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY
}

public class Main {
    public static void main(String[] args) {
        Day day = Day.valueOf(&quot;MONDAY&quot;);
        System.out.println(day);

        // 만약 문자열이 열거형 상수와 일치하지 않으면 예외가 발생합니다.
        try {
            Day invalidDay = Day.valueOf(&quot;FUNDAY&quot;);
        } catch (IllegalArgumentException e) {
            System.out.println(&quot;예외 발생: &quot; + e.getMessage());
        }
    }
}</code></pre>
<p>&amp;nbsp 위 예제 코드의 출력은 아래와 같습니다.</p>
<pre><code class="language-text">MONDAY
예외 발생: No enum constant Main.Day.FUNDAY</code></pre>
<p>&amp;nbsp 위 예제에서 <code>Day.valueOf(&quot;MONDAY&quot;)</code>는 <code>Day.MONDAY</code> 상수를 반환합니다. 하지만, <code>&quot;FUNDAY&quot;</code>는 <code>Day</code> 열거형에 없는 타입이므로 <code>IllegalArgumentException</code>이 발생합니다.</p>
<h4 id="요약-1">요약</h4>
<ul>
<li><code>values()</code> 메서드 : 해당 <code>enum</code> 타입의 모든 상수를 배열로 반환합니다.</li>
<li><code>valueOf(String name)</code> 메서드 : 주어진 문자열과 일치하는 <code>enum</code> 상수를 반환하며, 일치하는 상수가 없으면 <code>IllegalArgumentException</code>을 던집니다.</li>
</ul>
<p><br><br></p>
<h3 id="3-javalangenum">3. java.lang.Enum</h3>
<blockquote>
<p><code>java.lang.Enum</code> 클래스는 자바에서 모든 <code>enum</code> 타입의 공통적인 상위 클래스입니다. <strong>이 클래스는 <code>enum</code> 타입을 보다 유용하게 만들기 위해 다양한 메서드와 기능을 제공합니다.</strong></p>
<p><code>Enum</code> 클래스는 제네릭 클래스이며, <code>Enum&lt;E extends Enum&lt;E&gt;&gt;</code>로 정의되어 있습니다. 이는 모든 <code>enum</code> 타입이 이 클래스를 상속받아야 함을 의미합니다.</p>
</blockquote>
<br>

<h4 id="3-1-name">3-1 name()</h4>
<p>&amp;nbsp <code>name()</code> 메서드는 열거형 상수의 이름을 반환합니다. 이 이름은 열거형 상수가 선언된 그대로의 문자열입니다.</p>
<pre><code class="language-java">public enum Day {
    SUNDAY, MONDAY, TUESDAY
}

public class Main {
    public static void main(String[] args) {
        Day day = Day.MONDAY;
        System.out.println(day.name());  // &quot;MONDAY&quot; 출력
    }
}</code></pre>
<p><br><br></p>
<h4 id="3-2-ordinal">3-2 ordinal()</h4>
<p>&amp;nbsp <code>ordinal()</code> 메서드는 열거형 상수가 열거형 선언에서 정의된 순서를 반환합니다. 순서는 0부터 시작합니다.</p>
<pre><code class="language-java">public enum Day {
    SUNDAY, MONDAY, TUESDAY
}

public class Main {
    public static void main(String[] args) {
        Day day = Day.MONDAY;
        System.out.println(day.ordinal());  // 1 출력
    }
}</code></pre>
<p><br><br></p>
<h4 id="3-3-comparetoe-o">3-3 compareTo(E o)</h4>
<p>&amp;nbsp <code>compareTo(E o)</code> 메서드는 현재 열거형 상수와 주어진 열거형 상수를 비교합니다. 열거형 상수의 정의 순서에 따라 비교하며, 이 순서에 기반하여 정렬에 사용할 수 있습니다.</p>
<pre><code class="language-java">public enum Day {
    SUNDAY, MONDAY, TUESDAY
}

public class Main {
    public static void main(String[] args) {
        Day day1 = Day.MONDAY;
        Day day2 = Day.TUESDAY;
        System.out.println(day1.compareTo(day2));  // -1 출력
    }
}</code></pre>
<p><br><br></p>
<h4 id="3-4-tostring">3-4 toString()</h4>
<p>&amp;nbsp <code>toString()</code> 메서드는 열거형 상수의 이름을 반환합니다. <code>name()</code> 메서드와 동일한 결과를 반환합니다.</p>
<pre><code class="language-java">public enum Day {
    SUNDAY, MONDAY, TUESDAY
}

public class Main {
    public static void main(String[] args) {
        Day day = Day.MONDAY;
        System.out.println(day.toString());  // &quot;MONDAY&quot; 출력
    }
}</code></pre>
<p><br><br></p>
<h4 id="3-5-valueofclasst-enumtype-string-name">3-5 <code>valueOf(Class&lt;T&gt; enumType, String name)</code></h4>
<p>&amp;nbsp <code>valueOf(Class&lt;T&gt; enumType, String name)</code> 메서드는 주어진 클래스 객체와 문자열을 사용하여 열거형 상수를 반환합니다. 주어진 이름과 일치하는 열거형 상수가 없으면 <code>IllegalArgumentException</code>을 던집니다.</p>
<pre><code class="language-java">public enum Day {
    SUNDAY, MONDAY, TUESDAY
}

public class Main {
    public static void main(String[] args) {
        Day day = Enum.valueOf(Day.class, &quot;MONDAY&quot;);
        System.out.println(day);  // &quot;MONDAY&quot; 출력
    }
}</code></pre>
<p><br><br></p>
<h4 id="enum-클래스의-구조">Enum 클래스의 구조</h4>
<p>&amp;nbsp <code>java.lang.Enum</code> 클래스의 기본 구조는 다음과 같습니다.</p>
<pre><code class="language-java">public abstract class Enum&lt;E extends Enum&lt;E&gt;&gt; implements Comparable&lt;E&gt;, Serializable {
    private final String name;
    private final int ordinal;

    // 기본 생성자
    protected Enum(String name, int ordinal) {
        this.name = name;
        this.ordinal = ordinal;
    }

    // 기타 메서드...
}</code></pre>
<p><br><br></p>
<h4 id="요약-2">요약</h4>
<ul>
<li><p>모든 <code>enum</code> 타입의 공통적인 상위 클래스
<code>Enum</code>클래스는 모든 <code>enum</code> 타입이 자동으로 상속받는 클래스입니다.</p>
</li>
<li><p>이름과 순서
<code>Enum</code> 클래스는 각 열거형 상수의 이름과 순서를 저장합니다.</p>
</li>
<li><p>비교와 정렬
<code>compareTo()</code>메서드를 통해 열거형 상수 간의 비교와 정렬이 가능합니다.</p>
</li>
<li><p>직렬화 가능
<code>Enum</code> 클래스는 <code>Serializable</code> 인터페이스를 구현하여 열거형 상수가 직렬화 가능함을 보장합니다.</p>
</li>
<li><p>유용한 메서드 제공
<code>name()</code>, <code>ordinal()</code>, <code>valueOf()</code> 등 다양한 유용한 메서드를 제공합니다.</p>
</li>
</ul>
<p><br><br></p>
<h3 id="4-enumset">4. EnumSet</h3>
<blockquote>
<p><code>EnumSet</code>은 자바에서 <code>enum</code> 타입의 상수를 저장하기 위해 특별히 설계된 집합(Set) 구현체입니다. </p>
<p><code>EnumSet</code>은 일반적인 <code>Set</code>과는 다르게 성능 최적화 및 메모리 절약을 위해 특별한 내부 구조를 가지고 있습니다. <code>EnumSet</code>은 <code>java.util</code> 패키지에 속해 있으며, <code>enum</code> 상수 집합을 다룰 때 매우 유용합니다.</p>
</blockquote>
<br>

<h4 id="특징">특징</h4>
<ul>
<li><p><code>enum</code> 타입 전용
<code>EnumSet</code>은 특정 <code>enum</code> 타입의 상수들만 저장할 수 있습니다.</p>
</li>
<li><p>효율적이고 빠름
비트 백터(bit vector)로 내부적으로 구현되어 있어 메모리 사용이 적고 매우 빠릅니다.</p>
</li>
<li><p>정렬
저장된 요소들은 <code>enum</code> 상수가 정의된 순서대로 정렬됩니다.</p>
</li>
<li><p>불변 객체
<code>EnumSet</code> 자체는 변경 가능하지만, <code>enum</code> 상수는 불변 객체이므로 추가나 제거 시 항상 안전하게 작동합니다.</p>
</li>
</ul>
<br>

<h4 id="4-1-사용방법">4-1 사용방법</h4>
<blockquote>
<p><code>EnumSet</code>을 생성하는 방법은 아주 다양합니다.</p>
</blockquote>
<h5 id="allof"><code>allOf()</code></h5>
<p>특정 <code>enum</code> 타입의 모든 상수를 포함하는 <code>EnumSet</code>을 생성합니다.</p>
<pre><code class="language-java">enum Day {
    SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY
}

EnumSet&lt;Day&gt; allDays = EnumSet.allOf(Day.class);</code></pre>
<br>

<h5 id="nonof"><code>nonOf()</code></h5>
<p>비어있는 <code>EnumSet</code>을 생성합니다.</p>
<pre><code class="language-java">EnumSet&lt;Day&gt; noDays = EnumSet.noneOf(Day.class);</code></pre>
<br>

<h5 id="of"><code>of()</code></h5>
<p>하나 이상의 특정 <code>enum</code> 상수를 포함하는 <code>EnumSet</code>을 생성합니다.</p>
<pre><code class="language-java">EnumSet&lt;Day&gt; weekend = EnumSet.of(Day.SATURDAY, Day.SUNDAY);</code></pre>
<br>

<h5 id="range"><code>range()</code></h5>
<p>두 <code>enum</code> 상수 사이의 범위를 포함하는 <code>EnumSet</code>을 생성합니다.</p>
<pre><code class="language-java">EnumSet&lt;Day&gt; workdays = EnumSet.range(Day.MONDAY, Day.FRIDAY);</code></pre>
<br>

<h5 id="copyof"><code>copyOf()</code></h5>
<p>다른 컬렉션을 복사하여 <code>EnumSet</code>을 생성합니다.</p>
<pre><code class="language-java">Set&lt;Day&gt; someDays = EnumSet.of(Day.MONDAY, Day.WEDNESDAY);
EnumSet&lt;Day&gt; copiedDays = EnumSet.copyOf(someDays);</code></pre>
<p><br><br></p>
<h4 id="4-2-enumset의-메서드">4-2 <code>EnumSet</code>의 메서드</h4>
<p><code>EnumSet</code>은 <code>Set</code> 인터페이스를 구현하므로 일반적인 <code>Set</code> 메서드들을 사용할 수 있습니다.</p>
<pre><code class="language-java">public class Main {
    public static void main(String[] args) {
        EnumSet&lt;Day&gt; weekend = EnumSet.of(Day.SATURDAY, Day.SUNDAY);

        // 요소 추가
        weekend.add(Day.FRIDAY);
        System.out.println(&quot;주말과 금요일: &quot; + weekend);

        // 요소 제거
        weekend.remove(Day.FRIDAY);
        System.out.println(&quot;주말: &quot; + weekend);

        // 포함 여부 확인
        boolean isWeekend = weekend.contains(Day.SUNDAY);
        System.out.println(&quot;일요일이 포함되어 있는가? &quot; + isWeekend);

        // 반복
        for (Day day : weekend) {
            System.out.println(day);
        }
    }
}</code></pre>
<p>출력은 아래와 같습니다.</p>
<pre><code>주말과 금요일: [FRIDAY, SATURDAY, SUNDAY]
주말: [SATURDAY, SUNDAY]
일요일이 포함되어 있는가? true
SATURDAY
SUNDAY</code></pre><p><br><br></p>
<h4 id="4-3-활용-예시">4-3 활용 예시</h4>
<p><code>EnumSet</code>은 특정 <code>enum</code> 값들의 집합을 관리할 때 유용합니다. 예를 들어, 권한이나 상태를 관리하는데 사용할 수 있습니다.</p>
<pre><code class="language-java">enum Permission {
    READ, WRITE, EXECUTE
}

public class Main {
    public static void main(String[] args) {
        EnumSet&lt;Permission&gt; permissions = EnumSet.of(Permission.READ, Permission.WRITE);

        // 권한 추가
        permissions.add(Permission.EXECUTE);

        // 권한 확인
        if (permissions.contains(Permission.WRITE)) {
            System.out.println(&quot;쓰기 권한이 있습니다.&quot;);
        }

        // 권한 제거
        permissions.remove(Permission.READ);
        System.out.println(&quot;권한: &quot; + permissions);
    }
}</code></pre>
<p>출력은 아래와 같습니다.</p>
<pre><code class="language-java">쓰기 권한이 있습니다.
권한: [WRITE, EXECUTE]</code></pre>
<p><br><br></p>
<h4 id="요약-3">요약</h4>
<ul>
<li><p><code>EnumSet</code>은 특정 <code>enum</code> 타입의 상수를 저장하기 위한 효율적이고 메모리 절약형 집합입니다.</p>
</li>
<li><p><code>EnumSet</code>은 <code>enum</code> 상수의 순서를 유지하고, 다양한 유용한 메서드를 제공합니다.</p>
</li>
<li><p>다양한 생성 방법과 <code>Set</code> 인터페이스의 메서드들을 통해 쉽게 사용할 수 있습니다.</p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[멀티쓰레드 프로그래밍]]></title>
            <link>https://velog.io/@ha_bu/%EB%A9%80%ED%8B%B0%EC%93%B0%EB%A0%88%EB%93%9C-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D</link>
            <guid>https://velog.io/@ha_bu/%EB%A9%80%ED%8B%B0%EC%93%B0%EB%A0%88%EB%93%9C-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D</guid>
            <pubDate>Thu, 20 Jun 2024 09:41:58 GMT</pubDate>
            <description><![CDATA[<h3 id="목표">목표</h3>
<blockquote>
<p>자바의 멀티 쓰레드 프로그래밍에 대해 학습</p>
</blockquote>
<h3 id="목차">목차</h3>
<p><a href="#1.-thread-%ED%81%B4%EB%9E%98%EC%8A%A4%EC%99%80-runnable-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4">1. Thread 클래스와 Runnable 인터페이스</a>
<a href="#2-%EC%93%B0%EB%A0%88%EB%93%9C%EC%9D%98-%EC%83%81%ED%83%9C">2. 쓰레드의 상태</a>
<a href="#3-%EC%93%B0%EB%A0%88%EB%93%9C%EC%9D%98-%EC%9A%B0%EC%84%A0%EC%88%9C%EC%9C%84">3. 쓰레드의 우선순위</a>
<a href="#4-main-%EC%93%B0%EB%A0%88%EB%93%9C">4. Main 쓰레드</a>
<a href="#5-%EB%8F%99%EA%B8%B0%ED%99%94">5. 동기화</a>
<a href="#6-%EB%8D%B0%EB%93%9C%EB%9D%BD">6. 데드락</a></p>
<br>

<h3 id="1-thread-클래스와-runnable-인터페이스">1. Thread 클래스와 Runnable 인터페이스</h3>
<h4 id="1-1-thread-클래스">1-1 Thread 클래스</h4>
<blockquote>
<p><code>Thread</code> 클래스는 자바에서 스레드를 생성하고 제어할 수 있게 해주는 클래스입니다. 스레드는 프로그램 내에서 <strong>독립적으로 실행될 수 있는 작은 단위의 작업</strong>을 말합니다.</p>
</blockquote>
<p>** 사용방법 **</p>
<ul>
<li><p><code>Thread</code> 클래스를 상속받아 새로운 클래스를 정의하고, <code>run</code> 메서드를 오버라이드하여 실행할 코드를 작성합니다.</p>
</li>
<li><p><code>Thread</code> 객체를 생성한 후 <code>start</code> 메서드를 호출하면, 새로운 스레드가 시작되고 <code>run</code> 메서드 내의 코드가 실행됩니다.</p>
</li>
</ul>
<pre><code class="language-java">class MyThread extends Thread {
    public void run() {
        // 스레드에서 실행할 코드
        System.out.println(&quot;스레드 실행 중...&quot;);
    }
}

public class Main {
    public static void main(String[] args) {
        MyThread thread = new MyThread();
        thread.start();  
        // 새로운 스레드를 시작
    }
}</code></pre>
<br>

<h4 id="1-2-runnable-인터페이스">1-2 Runnable 인터페이스</h4>
<blockquote>
<p><code>Runnable</code> 인터페이스는 스레드로 실행할 작업을 정의하는 데 사용됩니다. </p>
<p><code>Runnable</code> 인터페이스를 구현한 클래스는 <code>run</code> 메서드를 오버라이드해야 합니다. <code>Runnable</code>은 스레드를 생성하는 <code>Thread</code> 클래스와 함께 사용됩니다.</p>
</blockquote>
<p>** 사용방법 **</p>
<ul>
<li><p><code>Runnable</code> 인터페이스를 구현하는 클래스를 정의하고, <code>run</code> 메서드를 오버라이드하여 실행할 코드를 작성합니다.</p>
</li>
<li><p><code>Thread</code> 객체를 생성할 때 <code>Runnable</code> 객체를 전달하고, <code>start</code> 메서드를 호출하여 스레드를 시작합니다.</p>
</li>
</ul>
<pre><code class="language-java">class MyRunnable implements Runnable {
    public void run() {
        // 스레드에서 실행할 코드
        System.out.println(&quot;Runnable 실행 중...&quot;);
    }
}

public class Main {
    public static void main(String[] args) {
        MyRunnable runnable = new MyRunnable();
        Thread thread = new Thread(runnable);
        thread.start();  // 새로운 스레드를 시작
    }
}</code></pre>
<br>

<h4 id="차이점">차이점</h4>
<ul>
<li><code>Thread</code> 클래스는 스레드를 생성하고 제어하는 기능을 포함하고 있고, 이 클래스를 상속받으면 다른 클래스를 상속받을 수 없습니다. 자바는 단일 상속만 지원하기 때문입니다.</li>
</ul>
<ul>
<li><code>Runnable</code> 인터페이스는 스레드로 실행할 작업만을 정의하며, 클래스를 다른 클래스에서 상속받는 것이 가능합니다. 이렇게 하면 보다 유연하게 코드를 작성할 수 있습니다.</li>
</ul>
<br>


<h4 id="✨-thread-vs-runnable">✨ Thread Vs Runnable</h4>
<p>보통 <code>Runnable</code> 인터페이스를 구현하여 사용하는 방법이 더 많이 권장됩니다. 이렇게 하면 스레드와 실행 로직을 분리할 수 있고, 더 유연하고 재사용 가능한 코드를 작성할 수 있습니다.</p>
<p>** 왜 Runnable이 더 나은 선택일까? **</p>
<ol>
<li><p>단일 <a href="https://velog.io/@ha_bu/%EC%83%81%EC%86%8D">상속</a>의 제약 회피
자바는 단일 상속만 지원하므로, <code>Thread</code> 클래스를 상속받으면 다른 클래스를 상속받을 수 없습니다. 반면, <code>Runnable</code> 인터페이스는 다른 클래스를 상속받으면서 동시에 구현할 수 있습니다.</p>
</li>
<li><p>유연한 설계
<code>Runnable</code> 인터페이스를 사용하면 실행 로직을 정의하는 클래스와 스레드 실행을 관리하는 클래스를 분리할 수 있습니다. 이렇게 하면 코드의 모듈성이 높아지고 재사용성이 증가합니다.</p>
</li>
</ol>
<p>결론적으로, <code>Runnable</code> 인터페이스를 사용하면 코드의 유연성과 재사용성이 높아지고, 불필요한 중복을 줄일 수 있습니다.</p>
<br>

<p>** Thread를 사용하는 경우 **</p>
<ol>
<li><p><code>Thread</code> 클래스의 메서드를 오버라이드할 필요가 있는 경우
<code>Thread</code> 클래스에는 <code>run</code> 메서드 외에도 여러 가지 메서드가 있습니다. 이 중 특정 메서드를 오버라이드하여 고유한 기능을 추가하고자 할 때 <code>Thread</code> 클래스를 상속받을 수 있습니다.</p>
</li>
<li><p><code>Thread</code>의 일부 기능을 변경해야 하는 경우
<code>Thread</code> 클래스의 특정 기능을 변경하거나 확장해야 할 때도 상속이 필요할 수 있습니다.</p>
</li>
</ol>
<p>예시는 아래와 같습니다.</p>
<pre><code class="language-java">class CustomThread extends Thread {
    private static int threadCount = 0;
    private int threadID;

    public CustomThread() {
        threadID = ++threadCount;
    }

    @Override
    public void run() {
        System.out.println(&quot;Thread &quot; + threadID + &quot; 시작&quot;);
        // 실행할 로직
        try {
            Thread.sleep(1000);  // 스레드 실행 중인 척
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(&quot;Thread &quot; + threadID + &quot; 종료&quot;);
    }

    @Override
    public void start() {
        System.out.println(&quot;Thread &quot; + threadID + &quot; 준비 중...&quot;);
        super.start();
    }
}

public class Main {
    public static void main(String[] args) {
        CustomThread thread1 = new CustomThread();
        CustomThread thread2 = new CustomThread();

        thread1.start();
        thread2.start();
    }
}</code></pre>
<p>&amp;nbsp 위 코드처럼 쓰레드가 시작될 때마다 고유한 ID를 부여하고, 종료될 때 로그를 출력하도록 커스텀 할 수 있습니다.</p>
<p><br><br></p>
<h3 id="2-쓰레드의-상태">2. 쓰레드의 상태</h3>
<blockquote>
<p>Java의 쓰레드는 여러 가지 상태를 가질 수 있으며, 각 상태는 쓰레드가 실행중 어떤 단계에 있는지를 나타냅니다.</p>
<p><code>Thread</code> 클래스에는 쓰레드 상태를 나타내는 <code>State</code> 열거형이 정의되어 있습니다.</p>
</blockquote>
<ol>
<li><p><strong>New</strong>
쓰레드가 생성되었지만, <code>start</code> 메서드가 호출되지 않은 상태입니다.</p>
</li>
<li><p><strong>RUNNABLE</strong>
쓰레드가 실행 가능한 상태입니다. 자바 가상 머신(JVM)에서는 이 상태를 <code>RUNNING</code> 상태와 구별하지 않습니다.</p>
</li>
<li><p><strong>BLOCKED</strong>
쓰레드가 동기화 블록에 들어가기 위해 대기하고 있는 상태입니다.</p>
</li>
<li><p><strong>WAITING</strong>
쓰레드가 다른 쓰레드가 특정 작업을 완료할 때까지 대기하고 있는 상태입니다. <code>Object.wait()</code> 메서드나 <code>Thread.join()</code> 메서드, <code>LockSupport.park()</code> 메서드를 호출하여 이 상태로 진입할 수 있습니다.</p>
</li>
<li><p><strong>TIMED_WAITING</strong>
쓰레드가 일정 시간 동안 기다리는 상태입니다. <code>Thread.sleep()</code>, <code>Object.wait(long timeout)</code>, <code>Thread.join(long millis)</code>, <code>LockSupport.parkNanos(long nanos)</code>, <code>LockSupport.parkUntil(long deadline)</code> 메서드를 호출하여 이 상태로 진입할 수 있습니다.</p>
</li>
<li><p><strong>TERMINATED</strong>
쓰레드가 실행을 마친 상태입니다. <code>run</code> 메서드가 종료되거나 예외로 인해 쓰레드가 종료된 경우 이 상태가 됩니다.</p>
</li>
</ol>
<h4 id="상태확인-예제">상태확인 예제</h4>
<blockquote>
<p>Java에서는 <code>Threada.getState()</code> 메서드를 사용하여 쓰레드의 현재 상태를 확인할 수 있습니다.</p>
</blockquote>
<pre><code class="language-java">public class ThreadStateExample {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        System.out.println(&quot;스레드 상태: &quot; + thread.getState());  
        // NEW 상태
        thread.start();
        System.out.println(&quot;스레드 상태: &quot; + thread.getState());  
        // RUNNABLE 상태

        Thread.sleep(500);
        System.out.println(&quot;스레드 상태: &quot; + thread.getState());  
        // TIMED_WAITING 상태

        thread.join();
        System.out.println(&quot;스레드 상태: &quot; + thread.getState());  
        // TERMINATED 상태
    }
}</code></pre>
<p><br><br></p>
<h3 id="3-쓰레드의-우선순위">3. 쓰레드의 우선순위</h3>
<blockquote>
<p>쓰레드에는 우선순위가 있습니다. 이 우선선위는 쓰레드가 <strong>실행될 순서를 결정하는데 사용</strong>됩니다. 우선순위는 <strong>1부터 10까지의 정수</strong> 값으로 설정할 수 있으며, 기본 우선순위는 5입니다.</p>
</blockquote>
<br> 

<h4 id="우선순위-상수">우선순위 상수</h4>
<ul>
<li><code>Thread.MIN_PRIORITY</code> (1) : 최소 우선순위</li>
<li><code>Thread.NORM_PRIORITY</code> (5) : 기본 우선순위</li>
<li><code>Thread.MAX_PRIORITY</code> (10) : 최대 우선순위</li>
</ul>
<br>

<h4 id="예제">예제</h4>
<pre><code class="language-java">class MyThread extends Thread {
    public MyThread(String name) {
        super(name);
    }

    public void run() {
        for (int i = 0; i &lt; 5; i++) {
            System.out.println(getName() + &quot; 실행 중, 우선순위: &quot; + getPriority());
        }
    }
}

public class Main {
    public static void main(String[] args) {
        MyThread thread1 = new MyThread(&quot;Thread1&quot;);
        MyThread thread2 = new MyThread(&quot;Thread2&quot;);
        MyThread thread3 = new MyThread(&quot;Thread3&quot;);

        thread1.setPriority(Thread.MIN_PRIORITY);  // 우선순위 1
        thread2.setPriority(Thread.NORM_PRIORITY); // 우선순위 5
        thread3.setPriority(Thread.MAX_PRIORITY);  // 우선순위 10

        thread1.start();
        thread2.start();
        thread3.start();
    }
}</code></pre>
<p> &amp;nbsp 위 코드에서 <code>Thread1</code>, <code>Thread2</code>, <code>Thread3</code>는 각각 다른 우선순위를 가집니다. <strong>우선순위가 높을수록 쓰레드가 더 자주 실행될 가능성이 있지만, 이는 운영체제의 스케줄러에 따라 다를 수 있습니다.</strong></p>
<br>

<h4 id="우선순위의-한계">우선순위의 한계</h4>
<ul>
<li><p><strong>플랫폼 의존적</strong>
Java 쓰레드 스케줄링은 운영체제에 따라 다릅니다. 일부 운영체제에서는 우선순위가 제대로 반영되지 않을 수 있습니다.</p>
</li>
<li><p><strong>비보장성</strong>
우선순위는 쓰레드의 실행 순서를 보장하지 않습니다. 쓰레드 스케줄러가 항상 높은 우선순위의 쓰레드를 먼저 실행하는 것은 아닙니다.</p>
</li>
<li><p><strong>복잡성 증가</strong>
우선순위 기반 스케줄링은 프로그램의 복잡성을 증가시키며, 잘못 사용하면 예상치 못한 결과를 초래할 수 있습니다.</p>
</li>
</ul>
<h4 id="결론">결론</h4>
<p>&amp;nbsp <U>쓰레드 우선순위는 쓰레드의 실행 순서를 결정하는 데 도움을 줄 수 있지만, 운영체제와 자바 런타임의 스케줄러에 따라 다르게 동작할 수 있습니다.</U> 따라서 우선순위는 보조적인 수단으로 사용하고, 주요 논리 흐름은 다른 방식으로 제어하는것이 좋습니다.</p>
<p><br><br></p>
<h3 id="4-main-쓰레드">4. Main 쓰레드</h3>
<blockquote>
<p>Java 프로그램이 실행될 때, Java 런타임 환경(JRE)은 기본적으로 하나의 쓰레드를 생성하여 프로그램을 시작합니다. 이 쓰레드를 <code>Main Thread</code>라고 합니다.</p>
<p>메인 쓰레드는 <code>main</code> 메서드를 실행하는 쓰레드로, 모든 자바 프로그램은 메인 쓰레드로 부터 시작됩니다.</p>
</blockquote>
<br>

<h4 id="메인-쓰레드의-역할">메인 쓰레드의 역할</h4>
<ol>
<li><p><strong>프로그램 시작</strong>
메인 쓰레드는 프로그램이 시작될 때 <code>main</code> 메서드를 실행합니다.</p>
</li>
<li><p><strong>다른 쓰레드 생성</strong>
메인 쓰레드는 필요에 따라 추가로 생성되는 다른 쓰레드의 부모 쓰레드가 됩니다. 새로운 쓰레드가 생성되면 메인 쓰레드가 해당 쓰레드를 시작할 수 있습니다.</p>
</li>
<li><p><strong>프로그램 종료</strong>
메인 쓰레드가 종료되면 프로그램이 종료됩니다. 단, 다른 사용자 정의 쓰레드가 실행 중인 경우에는 그 쓰레드들이 모두 종료될때까지 프로그램이 계속 실행됩니다.</p>
</li>
</ol>
<br>

<h4 id="메인-쓰레드와-쓰레드-관리">메인 쓰레드와 쓰레드 관리</h4>
<blockquote>
<p>메인 쓰레드도 다른 일반 쓰레드처럼 관리할 수 있습니다. 예를 들어, 메인 쓰레드의 우선순위를 변경하거나 메인 쓰레드의 상태를 확인할 수 있습니다.</p>
</blockquote>
<pre><code class="language-java">public class MainThreadExample {
    public static void main(String[] args) {
        // 현재 실행 중인 쓰레드 얻기 (메인 쓰레드)
        Thread mainThread = Thread.currentThread();

        // 메인 쓰레드의 이름 출력
        System.out.println(&quot;메인 쓰레드 이름: &quot; + mainThread.getName());

        // 메인 쓰레드의 우선순위 출력
        System.out.println(&quot;메인 쓰레드 우선순위: &quot; + mainThread.getPriority());

        // 메인 쓰레드의 우선순위 변경
        mainThread.setPriority(Thread.MAX_PRIORITY);
        System.out.println(&quot;변경된 메인 쓰레드 우선순위: &quot; + mainThread.getPriority());

        // 메인 쓰레드가 종료되기 전에 다른 작업 수행
        for (int i = 0; i &lt; 5; i++) {
            System.out.println(&quot;메인 쓰레드 작업: &quot; + i);
        }

        // 메인 쓰레드가 종료되면 프로그램이 종료됨
        System.out.println(&quot;메인 쓰레드 종료&quot;);
    }
}</code></pre>
<br>

<h4 id="메인-쓰레드의-종료와-프로그램-종료">메인 쓰레드의 종료와 프로그램 종료</h4>
<blockquote>
<p>메인 쓰레드가 종료되면, JVM은 다른 실행 중인 사용자 정의 쓰레드가 있는지 확인합니다. </p>
<p>만약 다른 모든 사용자 정의 쓰레드가 종료된 상태라면 JVM은 프로그램을 종료합니다.</p>
<p>하지만, 다른 사용자 정의 쓰레드가 실행 중이라면 그 쓰레드들이 모두 종료될 때까지 프로그램은 계속 실행됩니다.</p>
</blockquote>
<pre><code class="language-java">public class MainThreadExample {
    public static void main(String[] args) {
        // 새로운 쓰레드 생성 및 시작
        Thread newThread = new Thread(() -&gt; {
            for (int i = 0; i &lt; 5; i++) {
                System.out.println(&quot;새로운 쓰레드 작업: &quot; + i);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(&quot;새로운 쓰레드 종료&quot;);
        });

        newThread.start();

        // 메인 쓰레드 작업
        for (int i = 0; i &lt; 3; i++) {
            System.out.println(&quot;메인 쓰레드 작업: &quot; + i);
        }
        System.out.println(&quot;메인 쓰레드 종료&quot;);
    }
}</code></pre>
<p><br><br></p>
<h3 id="5-동기화">5. 동기화</h3>
<blockquote>
<p>동기화는 여러 쓰레드가 동시에 공유 자원에 접근할 때 발생할 수 있는 문제를 방지하기 위한 방법입니다.</p>
<p>동기화를 통해 하나의 쓰레드만이 공유 자원에 접근하도록 보장할 수 있습니다.</p>
<p>이를 통해 <strong>데이터의 일관성과 무결성을 유지</strong>할 수 있습니다.</p>
</blockquote>
<br>

<h4 id="동기화의-필요성">동기화의 필요성</h4>
<p>&amp;nbsp 멀티쓰레딩 환경에서는 여러 쓰레드가 동시에 공유 자원(변수, 객체 등)에 접근하고 수정할 수 있습니다. 이로 인해 아래와 같은 문제가 발생할 수 있습니다.</p>
<ol>
<li><p><strong>데이터 일관성 문제</strong>
여러 쓰레드가 동시에 데이터를 읽고 쓰는 경우, 데이터의 일관성이 깨질 수 있습니다.</p>
</li>
<li><p><strong>데드락(Deadlock)</strong>
두 개 이상의 쓰레드가 서로의 자원을 기다리며 무한 대기에 빠지는 현상입니다.</p>
</li>
<li><p><strong>레이스 컨디션(Race Condition)</strong>
여러 쓰레드가 동시에 자원에 접근할 때 발생하는 문제로, 쓰레드들이 경쟁적으로 자원에 접근하여 예기치 않은 결과를 초래할 수 있습니다.</p>
</li>
</ol>
<br>

<h4 id="동기화-방법">동기화 방법</h4>
<p>&amp;nbsp Java에서는 <code>synchronized</code> 키워드를 사용하여 동기화를 구현할 수 있습니다. 동기화 방법에는 두 가지 주요 방법이 있습니다. 바로 <code>메서드 동기화</code>와 <code>블록 동기화</code>입니다.</p>
<br>

<p>**  1. 메서드 동기화 **
&amp;nbsp 메서드에 <code>synchronized</code> 키워드를 붙여서 동기화할 수 있습니다. 이렇게 하면 메서드가 호출될 때 해당 메서드의 객체에 대해 락(Lock)을 획득하게 되어, 다른 쓰레드가 이 메서드를 호출하려면 락을 해제할 때까지 기다려야 합니다.</p>
<pre><code class="language-java">class Counter {
    private int count = 0;

    public synchronized void increment() {
        count++;
    }

    public int getCount() {
        return count;
    }
}

public class Main {
    public static void main(String[] args) throws InterruptedException {
        Counter counter = new Counter();

        Runnable task = () -&gt; {
            for (int i = 0; i &lt; 1000; i++) {
                counter.increment();
            }
        };

        Thread thread1 = new Thread(task);
        Thread thread2 = new Thread(task);

        thread1.start();
        thread2.start();

        thread1.join();
        thread2.join();

        System.out.println(&quot;Final count: &quot; + counter.getCount());  // 2000
    }
}</code></pre>
<p><br><br></p>
<p>** 2. 블록 동기화 **
&amp;nbsp 특정 코드 블록만 동기화할 수도 있습니다. 이 방법은 필요하지 않은 경우 전체 메서드를 동기화하는 대신, 특정 코드 블록만 동기화할 수 있어서 효율적입니다.</p>
<pre><code class="language-java">class Counter {
    private int count = 0;

    public void increment() {
        synchronized (this) {
            count++;
        }
    }

    public int getCount() {
        return count;
    }
}

public class Main {
    public static void main(String[] args) throws InterruptedException {
        Counter counter = new Counter();

        Runnable task = () -&gt; {
            for (int i = 0; i &lt; 1000; i++) {
                counter.increment();
            }
        };

        Thread thread1 = new Thread(task);
        Thread thread2 = new Thread(task);

        thread1.start();
        thread2.start();

        thread1.join();
        thread2.join();

        System.out.println(&quot;Final count: &quot; + counter.getCount());  // 2000
    }
}</code></pre>
<p><br><br></p>
<h4 id="주의-사항">주의 사항</h4>
<ol>
<li><p><strong>성능 저하</strong>
동기화는 성능을 저하시킬 수 있습니다. 동기화된 메서드나 블록은 동시에 하나의 쓰레드만 접근할 수 있으므로 병렬 처리를 제한할 수 있습니다.</p>
</li>
<li><p><strong>데드락</strong>
동기화된 코드에서 여러 락을 사용하다 보면 데드락이 발생할 수 있습니다. 데드락을 피하기 위해서는 락을 획득하는 순서를 일관되게 유지해야 합니다.</p>
</li>
<li><p><strong>대기 시간</strong>
동기화된 메서드나 블록에서 오랜 시간 동안 작업을 수행하면 다른 쓰레드가 오랫동안 대기해야 할 수 있습니다. 이를 피하기 위해 가능한 짧은 코드 블록을 동기화하는 것이 좋습니다.</p>
</li>
</ol>
<p><br><br></p>
<h3 id="6-데드락">6. 데드락</h3>
<blockquote>
<p>데드락(Deadlock)은 멀티쓰레드나 멀티프로세스 환경에서 발생할 수 있는 심각한 문제입니다.</p>
<p>데드락은 두 개 이상의 쓰레드나 프로세스가 서로 필요로 하는 <strong>자원을 무한히 기다리며 진행이 멈춘 상태</strong>를 말합니다. </p>
</blockquote>
<br>

<p>&amp;nbsp 각 쓰레드는 다음과 같은 조건을 만족할때 데드락에 빠집니다.</p>
<ol>
<li><p><strong>상호 배제(Mutual Exclusion)</strong>
자원은 한 번에 하나의 쓰레드나 프로세스만 사용할 수 있어야 합니다.</p>
</li>
<li><p><strong>점유와 대기(Hold and Wait)</strong>
최소한 하나의 자원을 점유하고 있는 상태에서 다른 쓰레드나 프로세스가 점유하고 있는 자원을 기다려야 합니다.</p>
</li>
<li><p><strong>비선점(No Preemption)</strong>
다른 쓰레드나 프로세스가 이미 점유한 자원을 강제로 빼앗아 사용할 수 없어야 합니다.</p>
</li>
<li><p><strong>순환 대기(Circular Wait)</strong>
쓰레드나 프로세스 사이에 무한 순환 형태로 자원을 요구하는 사이클이 형성되어야 합니다.</p>
</li>
</ol>
<p><br><br></p>
<h4 id="데드락-예제">데드락 예제</h4>
<pre><code class="language-java">class SharedResource {
    synchronized void method1(SharedResource resource) {
        System.out.println(Thread.currentThread().getName() + &quot; 메서드 1 실행&quot;);
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + &quot; 메서드 1에서 method2 호출&quot;);
        resource.method2(this);
        System.out.println(Thread.currentThread().getName() + &quot; 메서드 1 실행 완료&quot;);
    }

    synchronized void method2(SharedResource resource) {
        System.out.println(Thread.currentThread().getName() + &quot; 메서드 2 실행&quot;);
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + &quot; 메서드 2에서 method1 호출&quot;);
        resource.method1(this);
        System.out.println(Thread.currentThread().getName() + &quot; 메서드 2 실행 완료&quot;);
    }
}

public class DeadlockExample {
    public static void main(String[] args) {
        final SharedResource resource1 = new SharedResource();
        final SharedResource resource2 = new SharedResource();

        Thread thread1 = new Thread(() -&gt; {
            resource1.method1(resource2);
        });

        Thread thread2 = new Thread(() -&gt; {
            resource2.method2(resource1);
        });

        thread1.start();
        thread2.start();
    }
}</code></pre>
<p>&amp;nbsp 위 예제에서 <code>SharedResource</code> 클래스는 두 개의 메서드 <code>method1</code>과 <code>method2</code>를 가지고 있습니다.</p>
<p>&amp;nbsp 각 메서드는 <code>synchronized</code> 키워드로 동기화 되어 있어, 한 번에 하나의 쓰레드만이 접근할 수 있습니다. 그러나 두 쓰레드가 서로의 자원을 동시에 점유하려고 하고 있습니다. 따라서 이 예제는 데드락에 빠질 가능성이 높습니다.</p>
<br>

<h4 id="데드락-방지-및-해결-방법">데드락 방지 및 해결 방법</h4>
<ol>
<li><p><strong>상호 배제 원칙 사용 최소화</strong>
락을 최소한으로 사용하고, 필요한 경우만 사용합니다.</p>
</li>
<li><p><strong>락의 순서</strong>
여러 자원을 사용할 때 일관된 순서로 락을 획득하도록 합니다.</p>
</li>
<li><p><strong>시간 제한</strong>
자원을 얻기 위한 대기 시간을 제한합니다. 일정 시간 내에 자원을 얻지 못한다면 다시 시도하거나 포기합니다.</p>
</li>
<li><p><strong>락을 해제</strong>
락을 오랫동안 유지하지 않고 가능한 빨리 해제합니다.</p>
</li>
<li><p><strong>데드락 탐지 및 복구</strong>
시스템이 데드락을 탐지하고, 탐지되면 적절히 복구할 수 있는 방법을 구현합니다.</p>
</li>
</ol>
<p><br><br></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[예외 처리]]></title>
            <link>https://velog.io/@ha_bu/%EC%98%88%EC%99%B8-%EC%B2%98%EB%A6%AC</link>
            <guid>https://velog.io/@ha_bu/%EC%98%88%EC%99%B8-%EC%B2%98%EB%A6%AC</guid>
            <pubDate>Fri, 14 Jun 2024 08:25:44 GMT</pubDate>
            <description><![CDATA[<h3 id="목표">목표</h3>
<blockquote>
<p>자바의 예외 처리에 대해 학습</p>
</blockquote>
<h3 id="목차">목차</h3>
<p><a href="#1-%EC%9E%90%EB%B0%94%EC%97%90%EC%84%9C-%EC%98%88%EC%99%B8-%EC%B2%98%EB%A6%AC-%EB%B0%A9%EB%B2%95">1. 자바에서 예외 처리 방법 (try, catch, throw, throws, finally)</a>
<a href="#2-%EC%9E%90%EB%B0%94%EA%B0%80-%EC%A0%9C%EA%B3%B5%ED%95%98%EB%8A%94-%EC%98%88%EC%99%B8-%EA%B3%84%EC%B8%B5-%EA%B5%AC%EC%A1%B0">2. 자바가 제공하는 예외 계층 구조</a>
<a href="#3-exception%EA%B3%BC-error%EC%9D%98-%EC%B0%A8%EC%9D%B4">3. Exception과 Error의 차이는?</a>
<a href="#4-runtimeexception%EA%B3%BC-re%EA%B0%80-%EC%95%84%EB%8B%8C-%EA%B2%83%EC%9D%98-%EC%B0%A8%EC%9D%B4">4. RuntimeException과 RE가 아닌 것의 차이</a>
<a href="#5-%EC%BB%A4%EC%8A%A4%ED%85%80%ED%95%9C-%EC%98%88%EC%99%B8-%EB%A7%8C%EB%93%9C%EB%8A%94-%EB%B0%A9%EB%B2%95">5. 커스텀한 예외 만드는 방법</a></p>
<br>

<h3 id="1-자바에서-예외-처리-방법">1. 자바에서 예외 처리 방법</h3>
<blockquote>
<p>Java에서 예외 처리는 프로그램 실행 중 발생하는 예외 상황을 적절히 처리하여 프로그램이 갑작스럽게 종료되는 것을 방지하고, 사용자에게 유의미한 에러 메시지를 제공하며, 프로그램의 정상적인 흐름을 유지하기 위해 사용됩니다.</p>
<p>Java에서는 예외 처리를 위해 <code>try</code>, <code>catch</code>, <code>finally</code>, <code>throw</code>, <code>throws</code> 키워드를 사용합니다.</p>
</blockquote>
<h4 id="1-1-예외의-종류">1-1 예외의 종류</h4>
<ul>
<li><p><strong>Checked Exception</strong>
컴파일러가 예외 처리를 강제하는 예외입니다. 주로 외부 자원(파일, 네트워크 등)을 다룰 때 발생합니다. 
Ex) <code>IOException</code>, <code>SQLException</code></p>
</li>
<li><p><strong>Unchecked Exception</strong>
컴파일러가 예외 처리를 강제하지 않는 예외입니다. 주로 프로그래머의 실수로 발생합니다.
Ex) <code>NullPointerException</code>, <code>ArrayIndexOutOfBoundsException</code></p>
</li>
<li><p><strong>Error</strong>
시스템 수준에서 발생하는 심각한 오류로, 보통 애플리케이션에서 처리하지 않습니다.
Ex) <code>OutOfMemoryError</code></p>
</li>
</ul>
<p><a href="#3-exception%EA%B3%BC-error%EC%9D%98-%EC%B0%A8%EC%9D%B4">아래</a>에서 좀 더 자세하게 설명하겠습니다.</p>
<br>

<h4 id="1-2-예외-처리-키워드">1-2 예외 처리 키워드</h4>
<h4 id="try-catch">try-catch</h4>
<p>&amp;nbsp 예외가 발생할 수 있는 코드를 <code>try</code> 블록에 넣고, 예외가 발생했을 떄의 처리를 <code>catch</code>블록에 넣습니다.</p>
<pre><code class="language-java">try {
    // 예외가 발생할 수 있는 코드
} catch (예외타입 변수이름) {
    // 예외 처리 코드
}</code></pre>
<p><strong>예제</strong></p>
<pre><code class="language-java">public class ExceptionExample {
    public static void main(String[] args) {
        try {
            int result = 10 / 0; 
            // 여기서 ArithmeticException 발생
        } catch (ArithmeticException e) {
            System.out.println(&quot;예외 발생: &quot; + e.getMessage());
        }
    }
}</code></pre>
<p>&amp;nbsp 위 예제에서 <code>10 / 0</code> 연산으로 <code>ArithmeticException</code>이 발생하며, <code>catch</code> 블록에서 이를 처리합니다.</p>
<p><br><br></p>
<h4 id="finally">finally</h4>
<p>&amp;nbsp <code>try</code> 블록에서 <strong>예외가 발생하든 발생하지 않든 항상 실행되는 블록입니다.</strong> 주로 자원해제에 사용됩니다.</p>
<pre><code class="language-java">try {
    // 예외가 발생할 수 있는 코드
} catch (예외타입 변수이름) {
    // 예외 처리 코드
} finally {
    // 항상 실행되는 코드
}</code></pre>
<p><strong>예제</strong></p>
<pre><code class="language-java">public class FinallyExample {
    public static void main(String[] args) {
        try {
            int result = 10 / 0;
        } catch (ArithmeticException e) {
            System.out.println(&quot;예외 발생: &quot; + e.getMessage());
        } finally {
            System.out.println(&quot;finally 블록 실행&quot;);
        }
    }
}</code></pre>
<p>&amp;nbsp 앞서 설명한것과 같이 <code>finally</code>는 예외 발생 여부와 관계없이 항상 실행됩니다.</p>
<p><br><br></p>
<h4 id="throw">throw</h4>
<p>&amp;nbsp 프로그램의 특정 시점에서 예외를 직접 발생시킬 때 사용합니다.</p>
<pre><code class="language-java">public class ThrowExample {
    public static void main(String[] args) {
        try {
            validateAge(15);
        } catch (IllegalArgumentException e) {
            System.out.println(&quot;예외 발생: &quot; + e.getMessage());
        }
    }

    public static void validateAge(int age) {
        if (age &lt; 18) {
            throw new IllegalArgumentException(&quot;나이는 18 이상이어야 합니다.&quot;);
        }
    }
}</code></pre>
<p>&amp;nbsp 위 예제에서 <code>validateAge</code> 메서드는 나이가 18 미만일 경우 <code>IllegalArgumentException</code>을 발생시킵니다.</p>
<p><br><br></p>
<h4 id="throws">throws</h4>
<p>&amp;nbsp 메서드 선언부에 사용하여 해당 메서드가 특정 예외를 던질 수 있음을 선언합니다. 주로 CheckedException에 사용됩니다.</p>
<p>&amp;nbsp <code>throws</code>를 통해 컴파일러가 예외 처리 여부를 검증할 수 있게 합니다.</p>
<pre><code class="language-java">public class ThrowsExample {
    public static void main(String[] args) {
        try {
            checkFile();
        } catch (IOException e) {
            System.out.println(&quot;예외 발생: &quot; + e.getMessage());
        }
    }

    public static void checkFile() throws IOException {
        FileReader file = new FileReader(&quot;nonexistentfile.txt&quot;);
    }
}</code></pre>
<p>&amp;nbsp 위 예제에서 <code>checkFile</code> 메서드는 <code>FileReader</code> 객체를 생성할때 <code>IOException</code>을 던질 수 있음을 <code>throws</code> 키워드를 통해 선언합니다.</p>
<br>

<h4 id="✨-throws와-throw의-차이">✨ throws와 throw의 차이</h4>
<ul>
<li><code>throws</code> : 메서드 선언부에 사용되며, 해당 메서드가 어떤 예외를 던질 수 있는지 선언합니다.</li>
<li><code>throw</code> : 메서드 본문 내에서 사용되며, 실제로 예외를 던질 때 사용됩니다.</li>
</ul>
<br>


<h4 id="✨-throws의-예외-전파">✨ throws의 예외 전파</h4>
<blockquote>
<p>&amp;nbsp 메서드가 예외를 처리하지 않고 호출한 메서드로 예외를 전파할 수 있습니다. 호출한 메서드에서 예외를 처리해야 합니다!</p>
</blockquote>
<pre><code class="language-java">import java.io.IOException;

public class ExceptionPropagationExample {
    public static void main(String[] args) {
        try {
            method1();
        } catch (IOException e) {
            System.out.println(&quot;예외 발생: &quot; + e.getMessage());
        }
    }

    public static void method1() throws IOException {
        method2();
    }

    public static void method2() throws IOException {
        throw new IOException(&quot;파일을 읽을 수 없습니다.&quot;);
    }
}</code></pre>
<p>&amp;nbsp <code>method2</code>는 <code>IOException</code>을 던지고, <code>method1</code>은 이를 처리하지 않고 <code>throws IOException</code>을 통해 예외를 전파합니다. <code>main</code>메서드에서 최종적으로 예외를 처리합니다.</p>
<br>

<p>&amp;nbsp 이와 같이 <code>throws</code> 키워드를 사용하면 메서드가 던질 수 있는 예외를 명시적으로 선언할 수 있으며, 호출한 메서드에서 예외를 처리하거나, 다시 전파할 수 있습니다.</p>
<p><br><br></p>
<h4 id="사용자-정의-예외">사용자 정의 예외</h4>
<p>&amp;nbsp 기본 제공 예외 클래스 외에 사용자가 정의한 예외를 만들 수 있습니다. 사용자 정의 예외는 <code>Exception</code> 클래스를 상속하여 생성합니다.</p>
<pre><code class="language-java">class CustomException extends Exception {
    public CustomException(String message) {
        super(message);
    }
}

public class CustomExceptionExample {
    public static void main(String[] args) {
        try {
            validateAge(15);
        } catch (CustomException e) {
            System.out.println(&quot;예외 발생: &quot; + e.getMessage());
        }
    }

    public static void validateAge(int age) throws CustomException {
        if (age &lt; 18) {
            throw new CustomException(&quot;나이는 18 이상이어야 합니다.&quot;);
        }
    }
}</code></pre>
<p>&amp;nbsp <code>CustomException</code>은 사용자 정의 예외로, 나이가 18 미만일 경우, <code>validateAge</code> 메서드에서 <code>CustomException</code>을 던집니다.</p>
<br>

<h3 id="2-자바가-제공하는-예외-계층-구조">2. 자바가 제공하는 예외 계층 구조</h3>
<blockquote>
<p>Java에서 제공하는 예외 계층 구조는 예외를 체계적으로 관리하고 처리하기 위해 설계되었습니다. 예외 계층 구조는 크게 <code>Throwable</code> 클래스를 기반으로 두 가지 분류인 <code>Error</code>와 <code>Exceprion</code> 클래스로 나뉩니다.</p>
</blockquote>
<pre><code class="language-css">java.lang.Object
   └── java.lang.Throwable
         ├── java.lang.Error
         └── java.lang.Exception
              ├── java.lang.RuntimeException
              └── 기타 예외 클래스</code></pre>
<p>&amp;nbsp <code>Throwable</code> 클래스는 Java의 모든 예외와 오류의 최상위 클래스입니다. 이 클래스는 예외나 오류가 발생했을 때 잡히거나 던질 수 있는 객체를 나타냅니다.</p>
<br>

<h3 id="3-exception과-error의-차이">3. Exception과 Error의 차이</h3>
<p>&amp;nbsp <code>Exception</code>과 <code>Error</code>는 모두 <code>Throwable</code>클래스를 기반으로 하지만, 명확한 차이가 있습니다.</p>
<h4 id="3-1-error">3-1 Error</h4>
<blockquote>
<p>&amp;nbsp <code>Error</code> 클래스는 <strong>애플리케이션에서 복구할 수 없는 심각한 문제</strong>를 나타냅니다. 이러한 오류는 보통 애플리케이션 수준에서 처리하지 않으며, 주로 <strong>JVM</strong>에서 발생합니다.</p>
</blockquote>
<p>Ex) <code>OutOfMemoryError</code>, <code>StackOverflowError</code>, <code>VirtualMachineError</code></p>
<br>

<h4 id="3-2-exception">3-2 Exception</h4>
<blockquote>
<p><code>Exception</code> 클래스는 애플리케이션에서 발생할 수 있는 예외 상황을 나타냅니다. <code>Exception</code>은 다시 <code>Checked Exception</code>과 <code>Unchecked Exception</code>으로 나뉩니다.</p>
</blockquote>
<p>** Checked Exception **</p>
<p>&amp;nbsp Checked Exception은 컴파일러가 예외 처리를 강제하는 예외입니다. 즉, 이 예외를 처리하거나 메서드 선언부에 <code>throws</code> 키워드를 사용하여 선언해야 합니다.</p>
<p>Ex) <code>IOException</code>, <code>SQLException</code>, <code>ClassNotFoundException</code></p>
<br>

<p>** Unchecked Exception **</p>
<p>&amp;nbsp Unchecked Exception는 컴파일러가 예외 처리를 강제하지 않는 예외입니다. 이러한 예외는 주로 프로그래머의 실수로 인해 발생합니다. <strong>모든 Unchecked Exception은</strong><code>RuntimeException</code><strong>클래스를 상속합니다.</strong></p>
<br>

<p> &amp;nbsp <code>RuntimeException</code> 클래스는 <code>Unchecked Exception</code>중 최상위 클래스입니다. 일반적으로 프로그래밍 오류에 발생합니다. 이 예외는 명시적으로 선언하지 않아도 되며, 런타임에 발생할 수 있습니다.</p>
<br>

<h3 id="4-runtimeexception과-re가-아닌-것의-차이">4. RuntimeException과 RE가 아닌 것의 차이</h3>
<blockquote>
<p>&amp;nbsp 위에서도 여러번 설명드렸지만, 한번더 정리해보겠습니다.</p>
<p>&amp;nbsp <code>RuntimeException</code>과 <code>RuntimeException</code>이 아닌 예외의 주요 차이는 <strong>컴파일러가 예외 처리를 강제하는지 여부</strong>와 <strong>예외가 발생하는 상황</strong>에 있습니다.</p>
<p>&amp;nbsp 이 차이는 <code>Checked Exception</code>과 <code>Unchecked Exception</code>의 차이로 이해할 수 있습니다.</p>
</blockquote>
<br>

<h4 id="4-1-runtimeexception-unchecked-exception">4-1 RuntimeException (Unchecked Exception)</h4>
<p>&amp;nbsp <code>RuntimeException</code> 클래스는 <code>Unchecked Exception</code>의 최상위 클래스입니다. </p>
<p>&amp;nbsp <code>Unchecked Exception</code>은 컴파일러가 예외 처리를 강제하지 않는 예외로, 주로 프로그래머의 실수로 인해 발생하는 예외들입니다. 이 예외들은 <strong>프로그램의 논리적 오류를 나타내며, 런타임에만 발견될 수 있습니다.</strong></p>
<br>

<p><strong>특징</strong></p>
<ul>
<li>컴파일 시 예외 처리를 강제하지 않습니다.
(<code>throws</code> 키워드를 사용하지 않아도 됩니다.)</li>
<li>런타임에서만 예외 발생 여부를 알 수 있습니다.</li>
<li>주로 프로그래머의 실수로 발생합니다.
(Ex : 잘못된 타입 캐스팅, 잘못된 인덱스 접근 등)</li>
</ul>
<br>

<p>** 예시 **</p>
<ul>
<li><code>NullPointerException</code></li>
<li><code>ArrayIndexOutOfBoundsException</code></li>
<li><code>ArithmeticException</code></li>
<li><code>ClasscastException</code></li>
</ul>
<br>

<p>** 예제 **</p>
<pre><code class="language-java">public class RuntimeExceptionExample {
    public static void main(String[] args) {
        String str = null;
        System.out.println(str.length());  // NullPointerException 발생
    }
}</code></pre>
<p><br><br></p>
<h4 id="4-2-checked-exception">4-2 Checked Exception</h4>
<p>&amp;nbsp <code>Checked Exception</code>은 <code>Exception</code> 클래스의 서브클래스로, <code>RuntimeException</code>을 상속하지 않는 예외들입니다.</p>
<p>&amp;nbsp 이 예외들은 컴파일러가 예외 처리를 강제하며, 일반적으로 외부 환경과의 상호작용에서 발생하는 예외들입니다.</p>
<p>&amp;nbsp 이러한 예외는 <strong>반드시 예외 처리(<code>try-catch</code>)를 하거나 메서드 선언부에 *<em><code>throws</code> *</em>키워드를 사용하여 선언해야합니다.</strong></p>
<br>

<p>** 특징 **</p>
<ul>
<li>컴파일 시 예외 처리를 강제합니다.
(<code>throws</code>키워드를 사용하여 선언하거나, <code>try-catch</code>로 처리해야함)</li>
<li>주로 외부 자원(파일, 네트워크, 데이터베이스 등)과의 상호작용에서 발생합니다.</li>
<li>예외 처리를 통해 복구 가능한 상황을 나타냄</li>
</ul>
<br>

<p>** 예시 **</p>
<ul>
<li><code>IOException</code></li>
<li><code>SQLException</code></li>
<li><code>ClassNotFoundException</code></li>
<li><code>FileNotFoundException</code></li>
</ul>
<br>

<p>** 예제 **</p>
<pre><code class="language-java">import java.io.*;

public class CheckedExceptionExample {
    public static void main(String[] args) {
        try {
            readFile(&quot;nonexistentfile.txt&quot;);
        } catch (IOException e) {
            System.out.println(&quot;예외 발생: &quot; + e.getMessage());
        }
    }

    public static void readFile(String filename) throws IOException {
        FileReader file = new FileReader(filename);  
        // FileNotFoundException 발생 가능
        file.read();
        file.close();
    }
}</code></pre>
<h4 id="주요-차이점-요약">주요 차이점 요약</h4>
<table>
<thead>
<tr>
<th><strong>특징</strong></th>
<th><strong>RuntimeException (Unchecked Exception)</strong></th>
<th><strong>Checked Exception</strong></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>외부 자원과의 상호작용 (I/O, DB 등)</td>
</tr>
<tr>
<td><strong>예제</strong></td>
<td><code>NullPointerException</code>, <code>ArrayIndexOutOfBoundsException</code></td>
<td><code>IOException</code>, <code>SQLException</code></td>
</tr>
</tbody></table>
<p><br><br></p>
<h3 id="5-커스텀한-예외-만드는-방법">5. 커스텀한 예외 만드는 방법</h3>
<blockquote>
<p><code>Checked Exception</code>과 <code>Unchecked Exception</code>을 커스텀하게 만들 수 있습니다. <code>Exception</code>클래스나 <code>RuntimeException</code> 클래스를 상속받도록 하면 됩니다.</p>
</blockquote>
<br>

<h4 id="5-1-checked-exception">5-1 Checked Exception</h4>
<p>&amp;nbsp <code>Checked Exception</code>을 만들기 위해서는 <code>Exception</code> 클래스를 상속받아야 합니다. 이는 컴파일러가 예외 처리를 강제하는 예외입니다.</p>
<br>

<p>** 예제 **</p>
<pre><code class="language-java">// CustomCheckedException.java
public class CustomCheckedException extends Exception {
    public CustomCheckedException() {
        super();
    }

    public CustomCheckedException(String message) {
        super(message);
    }

    public CustomCheckedException(String message, Throwable cause) {
        super(message, cause);
    }

    public CustomCheckedException(Throwable cause) {
        super(cause);
    }
}</code></pre>
<br>

<p><strong>사용 예제</strong></p>
<pre><code class="language-java">public class CustomCheckedExceptionExample {
    public static void main(String[] args) {
        try {
            methodThatThrowsCustomException();
        } catch (CustomCheckedException e) {
            System.out.println(&quot;Custom checked exception caught: &quot; + e.getMessage());
        }
    }

    public static void methodThatThrowsCustomException() throws CustomCheckedException {
        throw new CustomCheckedException(&quot;This is a custom checked exception&quot;);
    }
}</code></pre>
<br>

<h4 id="5-2-unchecked-exception">5-2 Unchecked Exception</h4>
<p>&amp;nbsp <code>Unchecked Exception</code>을 만들기 위해서는 <code>RuntimeException</code> 클래스를 상속받아야 합니다. 이는 컴파일러가 예외 처리를 강제하지 않는 예외 입니다.</p>
<br>

<p>** 예제 **</p>
<pre><code class="language-java">// CustomUncheckedException.java
public class CustomUncheckedException extends RuntimeException {
    public CustomUncheckedException() {
        super();
    }

    public CustomUncheckedException(String message) {
        super(message);
    }

    public CustomUncheckedException(String message, Throwable cause) {
        super(message, cause);
    }

    public CustomUncheckedException(Throwable cause) {
        super(cause);
    }
}</code></pre>
<br>

<p>** 사용 예제 **</p>
<pre><code class="language-java">public class CustomUncheckedExceptionExample {
    public static void main(String[] args) {
        try {
            methodThatThrowsCustomException();
        } catch (CustomUncheckedException e) {
            System.out.println(&quot;Custom unchecked exception caught: &quot; + e.getMessage());
        }
    }

    public static void methodThatThrowsCustomException() {
        throw new CustomUncheckedException(&quot;This is a custom unchecked exception&quot;);
    }
}</code></pre>
<br>

<h4 id="요약">요약</h4>
<ul>
<li><p><strong>Checked Exception</strong> 만들기
<code>Exception</code> 클래스를 상속받아 정의합니다. 컴파일러가 예외 처리를 강제하게 됩니다.</p>
</li>
<li><p><strong>Unchecked Exception</strong> 만들기
<code>RuntimeException</code> 클래스를 상속받아 정의합니다. 컴파일러가 예외 처리를 강제하지 않습니다.</p>
</li>
</ul>
<p><br><br><br></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[인터페이스]]></title>
            <link>https://velog.io/@ha_bu/%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4</link>
            <guid>https://velog.io/@ha_bu/%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4</guid>
            <pubDate>Tue, 11 Jun 2024 07:35:52 GMT</pubDate>
            <description><![CDATA[<h3 id="목표">목표</h3>
<blockquote>
<p>자바의 인터페이스에 대해 학습</p>
</blockquote>
<h3 id="목차">목차</h3>
<p><a href="#1-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4-%EC%A0%95%EC%9D%98%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95">1. 인터페이스 정의하는 방법</a>
<a href="#2-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4-%EA%B5%AC%ED%98%84%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95">2. 인터페이스 구현하는 방법</a>
<a href="#3-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4-%EB%A0%88%ED%8D%BC%EB%9F%B0%EC%8A%A4%EB%A5%BC-%ED%86%B5%ED%95%B4-%EA%B5%AC%ED%98%84%EC%B2%B4%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95">3. 인터페이스 레퍼런스를 통해 구현체를 사용하는 방법</a>
<a href="#4-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4-%EC%83%81%EC%86%8D">4. 인터페이스 상속</a>
<a href="#5-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4%EC%9D%98-%EA%B8%B0%EB%B3%B8-%EB%A9%94%EC%86%8C%EB%93%9C-default-method-%EC%9E%90%EB%B0%94-8">5. 인터페이스의 기본 메소드 (Default Method), 자바 8</a>
<a href="#6-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4%EC%9D%98-static-%EB%A9%94%EC%86%8C%EB%93%9C-%EC%9E%90%EB%B0%94-8">6. 인터페이스의 static 메소드, 자바 8</a>
<a href="#7-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4%EC%9D%98-private-%EB%A9%94%EC%86%8C%EB%93%9C-%EC%9E%90%EB%B0%94-9">7. 인터페이스의 private 메소드, 자바 9</a></p>
<br>

<h3 id="1-인터페이스-정의하는-방법">1. 인터페이스 정의하는 방법</h3>
<blockquote>
<p>Java에서 인터페이스는 클래스가 구현해야 할 메서드의 집합을 정의하는 일종의 계약입니다. 인터페이스를 사용하면 클래스의 기능을 규격화하고 다형성을 구현할 수 있습니다.</p>
</blockquote>
<h4 id="기본-문법">기본 문법</h4>
<pre><code class="language-java">public interface 인터페이스이름 {
    // 상수 (static final 생략 가능)
    타입 상수이름 = 값;

    // 추상 메서드 (abstract 생략 가능)
    반환타입 메서드이름(매개변수);

    // 디폴트 메서드 (Java 8 이후)
    default 반환타입 메서드이름(매개변수) {
        // 메서드 구현
    }

    // 정적 메서드 (Java 8 이후)
    static 반환타입 메서드이름(매개변수) {
        // 메서드 구현
    }

    // private 메서드 (Java 9 이후)
    private 반환타입 메서드이름(매개변수) {
        // 메서드 구현
    }
}</code></pre>
<br>

<h4 id="예제">예제</h4>
<pre><code class="language-java">public interface Animal {
    // 상수
    int LEGS = 4;

    // 추상 메서드
    void sound();

    // 디폴트 메서드
    default void sleep() {
        System.out.println(&quot;Sleeping...&quot;);
    }

    // 정적 메서드
    static void printLegs() {
        System.out.println(&quot;This animal has &quot; + LEGS + &quot; legs.&quot;);
    }

    // private 메서드 (Java 9 이후)
    private void breathe() {
        System.out.println(&quot;Breathing...&quot;);
    }
}</code></pre>
<p><br><br></p>
<h3 id="2-인터페이스-구현하는-방법">2. 인터페이스 구현하는 방법</h3>
<blockquote>
<p>클래스는 <code>implements</code> 키워드를 사용하여 인터페이스를 구현할 수 있습니다. <strong>인터페이스의 모든 추상메서드를 구현해야만 합니다.</strong></p>
</blockquote>
<br>

<h4 id="기본-문법-1">기본 문법</h4>
<pre><code class="language-java">public class 클래스이름 implements 인터페이스이름 {
    // 인터페이스의 모든 추상 메서드를 구현해야 함
    @Override
    public void 메서드이름(매개변수) {
        // 메서드 구현
    }
}</code></pre>
<br>

<h4 id="예제-1">예제</h4>
<pre><code class="language-java">public class Dog implements Animal {
    @Override
    public void sound() {
        System.out.println(&quot;Bark&quot;);
    }

    // 디폴트 메서드 sleep()은 선택적으로 오버라이드 가능
}</code></pre>
<p><br><br></p>
<h3 id="3-인터페이스-레퍼런스를-통해-구현체를-사용하는-방법">3. 인터페이스 레퍼런스를 통해 구현체를 사용하는 방법</h3>
<blockquote>
<p>인터페이스 타입의 변수를 사용하면 해당 인터페이스를 구현한 클래스의 객체를 참조할 수 있습니다. 이를 통해 다형성을 구현할 수 있으며, 코드의 유연성과 확장성을 높일 수 있습니다.</p>
</blockquote>
<h4 id="예제-2">예제</h4>
<pre><code class="language-java">public interface Animal {
    void sound();
    void sleep();
}

public class Dog implements Animal {
    @Override
    public void sound() {
        System.out.println(&quot;Bark&quot;);
    }

    @Override
    public void sleep() {
        System.out.println(&quot;Dog is sleeping...&quot;);
    }
}

public class Cat implements Animal {
    @Override
    public void sound() {
        System.out.println(&quot;Meow&quot;);
    }

    @Override
    public void sleep() {
        System.out.println(&quot;Cat is sleeping...&quot;);
    }
}

public class Main {
    public static void main(String[] args) {
        Animal myDog = new Dog();
        Animal myCat = new Cat();

        myDog.sound(); // &quot;Bark&quot; 출력
        myDog.sleep(); // &quot;Dog is sleeping...&quot; 출력

        myCat.sound(); // &quot;Meow&quot; 출력
        myCat.sleep(); // &quot;Cat is sleeping...&quot; 출력
    }
}
</code></pre>
<p>&amp;nbsp <code>Animal</code> 타입의 변수를 사용하여 <code>Dog</code>와 <code>Cat</code> 객체를 참조할 수 있으며, 이를 통해 다형성을 구현합니다. 이렇게 하면 새로운 동물 클래스가 추가되어도 <code>Animal</code> 인터페이스를 구현하기만 하면 동일한 방식으로 사용할 수 있습니다.</p>
<p><br><br></p>
<h3 id="4-인터페이스-상속">4. 인터페이스 상속</h3>
<blockquote>
<p>인터페이스는 다른 인터페이스를 상속할 수 있습니다. 이 경우 <strong>하위 인터페이스는 상위 인터페이스의 모든 메서드를 상속받습니다.</strong></p>
</blockquote>
<br>

<h4 id="기본-문법-2">기본 문법</h4>
<pre><code class="language-java">public interface 상위인터페이스 {
    void 메서드1();
}

public interface 하위인터페이스 extends 상위인터페이스 {
    void 메서드2();
}</code></pre>
<p> &amp;nbsp 여기에서 <code>하위인터페이스</code>는 <code>상위인터페이스</code>를 상속받습니다. 따라서 <code>하위인터페이스</code>는 <code>상위인터페이스</code>의 메서드도 포함하게 됩니다. 구현 클래스는<code>하위인터페이스</code>의 모든 메서드를 구현해야합니다.</p>
<br>

<h4 id="예제-3">예제</h4>
<pre><code class="language-java">public interface Animal {
    void sound();
}

public interface Pet extends Animal {
    void play();
}

public class Dog implements Pet {
    @Override
    public void sound() {
        System.out.println(&quot;Bark&quot;);
    }

    @Override
    public void play() {
        System.out.println(&quot;Playing with the dog...&quot;);
    }
}

public class Main {
    public static void main(String[] args) {
        Pet myDog = new Dog();
        myDog.sound(); // &quot;Bark&quot; 출력
        myDog.play();  // &quot;Playing with the dog...&quot; 출력
    }
}</code></pre>
<p> &amp;nbsp <code>Animal</code> 인터페이스는 <code>sound()</code> 메서드를 선언하고, <code>Pet</code> 인터페이스는 <code>Animal</code> 인터페이스를 상속하여 <code>play()</code> 메서드를 추가로 선언합니다.</p>
<p> &amp;nbsp <code>Dog</code> 클래스는 <code>Pet</code> 인터페이스를 구현하며, <code>sound()</code><strong>와</strong> <code>play()</code> <strong>메서드를 모두 구현해야 합니다.</strong></p>
<br>

<p>&amp;nbsp 이러한 상속 구조를 통해 인터페이스 간의 관계를 정의하고, 코드의 재사용성을 높일 수 있습니다. 특히, <strong>다중 상속</strong>을 지원하는 인터페이스를 사용하면 여러 인터페이스를 결합하여 더 복잡한 기능을 가진 인터페이스를 만들 수 있습니다.</p>
<h4 id="다중-상속-예제">다중 상속 예제</h4>
<pre><code class="language-java">public interface Animal {
    void sound();
}

public interface Playable {
    void play();
}

public interface Pet extends Animal, Playable {
}

public class Dog implements Pet {
    @Override
    public void sound() {
        System.out.println(&quot;Bark&quot;);
    }

    @Override
    public void play() {
        System.out.println(&quot;Playing with the dog...&quot;);
    }
}

public class Main {
    public static void main(String[] args) {
        Pet myDog = new Dog();
        myDog.sound(); // &quot;Bark&quot; 출력
        myDog.play();  // &quot;Playing with the dog...&quot; 출력
    }
}</code></pre>
<p>&amp;nbsp <code>Pet</code> 인터페이스는 <code>Animal</code>과 <code>Playable</code> 인터페이스를 동시에 상속받습니다. <code>Dog</code>클래스는 <code>Pet</code> 인터페이스를 구현하며, <code>sound()</code>와 <code>play()</code>메서드를 모두 구현합니다. </p>
<p>&amp;nbsp 이를 통해 <code>Pet</code> 인터페이스는 두 부모 인터페이스의 모든 메서드를 포함하게 됩니다.</p>
<br>
&nbsp 인터페이스 상속을 통해 더 복잡한 인터페이스를 구성할 수 있으며, 코드의 유연성과 재사용성을 크게 향상시킬 수 있습니다.



<p><br><br></p>
<h3 id="5-인터페이스의-기본-메소드-default-method-자바-8">5. 인터페이스의 기본 메소드 (Default Method), 자바 8</h3>
<blockquote>
<p><U>Java 8</U>부터 인터페이스는<code>default</code> 키워드를 사용하여 디폴트 메서드를 정의할 수 있습니다. 디폴드 메서드는 인터페이스를 구현하는 클래스에서 선택적으로 오버라이드할 수 있으며, <strong>기본 구현을 제공하므로 구현 클래스에서 반드시 구현할 필요는 없습니다.</strong></p>
</blockquote>
<h4 id="예제-4">예제</h4>
<pre><code class="language-java">public interface Animal {
    void sound();

    default void sleep() {
        System.out.println(&quot;Sleeping...&quot;);
    }
}

public class Dog implements Animal {
    @Override
    public void sound() {
        System.out.println(&quot;Bark&quot;);
    }

    // sleep() 메서드는 디폴트 구현을 사용
}

public class Cat implements Animal {
    @Override
    public void sound() {
        System.out.println(&quot;Meow&quot;);
    }

    @Override
    public void sleep() {
        System.out.println(&quot;Cat is sleeping...&quot;);
    }
}

public class Main {
    public static void main(String[] args) {
        Animal myDog = new Dog();
        Animal myCat = new Cat();

        myDog.sleep(); // &quot;Sleeping...&quot; 출력
        myCat.sleep(); // &quot;Cat is sleeping...&quot; 출력
    }
}</code></pre>
<p>&amp;nbsp 위 예제에서 <code>Animal</code> 인터페이스는 디폴트 메서드인 <code>sleep()</code>을 제공합니다. <code>Dog</code> 클래스는 이 메서드를 오버라이드하지 않고 디폴트 구현을 사용합니다.</p>
<p>&amp;nbsp 반면 <code>Cat</code> 클래스는 <code>sleep()</code> 메서드를 오버라이드하여 자신만의 구현을 제공합니다.</p>
<p>&amp;nbsp <strong>디폴트 메서드를 사용하면 인터페이스를 확장할 때 기존 코드를 깨지 않고 새로운 메서드를 추가할 수 있습니다.</strong> 
(인터페이스 추상메서드를 추가하면, 상속받는 모든 클래스에 구현이 추가되어야 하기 때문에...)</p>
<p><br><br></p>
<h3 id="6-인터페이스의-static-메소드-자바-8">6. 인터페이스의 static 메소드, 자바 8</h3>
<blockquote>
<p><U>Java 8부터</U> 인터페이스는 <code>static</code> 키워드를 사용하여 정적 메서드를 정의할 수 있습니다. 정적 메서드는 인스턴스가 아닌 인터페이스 이름을 통해 호출할 수 있으며, 인터페이스의 공통 기능을 제공하는 데 사용될 수 있습니다.</p>
</blockquote>
<h4 id="예제-5">예제</h4>
<pre><code class="language-java">public interface Animal {
    void sound();

    static void printLegs() {
        System.out.println(&quot;This animal has 4 legs.&quot;);
    }
}

public class Main {
    public static void main(String[] args) {
        Animal.printLegs(); 
        // &quot;This animal has 4 legs.&quot; 출력
    }
}</code></pre>
<p>&amp;nbsp 위 예제에서 <code>Animal</code> 인터페이스는 <code>printLegs()</code>라는 정적 메서드를 정의합니다. 정적 메서드는 인스턴스 없이 인터페이스 이름을 통해 직접 호출됩니다.</p>
<p>&amp;nbsp 이를 통해 공통 기능을 인터페이스에 정의하고 모든 구현 클래스에서 사용할 수 있습니다.</p>
<p><br><br></p>
<h3 id="7-인터페이스의-private-메소드-자바-9">7. 인터페이스의 private 메소드, 자바 9</h3>
<blockquote>
<p><U>Java 9</U>부터 인터페이스는 <code>private</code> 키워드를 사용하여 프라이빗 메서드를 정의할 수 있습니다.</p>
<p>프라이빗 메서드는 <strong>인터페이스 내에서만 사용될 수 있으며</strong>, 공통 코드의 재사용을 돕습니다. </p>
<p>프라이빗 메서드는 다른 디폴트 메서드나 정적 메서드 내에서 호출될 수 있습니다.</p>
</blockquote>
<h4 id="예제-6">예제</h4>
<pre><code class="language-java">public interface Animal {
    void sound();

    default void sleep() {
        breathe();
        System.out.println(&quot;Sleeping...&quot;);
    }

    private void breathe() {
        System.out.println(&quot;Breathing...&quot;);
    }
}

public class Dog implements Animal {
    @Override
    public void sound() {
        System.out.println(&quot;Bark&quot;);
    }
}

public class Main {
    public static void main(String[] args) {
        Animal myDog = new Dog();
        myDog.sleep(); 
        // &quot;Breathing...&quot; 및 &quot;Sleeping...&quot; 출력
    }
}</code></pre>
<p>&amp;nbsp 위 예제에서 <code>Animal</code> 인터페이스는 <code>breath()</code>라는 프라이빗 메서드를 정의하고, 이를 <code>sleep()</code> 디폴트 메서드에서 호출합니다. </p>
<p>&amp;nbsp <code>breathe()</code> 메서드는 외부에서 직접 접근할 수 없고, 인터페이스 내에서만 사용됩니다. 이를 통해 인터페이스 내에서 공통 코드의 재사용이 가능해집니다.</p>
<p>&amp;nbsp 이와 같이 인터페이스는 클래스 간의 결합도를 낮추고, 코드의 유연성과 재사용성을 높이는 데 중요한 역할을 합니다. Java의 다양한 인터페이스 기능을 활용하면 더욱 견고하고 유지보수하기 쉬운 코드를 작성할 수 있습니다.</p>
<br>



]]></description>
        </item>
        <item>
            <title><![CDATA[패키지]]></title>
            <link>https://velog.io/@ha_bu/%ED%8C%A8%ED%82%A4%EC%A7%80</link>
            <guid>https://velog.io/@ha_bu/%ED%8C%A8%ED%82%A4%EC%A7%80</guid>
            <pubDate>Mon, 10 Jun 2024 08:10:52 GMT</pubDate>
            <description><![CDATA[<h3 id="목표">목표</h3>
<blockquote>
<p>자바의 패키지에 대해 학습</p>
</blockquote>
<h3 id="목차">목차</h3>
<p><a href="#1-package-%ED%82%A4%EC%9B%8C%EB%93%9C">1. package 키워드</a>
<a href="#2-import-%ED%82%A4%EC%9B%8C%EB%93%9C">2. import 키워드</a>
<a href="#3-%ED%81%B4%EB%9E%98%EC%8A%A4%ED%8C%A8%EC%8A%A4">3. 클래스패스</a>
<a href="#4-classpath-%ED%99%98%EA%B2%BD%EB%B3%80%EC%88%98">4. CLASSPATH 환경변수</a>
<a href="#5--classpath-%EC%98%B5%EC%85%98">5. -classpath 옵션</a>
<a href="#6-%EC%A0%91%EA%B7%BC%EC%A7%80%EC%8B%9C%EC%9E%90">6. 접근지시자</a></p>
<br>

<h2 id="1-package-키워드">1. package 키워드</h2>
<blockquote>
<p><code>package</code> 키워드는 Java에서 클래스들을 그룹하하는 데 사용됩니다. 패키지는 비슷한 기능을하는 클래스들을 논리적으로 묶어 관리할 수 있도록 해줍니다. 패키지를 사용하면 클래스의 이름의 충돌을 피할 수 있고, 코드의 가독성과 유지보수성를 높일 수 있습니다.</p>
</blockquote>
<h4 id="1-1-기본-문법">1-1 기본 문법</h4>
<p>&amp;nbsp 패키지는 소스 파일의 가장 첫 번째 줄에 선언됩니다. 패키지를 선언하는 방법은 다음과 같습니다.</p>
<pre><code class="language-java">package com.example.myapp;</code></pre>
<p>위의 코드는 <code>com.example.myapp</code>이라는 패키지에 해당 클래스를 포함시킵니다.</p>
<h4 id="1-2-패키지의-역할">1-2 패키지의 역할</h4>
<ol>
<li>이름 충돌 방지
동일한 이름을 가진 클래스들이 다른 패키지에 존재할 수 있습니다.<br></li>
<li>조직화
관련된 클래스들을 묶어서 관리할 수 있습니다.<br></li>
<li>접근 제어
패키지 레벨의 접근 제어를 통해 클래스와 멤버에 대한 접근을 제어할 수 있습니다.<br>

</li>
</ol>
<h4 id="예제">예제</h4>
<pre><code class="language-java">package com.example.utils;

public class MathUtils {
    public static int add(int a, int b) {
        return a + b;
    }
}</code></pre>
<p>&amp;nbsp 이렇게 만들어둔 MathUtils를 다른 패키지에서 <code>import</code> 키워드를 통해 사용할 수 있습니다.</p>
<pre><code class="language-java">import com.example.utils.MathUtils;

public class Main {
    public static void main(String[] args) {
        int result = MathUtils.add(5, 3);
        System.out.println(&quot;Result: &quot; + result);
    }
}</code></pre>
<br>

<h2 id="2-import-키워드">2. import 키워드</h2>
<blockquote>
<p>위에서 언급한 <code>import</code> 키워드는 Java에서 다른 패키지에 정의된 클래스를 현재 클래스에서 사용할 수 있게 해줍니다. 이를 통해 필요한 클래스나 패키지를 가져와서 코드에서 활용할 수 있습니다.</p>
</blockquote>
<h4 id="2-1-기본-문법">2-1 기본 문법</h4>
<p>&amp;nbsp <code>import</code> 키워드는 클래스나 패키지를 가져올 때 사용됩니다. <code>import</code>문은 패키지 선언문 다음에, 클래스 선언문 전에 위치합니다.</p>
<pre><code class="language-java">import 패키지명.클래스명;</code></pre>
<p>&amp;nbsp 또는 패키지 내의 모든 클래스를 가져오려면 <code>*</code>를 사용할 수 있습니다.</p>
<pre><code class="language-java">import 패키지명.*;</code></pre>
<h4 id="예제-1">예제</h4>
<pre><code class="language-java">import java.util.*;

public class Main {
    public static void main(String[] args) {
        ArrayList&lt;String&gt; list = new ArrayList&lt;&gt;();
        HashMap&lt;String, String&gt; map = new HashMap&lt;&gt;();

        list.add(&quot;Hello&quot;);
        map.put(&quot;key&quot;, &quot;value&quot;);

        System.out.println(list);
        System.out.println(map);
    }
}</code></pre>
<p>&amp;nbsp 이는 java.util의 Date와 ArrayList를 가져와 사용한 예제입니다. <code>*</code>를 통해 한번에 가져와 사용해 보았습니다.</p>
<h4 id="주의-사항">주의 사항</h4>
<blockquote>
<ul>
<li><code>import</code> 문은 코드의 가독성을 높이고, 명확하게 하기 위해 사용됩니다.</li>
</ul>
</blockquote>
<ul>
<li><code>java.lang</code> 패키지는 자동으로 <code>import</code>되므로, <code>String</code>, <code>System</code>등의 클래스를 사용할 때는 <code>import</code>문이 필요없습니다.</li>
<li>같은 패키지 내의 클래스는 <code>import</code> 없이 사용할 수 있습니다.</li>
<li><code>import</code> 문을 과도하게 사용하면 코드가 복잡해질 수 있으므로, 필요한 클래스만 선택적으로 임포트하는 것이 좋습니다.</li>
</ul>
<br>

<h2 id="3-클래스패스">3. 클래스패스</h2>
<blockquote>
<p>클래스패스(Classpath)는 Java 프로그램이 컴파일되고 실행될 때, Java 런타임이 클래스 파일을 찾는 데 사용하는 경로입니다. 클래스패스는 Java 컴파일러와 <a href="https://velog.io/@ha_bu/JVM%EC%9D%98-%EA%B0%9C%EB%85%90%EA%B3%BC-JDKJRE">JVM(Java Virtual Machine)</a>에게 프로그램 실행 시 필요한 클래스와 패키기의 위치를 알려줍니다.</p>
</blockquote>
<h4 id="3-1-클래스패스의-구성-요소">3-1 클래스패스의 구성 요소</h4>
<p>&amp;nbsp 클래스패스는 디렉토리, JAR 파일, ZIP 파일의 경로를 포함할 수 있습니다. <strong>여러 경로를 지정할 때는 운영체제에 따라 구분자가 다릅니다.</strong></p>
<ul>
<li>Windows   : 세미콜론(<code>;</code>)</li>
<li>Linux/Mac : 콜론(<code>:</code>)</li>
</ul>
<p>&amp;nbsp 예를 들어, 두 개의 디렉토리와 하나의 JAR 파일을 클래스패스에 추가하려면 아래와 같이 설정할 수 있습니다.</p>
<p><strong>Windows</strong></p>
<pre><code class="language-sh">set CLASSPATH=C:\dir1;C:\dir2;C:\path\to\library.jar</code></pre>
<p><strong>Linux/Mac</strong></p>
<pre><code>export CLASSPATH=/dir1:/dir2:/path/to/library.jar</code></pre><h4 id="예제-2">예제</h4>
<pre><code class="language-css">project/
  ├─ main/
  │    └─ Main.java
  └─ util/
       └─ Util.java</code></pre>
<p>&amp;nbsp 두 개의 클래스 파일 <code>Main.java</code>와 <code>Util.java</code>가 각각 다른 디렉토리에 있는 경우입니다.</p>
<br>

<p><strong>Main.java</strong></p>
<pre><code class="language-java">package main;

import util.Util;

public class Main {
    public static void main(String[] args) {
        Util.printMessage();
    }
}</code></pre>
<p><strong>Util.java</strong></p>
<pre><code class="language-java">package util;

public class Util {
    public static void printMessage() {
        System.out.println(&quot;Hello from Util!&quot;);
    }
}</code></pre>
<p><strong>컴파일과 실행 명령</strong></p>
<pre><code class="language-sh">javac -cp . main/Main.java util/Util.java
java -cp . main.Main</code></pre>
<br>

<h2 id="4-classpath-환경변수">4. CLASSPATH 환경변수</h2>
<blockquote>
<p><code>CLASSPATH</code> 환경 변수를 적절히 설정하지 않으면 Java 런타임이 필요한 클래스를 찾지 못해 <code>ClassNotFoundException</code>이 발생할 수 있습니다.</p>
</blockquote>
<h4 id="4-1-클래스패스-설정-방법">4-1 클래스패스 설정 방법</h4>
<p>** 1) 명령줄에서 설정 **
<code>-classpath</code> 또는 <code>-cp</code>옵션을 사용하여 설정할 수 있습니다.</p>
<pre><code class="language-sh">javac -classpath /path/to/library myprogram.java
java -classpath /path/to/library myprogram

# 또는
javac -cp /path/to/library myprogram.java
java -cp /path/to/library myprogram</code></pre>
<br>

<p>** 2) 환경 변수 설정 **
<code>CLASSPATH</code> 환경 변수를 설정하여 클래스패스를 지정할 수 있습니다.</p>
<p>Windows</p>
<pre><code class="language-sh">set CLASSPATH=C:\path\to\library</code></pre>
<p>Linux</p>
<pre><code class="language-sh">export CLASSPATH=/path/to/library</code></pre>
<br>

<p>** 3) IDE에서 설정 **</p>
<p>&amp;nbsp Eclipse, IntelliJ IDEA 등의 통합 개발 환경(IDE)에서는 프로젝트 속성에서 클래스패스를 설정할 수 있습니다. 보통 프로젝트의 빌드 패스(build path)나 라이브러리 설정에서 JAR 파일이나 클래스 파일을 추가하여 설정합니다.
<br></p>
<h2 id="5--classpath-옵션">5. -classpath 옵션</h2>
<blockquote>
<p>앞에서도 간단하게 설명하긴 했습니다만... 추가로 설명하자면</p>
<p><code>-classpath</code> 또는 <code>-cp</code> 옵션은 Java 컴파일러(<code>javac</code>)와 Java 런타임(<code>java</code>)에서 클래스 파일이나 JAR 파일의 경로를 지정할 때 사용됩니다. 이 옵션은 <code>CLASSPATH</code> 환경 변수를 설정하는 것과 유사하게 동작하지만, 명령줄에서 <strong>특정 컴파일 또는 실행 명령에만 적용된다는 점</strong>에서 차이가 있습니다.</p>
</blockquote>
<br>

<h4 id="예제-3">예제</h4>
<p>&amp;nbsp 예를 들어, 두 개의 디렉토리와 하나의 JAR 파일을 포함한 프로젝트가 있다고 가정합니다. <code>Main.java</code> 파일이 <code>src</code> 디렉토리에 있고, 필요한 라이브러리는 <code>libs</code> 디렉토리에 있습니다.</p>
<pre><code class="language-css">project/
  ├─ src/
  │    └─ Main.java
  ├─ classes/
  └─ libs/
       └─ example-library.jar</code></pre>
<p>** 컴파일 **</p>
<pre><code class="language-sh">javac -d classes -cp libs/example-library.jar src/Main.java</code></pre>
<p>** 실행 **</p>
<pre><code class="language-sh">java -cp classes:libs/example-library.jar Main</code></pre>
<p>&amp;nbsp 이 예제에서 <code>-d</code> 옵션은 클래스 파일이 저장될 디렉토리를 지정하고, <code>-cp</code> 옵션은 필요한 라이브러리 경로를 지정합니다.</p>
<h4 id="요약">요약</h4>
<p><code>-classpath</code> 또는 <code>-cp</code> 옵션은 Java 프로그램을 컴파일하고 실행할 때 클래스와 라이브러리의 경로를 명령줄에서 설정하는 데 유용합니다. 이는 특정 작업에만 적용되므로 <code>CLASSPATH</code> 환경 변수를 설정하는 것보다 유연하게 사용할 수 있습니다.</p>
<br>

<h2 id="6-접근지시자">6. 접근지시자</h2>
<blockquote>
<p>이전 포스팅에도 한번씩 언급되었던 접근지시자 입니다.</p>
<p>&amp;nbsp 접근지시자는 Java에서 클래스, 변수, 메소드 및 생성자의 접근 수준을 제어하는 키워드입니다. </p>
<p>&amp;nbsp 접근지시자는 코드의 가시성을 관리하고, 클래스 간의 <strong>결합도를 낮추며</strong>, <strong>캡슐화</strong>를 구현하는데 중요한 역할을합니다.</p>
</blockquote>
<h3 id="종류와-역할">종류와 역할</h3>
<h4 id="1-public">1. public</h4>
<ul>
<li>정의 : 모든 클래스에서 접근할 수 있습니다.</li>
<li>사용 예 : 클래스, 메서드, 변수, 생성자 등<pre><code class="language-java">public class MyClass {
  public int publicVar;
  public void publicMethod() {
      // ...
  }
}</code></pre>
</li>
</ul>
<h4 id="2-protected">2. protected</h4>
<ul>
<li>정의 : 동일한 패키지 내의 클래스와 하위 클래스(다른 패키지에 있어도)에서 접근할 수 있습니다.</li>
<li>사용 예 : 메서드, 변수, 생성자 등(클래스에서는 사용할 수 없음)<pre><code class="language-java">public class MyClass {
  protected int protectedVar;
  protected void protectedMethod() {
      // ...
  }
}</code></pre>
</li>
</ul>
<h4 id="3-default">3. default</h4>
<ul>
<li>정의 : 동일한 패키지 내의 클래스에서만 접근할 수 있습니다.(패키지 접근수준)</li>
<li>사용 예 : 클래스, 메서드, 변수, 생성자 등<pre><code class="language-java">class MyClass {
  int defaultVar;
  void defaultMethod() {
      // ...
  }
}</code></pre>
</li>
</ul>
<h4 id="4-private">4. private</h4>
<ul>
<li>정의 : 동일한 클래스 내에서만 접근할 수 있습니다</li>
<li>사용 예 : 메서드, 변수, 생성자 등(클래스에는 사용할 수 없음)<pre><code class="language-java">public class MyClass {
  private int privateVar;
  private void privateMethod() {
      // ...
  }
}</code></pre>
</li>
</ul>
<h4 id="접근지시자의-적용-범위">접근지시자의 적용 범위</h4>
<table>
<thead>
<tr>
<th>접근지시자</th>
<th>클래스 내부</th>
<th>동일 패키지</th>
<th>하위 클래스 (다른 패키지)</th>
<th>모든 클래스</th>
</tr>
</thead>
<tbody><tr>
<td><code>public</code></td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>O</td>
</tr>
<tr>
<td><code>protected</code></td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>X</td>
</tr>
<tr>
<td><code>default</code></td>
<td>O</td>
<td>O</td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td><code>private</code></td>
<td>O</td>
<td>X</td>
<td>X</td>
<td>X</td>
</tr>
</tbody></table>
<br>

<h3 id="예시">예시</h3>
<pre><code class="language-java">public class AccessModifiersExample {

    public int publicVar = 1;
    protected int protectedVar = 2;
    int defaultVar = 3;
    private int privateVar = 4;

    public void publicMethod() {
        System.out.println(&quot;Public Method&quot;);
    }

    protected void protectedMethod() {
        System.out.println(&quot;Protected Method&quot;);
    }

    void defaultMethod() {
        System.out.println(&quot;Default Method&quot;);
    }

    private void privateMethod() {
        System.out.println(&quot;Private Method&quot;);
    }

    public static void main(String[] args) {
        AccessModifiersExample example = new AccessModifiersExample();

        // 같은 클래스 내에서는 모든 접근지시자에 접근 가능
        System.out.println(&quot;Public Variable: &quot; + example.publicVar);
        System.out.println(&quot;Protected Variable: &quot; + example.protectedVar);
        System.out.println(&quot;Default Variable: &quot; + example.defaultVar);
        System.out.println(&quot;Private Variable: &quot; + example.privateVar);

        example.publicMethod();
        example.protectedMethod();
        example.defaultMethod();
        example.privateMethod();
    }
}</code></pre>
<br>

<p>&amp;nbsp 다른 클래스에서 <code>AccessModifiersExample</code> 클래스를 사용할 때 접근할 수 있는 멤버는 접근지시자에 따라달라집니다.</p>
<p>&amp;nbsp 예를들어, 동일한 패키지 내의 다른 클래스에서는 <code>public</code>, <code>protected</code>, <code>default</code> 멤버에 접근할 수 있지만, <code>private</code>멤버에는 접근할 수 없습니다.</p>
<p>&amp;nbsp 접근지시자를 적절히 사용하면 코드의 가독성과 유지보수성을 높이고, 불필요한 외부 접근을 막아 클래스의 일관성을 유지할 수 있습니다.</p>
<br>
]]></description>
        </item>
        <item>
            <title><![CDATA[상속(Inheritance)]]></title>
            <link>https://velog.io/@ha_bu/%EC%83%81%EC%86%8D</link>
            <guid>https://velog.io/@ha_bu/%EC%83%81%EC%86%8D</guid>
            <pubDate>Thu, 06 Jun 2024 15:27:28 GMT</pubDate>
            <description><![CDATA[<h3 id="목표">목표</h3>
<blockquote>
<p>자바의 상속에 대해 학습</p>
</blockquote>
<h3 id="목차">목차</h3>
<p><a href="#1-%EC%9E%90%EB%B0%94-%EC%83%81%EC%86%8D%EC%9D%98-%ED%8A%B9%EC%A7%95">1. 자바 상속의 특징</a>
<a href="#2-super-%ED%82%A4%EC%9B%8C%EB%93%9C">2. super 키워드</a>
<a href="#3-%EB%A9%94%EC%86%8C%EB%93%9C-%EC%98%A4%EB%B2%84%EB%9D%BC%EC%9D%B4%EB%94%A9">3. 메소드 오버라이딩</a>
<a href="#4-%EB%8B%A4%EC%9D%B4%EB%82%98%EB%AF%B9-%EB%A9%94%EC%86%8C%EB%93%9C-%EB%94%94%EC%8A%A4%ED%8C%A8%EC%B9%98">4. 다이나믹 메소드 디스패치 (Dynamic Method Dispatch)</a>
<a href="#5-%EC%B6%94%EC%83%81-%ED%81%B4%EB%9E%98%EC%8A%A4">5. 추상 클래스</a>
<a href="#6-final-%ED%82%A4%EC%9B%8C%EB%93%9C">6. final 키워드</a>
<a href="#7-object-%ED%81%B4%EB%9E%98%EC%8A%A4">7. Object 클래스</a></p>
<br>

<h2 id="1-자바-상속의-특징">1. 자바 상속의 특징</h2>
<blockquote>
<p>상속은 객체 지향 프로그래밍(OOP)의 중요한 개념 중 하나로, 자바에서도 매우 중요한 역할을 합니다. <strong>상속을 통해 기존 클래스의 속성과 메소드를 새로운 클래스에서 재사용하고 확장할 수 있습니다.</strong></p>
</blockquote>
<h4 id="1-1-상속의-개념">1-1 상속의 개념</h4>
<p>&amp;nbsp 상속을 사용하면 <strong>새로운 클래스</strong>(자식 클래스 도는 서브 클래스)가 <strong>기존 클래스</strong>(부모 클래스 또는 슈퍼 클래스)의 <strong>특성과 동작을 물려받을 수 있습니다.</strong></p>
<p>&amp;nbsp 자식 클래스는 부모 클래스의 <U>모든 필드와 메소드를 상속받으며</U>, 필요한 경우 이를 <strong>재정의(오버라이딩)</strong>하거나 <strong>새로운 특성과 동작을 추가</strong>할 수 있습니다.</p>
<br>

<h4 id="1-2-상속의-특징">1-2 상속의 특징</h4>
<p><strong>1) 재사용성</strong></p>
<ul>
<li>상속은 기존 클래스의 코드를 재사용할 수 있게 합니다. 이를 통해 코드 중복을 줄이고, 유지보수를 쉽게 합니다.</li>
</ul>
<p><strong>2) 계층 구조</strong></p>
<ul>
<li>클래스간의 상속 관계를 통해 계층 구조를 만들 수 있습니다. 이는 복잡한 시스템을 더 이해하기 쉽고, 관리하기 쉽게 만듭니다.</li>
</ul>
<p><strong>3) 확장성</strong></p>
<ul>
<li>자식 클래스는 부모 클래스의 기능을 확장할 수 있습니다. 새로운 속성이나 메소드를 추가하거나 부모 클래스의 메소드를 재정의(오버라이딩)하여 기능을 변경할 수 있습니다.</li>
</ul>
<p><strong>4) 다형성</strong></p>
<ul>
<li>상속은 다형성을 지원합니다. 자식 클래스의 인스턴스를 부모클래스의 타입으로 처리할 수 있습니다. 이를 통해 동일한 인터페이스나 부모 클래스를 공유하는 여러 객체를 동일한 방법으로 다룰 수 있습니다.</li>
</ul>
<p><strong>5) 접근 제어자</strong></p>
<ul>
<li>부모 클래스의 필드와 메소드는 접근 제어자에 따라 자식 클래스에서 접근 가능 여부가 달라집니다.</li>
</ul>
<blockquote>
<p><code>public</code> : 모든 클래스에서 접근 가능
<code>protected</code> : 같은 패키지와 자식 클래스에서 접근 가능
<code>default(접근제어자가 없을때)</code> : 같은 패키지에서 접근 가능
<code>private</code> : 동일 클래스 내에서만  접근 가능</p>
</blockquote>
<p><strong>6) 단일 상속</strong></p>
<ul>
<li>자바는 단일 상속만을 지원합니다. 즉, 한 클래스는 하나의 부모 클래스만 가질 수 있습니다. 다중 상속은 인터페이스를 통해 구현됩니다.</li>
</ul>
<br>

<h4 id="✨-다이아-몬드-문제diamond-problem">✨ 다이아 몬드 문제(Diamond Problem)</h4>
<blockquote>
<p><a href="https://velog.io/@ha_bu/%EB%8B%A4%EC%9D%B4%EC%95%84-%EB%AA%AC%EB%93%9C-%EB%AC%B8%EC%A0%9CDiamond-Problem">다이아몬드 문제</a> 를 참고해주세요!</p>
</blockquote>
<br>

<h4 id="1-3-예시-코드">1-3 예시 코드</h4>
<pre><code class="language-java">// 부모 클래스
class Animal {
    String name;

    void eat() {
        System.out.println(&quot;Eating...&quot;);
    }

    void sleep() {
        System.out.println(&quot;Sleeping...&quot;);
    }
}

// 자식 클래스
class Dog extends Animal {
    void bark() {
        System.out.println(&quot;Barking...&quot;);
    }
}

public class Main {
    public static void main(String[] args) {
        Dog myDog = new Dog();
        myDog.name = &quot;Buddy&quot;;
        myDog.eat();   // 부모 클래스의 메소드 호출
        myDog.sleep(); // 부모 클래스의 메소드 호출
        myDog.bark();  // 자식 클래스의 메소드 호출
    }
}</code></pre>
<br>

<h4 id="1-4-상속과-오버라이딩">1-4 상속과 오버라이딩</h4>
<blockquote>
<p>상속받은 메소드를 자식 클래스에서 재정의(오버라이딩)할 수 있습니다. 이를 통해 부모 클래스의 동작을 변경하거나 확장할 수 있습니다.</p>
</blockquote>
<pre><code class="language-java">// 부모 클래스
class Animal {
    void makeSound() {
        System.out.println(&quot;Some generic animal sound&quot;);
    }
}

// 자식 클래스
class Dog extends Animal {
    @Override
    void makeSound() {
        System.out.println(&quot;Bark&quot;);
    }
}

public class Main {
    public static void main(String[] args) {
        Animal myAnimal = new Animal();
        myAnimal.makeSound(); // 출력: Some generic animal sound

        Dog myDog = new Dog();
        myDog.makeSound(); // 출력: Bark
    }
}</code></pre>
<p>&amp;nbsp @Override를 붙여 재정의 할 수 있습니다. 그래서 Animal의 makeSound와 Dog의 makeSound가 다르게 출력됩니다.</p>
<p>&amp;nbsp 이처럼 상속(Inheritance)은 코드 재사용성을 높이고, 계츨 구조를 형성하며, 다형성을 지원하는 강력한 도구라고 할 수 있겠습니다.</p>
<p><br><br></p>
<h2 id="2-super-키워드">2. super 키워드</h2>
<blockquote>
<p><code>super</code> 키워드는 자바에서 <strong>부모 클래스의 멤버(필드, 메소드, 생성자)에 접근할 때 사용되는 특별한 키워드 입니다.</strong> 이를 통해 자식 클래스는 부모 클래스의 필드와 메소드에 접근하거나 부모 클래스의 생성자를 호출할 수 있습니다.</p>
</blockquote>
<h4 id="경우">경우</h4>
<ol>
<li><p>부모 클래스의 메소드 호출</p>
<blockquote>
<p>자식 클래스에서 부모 클래스의 메소드를 호출 할때, <code>super</code> 키워드를 사용합니다. 이를 통해 자식 클래스에서 재정의(오버라이딩)된 메소드를 호출할 수 있습니다.</p>
</blockquote>
</li>
<li><p>부모 클래스의 필드 접근</p>
<blockquote>
<p>자식 클래스에서 부모 클래스의 필드에 접근할 때 <code>super</code>키워드를 사용합니다. </p>
</blockquote>
</li>
<li><p>부모 클래스의 생성자 호출</p>
<blockquote>
<p>자식 클래스의 생성자에서 부모 클래스의 생성자를 호출할 때 <code>super</code> 키워드를 사용합니다. 이는 부모 클래스의 초기화 작업을 수행하기 위해 필요합니다.</p>
</blockquote>
</li>
<li><p>부모 클래스의 매개변수가 있는 생성자 호출</p>
<blockquote>
<p>자식 클래스의 생성자에서 부모 클래스의 매개변수가 있는 생성자를 호출할때 <code>super</code> 키워드를 사용할 수 있습니다.</p>
</blockquote>
</li>
</ol>
<br>

<h4 id="예시-코드">예시 코드</h4>
<pre><code class="language-java">class Parent {
    // 부모 클래스의 필드
    int value = 100;

    // 부모 클래스의 기본 생성자
    Parent() {
        System.out.println(&quot;Parent Constructor&quot;);
    }

    // 부모 클래스의 매개변수가 있는 생성자
    Parent(String message) {
        System.out.println(&quot;Parent Constructor: &quot; + message);
    }

    // 부모 클래스의 메소드
    void display() {
        System.out.println(&quot;Display from Parent&quot;);
    }
}

class Child extends Parent {
    // 자식 클래스의 필드
    int value = 200;

    // 자식 클래스의 기본 생성자
    Child() {
        super(&quot;Hello from Child&quot;); // 부모 클래스의 매개변수가 있는 생성자 호출
        System.out.println(&quot;Child Constructor&quot;);
    }

    // 자식 클래스의 메소드
    @Override
    void display() {
        System.out.println(&quot;Display from Child&quot;);
    }

    // 자식 클래스의 메소드
    void show() {
        super.display(); // 부모 클래스의 display() 메소드 호출
        this.display();  // 현재 클래스의 display() 메소드 호출

        System.out.println(&quot;Value from Parent: &quot; + super.value); // 부모 클래스의 value 필드
        System.out.println(&quot;Value from Child: &quot; + this.value);   // 현재 클래스의 value 필드
    }
}

public class Main {
    public static void main(String[] args) {
        Child child = new Child();
        child.show();
    }
}</code></pre>
<br>

<h4 id="출력-결과">출력 결과</h4>
<pre><code class="language-csharp">Parent Constructor: Hello from Child
Child Constructor
Display from Parent
Display from Child
Value from Parent: 100
Value from Child: 200</code></pre>
<h4 id="요약">요약</h4>
<ul>
<li>생성자 호출: <code>super(&quot;Hello from Child&quot;)</code>를 사용하여 부모 클래스의 매개변수가 있는 생성자를 호출했습니다.</li>
</ul>
<ul>
<li>메소드 호출: <code>super.display()</code>를 사용하여 부모 클래스의 <code>display</code> 메소드를 호출하고, <code>this.display()</code>를 사용하여 자식 클래스의 <code>display</code> 메소드를 호출했습니다.</li>
</ul>
<ul>
<li>필드 접근: <code>super.value</code>를 사용하여 부모 클래스의 <code>value</code> 필드에 접근하고, <code>this.value</code>를 사용하여 자식 클래스의 <code>value</code> 필드에 접근했습니다.</li>
</ul>
<p><br><br></p>
<h2 id="3-메소드-오버라이딩">3. 메소드 오버라이딩</h2>
<blockquote>
<p>메소드 오버라이딩(Method Oberriding)은 자바에서 상속 관계에 있는 클래스들간에 부모 클래스의 메소드를 <strong>자식 클래스에서 재정의 하여 사용</strong>하는 기능입니다.</p>
<p>이는 다형성(Polymorphism)의 중요한 요소로, 부모 클래스의 기본 동작을 자식 클래스에서 변경할 때 사용됩니다.</p>
</blockquote>
<h4 id="3-1-메소드-오버라이딩의-특징">3-1 메소드 오버라이딩의 특징</h4>
<ol>
<li><p><strong>동일한 메소드 이름</strong>
부모 클래스의 메소드와 동일한 이름을 가져야 합니다.</p>
</li>
<li><p><strong>동일한 매개변수 목록</strong>
매개변수의 개수, 타입, 순서가 부모 클래스의 메소드와 동일해야 합니다.</p>
</li>
<li><p><strong>동일한 반환 타입</strong>
반환 타입이 부모 클래스의 메소드와 동일해야 합니다. 자바 5 이후부터는 <strong>공변 반환 타입(Convariant Return Type)</strong>을 허용하여 자식 클래스에서 반환 타입을 부모 클래스의 반환 타입의 서브 클래스로 변경할 수 있습니다.</p>
</li>
</ol>
<h4 id="✨-잠깐-공변-변환-타입">✨ 잠깐...! 공변 변환 타입</h4>
<pre><code class="language-java">class Animal {
    public Animal getInstance() {
        return new Animal();
    }
}

class Dog extends Animal {
    @Override
    public Dog getInstance() { 
    // 공변 반환 타입: Animal의 서브 타입인 Dog 반환
        return new Dog();
    }
}

public class Main {
    public static void main(String[] args) {
        Animal animal = new Animal();
        Animal animalInstance = animal.getInstance(); 
        // Animal 객체 반환

        Dog dog = new Dog();
        Dog dogInstance = dog.getInstance(); 
        // Dog 객체 반환

        Animal polyAnimal = new Dog();
        Animal polyAnimalInstance = polyAnimal.getInstance(); 
        // 다형성 사용 시 여전히 Dog 객체 반환
    }
}
</code></pre>
<p>&amp;nbsp 이렇게 원래라면 Animal을 반환해야하지만, Dog 타입을 반환할 수 있게 되었습니다. <strong>타입 안정성, 가독성 향상, 다형성 지원 강화</strong>라는 장점이 있겠습니다.</p>
<p>&amp;nbsp <strong>요약하자면,</strong></p>
<ul>
<li>공변 변환 타입은 자식 클래스에서 메소드를 오버라이딩할 때 부모 클래스의 메소드가 반환하는 타입의 하위 타입을 반환할 수 있도록 허용하는 기능입니다.</li>
<li>자바 5부터 도입되었으며, 타입 안정성과 코드 가독성을 높이고, 다형성을 유연하게 지원합니다.</li>
<li>공변 반환 타입은 상속 계층 및 인터페이스 구현에서 유용하게 사용할 수 있습니다.</li>
</ul>
<hr>
<ol start="4">
<li>접근 제어자</li>
</ol>
<p><strong>부모 클래스의 메소드 보다 더 강한 접근 제어자를 가질 수 없습니다.</strong> 예를 들어, 부모 클래스의 메소드가 <code>protected</code>이면 자식 클래스에서는 <code>protected</code> 또는 <code>public</code>만 가능합니다.</p>
<h4 id="예시-코드-1">예시 코드</h4>
<pre><code class="language-java">class Parent {
    // 부모 클래스의 메소드
    void display() {
        System.out.println(&quot;Display from Parent&quot;);
    }
}

class Child extends Parent {
    // 자식 클래스에서 메소드 오버라이딩
    @Override
    void display() {
        System.out.println(&quot;Display from Child&quot;);
    }
}

public class Main {
    public static void main(String[] args) {
        Parent parent = new Parent();
        parent.display(); 
        // Output: Display from Parent

        Child child = new Child();
        child.display(); 
        // Output: Display from Child

        Parent parentRef = new Child();
        parentRef.display(); 
        // Output: Display from Child (다형성)
    }
}</code></pre>
<br>

<h4 id="예외-처리">예외 처리</h4>
<p>&amp;nbsp 자식 클래스에서 오버라이딩하는 메소드는 부모클래스의 메소드가 던지는 예외보다 더 많은 예외를 던질 수 없습니다. 던지는 예외의 범위는 같거나 더 좁아야합니다.</p>
<pre><code class="language-java">class Parent {
    void display() throws IOException {
        System.out.println(&quot;Display from Parent&quot;);
    }
}

class Child extends Parent {
    @Override
    void display() throws FileNotFoundException { 
    // 허용됨: 더 좁은 범위의 예외
        System.out.println(&quot;Display from Child&quot;);
    }
}</code></pre>
<h4 id="요약-1">요약</h4>
<ul>
<li>메소드 오버라이딩은 자식 클래스에서 부모 클래스의 메소드를 재정의 하는 것입니다.</li>
<li>다형성을 통해 부모 클래스 타입의 참조 변수로 자식 클래스의 오버라이딩된 메소드를 호출할 수 있습니다.</li>
<li><code>@Override</code> 어노테이션을 사용하여 오버라이딩을 명시적으로 표시하고, 컴파일러의 체크를 받을 수 있습니다.</li>
<li>접근 제어자와 예외 처리 규칙을 준수해야 합니다.</li>
</ul>
<p><br><br></p>
<h2 id="4-다이나믹-메소드-디스패치">4. 다이나믹 메소드 디스패치</h2>
<blockquote>
<p>다이나믹 메소드 디스패치(Dynamic Method Dispatch)는 객체 지향 프로그래밍에서 다형성을 구현하는 기술 중 하나입니다. 이는 컴파일 시점에는 어떤 메소드가 호출될지 결정되지 않고, <strong>실행 시점에 객체의 실제 타입에 따라 메소드가 동적으로 호출되는 것</strong>을 의미합니다.</p>
</blockquote>
<p>&amp;nbsp 자바에서는 메소드 오버라이딩과 함께 다이나믹 메소드 디스패치를 통해 다형성을 구현합니다. 예를 들어, 부모 클래스의 참조 변수로 자식 클래스의 인스턴스를 참조할 때, 메소드 호출은 실제 객체의 타입에 따라 동적으로 결정됩니다.</p>
<pre><code class="language-java">class Animal {
    void makeSound() {
        System.out.println(&quot;Animal makes sound&quot;);
    }
}

class Dog extends Animal {
    @Override
    void makeSound() {
        System.out.println(&quot;Dog barks&quot;);
    }
}

public class Main {
    public static void main(String[] args) {
        Animal animal = new Dog(); 
        // 다형성: 부모 클래스의 참조 변수로 자식 클래스의 인스턴스를 참조
        animal.makeSound(); 
        // Output: Dog barks 
        // (실제 객체인 Dog의 makeSound 메소드가 호출됨)
    }
}</code></pre>
<br>

<p>&amp;nbsp 위 예제에서 <code>animal.makeSound()</code> 호출 시, 컴파일 시점에는 <code>Animal</code> 클래스의 <code>makeSound</code> 메소드가 호출될 것으로 예상되지만, 실행 시점에는 실제 객체가 <code>Dog</code> 클래스의 인스턴스이므로 <code>Dog</code> 클래스의 <code>makeSound</code> 메소드가 호출됩니다.</p>
<p>&amp;nbsp 이렇게 <strong>컴파일 시점에는 어떤 메소드가 호출될지 확정되지 않고, 실행 시점에 결정되는 것</strong>이 다이나믹 메소드 디스패치의 핵심입니다.</p>
<h4 id="장점">장점</h4>
<ol>
<li><p><strong>다형성</strong>
객체 지향 프로그래밍의 핵심인 다형성을 구현할 수 있습니다. 부모 클래스의 참조 변수로 여러 종류의 자식 클래스 인스턴스를 참조하여 각각의 메소드를 호출할 수 있습니다.</p>
</li>
<li><p><strong>유연성</strong>
실행 시점에 메소드 호출이 결정되므로 프로그램의 동작을 동적으로 조절할 수 있습니다. 이는 프로그램의 유연성과 확장성을 향상시킵니다.</p>
</li>
<li><p><strong>코드 재사용</strong>
메소드 오버라이딩을 통해 부모 클래스의 기능을 자식 클래스에서 재정의할 수 있습니다. 이는 코드의 재사용성을 높여줍니다.</p>
</li>
</ol>
<h4 id="원리">원리</h4>
<p>&amp;nbsp 자바에서는 다이나믹 메소드 디스패치를 가상 메소드 테이블(Virtual Method Table, <strong>VMT</strong>)을 통해 구현합니다. 각 클래스에는 해당 클래스의 메소드들에 대한 참조를 가지고 있는 VMT가 존재하며, <strong>객체가 생성될 때마다 VMT가 생성됩니다.</strong> 메소드 호출 시에는 객체의 VMT를 참조하여 해당 메소드의 주소를 찾아서 호출하게 됩니다.</p>
<h4 id="요약-2">요약</h4>
<ul>
<li><p>다이나믹 메소드 디스패치는 실행 시점에 메소드 호출이 결정되는 기술로, 다형성을 구현하는 중요한 요소입니다.</p>
</li>
<li><p>다형성을 통해 부모 클래스의 참조 변수로 여러 종류의 자식 클래스 인스턴스를 참조하여 다양한 메소드를 호출할 수 있습니다.</p>
</li>
<li><p>자바에서는 가상 메소드 테이블을 사용하여 다이나믹 메소드 디스패치를 구현합니다.</p>
</li>
</ul>
<p><br><br></p>
<h2 id="5-추상-클래스">5. 추상 클래스</h2>
<blockquote>
<p>&amp;nbsp 추상 클래스는 상속 관계에서 공통된 동작을 정의하고 확장하기 위한 용도로 사용됩니다. </p>
<p>&amp;nbsp 예를 들어, 동물의 동물을 나타내는 추상 클래스에서는 추상 메소드로 <code>움직이다</code>, <code>소리내다</code> 등의 행동을 정의할 수 있고, 실제 동물 종류(개, 고양이 등)를 나타내는 구체적인 클래스에서는 이러한 메소드를 구현할 수 있습니다.</p>
</blockquote>
<h4 id="특징">특징</h4>
<ol>
<li><p><strong>추상 메소드 포함 가능</strong>
&amp;nbsp 추상 클래스는 추상 메소드(Abstract Method)를 포함할 수 있습니다. <br><br> 추상 메소드는 메소드의 시그니처(이름, 매개변수, 반환 타입)만을 정의하고 메소드의 본문(구현)은 포함하지 않습니다. <strong>따라서 추상 메소드를 가지는 클래스는 반드시 추상 클래스여야 합니다.</strong> </p>
<br>
</li>
<li><p><strong>일반 메소드 포함 가능</strong>
추상 클래스는 추상 메소드 뿐만 아니라 일반 메소드를 포함할 수도 있습니다. 일반 메소드는 메소드의 시그니처와 구현을 모두 포함합니다. </p>
<br>
</li>
<li><p><strong>인스턴스 생성 불가능</strong>
추상 클래스는 직접적으로 인스턴스를 생성할 수 없습니다. 즉, <strong>추상 클래스로부터 객체를 생성할 수 없으며</strong>, 추상 클래스를 상속받아서 추상메소드를 구현한 <strong>하위 클래스를 통해서만 인스턴스를 생성할 수 있습니다.</strong> 또한 <U><strong>추상메소드가 있다면, 반드시 구현부를 작성해야합니다.</strong></U></p>
<br>
</li>
<li><p><strong>상속을 통한 확장</strong>
추상 클래스는 다른 클래스에게 공통된 메소드나 속성을 상속하여 코드의 재사용성을 높일 수 있습니다. <strong>하위 클래스에서는 추상 클래스의 추상 메소드를 구현하거나 재정의하여 사용할 수 있습니다.</strong></p>
<br>

</li>
</ol>
<h4 id="✨-잠깐-추상클래스가-일반메소드만-포함한다면">✨ 잠깐...! 추상클래스가 일반메소드만 포함한다면...?</h4>
<blockquote>
<p>원래 추상클래스는 추상메소드를 포함할때, 구현부가 없기때문에, 하위 클래스에서 구현한 뒤, 인스턴스를 생성할 수 있습니다만...</p>
<p>만약 추상클래스가 일반 메소드만 가지고 있다면, 하위 클래스에서 따로 구현할 필요 없이 바로 인스턴스를 생성해서 사용이 가능합니다.</p>
</blockquote>
<br>

<h4 id="✨-여기서-하나더-추상-메소드만-포함하는-추상클래스는-인터페이스와-뭐가-다르지">✨ 여기서 하나더... 추상 메소드만 포함하는 추상클래스는 인터페이스와 뭐가 다르지..?</h4>
<ol>
<li><p><strong>구현의 유연성</strong>
추상 클래스의 하위 클래스는 원하는 메소드만 가져다 사용할 수 있지만, 인터페이스는 강제적으로 전부 구현해야합니다.</p>
<br>
</li>
<li><p><strong>다중 상속</strong>
자바는 단일 상속만 지원하기 때문에, 하나의 클래스가 여러개의 인터페이스를 구현할 수 있습니다. 이를 통해 다중 상속의 장점을 일부 활용할 수 있습니다. 하지만 추상클래스는 여러개의 추상 클래스를 동시에 상속받을 수 없습니다.</p>
<br>
</li>
<li><p><strong>관련성</strong>
추상 클래스는 주로 <code>is-a</code> 관계를 나타내는데 사용됩니다. 즉, <code>개(Dog)</code>는 <code>동물(Animal)</code>의 일종이므로 추상 클래스로 구현할 수 있습니다. <br><br> 반면 인터페이스는 <code>can-do</code>의 관계를 나타내는데 사용됩니다. 즉, 클래스가 특정 동작을 할 수 있는지 여부를 나타내는데 사용됩니다. 예를 들어<code>날수있는(Flyable)</code>또는 <code>수행할 수 있는(Perfomable)</code>등의 동작을 나타내는 인터페이스를 구현할 수 있습니다.</p>
<br>
</li>
<li><p><strong>용도</strong>
추상 클래스는 클래스 간의 코드 재사용과 확장을 위해 사용됩니다. <br><br> 반면 인터페이스는 클래스 간의 느슨한 결합(loose coupling)을 위해 사용됩니다. 인터페이스를 통해 다양한 구현체를 대체할 수 있으며, 이는 유연하고 확장 가능한 설계를 위한 중요한 도구 입니다.</p>
</li>
</ol>
<p><br><br></p>
<h2 id="6-final-키워드">6. final 키워드</h2>
<blockquote>
<p><code>final</code> 키워드는 자바에서 변수, 메소드, 클래스에 적용될 수 있습니다.</p>
</blockquote>
<br>

<h4 id="6-1-변수에-적용할-때">6-1 변수에 적용할 때</h4>
<p>&amp;nbsp 변수에 <code>final</code> 키워드를 사용하면 해당 변수는 상수(Constant)로 선언됩니다. 한 번 초기화된 이후에는 값을 변경할 수 없게됩니다.</p>
<pre><code class="language-java">final int MAX_SIZE = 10; // final 변수 선언과 동시에 초기화

final double PI; // final 변수 선언
PI = 3.14; // 생성자에서 final 변수 초기화</code></pre>
<br>

<h4 id="6-2-메소드에-적용할-때">6-2 메소드에 적용할 때</h4>
<p>&amp;nbsp 메소드에 <code>final</code> 키워드를 사용하면 해당 메소드는 <strong>하위 클래스에서 오버라이딩(재정의)할 수 없습니다.</strong> 즉, final 메소드는 부모 클래스에서 정의된 그대로의 동작을 보장하게 됩니다.</p>
<pre><code class="language-java">class Parent {
    final void doSomething() { // final 메소드
        // 메소드 구현
    }
}

class Child extends Parent {
    // 오버라이딩을 시도하면 컴파일 에러 발생
    // void doSomething() {
    //     // 오버라이딩 불가
    // }
}</code></pre>
<br>

<h4 id="6-3-클래스에-적용할때">6-3 클래스에 적용할때</h4>
<p>&amp;nbsp 클래스에 <code>final</code> 키워드를 사용하면 해당 클래스는 상속될 수 없게 됩니다. 즉, <code>final</code> 클래스는 <strong>다른 클래스에서 확장될 수 없습니다.</strong></p>
<pre><code class="language-java">final class FinalClass {
    // 클래스 내용
}

// FinalClass를 상속하려고 하면 컴파일 에러 발생
// class SubClass extends FinalClass {
//     // 상속 불가
// }</code></pre>
<br>

<h4 id="결론">결론</h4>
<p><code>final</code> 키워드는 코드의 안정성과 확장성을 높이는데 사용됩니다. <code>final</code> 변수는 변하지 않는 값으로사용되며, <code>final</code> 메소드와 클래스는 의도적으로 오버라이딩이나, 상속을 제한하여 코드의 안정성을 확보합니다.</p>
<p><br><br></p>
<h2 id="7-object-클래스">7. Object 클래스</h2>
<blockquote>
<p><code>Object</code> 클래스는 자바에서 모든 클래스의 최상위 부모 클래스이며, <strong>모든 클래스는</strong> <code>Object</code> <strong>클래스에서 상속을 받습니다.</strong> 따라서 자바에서 정의된 모든 클래스는 <code>Object</code> 클래스의 멤버들을 상속받아 사용할 수 있습니다. </p>
</blockquote>
<h4 id="object-클래스가-포함하는-주요-메소드">Object 클래스가 포함하는 주요 메소드</h4>
<ol>
<li><p><strong>equals(Object obj)</strong>
객체의 동등성을 확인하기 위해 사용됩니다. 두 객체가 동일한 값을 가지는지 비교하여 <code>true</code> 또는 <code>false</code>를 반환합니다. <br><br> 기본적으로는 객체의 <code>참조 값(identity)</code>을 비교하지만, 클래스에서 이 메소드를오버라이딩 하여 동등성 비교를 사용자 정의할 수 있습니다.</p>
<br>
</li>
<li><p><strong>hashCode()</strong>
객체의 해시 코드 값을 반환합니다. 이 메소드는 객체를 저장허거나 검색하는데 사용되는 해시 기반 컬렉션에서 객체를 식별하는 데 사용됩니다. <br><br> <code>equals</code> 메소드를 오버라이딩한 경우에는 <code>hashCode</code> 메소드도 함께 오버라이딩하여 일관성을 유지해야합니다.</p>
<br>
</li>
<li><p><strong>toString()</strong>
객체의 문자열 표현을 반환합니다. 기본적으로는 객체의 클래스 이름과 해시 코드 값을 반환하지만, 클래스에서 이 메소드를 오버라이딩 하여 사용자 정의 문자열 표현을 제공할 수 있습니다.</p>
<br>
</li>
<li><p><strong>getClass()</strong>
객체의 클래스를 나타내는 <code>Class</code> 객체를 반환합니다. <code>Class</code> 객체는 클래스에 대한 정보를 제공하며, <code>리플랙션(reflection)</code>을 통해 클래스의 메타 데이터를 다룰 수 있게 해줍니다.</p>
<br>
</li>
<li><p><strong>clone()</strong>
객체의 <code>얕은 복사(Shallow Copy)</code>를 생성하여 반환합니다. 이 메소드는 Cloneable 인터페이스를 구현한 클래스에서만  사용할 수 있으며, 클래스 에서 이 메소드를 오버라이딩 하여 <code>깊은 복사(Deep Copy)</code>를 수행할 수 있습니다.</p>
<br>
</li>
<li><p><strong>finalize()</strong>
객체가 더 이상 사용되지 않을 때 가비지 컬렉터에 의해 호출되는 메소드입니다. 이 메소드는 자원의 해제나 정리 작업을 수행할 수 있습니다.</p>
<br>

</li>
</ol>
<h4 id="정리">정리</h4>
<p>&amp;nbsp <code>Object</code> 클래스의 이러한 메소드들은 모든 자바 클래스에서 사용할 수 있으며, 필요에 따라 클래스에서 이러한 메소드를 오버라이딩하여 특정 동작을 정의할 수 있습니다.</p>
<p><br><br></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[다이아 몬드 문제(Diamond Problem)]]></title>
            <link>https://velog.io/@ha_bu/%EB%8B%A4%EC%9D%B4%EC%95%84-%EB%AA%AC%EB%93%9C-%EB%AC%B8%EC%A0%9CDiamond-Problem</link>
            <guid>https://velog.io/@ha_bu/%EB%8B%A4%EC%9D%B4%EC%95%84-%EB%AA%AC%EB%93%9C-%EB%AC%B8%EC%A0%9CDiamond-Problem</guid>
            <pubDate>Thu, 06 Jun 2024 11:46:51 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>나, D는 
  B의 말을 들어야할것인가...<br>  C의 말을 들어야 할것인가...<br>  아주 모호해요... 아주 곤란하군요...</p>
</blockquote>
<br>

<h3 id="다이아몬드-문제diamond-problem">다이아몬드 문제(Diamond Problem)</h3>
<p>&amp;nbsp 다이아몬드 문제는 객체 지향 프로그래밍에서 다중 상속을 지원하는 언어에서 발생할 수 있는 모호성 문제입니다.</p>
<p>&amp;nbsp 이는 <strong><U>두 개 이상의 부모 클래스가 동일한 메소드</U>를 가지며, 자식 클래스가 이를 상속받을 때 <U>어떤 부모 클래스의 메소드를 상속받아야 하는지 모호해지는 상황</U>을 의미합니다.</strong></p>
<p><br><br></p>
<h3 id="다이아몬드-문제의-구조">다이아몬드 문제의 구조</h3>
<p>&amp;nbsp 다이아몬드 문제는 다음과 같은 구조를 가집니다.</p>
<blockquote>
<ol>
<li>두 클래스(<code>B</code> 와 <code>C</code>)가 하나의 클래스(<code>A</code>)를 상속받습니다.</li>
<li>또 다른 클래스(<code>D</code>)가 <code>B</code>와 <code>C</code>를 동시에 상속받습니다.</li>
</ol>
</blockquote>
<p>&amp;nbsp 이러한 상속 구조가 다이아몬드 형태를 이루기 때문에 다이아 몬드 문제라고 불립니다.</p>
<pre><code class="language-css">      A
     / \
    B   C
     \ /
      D</code></pre>
<p><br><br></p>
<h3 id="다이아-몬드-문제의-예시">다이아 몬드 문제의 예시</h3>
<p>&amp;nbsp 다중 상속을 지원하는 언어(C++ 등)에서 다이아몬드 문제는 아래와 같은 코드로 나타낼 수 있습니다.</p>
<pre><code class="language-cpp">class A {
public:
    void sayHello() {
        std::cout &lt;&lt; &quot;Hello from A&quot; &lt;&lt; std::endl;
    }
};

class B : public A { };

class C : public A { };

class D : public B, public C { };

int main() {
    D d;
    d.sayHello(); // 모호성 문제 발생
    return 0;
}</code></pre>
<p>&amp;nbsp 위 코드에서 <code>D</code>클래스는 <code>B</code>와 <code>C</code>를 상속 받습니다. 그러나 <code>B</code>와 <code>C</code>는 모두 <code>A</code>를 상속받고 있으며, <code>A</code>클래스의 <code>sayHello</code> 메소드를 가지고 있습니다. 이로 인해 <code>D</code> 클래스의 인스턴스에서 <code>sayHello</code> 메소드를 호출할 때 문제가 발생합니다.</p>
<blockquote>
<p><code>B</code>를 통해 상속받은 <code>A</code>의 <code>sayHello</code>인지, <code>C</code>를 통해 상속받은 <code>A</code>의 <code>sayHello</code>인지 모호해지게 됩니다.</p>
</blockquote>
<p>** 참고 **</p>
<p>&amp;nbsp 위의 C++ 코드는 컴파일 에러가 발생하게 됩니다. 위 상황같은 다이아몬드 문제를 해결하려면 </p>
<ol>
<li>가상 상속(Virtual Inheritance)<ul>
<li><code>virtual</code> 키워드를 사용하여 하나의 공통 부모 클래스를 명시적으로 상속받게 합니다.</li>
</ul>
</li>
<li>명시적 호출(Explicit Call)<ul>
<li>특정 부모 클래스의 메소드를 명시적으로 호출하여 모호성을 해결합니다.</li>
</ul>
</li>
</ol>
<p>이러한 2가지 방법을 통해 해결할 수 있습니다.</p>
<p><br><br></p>
<h3 id="자바에서의-해결책-인터페이스">자바에서의 해결책. 인터페이스</h3>
<p>&amp;nbsp 자바는 <strong>클래스 간의 다중 상속을 지원하지 않기 때문</strong>에 다이아몬드 문제가 발생하지 않습니다. 대신, 자바는 <strong>인터페이스를 사용</strong>하여 다중 상속의 유연성을 제공합니다.</p>
<p>&amp;nbsp 인터페이스는 구현만을 강제할 뿐, 상태(필드)를 가지지 않기 때문에 다이아몬드 문제가 발생하지 않습니다.</p>
<pre><code class="language-java">interface A {
    void sayHello();
}

interface B extends A { }

interface C extends A { }

class D implements B, C {
    @Override
    public void sayHello() {
        System.out.println(&quot;Hello from D&quot;);
    }
}

public class Main {
    public static void main(String[] args) {
        D d = new D();
        d.sayHello(); // Hello from D
    }
}</code></pre>
<p>&amp;nbsp 위 코드에서 <code>D</code> 클래스는 <code>B</code>와 <code>C</code>인터페이스를 구현합니다. <code>B</code>와 <code>C</code>는 모두 <code>A</code> 인터페이스를 상속받지만, <code>D</code> 클래스가 <code>sayHello</code> 메소드를 구현하기 때문에 모호성 문제가 발생하지 않습니다.</p>
<pre><code class="language-java">interface A {
    void sayHello();
}

interface B extends A { }

interface C extends A { }

class D implements B, C {
    @Override
    public void sayHello() {
        System.out.println(&quot;Hello from D&quot;);
    }
}

public class Main {
    public static void main(String[] args) {
        D d = new D();
        d.sayHello(); // Hello from D
    }
}</code></pre>
<p>&amp;nbsp 위 코드에서 <code>D</code> 클래스는 <code>B</code>와 <code>C</code> 인터페이스를 구현합니다. <code>B</code>와 <code>C</code>는 모두 <code>A</code> 인터페이스를 상속받지만, <code>D</code> 클래스가 <code>sayHello</code> 메소드를 구현하기 때문에 모호성 문제가 발생하지 않습니다. </p>
<p><br><br></p>
<h3 id="인터페이스의-기본-메소드">인터페이스의 기본 메소드</h3>
<p>&amp;nbsp 자바 8부터 인터페이스는 기본 메소드(Default Method)를 가질 수 있습니다. 기본 메소드는 구현을 포함할 수 있기 때문에 다이아몬드 문제가 다시 발생할 가능성이 있습니다.</p>
<blockquote>
<p>자바는 이를 해결하기 위해 명시적인 방법을 제시했습니다.</p>
</blockquote>
<pre><code class="language-java">interface A {
    default void sayHello() {
        System.out.println(&quot;Hello from A&quot;);
    }
}

interface B extends A {
    @Override
    default void sayHello() {
        System.out.println(&quot;Hello from B&quot;);
    }
}

interface C extends A { }

class D implements B, C {
    @Override
    public void sayHello() {
        B.super.sayHello(); // 명시적으로 B의 sayHello 호출
    }
}

public class Main {
    public static void main(String[] args) {
        D d = new D();
        d.sayHello(); // Hello from B
    }
}</code></pre>
<p>&amp;nbsp 위 코드에서 <code>D</code> 클래스는 <code>B</code>와 <code>C</code> 인터페이스를 구현합니다. <code>B</code>는 <code>A</code>의 <code>sayHello</code> 메소드를 오버라이드 하여 새로운 구현을 제공합니다. <code>D</code> 클래스는 <code>sayHello</code> 메소드에서 <code>B</code>의 <code>sayHello</code> 메소드를 명시적으로 호출합니다.</p>
<p><br><br></p>
<h3 id="요약">요약</h3>
<ul>
<li><p>다이아몬드 문제: 다중 상속으로 인해 어떤 부모 클래스의 메소드를 상속받아야 할지 모호해지는 문제가 발생합니다.</p>
</li>
<li><p>자바에서의 해결책: 자바는 클래스의 다중 상속을 지원하지않지만, 인터페이스를 통해 다중 상속의 유연성을 제공합니다.</p>
</li>
<li><p>기본 메소드: 자바 8부터 인터페이스는 기본 메소드를 가질 수 있으며, 다이아몬드 문제를 명시적으로 해결할 수 있는 방법을 제공합니다.</p>
</li>
</ul>
<p><br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><br><br></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[클래스]]></title>
            <link>https://velog.io/@ha_bu/%ED%81%B4%EB%9E%98%EC%8A%A4</link>
            <guid>https://velog.io/@ha_bu/%ED%81%B4%EB%9E%98%EC%8A%A4</guid>
            <pubDate>Sun, 02 Jun 2024 11:19:33 GMT</pubDate>
            <description><![CDATA[<h2 id="목표">목표</h2>
<blockquote>
<p>자바의 Class에 대해 학습</p>
</blockquote>
<h3 id="목차">목차</h3>
<p><a href="#1-%ED%81%B4%EB%9E%98%EC%8A%A4-%EC%A0%95%EC%9D%98%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95">1. 클래스 정의하는 방법</a>
<a href="#2-%EA%B0%9D%EC%B2%B4-%EB%A7%8C%EB%93%9C%EB%8A%94-%EB%B0%A9%EB%B2%95">2. 객체 만드는 방법 (new 키워드 이해하기)</a>
<a href="#3-%EB%A9%94%EC%86%8C%EB%93%9C-%EC%A0%95%EC%9D%98%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95">3. 메소드 정의하는 방법</a>
<a href="#4-%EC%83%9D%EC%84%B1%EC%9E%90-%EC%A0%95%EC%9D%98%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95">4. 생성자 정의하는 방법</a>
<a href="#5-this-%ED%82%A4%EC%9B%8C%EB%93%9C-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0">5. this 키워드 이해하기</a></p>
<br>

<h2 id="1-클래스-정의하는-방법">1. 클래스 정의하는 방법</h2>
<blockquote>
<p>자바에서 클래스는 객체를 생성하기 위한 청사진(blueprint) 역할을 하며, <strong>속성(필드)</strong>과 <strong>동작(메소드)</strong>를 정의하여 사용합니다.</p>
</blockquote>
<h4 id="1-1-클래스의-정의">1-1 클래스의 정의</h4>
<p>&amp;nbsp 클래스는 <code>class</code> 키워드를 사용하여 정의합니다. 기본적인 구조는 아래와 같습니다.</p>
<br>

<pre><code class="language-java">public class ClassName {
    // 필드 (속성)
    // 생성자
    // 메소드 (동작)
}</code></pre>
<ul>
<li><p>여기서 <code>public</code>은 <strong>접근 제어자</strong> 입니다. 이 위치에 클래스에 접근할 수 있는 범위를 지정할 수 있습니다.</p>
</li>
<li><p><code>className</code>은 클래스의 이름입니다. <strong><em>클래스 이름은 대문자로 시작하는것</em></strong>이 관례라고 합니다.</p>
</li>
</ul>
<br>

<h4 id="1-2-필드속성-정의">1-2 필드(속성) 정의</h4>
<blockquote>
<p>필드는 클래스의 상태를 저장하는 변수입니다.</p>
</blockquote>
<p>예시)</p>
<pre><code class="language-java">public class Car {
    // 필드
    private String color;
    private String model;
    private int year;
}</code></pre>
<p>&amp;nbsp <code>car</code> 라는 클래스에 색상, 모델, 만들어진 연도 등의 정보를 담을 수 있겠습니다. 위 클래스를 통해 만들어지는 <code>car</code>들은 각각 다른 정보드를 가지고 있을 수 있습니다. 그렇기 때문에 <strong>청사진(blueprint, 여러번 찍어낼 수 있는..)</strong>와 비슷하다고 이해하면 알기 쉽습니다.</p>
<p>** ※ 여기서 <code>private</code>는 접근 제어자 중 하나로, 해당 필드가 클래스 내부에서만 접근 가능하도록 합니다. **</p>
<br>

<h4 id="1-3-생성자-정의">1-3 생성자 정의</h4>
<blockquote>
<p>생성자는 클래스의 인스턴스가 생성될 때 호출 되며, 주로 필드를 초기화하는 데 사용됩니다. <strong>생성자의 이름은 클래스의 이름과 같아야 하며, 반환타입이 없습니다.</strong></p>
</blockquote>
<br>

<h4 id="1-4-메소드-동작-정의">1-4 메소드 (동작) 정의</h4>
<blockquote>
<p>메소드는 클래스의 동작을 정의합니다. 메소드는 특정 작업을 수행하는 코드 블럭입니다.</p>
</blockquote>
<p>예시)</p>
<pre><code class="language-java">public class Car {
    private String color;
    private String model;
    private int year;

    public Car(String color, String model, int year) {
        this.color = color;
        this.model = model;
        this.year = year;
    }

    // 메소드
    public void startEngine() {
        System.out.println(&quot;Engine started&quot;);
    }

    public void stopEngine() {
        System.out.println(&quot;Engine stopped&quot;);
    }

    public String getColor() {
        return this.color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public String getModel() {
        return this.model;
    }

    public void setModel(String model) {
        this.model = model;
    }

    public int getYear() {
        return this.year;
    }

    public void setYear(int year) {
        this.year = year;
    }
}</code></pre>
<h4 id="설명">설명</h4>
<ol>
<li><code>public</code> 메소드는 클래스 외부에서도 접근할 수 있습니다.</li>
<li><code>void</code>는 반환 타입으로, 해당 메소드는 값을 반환하지 않음을 의미합니다.</li>
<li>메소드 이름은 소문자로 시작하며, 동사형을 사용하는 것이 관례입니다.</li>
<li><code>getColor</code>와 <code>setColor</code>메소드는 필드에 접근하고 수정하는 데 사용되는 getter와 setter 메소드입니다. <strong>이를 통해 private 로 지정된 필드에 접근할 수 있습니다.</strong></li>
</ol>
<p><br><br></p>
<h2 id="2-객체-만드는-방법">2. 객체 만드는 방법</h2>
<blockquote>
<p>객체는 위에서 설명한 class를 기반으로 생성이 되며, <strong>객체는 클래스의 <U>인스턴스</U>라고도 불리웁니다.</strong> 객체는 클래스로 부터 생성된 실제 존재하는 개체를 의미한다고 볼 수 있겠습니다.</p>
</blockquote>
<h4 id="2-1-객체-생성">2-1 객체 생성</h4>
<p>&amp;nbsp 객체를 생성하려면 <code>new</code> 키워드를 사용하여 클래스의 생성자를 호출합니다. 기본적인 형시은 아래와 같습니다.</p>
<pre><code class="language-java">ClassName objectName = new ClassName(parameters);</code></pre>
<ul>
<li><code>className</code>은 객체를 생성할 클래스의 이름입니다.</li>
<li><code>objectName</code>은 생성된 객체를 참조할 변수의 이름입니다.</li>
<li><code>new</code> 키워드는 객체를 힙 메모리에 생성합니다.</li>
<li><code>ClassName(parameters)</code>는 클래스의 생성자를 호출합니다. <code>parameters</code>는 생성자가 필요로 하는 인자입니다.</li>
</ul>
<br>

<p>&amp;nbsp 기껏 위에서 <code>Car</code>클래스를 만들어 두었으니, 이를 사용해 예시를 보여드리겠습니다.</p>
<pre><code class="language-java">public class Main {
    public static void main(String[] args) {
        // Car 객체 생성
        Car myCar = new Car(&quot;Red&quot;, &quot;KIA&quot;, 2020);

        // 객체의 메소드 호출
        myCar.startEngine(); 
        // 출력: Engine started
        System.out.println(&quot;Car color: &quot; + myCar.getColor()); // 출력: Car color: Red

        // 객체의 필드 변경
        myCar.setColor(&quot;Blue&quot;);
        System.out.println(&quot;Updated car color: &quot; + myCar.getColor()); 
        // 출력: Updated car color: Blue

        // 다른 Car 객체 생성
        Car anotherCar = new Car(&quot;Black&quot;, &quot;HD&quot;, 2018);
        System.out.println(&quot;Another car model: &quot; + anotherCar.getModel()); 
        // 출력: Another car model: Honda
    }
}</code></pre>
<h4 id="2-2-객체-생성과-관련된-주요-개념">2-2 객체 생성과 관련된 주요 개념</h4>
<ul>
<li><p><strong>생성자</strong> : 생성자는 객체가 생성될 때 호출되는 특별한 메소드입니다. 객체의 필드를 초기화하는 역할을 합니다.</p>
</li>
<li><p><strong>필드 접근 및 수정</strong> : 객체의 필드를 직접 접근하거나 수정할 때는 보통 <strong>getter</strong>와 <strong>setter</strong> 메소드를 사용합니다. 이는 <strong>필드의 직접 접근을 막고 캡슐화를 유지하기 위해서입니다.</strong></p>
</li>
<li><p><strong>메소드 호출</strong> : 객체가 생성되면 객체의 메소드를 호출하여 다양한 동작을 수행할 수 있습니다.</p>
</li>
</ul>
<br>

<h4 id="2-3-여러-객체-생성">2-3 여러 객체 생성</h4>
<pre><code class="language-java">public class Main {
    public static void main(String[] args) {
        Car car1 = new Car(&quot;Red&quot;, &quot;Toyota&quot;, 2020);
        Car car2 = new Car(&quot;Blue&quot;, &quot;Honda&quot;, 2019);

        // 각 객체의 필드와 메소드에 독립적으로 접근 가능
        System.out.println(&quot;Car 1 color: &quot; + car1.getColor()); // 출력: Car 1 color: Red
        System.out.println(&quot;Car 2 color: &quot; + car2.getColor()); // 출력: Car 2 color: Blue

        car1.startEngine(); // 출력: Engine started
        car2.stopEngine();  // 출력: Engine stopped
    }
}</code></pre>
<p>&amp;nbsp 이처럼 클래스는 객체를 생성하기 위한 템플릿을 제공하며, 각 객체는 독립적인 필드와 메소드를 가집니다. 객체는 클래스의 인스턴스로, <code>new</code> 키워드를 통해 생성되고 생성자를 통해 초기화 됩니다.</p>
<p><br><br></p>
<h2 id="3-메소드-정의하는-방법">3. 메소드 정의하는 방법</h2>
<blockquote>
<p>자바에서 메소드는 특정 작업을 수행하기 위해 클래스 내에 정의된 코드 블록입니다. 메소드는 재사용 가능한 코드를 만들고, 객체의 행동을 정의하는 데 사용됩니다. 메소드 정의는 크게 두 가지 부분으로 나뉩니다. 여기서는 메소드 선언과 메소드 분문 이 두 부분을 보겠습니다.</p>
</blockquote>
<h4 id="3-1-메소드-선언">3-1 메소드 선언</h4>
<p>&amp;nbsp 메소드 선언은 메소드의 이름, 반환 타입, 매개변수 목록을 정의합니다. 기본적인 구조는 아래와 같습니다.</p>
<pre><code class="language-java">accessModifier returnType methodName(parameterList) {
    // 메소드 본문
}</code></pre>
<ul>
<li><p><code>accessModifier</code> : 메소드의 접근 제어자를 지정합니다. (예: <code>public</code>, <code>private</code>, <code>protected</code>, <code>default</code>)</p>
</li>
<li><p><code>returnType</code> : 메소드가 반환하는 값의 타입을 지정합니다. 반환값이 없는 경우, <code>void</code>를 사용합니다.</p>
</li>
<li><p><code>methodName</code> : 메소드가 받을 매개변수 목록을 정의합니다. 매개변수가 없으면 빈 괄호 <code>()</code>를 사용하면됩니다.</p>
</li>
</ul>
<br>

<blockquote>
<p>** 메소드 본문은 <code>{}</code>로 감싸며, 이 안에 실행할 코드를 작성합니다. **</p>
</blockquote>
<h4 id="예제">예제</h4>
<pre><code class="language-java">public class MathUtils {

    // 두 숫자의 합을 반환하는 메소드
    public int add(int a, int b) {
        return a + b;
    }

    // 두 숫자의 차를 반환하는 메소드
    public int subtract(int a, int b) {
        return a - b;
    }

    // 인삿말을 출력하는 메소드
    public void printGreeting(String name) {
        System.out.println(&quot;Hello, &quot; + name + &quot;!&quot;);
    }
}</code></pre>
<ul>
<li><p><code>add</code> : 두 정수를 입력받아, 합을 반환합니다. 여기서 알 수 있듯이, 반환 타입은 <code>int</code> 타입입니다.</p>
</li>
<li><p><code>subtract</code> : 두 정수를 입력받아 차를 반환합니다. 마찬가지로 <code>int</code> 타입을 반환합니다.</p>
</li>
<li><p><code>printGreeting</code> : 문자열을 입력받아 인사말을 출력합니다. 출력하고 끝이므로, 반환값이 없어 <code>void</code>입니다.</p>
</li>
</ul>
<br>

<h4 id="3-2-메소드-호출">3-2 메소드 호출</h4>
<p>&amp;nbsp 정의된 메소드는 클래스의 객체를 통해 호출할 수 있습니다.</p>
<pre><code class="language-java">public class Main {
    public static void main(String[] args) {
        // MathUtils 객체 생성
        MathUtils mathUtils = new MathUtils();

        // add 메소드 호출
        int sum = mathUtils.add(5, 3);
        System.out.println(&quot;Sum: &quot; + sum); 
        // 출력: Sum: 8

        // subtract 메소드 호출
        int difference = mathUtils.subtract(10, 4);
        System.out.println(&quot;Difference: &quot; + difference); 
        // 출력: Difference: 6

        // printGreeting 메소드 호출
        mathUtils.printGreeting(&quot;Alice&quot;); 
        // 출력: Hello, Alice!
    }
}</code></pre>
<br>

<h4 id="3-3-메소드-오버로딩">3-3 메소드 오버로딩</h4>
<blockquote>
<p>메소드 오버로딩은 <strong>동일한 이름의 메소드를 여러 개 정의</strong>하되, <strong>매개변수 목록이 다르도록 하는 것</strong>입니다.</p>
</blockquote>
<pre><code class="language-java">public class MathUtils {

    // 두 정수를 더하는 메소드
    public int add(int a, int b) {
        return a + b;
    }

    // 세 정수를 더하는 메소드 (오버로딩)
    public int add(int a, int b, int c) {
        return a + b + c;
    }

    // 두 실수를 더하는 메소드 (오버로딩)
    public double add(double a, double b) {
        return a + b;
    }
}</code></pre>
<h4 id="예제-1">예제</h4>
<pre><code class="language-java">public class Main {
    public static void main(String[] args) {
        MathUtils mathUtils = new MathUtils();

        int sum1 = mathUtils.add(1, 2);
        int sum2 = mathUtils.add(1, 2, 3);
        double sum3 = mathUtils.add(1.5, 2.5);

        System.out.println(&quot;Sum1: &quot; + sum1); 
        // 출력: Sum1: 3
        System.out.println(&quot;Sum2: &quot; + sum2); 
        // 출력: Sum2: 6
        System.out.println(&quot;Sum3: &quot; + sum3); 
        // 출력: Sum3: 4.0
    }
}</code></pre>
<br>

<h4 id="3-4-기타-중요-개념">3-4 기타 중요 개념</h4>
<ul>
<li><p><strong>반환 타입</strong> : 메소드는 작업을 수행한 결과를 호출자에게 반환할 수 있습니다. 반환 타입이 <code>void</code>가 아닌 경우 <code>return</code> 키워드를 사용하여 값을 반환합니다.</p>
</li>
<li><p><strong>매개변수</strong> : 메소드는 호출 시 전달받은 값을 매개변수를 통해 사용할 수 있습니다. 매개변수는 타입과 이름을 지정하여 선언합니다.</p>
</li>
<li><p><strong>접근 제어자</strong> : 메소드의 접근 수준을 정의합니다. <code>public</code>, <code>private</code>, <code>protected</code>, <code>default</code> 등이 있습니다.</p>
</li>
<li><p><strong>스코프</strong> : 메소드 내에서 선언된 변수는 해당 메소드 내에서만 유효합니다. 이를 지역 변수라고 합니다. </p>
</li>
</ul>
<blockquote>
<p>스코프 관련해서 <strong>call of value</strong> vs <strong>call of reference</strong> 를 한번 찾아 보시면 좋을것 같습니다.</p>
</blockquote>
<p>&amp;nbsp 이처럼 자바에서 메소드는 클래스의 동작을 정의하며, 메소드 선언과 본문을 통해 다양한 작업을 수행할 수 있습니다. <strong>메소드는 객체의 행동을 정의하고, <U>재사용 가능한 코드를 작성</U>하는 데 중요한 역할을 합니다.</strong></p>
<p><br><br></p>
<h2 id="4-생성자-정의하는-방법">4. 생성자 정의하는 방법</h2>
<blockquote>
<p>&amp;nbsp <strong>자바에서 생성자는 클래스의 인스턴스를 초기화하는 특별한 메소드입니다.</strong>  <br> </p>
<p>&amp;nbsp 생성자의 이름은 클래스의 이름과 같아야 하며, 반환 타입이 없습니다. 생성자는 객체가 생성될 때 호출되며, 객체의 필드를 초기화하거나 초기 설정 작업을 수행하는데 사용됩니다.</p>
</blockquote>
<h4 id="4-1-기본-생성자">4-1 기본 생성자</h4>
<p>&amp;nbsp 기본 생성자는 매개변수를 가지지 않는 생성자입니다. 클래스에 명시적으로 생성자를 정의하지 않으면 컴파일러가 자동으로 기본 생성자를 제공합니다.</p>
<p>&amp;nbsp 하지만 생성자가 하나라도 명시적으로 정의되어 있으면 기본 생성자는 자동으로 제공되지 않습니다.</p>
<pre><code class="language-java">public class Car {
    private String color;
    private String model;
    private int year;

    // 기본 생성자
    public Car() {
        // 필드 초기화 (기본값)
        this.color = &quot;Unknown&quot;;
        this.model = &quot;Unknown&quot;;
        this.year = 0;
    }
}</code></pre>
<br>

<h4 id="4-2-매개변수가-있는-생성자">4-2 매개변수가 있는 생성자</h4>
<p>&amp;nbsp 매개변수가 있는 생성자는 객체를 생성할 때 필요한 값을 전달받아 필드를 초기화 합니다.</p>
<pre><code class="language-java">public class Car {
    private String color;
    private String model;
    private int year;

    // 매개변수가 있는 생성자
    public Car(String color, String model, int year) {
        this.color = color;
        this.model = model;
        this.year = year;
    }
}</code></pre>
<br>

<h4 id="4-3-여러-생성자생성자-오버로딩">4-3 여러 생성자(생성자 오버로딩)</h4>
<p>&amp;nbsp 클래스는 여러 개의 생성자를 가질 수 있으며, 이를 생성자 오버로딩이라고 합니다. 각 생성자는 다른 매개변수 목록을 가질 수 있습니다.</p>
<pre><code class="language-java">public class Car {
    private String color;
    private String model;
    private int year;

    // 기본 생성자
    public Car() {
        this.color = &quot;Unknown&quot;;
        this.model = &quot;Unknown&quot;;
        this.year = 0;
    }

    // 매개변수가 있는 생성자
    public Car(String color, String model, int year) {
        this.color = color;
        this.model = model;
        this.year = year;
    }

    // 일부 필드만 초기화하는 생성자
    public Car(String color, String model) {
        this.color = color;
        this.model = model;
        this.year = 0;
    }
}</code></pre>
<br>

<h4 id="4-4-생성자-호출">4-4 생성자 호출</h4>
<p>&amp;nbsp 생성자는 <code>new</code> 키워드를 사용하여 객체를 생성할 때 호출됩니다. 예신느 아래와 같습니다.</p>
<h4 id="예시">예시</h4>
<pre><code class="language-java">public class Main {
    public static void main(String[] args) {
        // 기본 생성자를 사용하여 객체 생성
        Car defaultCar = new Car();
        System.out.println(&quot;Default car: &quot; + defaultCar.getColor() + &quot;, &quot; + defaultCar.getModel() + &quot;, &quot; + defaultCar.getYear());

        // 매개변수가 있는 생성자를 사용하여 객체 생성
        Car myCar = new Car(&quot;Red&quot;, &quot;KIA&quot;, 2020);
        System.out.println(&quot;My car: &quot; + myCar.getColor() + &quot;, &quot; + myCar.getModel() + &quot;, &quot; + myCar.getYear());

        // 일부 필드만 초기화하는 생성자를 사용하여 객체 생성
        Car anotherCar = new Car(&quot;Blue&quot;, &quot;HD&quot;);
        System.out.println(&quot;Another car: &quot; + anotherCar.getColor() + &quot;, &quot; + anotherCar.getModel() + &quot;, &quot; + anotherCar.getYear());
    }
}</code></pre>
<h4 id="출력">출력</h4>
<pre><code class="language-java">Default car: Unknown, Unknown, 0
My car: Red, KIA, 2020
Another car: Blue, HD, 0</code></pre>
<h4 id="4-5-주의-사항">4-5 주의 사항</h4>
<ul>
<li><p>생성자는 클래스의 이름과 동일해야 하며, 반환 타입이 없어야 합니다.</p>
</li>
<li><p>생성자는 오버로딩이 가능하므로 여러개 정의할 수 있습니다.</p>
</li>
<li><p>하나의 생성자에서 다른 생성자를 호출할 때는 <code>this</code> 키워드를 사용하며, 이 경우 호출하는 구문은 반드시 첫 번째 줄에 위치해야 합니다.</p>
</li>
</ul>
<h4 id="결론">결론</h4>
<p>&amp;nbsp 생성자는 클래스의 인스턴스를 초기화하는데 중요한 역할을 하며, 객체가 생성될 때 필드의 초기값을 설정하거나 초기 설정 작업을 수행합니다.</p>
<p>&amp;nbsp 생성자 오버로딩을 통해 다양한 방법으로 객체를 생성할 수 있으며, <code>this</code> 키워드를 사용하여 코드의 중복을 줄일 수 있습니다.</p>
<p><br><br></p>
<h2 id="5-this-키워드-이해하기">5. this 키워드 이해하기</h2>
<blockquote>
<p>&amp;nbsp <code>this</code> 키워드는 자바에서 중요한 개념 중 하나로, 현재 객체 자신을 참조하는 데 사용됩니다.</p>
<p>&amp;nbsp <code>this</code> 키워드를 이해하면 객체 지향 프로그래밍에서 객체와 인스턴스 변수를 다루는 방법을 명확히 이해할 수 있습니다.</p>
</blockquote>
<h4 id="5-1-현재-객체-참조">5-1 현재 객체 참조</h4>
<p>&amp;nbsp <code>this</code> 키워드는 클래스의 인스턴스 메소드나 생성자 내에서 현재 객체를 참조합니다. 이는 <strong>메소드나 생성자에서 클래스의 필드와 메소드를 명확하게 접근할 수 있도록 합니다.</strong></p>
<br>

<h4 id="5-2-인스턴스-변수와-로컬-변수-구분">5-2 인스턴스 변수와 로컬 변수 구분</h4>
<p>&amp;nbsp 가장 일반적인 사용 사례는 인스턴스 변수와 로컬 변수의 이름이 동일할 때, 이를 구분하는 것입니다. <code>this</code> 키워드는 인스턴스 변수를 명확하게 참조하는데 사용됩니다.</p>
<pre><code class="language-java">public class Car {
    private String color;
    private String model;
    private int year;

    // 생성자
    public Car(String color, String model, int year) {
        this.color = color;  
        // this.color는 인스턴스 변수, color는 매개변수
        this.model = model;  
        // this.model는 인스턴스 변수, model은 매개변수
        this.year = year;    
        // this.year는 인스턴스 변수, year는 매개변수
    }

    // 인스턴스 메소드
    public void setColor(String color) {
        this.color = color;  
        // this.color는 인스턴스 변수, color는 매개변수
    }
}</code></pre>
<br>

<h4 id="5-3-생성자에서-다른-생성자-호출">5-3 생성자에서 다른 생성자 호출</h4>
<p>&amp;nbsp <code>this</code> 키워드는 같은 클래스 내의 다른 생성자를 호출할 때 사용됩니다. 이를 통해 코드의 중복을 줄이고, 공통 초기화 로직을 하나의 생성자로 집중시킬 수 있습니다.</p>
<p>&amp;nbsp 이때 <code>this</code> 키워드를 사용한 생성자 호출은 반드시 생성자의 첫 번째 줄에 위치해야 합니다.</p>
<pre><code class="language-java">public class Car {
    private String color;
    private String model;
    private int year;

    // 기본 생성자
    public Car() {
        this(&quot;Unknown&quot;, &quot;Unknown&quot;, 0); 
        // 다른 생성자 호출
    }

    // 매개변수가 있는 생성자
    public Car(String color, String model, int year) {
        this.color = color;
        this.model = model;
        this.year = year;
    }

    // 일부 필드만 초기화하는 생성자
    public Car(String color, String model) {
        this(color, model, 0); // 다른 생성자 호출
    }
}</code></pre>
<br>

<h4 id="5-4-메소드-체이닝method-chaining">5-4 메소드 체이닝(Method Chaining)</h4>
<p>&amp;nbsp <code>this</code> 키워드는 메소드 체이닝을 구현할 때 사용됩니다. 메소드 체이닝은 객체의 메소드를 연속적으로 호출 할 수 있게 하는 패턴입니다. 이를 위해 메소드가 <code>this</code>를 반환하도록 정의됩니다.</p>
<pre><code class="language-java">public class Car {
    private String color;
    private String model;
    private int year;

    // 생성자
    public Car(String color, String model, int year) {
        this.color = color;
        this.model = model;
        this.year = year;
    }

    // 메소드 체이닝을 위한 메소드
    public Car setColor(String color) {
        this.color = color;
        return this;  // 현재 객체 반환
    }

    public Car setModel(String model) {
        this.model = model;
        return this;  // 현재 객체 반환
    }

    public Car setYear(int year) {
        this.year = year;
        return this;  // 현재 객체 반환
    }
}

// 메소드 체이닝 사용 예
public class Main {
    public static void main(String[] args) {
        Car myCar = new Car(&quot;Red&quot;, &quot;Toyota&quot;, 2020);
        myCar.setColor(&quot;Blue&quot;)
             .setModel(&quot;Honda&quot;)
             .setYear(2022);

        System.out.println(&quot;Car: &quot; + myCar.getColor() + &quot;, &quot; + myCar.getModel() + &quot;, &quot; + myCar.getYear());
    }
}</code></pre>
<br>

<h4 id="5-5-내부-클래스에서-외부-클래스-참조">5-5 내부 클래스에서 외부 클래스 참조</h4>
<p>&amp;nbsp 내부 클래스에서 외부 클래스의 인스턴스를 참조할 때 <code>outerClass.this</code> 형식을 사용합니다.</p>
<pre><code class="language-java">public class OuterClass {
    private int outerValue = 10;

    public class InnerClass {
        private int innerValue = 20;

        public void display() {
            System.out.println(&quot;Outer value: &quot; + OuterClass.this.outerValue);
            System.out.println(&quot;Inner value: &quot; + this.innerValue);
        }
    }
}

// 사용 예
public class Main {
    public static void main(String[] args) {
        OuterClass outer = new OuterClass();
        OuterClass.InnerClass inner = outer.new InnerClass();
        inner.display();
    }
}</code></pre>
<br>

<h4 id="요약">요약</h4>
<ul>
<li><p><strong>현재 객체 참조</strong> : <code>this</code> 키워드는 현재 객체를 참조합니다.</p>
</li>
<li><p><strong>인스턴스 변수와 로컬 변수 구분</strong> : <code>this</code>를 사용화여 인스턴스 변수와 로컬 변수를 구분합니다.</p>
</li>
<li><p><strong>다른 생성자 호출</strong> : 생성자 내에서 다른 생성자를 호출할 때 <code>this</code>를 사용합니다.</p>
</li>
<li><p><strong>메소드 체이닝</strong> : <code>this</code>를 반환하여 메소드 체이닝을 구현할 수 있습니다.</p>
</li>
<li><p><strong>내부 클래스에서 외부 클래스 참조</strong> : 내부 클래스에서 외부 클래스의 인스턴스를 참조할 때 사용됩니다.</p>
</li>
</ul>
<br>

<p>&amp;nbsp <code>this</code> 키워드는 객체 지향 프로그래밍에서 중요한 역할을 하며, 이를 잘 활용하면 코드의 가독성과 재사용성을 높일 수 있습니다.</p>
<p><br><br></p>
<p><br><br></p>
<p><br><br></p>
<p><br><br></p>
<p><br><br></p>
<p><br><br></p>
<p><br><br></p>
<p><br><br></p>
<p><br><br></p>
<p><br><br></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[제어문]]></title>
            <link>https://velog.io/@ha_bu/%EC%A0%9C%EC%96%B4%EB%AC%B8</link>
            <guid>https://velog.io/@ha_bu/%EC%A0%9C%EC%96%B4%EB%AC%B8</guid>
            <pubDate>Mon, 27 May 2024 07:01:40 GMT</pubDate>
            <description><![CDATA[<h2 id="목표">목표</h2>
<blockquote>
<p>자바가 제공하는 제어문을 학습</p>
</blockquote>
<h3 id="목차">목차</h3>
<p><a href="#1-%EC%84%A0%ED%83%9D%EB%AC%B8">1. 선택문</a>
<a href="#2-%EB%B0%98%EB%B3%B5%EB%AC%B8">2. 반복문</a></p>
<br>

<h2 id="1-선택문">1. 선택문</h2>
<p>&amp;nbsp 크게 if문과 switch 문이 존재합니다. 먼저 if 문을 살펴보겠습니다.</p>
<h4 id="1-if문">1) if문</h4>
<pre><code class="language-java">int number = 0;
if (number &gt; 0) {
    System.out.println(&quot;The number is positive.&quot;);
} else if (number &lt; 0) {
    System.out.println(&quot;The number is negative.&quot;);
} else {
    System.out.println(&quot;The number is zero.&quot;);
}</code></pre>
<p>&amp;nbsp 가장먼저 if문 내부의 조건을 확인합니다. 순차적으로 조건을 검사하며, 첫 번째 참인 조건의 코드 블록을 실행합니다. 만약 마지막까지 조건이 일치하지 않는다면, else문의 코드블럭을 실행합니다.</p>
<h4 id="2-switch문">2) switch문</h4>
<p>&amp;nbsp switch 문은 하나의 변수 값에 따라 여러 코드 블록 중 하나를 실행할 때 사용합니다. switch 문은 <code>정수</code>, <code>문자열</code>, <code>열거형(enum)</code> 값에 대해 사용할 수 있습니다.</p>
<pre><code class="language-java">int day = 3;
switch (day) {
    case 1:
        System.out.println(&quot;1&quot;);
        break;
    case 2:
        System.out.println(&quot;2&quot;);
        break;
    case 3:
        System.out.println(&quot;3&quot;);
        break;
    default:
        System.out.println(&quot;Invalid num&quot;);
        break;
}</code></pre>
<blockquote>
<p><code>break</code>: 각 <code>case</code>블록의 끝에 사용되며, 해당 블록이 실행된 후 <code>switch</code>문을 빠져나갑니다. <code>break</code><strong>를 사용하지 않으면, 다음 **<code>case</code></strong>블럭이 실행됩니다.**</p>
</blockquote>
<h4 id="3-java13의-switch-표현식">3) Java13의 switch 표현식</h4>
<p>&amp;nbsp 이전 포스팅에서도 소개하였지만, Java13부터 <code>switch</code>문은 표현식으로 사용될 수 있으며, <code>yield</code> 키워드를 사용하여 값을 반환할 수 있습니다. </p>
<h4 id="예시-1">예시 1</h4>
<pre><code class="language-java">int day = 3;
String dayName = switch (day) {
    case 1 -&gt; &quot;Monday&quot;;
    case 2 -&gt; &quot;Tuesday&quot;;
    case 3 -&gt; &quot;Wednesday&quot;;
    case 4 -&gt; &quot;Thursday&quot;;
    case 5 -&gt; &quot;Friday&quot;;
    case 6 -&gt; &quot;Saturday&quot;;
    case 7 -&gt; &quot;Sunday&quot;;
    default -&gt; &quot;Invalid day&quot;;
};
System.out.println(dayName);</code></pre>
<p>&amp;nbsp 여기서는 <code>day</code> 변수의 값에 따라 <code>dayName</code> 변수가 설정됩니다. <code>case</code> 블록은 화살표(<code>-&gt;</code>)를 사용하여 값을 반환합니다.</p>
<h4 id="예시-2">예시 2</h4>
<p>&amp;nbsp 각 <code>case</code>에서 여러 레이블을 쉼표로 구분할 수 있으며, 복잡한 로직을 처리하기 위해 중괄호 <code>{}</code>를 사용하여 코드 블록을 작성할 수 있습니다.</p>
<pre><code class="language-java">int score = 85;
String grade = switch (score) {
    case 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100 -&gt; &quot;A&quot;;
    case 80, 81, 82, 83, 84, 85, 86, 87, 88, 89 -&gt; &quot;B&quot;;
    case 70, 71, 72, 73, 74, 75, 76, 77, 78, 79 -&gt; &quot;C&quot;;
    case 60, 61, 62, 63, 64, 65, 66, 67, 68, 69 -&gt; &quot;D&quot;;
    default -&gt; {
        if (score &lt; 60) {
            yield &quot;F&quot;;
        } else {
            yield &quot;Invalid score&quot;;
        }
    }
};
System.out.println(&quot;Grade: &quot; + grade);</code></pre>
<h4 id="yield-키워드를-사용하여-값-반환">yield 키워드를 사용하여 값 반환</h4>
<p><code>yield</code> 키워드는 중괄호를 사용한 복잡한 코드 블록 내에서 값을 반환할 때 사용됩니다.</p>
<pre><code class="language-java">int num = 10;
String parity = switch (num % 2) {
    case 0 -&gt; {
        String result = &quot;even&quot;;
        yield result;
    }
    case 1 -&gt; {
        String result = &quot;odd&quot;;
        yield result;
    }
    default -&gt; throw new IllegalStateException(&quot;Unexpected value: &quot; + num % 2);
};
System.out.println(&quot;The number is &quot; + parity);</code></pre>
<h4 id="요약">요약</h4>
<ul>
<li>더 간결한 문법으로 가독성이 향상되는 장점이 있습니다.</li>
<li>각 <code>case</code> 블록에서 명시적으로<code>break</code>를 사용하지 않아도 됩니다.</li>
<li>값을 반환하여 함수형 프로그래밍 스타일을 지원</li>
<li>다중 레이블과 <code>yield</code> 키워드를 사용하여 보다 복잡한 로직을 처리할 수 있음</li>
</ul>
<br>
<br>


<h2 id="2-반복문">2. 반복문</h2>
<h4 id="1-1-for문">1-1) for문</h4>
<p><code>for</code> 문은 반복 횟수가 명확할 때 주로 사용됩니다. 초기화, 조건 검사, 증감식을 한 줄에 작성하여 반복문을 제어합니다.</p>
<pre><code class="language-java">for (initialization; condition; update) {
    // 반복할 코드
}

for (int i = 0; i &lt; 5; i++) {
    System.out.println(&quot;i: &quot; + i);
}</code></pre>
<h4 id="1-2-for-each">1-2) for-each</h4>
<p>&amp;nbsp 향상된 for문이라고도 불립니다. 반복자를 사용하지 않고도 각 요소에 접근할 수 있습니다.</p>
<pre><code class="language-java">for (type element : array/collection) {
    // 반복할 코드
}

int[] numbers = {1, 2, 3, 4, 5};
for (int number : numbers) {
    System.out.println(&quot;number: &quot; + number);
}</code></pre>
<h4 id="2-while-문">2) while 문</h4>
<p><code>while</code> 문은 반복 횟수가 명확하지 않고, 조건이 참인 동안 반복을 계속할 때 사용됩니다. 조건이 처음에 검사됩니다.</p>
<pre><code class="language-java">while (condition) {
    // 반복할 코드
}

int i = 0;
while (i &lt; 5) {
    System.out.println(&quot;i: &quot; + i);
    i++;
}</code></pre>
<h4 id="3-do-while-문">3) do-while 문</h4>
<p><code>do-while</code> 문은 조건이 참인지 여부에 상관없이 코드를 최소한 한 번 실행하고, 이후 조건이 참인 동안 반복을 계속합니다. 조건이 나중에 검사됩니다.</p>
<pre><code class="language-java">do {
    // 반복할 코드
} while (condition);


int i = 0;
do {
    System.out.println(&quot;i: &quot; + i);
    i++;
} while (i &lt; 5);</code></pre>
<h4 id="4-반복문-제어-키워드">4) 반복문 제어 키워드</h4>
<ul>
<li><code>break</code> : 반복문을 즉시 종료합니다.</li>
<li><code>continue</code> : 현재 반복을 건너뛰고, 다음 반복을 시작합니다.</li>
</ul>
<pre><code class="language-java">// break
for (int i = 0; i &lt; 10; i++) {
    if (i == 5) {
        break;
    }
    System.out.println(&quot;i: &quot; + i);
}


// continue
for (int i = 0; i &lt; 10; i++) {
    if (i % 2 == 0) {
        continue;
    }
    System.out.println(&quot;i: &quot; + i);
}</code></pre>
<br>
<br>










]]></description>
        </item>
        <item>
            <title><![CDATA[연산자]]></title>
            <link>https://velog.io/@ha_bu/%EC%97%B0%EC%82%B0%EC%9E%90</link>
            <guid>https://velog.io/@ha_bu/%EC%97%B0%EC%82%B0%EC%9E%90</guid>
            <pubDate>Sun, 26 May 2024 09:17:40 GMT</pubDate>
            <description><![CDATA[<h2 id="목표">목표</h2>
<blockquote>
<p>자바가 제공하는 다양한 연산자를 학습</p>
</blockquote>
<h3 id="목차">목차</h3>
<p><a href="#1-%EC%82%B0%EC%88%A0-%EC%97%B0%EC%82%B0%EC%9E%90">1. 산술 연산자</a>
<a href="#2-%EB%B9%84%ED%8A%B8-%EC%97%B0%EC%82%B0%EC%9E%90">2. 비트 연산자</a>
<a href="#3-%EA%B4%80%EA%B3%84-%EC%97%B0%EC%82%B0%EC%9E%90">3. 관계 연산자</a>
<a href="#4-%EB%85%BC%EB%A6%AC-%EC%97%B0%EC%82%B0%EC%9E%90">4. 논리 연산자</a>
<a href="#5-instanceof">5. instanceof</a>
<a href="#6-assignment-operator">6. assignment(=) operator</a>
<a href="#7-%ED%99%94%EC%82%B4%ED%91%9C-%EC%97%B0%EC%82%B0%EC%9E%90">7. 화살표(-&gt;) 연산자</a>
<a href="#8-3%ED%95%AD-%EC%97%B0%EC%82%B0%EC%9E%90">8. 3항 연산자</a>
<a href="#9-%EC%97%B0%EC%82%B0%EC%9E%90-%EC%9A%B0%EC%84%A0-%EC%88%9C%EC%9C%84">9. 연산자 우선 순위</a>
<a href="#10-optional-java-13-switch-%EC%97%B0%EC%82%B0%EC%9E%90">10. (optional) Java 13. switch 연산자</a></p>
<br>


<h2 id="1-산술-연산자">1. 산술 연산자</h2>
<blockquote>
<p>산술 연산을 수행하는 연산자입니다.</p>
</blockquote>
<p>&amp;nbsp 산술 연산자의 종류: +, -, *, /, %
특히 나눗셈 연산자의 경우 두 피연산자가 정수인 경우에는 정수형 나눗셈이, 실수인 경우에는 실수형 나눗셈이 진행됩니다.</p>
<p>&amp;nbsp 추가로 증가연산자(++) 감소연산자(--) 가 있습니다.
값을 1씩 증가하거나 감소시키는데, 이 연산자의 위치에 따라 조금 사용법이 다릅니다.** 앞에 붙게되면 증/감 후 연산수행하고, 뒤에 붙게되면 연산후 증/감 됩니다.**</p>
<br>
<br>

<h2 id="2-비트-연산자">2. 비트 연산자</h2>
<blockquote>
<p>비트 연산자는 정수형 데이터의 개별 비트를 직접 조작하는 데 사용됩니다. Java에서 제공하는 주요 비트 연산자는 다음과 같습니다</p>
</blockquote>
<table>
<thead>
<tr>
<th align="center">연산자</th>
<th align="center">설명</th>
<th align="center">예제</th>
</tr>
</thead>
<tbody><tr>
<td align="center">비트 AND (<code>&amp;</code>)</td>
<td align="center">두 비트가 모두 1일 때만 1을 반환합니다.</td>
<td align="center"><code>int result = a &amp; b;</code></td>
</tr>
<tr>
<td align="center">비트 OR (<code>|</code>)</td>
<td align="center">두 비트 중 하나라도 1이면 1을 반환합니다.</td>
<td align="center"><code>int result = a | b;</code></td>
</tr>
<tr>
<td align="center">비트 XOR (<code>^</code>)</td>
<td align="center">두 비트가 다를 때만 1을 반환합니다.</td>
<td align="center"><code>int result = a ^ b;</code></td>
</tr>
<tr>
<td align="center">비트 NOT (<code>~</code>)</td>
<td align="center">비트의 값을 반전시킵니다 (0을 1로, 1을 0으로).</td>
<td align="center"><code>int result = ~a;</code></td>
</tr>
<tr>
<td align="center">왼쪽 시프트 (<code>&lt;&lt;</code>)</td>
<td align="center">비트를 왼쪽으로 이동시키고, 오른쪽에 0을 채웁니다.</td>
<td align="center"><code>int result = a &lt;&lt; 2;</code> (a의 비트를 왼쪽으로 2칸 이동)</td>
</tr>
<tr>
<td align="center">오른쪽 시프트 (<code>&gt;&gt;</code>)</td>
<td align="center">비트를 오른쪽으로 이동시키고, 왼쪽에 부호 비트를 채웁니다.</td>
<td align="center"><code>int result = a &gt;&gt; 2;</code> (a의 비트를 오른쪽으로 2칸 이동)</td>
</tr>
<tr>
<td align="center">부호 없는 오른쪽 시프트 (<code>&gt;&gt;&gt;</code>)</td>
<td align="center">비트를 오른쪽으로 이동시키고, 왼쪽에 0을 채웁니다.</td>
<td align="center"><code>int result = a &gt;&gt;&gt; 2;</code> (a의 비트를 오른쪽으로 2칸 이동)</td>
</tr>
</tbody></table>
<p>&amp;nbsp 이 연산자들은 정수 값을 비트 수준에서 조작할 때 유용하며, 특정 비트 패턴을 빠르게 계산하거나 확인하는 데 자주 사용됩니다.</p>
<br>
<br>

<h2 id="3-관계-연산자">3. 관계 연산자</h2>
<blockquote>
<p>관계 연산자는 두 피연산자 간의 관계를 비교하는 데 사용됩니다. Java에서 제공하는 주요 관계연산자는 다음과 같습니다.</p>
</blockquote>
<table>
<thead>
<tr>
<th align="center">연산자</th>
<th align="center">설명</th>
<th align="center">예제</th>
</tr>
</thead>
<tbody><tr>
<td align="center"><code>==</code></td>
<td align="center">두 피연산자가 서로 같으면 <code>true</code>를 반환합니다.</td>
<td align="center"><code>if (a == b)</code></td>
</tr>
<tr>
<td align="center"><code>!=</code></td>
<td align="center">두 피연산자가 서로 다르면 <code>true</code>를 반환합니다.</td>
<td align="center"><code>if (a != b)</code></td>
</tr>
<tr>
<td align="center"><code>&gt;</code></td>
<td align="center">왼쪽 피연산자가 오른쪽 피연산자보다 크면 <code>true</code>를 반환합니다.</td>
<td align="center"><code>if (a &gt; b)</code></td>
</tr>
<tr>
<td align="center"><code>&lt;</code></td>
<td align="center">왼쪽 피연산자가 오른쪽 피연산자보다 작으면 <code>true</code>를 반환합니다.</td>
<td align="center"><code>if (a &lt; b)</code></td>
</tr>
<tr>
<td align="center"><code>&gt;=</code></td>
<td align="center">왼쪽 피연산자가 오른쪽 피연산자보다 크거나 같으면 <code>true</code>를 반환합니다.</td>
<td align="center"><code>if (a &gt;= b)</code></td>
</tr>
<tr>
<td align="center"><code>&lt;=</code></td>
<td align="center">왼쪽 피연산자가 오른쪽 피연산자보다 작거나 같으면 <code>true</code>를 반환합니다.</td>
<td align="center"><code>if (a &lt;= b)</code></td>
</tr>
</tbody></table>
<p>&amp;nbsp 주로 조건문과 함께 사용되며, 두 값의 관계를 판단하여 프름을 제어하는데 유용합니다.</p>
<br>
<br>

<h2 id="4-논리-연산자">4. 논리 연산자</h2>
<blockquote>
<p>논리식의 결과에 따라 true, 또는 false를 반환하는 연산자 입니다.</p>
</blockquote>
<p>연산자의 종류 : <code>&amp;&amp;, ||, !</code></p>
<table>
<thead>
<tr>
<th align="center">피연산자1</th>
<th align="center">피연산자2</th>
<th align="center">연산 결과 ( &amp;&amp; )</th>
</tr>
</thead>
<tbody><tr>
<td align="center">true</td>
<td align="center">true</td>
<td align="center">true</td>
</tr>
<tr>
<td align="center">true</td>
<td align="center">false</td>
<td align="center">false</td>
</tr>
<tr>
<td align="center">false</td>
<td align="center">true</td>
<td align="center">false</td>
</tr>
<tr>
<td align="center">false</td>
<td align="center">false</td>
<td align="center">false</td>
</tr>
</tbody></table>
<br>
<br>

<table>
<thead>
<tr>
<th align="center">피연산자1</th>
<th align="center">피연산자2</th>
<th align="center">연산 결과 ( || )</th>
</tr>
</thead>
<tbody><tr>
<td align="center">true</td>
<td align="center">true</td>
<td align="center">true</td>
</tr>
<tr>
<td align="center">true</td>
<td align="center">false</td>
<td align="center">true</td>
</tr>
<tr>
<td align="center">false</td>
<td align="center">true</td>
<td align="center">true</td>
</tr>
<tr>
<td align="center">false</td>
<td align="center">false</td>
<td align="center">false</td>
</tr>
</tbody></table>
<br>

<h4 id="주의-할점">주의 할점</h4>
<pre><code class="language-java">public class Operator {
    public static void main(String[] args){
        int num1 = 0;
        int num2 = 0;
        boolean result;

        result = ((num1 += 10) &lt; 0) &amp;&amp; ((num2 += 10) &gt; 0);
        System.out.println(&quot;num1: &quot;+num1+&quot; num2: &quot;+num2 + &quot; result: &quot; + result);
        // 실행 결과: num1: 10 num2: 0 result: false
    }
}</code></pre>
<p>&amp;nbsp num1과 num2가 모두 10이 되어야 할것같지만, 실제로 num1은 10, num2는 0의 결과를 리턴합니다.</p>
<br>

<h4 id="왜-그럴까">왜 그럴까?</h4>
<p>&amp;nbsp 이유는 연산의 특성중 <code>Short-Circuit Evaluation(SCE)</code>에서 이유를 찾을 수 있습니다.</p>
<p>&amp;nbsp <code>((num1 += 10) &lt; 0) &amp;&amp; ((num2 += 10) &gt; 0)</code> 이 연산을 진행할 때, &amp;&amp;의 왼편에 있는 연산이 먼저 실행되는데, 이때 num1은 증가합니다. 그리고 <code>&lt;</code> 연산결과는 <code>false</code>이므로 아래와 같다고 볼 수있습니다.</p>
<p><code>false &amp;&amp; ((num2 += 10) &gt; 0)</code></p>
<p>&amp;nbsp <code>&amp;&amp;</code>의 오른쪽 연산을 진행해야하지만, <code>&amp;&amp;</code>의 이전에 false가 왔기때문에, <strong>오른쪽의 결과가 어떻든간에 result는 <code>false</code>가 됩니다.</strong></p>
<blockquote>
<p>그렇기 때문에 오른쪽을 비교할 필요가 없습니다.</p>
</blockquote>
<p>&amp;nbsp 여기서 SCE의 특성이 나오는데, 정리하자면 아래와 같습니다.</p>
<ul>
<li>&amp;&amp;의 왼쪽 피연산자가 false이면, 오른쪽 피연산자는 확인하지 않는다.</li>
<li>||의 왼쪽 피연산자가 true이면, 오른쪽 피연산자는 확인하지 않는다.</li>
</ul>
<br>
<br>

<h2 id="5-instanceof">5. instanceof</h2>
<p>&amp;nbsp instanceof는 객체가 특정 클래스의 인스턴스인지를 확인하는데 사용되는 연산자 입니다. 리턴값은 <code>true</code>, <code>false</code> 입니다.</p>
<h4 id="예시-코드">예시 코드</h4>
<pre><code class="language-java">class Animal {
    // Animal 클래스 구현 내용
}

class Dog extends Animal {
    // Dog 클래스 구현 내용
}

class Cat extends Animal {
    // Cat 클래스 구현 내용
}

public class Main {
    public static void main(String[] args) {
        Animal animal1 = new Dog();
        Animal animal2 = new Cat();

        System.out.println(animal1 instanceof Dog); // true
        System.out.println(animal2 instanceof Dog); // false
        System.out.println(animal2 instanceof Cat); // true
    }
}</code></pre>
<ul>
<li>Animal1은 Dog의 클래스의 인스턴스 이므로 <code>true</code>를 반환합니다.</li>
<li>그러나 animal2는 Cat의 인스턴스이므로 <code>false</code>를 반환합니다.</li>
<li>마지막은 물론 animal2는 Cat이므로 <code>true</code>입니다.</li>
</ul>
<br>
<br>

<h2 id="6-assignment-operator">6. assignment(=) operator</h2>
<blockquote>
<p>할당(대입) 연산자 <code>=</code>는 값을 할당하는데 사용됩니다. 왼쪽 피연산자에 오른쪽 피연산자 값을 할당합니다.</p>
</blockquote>
<pre><code class="language-java">int x = 10;             // 정수 값 할당
double y = 3.14;        // 실수 값 할당
char c = &#39;A&#39;;           // 문자 값 할당
boolean flag = true;    // 논리 값 할당
String name = &quot;Lee&quot;;    // 문자열 값 할당</code></pre>
<br>
<br>

<h2 id="7-화살표--연산자">7. 화살표(-&gt;) 연산자</h2>
<blockquote>
<p>화살표(<code>-&gt;</code>) 연산자는 <strong>람다 표현식</strong>에서 사용됩니다. 람다 표현식은 함수형 프로그래밍의 핵심 개념으로, 익명 함수를 간결하게 표현하는 방법입니다. <strong>Java8부터 도입되었습니다.</strong></p>
</blockquote>
<h4 id="사용-방법">사용 방법</h4>
<pre><code class="language-java">(parameters) -&gt; expression
// 또는
(parameters) -&gt; { statements; }</code></pre>
<p>&amp;nbsp 매개변수를 본문(하나의 표현식이거나 여러 문장의 블록)에 연결합니다.</p>
<h4 id="예시-코드-1">예시 코드</h4>
<pre><code class="language-java">Comparator&lt;Integer&gt; comparator = new Comparator&lt;Integer&gt;() {
    public int compare(Integer a, Integer b) {
        return a.compareTo(b);
    }
};</code></pre>
<p>이랬던 코드가</p>
<pre><code class="language-java">Comparator&lt;Integer&gt; comparator = (a, b) -&gt; a.compareTo(b);</code></pre>
<p>이렇게 변화 합니다.</p>
<p>&amp;nbsp 여기서 (a, b) -&gt; a.compareTo(b)는 두 개의 정수를 비교하는 비교자를 나타냅니다. 이것은 두 정수를 받아서 첫 번째 정수가 두 번째 정수보다 작으면 음수를 반환하고, 같으면 0을 반환하고, 크면 양수를 반환합니다.</p>
<p>&amp;nbsp 람다 표현식을 사용하면 코드를 더 간결하고 가독성 있게 만들 수 있으며, 함수형 프로그래밍 스타일을 채택할 수 있습니다.</p>
<br>
<br>

<h2 id="8-3항-연산자">8. 3항 연산자</h2>
<blockquote>
<p>3항 연산자는 세 개의 피연산자를 갖는 조건부 연산자입니다. 조건식의 결과에 따라 두 개의 표현식 중 하나를 선택하여 반환합니다.</p>
</blockquote>
<p><strong>조건식 ? 표현식1 : 표현식2</strong>
&amp;nbsp 여기서 <code>조건식</code>은 참 또는 거짓으로 평가될 수 있는 표현식 입니다. 만약 <code>조건식</code>이 참이면 <code>표현식1</code>이 반환되고, 거짓이면 <code>표현식2</code>가 반환됩니다.</p>
<h4 id="예시-코드-2">예시 코드</h4>
<pre><code class="language-java">int x = 10;
String result = (x &gt; 0) ? &quot;양수입니다.&quot; : &quot;음수입니다.&quot;;
System.out.println(result);</code></pre>
<p>이 코드에서 출력값은 <code>양수입니다.</code>가 출력될 것입니다.</p>
<br>
<br>

<h2 id="9-연산자-우선-순위">9. 연산자 우선 순위</h2>
<blockquote>
<p>연산자의 우선 순위는 표현식에서 연산이 수행되는 순서를 결정합니다. <strong>우선 순위가 높은 연산자가 먼저</strong> 계산되고, <strong>낮은 우선 순위 연산자는 나중에</strong> 계산됩니다. 수학적인 우선 순위와 비슷합니다.</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/ha_bu/post/b3b52491-9c33-49b2-9ff5-6bcb3c2da240/image.png" alt=""></p>
<p>&amp;nbsp 기본적으로 연산자에는 우선수누이가 있으며, <code>괄호</code>의 우선순위가 제일 높습니다. 다음으로는 <code>산술</code> &gt; <code>비교</code> &gt; <code>논리</code> &gt; <code>대입</code>의 순서이며, <code>단항</code> &gt; <code>이항</code> &gt; <code>삼항</code>의 순서입니다.</p>
<p>&amp;nbsp 연산자의 연산 진행방향은 왼쪽에서 오른쪽으로 수행되며, 단항 연산자와 대입 연산자의 경우에는 오른쪽에서 왼쪽으로 수행됩니다.</p>
<br>
<br>

<h2 id="10-optional-java-13-switch-연산자">10. (optional) Java 13. switch 연산자</h2>
<blockquote>
<p>switch 문의 확장된 형태입니다. 기존의 switch 문과는 다르게 switch 표현식은 값을 반환할 수 있으며, 각 case에 대한 값도 명시적으로 지정할 수 있습니다.</p>
</blockquote>
<h4 id="예시-코드-3">예시 코드</h4>
<pre><code class="language-java">int dayOfWeek = 3;
String dayName = switch (dayOfWeek) {
    case 1 -&gt; &quot;Monday&quot;;
    case 2 -&gt; &quot;Tuesday&quot;;
    case 3 -&gt; &quot;Wednesday&quot;;
    case 4 -&gt; &quot;Thursday&quot;;
    case 5 -&gt; &quot;Friday&quot;;
    case 6, 7 -&gt; {
        yield &quot;Weekend&quot;;
    }
    default -&gt; throw new IllegalArgumentException(&quot;Invalid day of the week: &quot; + dayOfWeek);
};
</code></pre>
<p>&amp;nbsp 이 코드에서 switch 표현식은 <code>dayOfWeek</code> 변수를 평가하고 해당하는 문자열 값을 <code>dayName</code> 변수에 할당합니다. 즉, <code>dayOfWeek</code>가 3이면 <code>dayName</code>에는 <code>&quot;Wednesday&quot;</code>가 할당됩니다.</p>
<p>&amp;nbsp <code>yield</code> 키워드는 <code>&quot;Weekend&quot;</code>라는 것을 반환하고 switch 블록을 종료합니다.</p>
<br>

<p><strong>switch 표현식의 주요 특징은 다음과 같습니다</strong></p>
<ol>
<li>case 라벨은 콜론(:) 대신 화살표(-&gt;)를 사용합니다.</li>
<li>각 case는 값을 반환할 수 있습니다.</li>
<li>여러 case를 쉼표(,)로 결합하여 하나의 case로 처리할 수 있습니다.</li>
<li>default 블록도 값을 반환할 수 있습니다.</li>
<li>모든 경우를 처리하거나, default 블록을 제공해야합니다.</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[자바 데이터타입 & 변수 & 배열]]></title>
            <link>https://velog.io/@ha_bu/%EC%9E%90%EB%B0%94-%EB%8D%B0%EC%9D%B4%ED%84%B0%ED%83%80%EC%9E%85-%EB%B3%80%EC%88%98-%EB%B0%B0%EC%97%B4</link>
            <guid>https://velog.io/@ha_bu/%EC%9E%90%EB%B0%94-%EB%8D%B0%EC%9D%B4%ED%84%B0%ED%83%80%EC%9E%85-%EB%B3%80%EC%88%98-%EB%B0%B0%EC%97%B4</guid>
            <pubDate>Fri, 24 May 2024 02:45:16 GMT</pubDate>
            <description><![CDATA[<h2 id="목표">목표</h2>
<blockquote>
<p>자바의 프리미티브 타입, 변수 그리고 배열을 사용하는 방법을익힙니다.</p>
</blockquote>
<h3 id="목차">목차</h3>
<p><a href="#1-%ED%94%84%EB%A6%AC%EB%AF%B8%ED%8B%B0%EB%B8%8C-%ED%83%80%EC%9E%85-%EC%A2%85%EB%A5%98%EC%99%80-%EA%B0%92%EC%9D%98-%EB%B2%94%EC%9C%84-%EA%B7%B8%EB%A6%AC%EA%B3%A0-%EA%B8%B0%EB%B3%B8-%EA%B0%92">1. 프리미티브 타입 종류와 값의 범위 그리고 기본 값</a>
<a href="#2-%ED%94%84%EB%A6%AC%EB%AF%B8%ED%8B%B0%EB%B8%8C-%ED%83%80%EC%9E%85%EA%B3%BC-%EB%A0%88%ED%8D%BC%EB%9F%B0%EC%8A%A4-%ED%83%80%EC%9E%85">2. 프리미티브 타입과 레퍼런스 타입</a>
<a href="#3-%EB%A6%AC%ED%84%B0%EB%9F%B4">3. 리터럴</a>
<a href="#4-%EB%B3%80%EC%88%98-%EC%84%A0%EC%96%B8-%EB%B0%8F-%EC%B4%88%EA%B8%B0%ED%99%94%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95">4. 변수 선언 및 초기화하는 방법</a>
<a href="#5-%EB%B3%80%EC%88%98%EC%9D%98-%EC%8A%A4%EC%BD%94%ED%94%84%EC%99%80-%EB%9D%BC%EC%9D%B4%ED%94%84%ED%83%80%EC%9E%84">5. 변수의 스코프와 라이프타임</a>
<a href="#6-%ED%83%80%EC%9E%85-%EB%B3%80%ED%99%98-%EC%BA%90%EC%8A%A4%ED%8C%85-%EA%B7%B8%EB%A6%AC%EA%B3%A0-%ED%83%80%EC%9E%85-%ED%94%84%EB%A1%9C%EB%AA%A8%EC%85%98">6. 타입 변환, 캐스팅 그리고 타입 프로모션</a>
<a href="#7-1%EC%B0%A8-%EB%B0%8F-2%EC%B0%A8-%EB%B0%B0%EC%97%B4-%EC%84%A0%EC%96%B8%ED%95%98%EA%B8%B0">7. 1차 및 2차 배열 선언하기</a>
<a href="#8-%ED%83%80%EC%9E%85-%EC%B6%94%EB%A1%A0-var">8. 타입 추론, var</a></p>
<br>

<h2 id="1-프리미티브-타입-종류와-값의-범위-그리고-기본-값">1. 프리미티브 타입 종류와 값의 범위 그리고 기본 값</h2>
<p><img src="https://velog.velcdn.com/images/ha_bu/post/adf8794a-6b1e-4eba-8d97-c43da7dd5750/image.png" alt=""></p>
<p align="center" style="font-size: 0.9em; color: #555; margin-top: -45px;">Primitive Type 요약</p>

<p>&amp;nbsp primitive type은 자바의 기본 타입들이라고 할 수 있습니다. 총 8개로 이루어져있으며, 자바에서는 필드 선언시 초기화를 하지 않으면, 기본값으로 초기화 됩니다.</p>
<p>&amp;nbsp기본자료형 혹은 원시 자료형 이라고 불리는 프리미티브 타입은 값을 할당할 때 변수의 주소값에 값이 그 자체로 저장되는 데이터 타입입니다. 해당 데이터 타입은 값이 할당되면 JVM Runtime Data Area 영역 중 Stack 영역에 값이 저장됩니다.</p>
<h3 id="프리미티브-타입의-종류">프리미티브 타입의 종류</h3>
<blockquote>
<p>정수형 : byte, short, int, long
실수형 : float, double
문자형 : char
논리형 : Boolean</p>
</blockquote>
<br>

<h2 id="2-프리미티브-타입과-레퍼런스-타입">2. 프리미티브 타입과 레퍼런스 타입</h2>
<p><strong>Reference Type?</strong></p>
<p>&amp;nbsp Reference Type은 Primitive Type을 제외한 모든 타입을 포함합니다. 참조값을 통해 관리하기 때문에 Reference Type이라고 불리며, Null을 사용할 수 있습니다.</p>
<p>&amp;nbsp 또한 Reference Type은 변수 선언시 변수에 값이 저장되는 것이 아니라 객체에 대한 힙 영역의 참조를 저장하게 됩니다. 즉, <U><strong>*프리미티브 타입과 다르게 변수의 주소가 아닌, heap영역에 할당된 주소가 저장됩니다. *</strong></U></p>
<br>

<p>*<em>※ WrapperClass *</em></p>
<blockquote>
<p><U><strong>Primitive Type을 인스턴스로 다룰 수 있게끔 도와주는 것</strong></U>들을 말합니다. 값을 조작하기 위해 작성된 UtilMethod를 사용하기 위해서 이용하는 경우도 많습니다.</p>
</blockquote>
<pre><code class="language-java">// 대응 클래스
// 가장 앞 문자를 대문자로 사용하면 됩니다.
byte -&gt; Byte      char -&gt; Character
short -&gt; Short    float -&gt; Float
int -&gt; Integer    double -&gt; Double
long -&gt; Long      boolean -&gt; Boolean

// 선언 예시
Integer num = new Integer(10);</code></pre>
<br>

<h2 id="3-리터럴">3. 리터럴</h2>
<p>&amp;nbsp리터럴(literal)은 프로그래밍에서 변수에 저장되는 값을 나타내는 구체적인 표기입니다. 즉, 코드에서 고정된 값으로 직접 작성되는 데이터를 말합니다. 리터럴은 여러가지 유형이 있으며, 각 유형은 특정한 데이터 타입을 나타냅니다.</p>
<pre><code class="language-java">// ex) 정수
`10`, `-5` ...

// 실수(float)
`3.14`, `-0.001`, ..

이 외에도 list([ ]), tuple(( )), set({ }),
dictionary({&#39;key&#39;: &#39;value&#39;}), None, boolean 등이 있습니다.

참고로 특수문자 리터럴도 존재합니다.(\t, \n, \r 등등)</code></pre>
<br>

<h2 id="4-변수-선언-및-초기화하는-방법">4. 변수 선언 및 초기화하는 방법</h2>
<h4 id="declaration--initialization">Declaration / Initialization</h4>
<blockquote>
<ul>
<li>Declaration
변수를 선언한다는 것은, 저장공간을 확보하겠다는 의미라고 볼 수 있습니다. </li>
</ul>
</blockquote>
<ul>
<li>Initialization
변수를 초기화 한다는 것은, 저장공간에 원하는 값을 저장하는 것을 의미합니다.</li>
</ul>
<pre><code class="language-java">// Declaration
int a;

// Initialization
a = 10;</code></pre>
<p>&amp;nbsp 위 코드의 Declaration을 보면 int 타입의 a 라는 이름으로 4byte(int는 4byte)를 확보했다고 볼 수 있겠습니다. 이어서 Initialization을 보면, a 이름에 10이라는 값을 할당해 주었다는 것을 알 수 있습니다.</p>
<br>

<h2 id="5-변수의-스코프와-라이프타임">5. 변수의 스코프와 라이프타임</h2>
<p>여기서 <strong>scope는 변수의 유효범위</strong>를 뜻하고, <strong>lifetime은 존재 기간</strong>을 의미합니다.</p>
<h3 id="스코프scope">스코프(Scope)</h3>
<h4 id="1-클래스-스코프class-scope">1) 클래스 스코프(Class Scope)</h4>
<ul>
<li>클래스 내에서 선언된 변수(필드)는 클래스 전체에서 접근 가능합니다.</li>
<li>클래스 변수(static 변수)는 클래스의 모든 인스턴스에서 공유됩니다.</li>
<li>인스턴스 변수(non-static 변수)는 각 인스턴스마다 개별적으로 존재합니다.</li>
</ul>
<pre><code class="language-java">public class MyClass {
    // 클래스 변수 (static)
    static int staticVar;

    // 인스턴스 변수 (non-static)
    int instanceVar;

    public void myMethod() {
        // 메서드 내부에서는 static 변수와 인스턴스 변수 모두 접근 가능
        staticVar = 10;
        instanceVar = 20;
    }
}
</code></pre>
<br>

<h4 id="2-메서드-스코프method-scope">2) 메서드 스코프(Method Scope)</h4>
<ul>
<li>메서드 내에서 선언된 변수는 메서드가 실행되는 동안에만 유효합니다.</li>
<li>메서드가 종료되면 메서드 스코프 내의 변수는 더 이상 접근할 수 없습니다.<pre><code class="language-java">public void myMethod() {
  int localVar = 10; // 지역 변수
  // localVar은 myMethod 내에서만 접근 가능
}</code></pre>
</li>
</ul>
<h4 id="3-블록-스코프block-scope">3) 블록 스코프(Block Scope)</h4>
<ul>
<li>중괄호 <code>{}</code> 로 둘러싸인 블록 내에서 선언된 변수는 해당 블록 내에서만 유효합니다.</li>
<li>블론이 종료되면 블록 스코프 내의 변수는 더 이상 접근 할 수 없습니다.<pre><code class="language-java">public void myMethod() {
  if (true) {
      int blockVar = 10; // 블록 변수
      // blockVar은 if 블록 내에서만 접근 가능
  }
  // 여기서는 blockVar에 접근할 수 없음
}</code></pre>
</li>
</ul>
<h3 id="라이프-타임lifetime">라이프 타임(Lifetime)</h3>
<p>&amp;nbsp 변수의 라이프타임은 변수가 메모리에 존재하는기간을 의미합니다. 변수의 스코프와 라이프타임은 종종 밀접하게 관련되어 있지만, 두 개념은 다릅니다.</p>
<h4 id="1-클래스-변수static-변수">1) 클래스 변수(static 변수)</h4>
<ul>
<li><U><strong>프로그램 시작 시 메모리에 할당되고, 프로그램 종료시 해제</strong></U> 됩니다.</li>
<li>클래스 로더에 의해 클래스가 메모리에 로드될 때 생성되며, JVM이 종료될 때까지 유지됩니다.</li>
</ul>
<br>

<h4 id="2-인스턴스-변수non-static-변수">2) 인스턴스 변수(non-static 변수)</h4>
<ul>
<li><U><strong>객체가 생성될 때 메모리에 할당</strong></U>되고, <U><strong>객체가 Garbage Collection에 의해 소멸될 때 해제</strong></U>됩니다.</li>
<li>객체가 메모리에 존재하는 동안 인스턴스 변수도 함께 존재합니다.</li>
</ul>
<br>

<h4 id="3-지역-변수local-variable">3) 지역 변수(Local Variable)</h4>
<ul>
<li>메서드 또는 블록이 실행될 때 메모리에 할당되고, 메서드 또는 블록이 종료되면 해제됩니다.</li>
<li>지역 변수는 스택 메모리에 저장되며, 메서드 호출이 끝나면 스택프레임과 함께 제거됩니다.</li>
</ul>
<br>

<pre><code class="language-java">public class VariableScope {
    // 클래스 변수 (static)
    static int classVar = 10;

    // 인스턴스 변수 (non-static)
    int instanceVar = 20;

    public void method() {
        // 지역 변수 (local)
        int localVar = 30;

        // 블록 내에서 선언된 블록 변수 (block scope)
        if (true) {
            int blockVar = 40;
            // 여기서는 classVar, instanceVar, localVar, blockVar 모두 접근 가능
        }
        // 여기서는 blockVar에 접근할 수 없음
    }

    public static void main(String[] args) {
        // main 메서드도 하나의 블록이므로, 
        // 여기서 선언된 변수는 이 블록 내에서만 유효
        VariableScope obj = new VariableScope();
        obj.method();
    }
}</code></pre>
<p>&amp;nbsp 이 예제에서 classVar는 프로그램이 종료될 때까지 유효하며, instanceVar는 obj 객체가 가비지 컬렉션될 때까지 유효합니다. localVar는 method가 실행되는 동안에만 유효하고, blockVar는 if 블록 내에서만 유효합니다.</p>
<br>
<br>

<h2 id="6-타입-변환-캐스팅-그리고-타입-프로모션">6. 타입 변환, 캐스팅 그리고 타입 프로모션</h2>
<h3 id="타입-변환type-conversion">타입 변환(Type Conversion)</h3>
<p>&amp;nbsp 타입 변환은 하나의 데이터 타입을 다른 데이터 타입으로 변환하는 과정입니다. 타입 변환은 암시적(자동) 또는 명시적(수동)으로 이루어질 수 있습니다. </p>
<h4 id="1-자동-타입-변환implicit-type-conversion-widening-conversion">1) 자동 타입 변환(Implicit Type Conversion, Widening Conversion)</h4>
<ul>
<li>작은 크기의 데이터 타입이 큰 크기의 데이터 타입으로 자동으로 변환되는 것을 말합니다.</li>
<li>데이터 손실이 발생하지 않으므로 안전한 변환입니다.</li>
</ul>
<pre><code class="language-java">int intValue = 100;
long longValue = intValue;  // int가 long으로 자동 변환
double doubleValue = intValue;  // int가 double로 자동 변환</code></pre>
<h4 id="2-명시적-타입-변환explicit-type-conversion-narrowing-conversion">2) 명시적 타입 변환(Explicit Type Conversion, Narrowing Conversion)</h4>
<ul>
<li>큰 크기의 데이터 타입 작은 크기의 데이터 타입으로 변환할 때 명시적으로 변환을 지정해야 합니다.</li>
<li>데이터 손실이 발생할 수 있으므로 주의가 필요합니다.<pre><code class="language-java">int intValue = 100;
long longValue = intValue;  // int가 long으로 자동 변환
double doubleValue = intValue;  // int가 double로 자동 변환</code></pre>
</li>
</ul>
<br>

<h3 id="캐스팅-casting">캐스팅 (Casting)</h3>
<p>캐스팅은 명시적 타입 변환의 한 형태로, 주로 참조 타입(객체) 사이의 변환을 가리킵니다. 캐스팅은 상속 관계에 있는 클래스 간에 이루어집니다.</p>
<br>

<h4 id="1-업케스팅-upcasting">1) 업케스팅 (Upcasting)</h4>
<ul>
<li>서브 클래스 타입을 슈퍼 클래스 타입으로 변환합니다.</li>
<li>암시적으로 이루어지며, 명시적인 캐스팅이 필요하지 않습니다.<pre><code class="language-java">class Animal { }
class Dog extends Animal { }
</code></pre>
</li>
</ul>
<p>Animal animal = new Dog();  // 업캐스팅</p>
<pre><code>
&lt;br&gt;

#### 2) 다운캐스팅 (Downcasting)
- 슈퍼 클래스 타입 서브 클래스 타입으로 변환합니다.
- 명시적인 캐스팅이 필요하며, 런타임에 &#39;ClassCastException&#39;이 발생할 수 있습니다.
```java
Animal animal = new Dog();
Dog dog = (Dog) animal;  // 다운캐스팅</code></pre><br>

<h3 id="타입-프로모션-type-promotion">타입 프로모션 (Type Promotion)</h3>
<p>&amp;nbsp타입 프로모션은 표현식을 평가할 때 작은 데이터 타입의 피연산자가 큰 데이터 타입으로 자동 변환되는 과정입니다. 이는 주로 연산자와 함께 사용됩니다.</p>
<h4 id="1-정수형-타입-프로모션">1) 정수형 타입 프로모션</h4>
<ul>
<li>byte, short, char 타입의 값이 int 타입으로 자동 프로모션됩니다.</li>
<li>여러 피연산자가 있을 경우, 피연산자의 데이터 타입이 가장 큰 타입으로 프로모션 됩니다.</li>
</ul>
<pre><code class="language-java">byte b = 42;
char c = &#39;a&#39;;
int i = b + c;  // b와 c가 int로 프로모션됨</code></pre>
<h4 id="2-실수형-타입-프로모션">2) 실수형 타입 프로모션</h4>
<ul>
<li>float 타입이 double 타입으로 자동 프로모션 됩니다.<pre><code>float f = 3.14f;
double d = f + 2.0;  // f가 double로 프로모션됨</code></pre></li>
</ul>
<h3 id="예재-코드">예재 코드</h3>
<pre><code class="language-java">public class TypeConversionExample {

    public static void main(String[] args) {
        // 자동 타입 변환 (Widening)
        int intVal = 100;
        long longVal = intVal;  // int to long
        double doubleVal = intVal;  // int to double

        // 명시적 타입 변환 (Narrowing)
        double doubleNum = 9.78;
        int intNum = (int) doubleNum;  // double to int
        System.out.println(&quot;Converted double to int: &quot; + intNum);

        // 업캐스팅
        Animal animal = new Dog();  // Upcasting
        animal.makeSound();  // Animal의 메서드를 호출

        // 다운캐스팅
        Dog dog = (Dog) animal;  // Downcasting
        dog.bark();  // Dog의 메서드를 호출

        // 타입 프로모션
        byte byteVal = 42;
        char charVal = &#39;a&#39;;
        int result = byteVal + charVal;  // byte와 char가 int로 프로모션됨
        System.out.println(&quot;Promoted result: &quot; + result);

        float floatVal = 3.14f;
        double doubleResult = floatVal + 2.0;  // float가 double로 프로모션됨
        System.out.println(&quot;Promoted double result: &quot; + doubleResult);
    }
}

class Animal {
    public void makeSound() {
        System.out.println(&quot;Animal makes a sound&quot;);
    }
}

class Dog extends Animal {
    public void bark() {
        System.out.println(&quot;Dog barks&quot;);
    }
}</code></pre>
<br>

<h2 id="7-1차-및-2차-배열-선언하기">7. 1차 및 2차 배열 선언하기</h2>
<h3 id="1차원-배열">1차원 배열</h3>
<p>&amp;nbsp 1차원 배열은 단일 차원의 배열을 의미합니다. 배열은 동일한 데이터 타입의 요소를 저장하는 연속된 공간을 갖습니다.</p>
<h4 id="1-선언">1) 선언</h4>
<p>array라는 이름의 정수형 배열</p>
<pre><code class="language-java">int[] array;</code></pre>
<h4 id="2-배열생성-및-초기화">2) 배열생성 및 초기화</h4>
<p>길이가 5인 정수 배열을 생성합니다. 배열 요소는 자동으로 기본값(정수의 경우 0)으로 초기화 됩니다.</p>
<pre><code class="language-java">array = new int[5]; // 길이가 5인 배열 생성</code></pre>
<h4 id="3-선언과-동시에-초기화">3) 선언과 동시에 초기화</h4>
<pre><code class="language-java">int[] array = new int[5];</code></pre>
<h4 id="4-선언과-동시에-값-할당">4) 선언과 동시에 값 할당</h4>
<pre><code class="language-java">int[] array = {1, 2, 3, 4, 5}</code></pre>
<h3 id="2차원-배열">2차원 배열</h3>
<h4 id="1-배열-선언">1) 배열 선언</h4>
<pre><code class="language-java">int[][] matrix;</code></pre>
<h4 id="2-배열-생성-및-초기화">2) 배열 생성 및 초기화</h4>
<pre><code class="language-java">matrix = new int[3][4]; // 3x4 배열 생성</code></pre>
<p>이 구문은 3개의 행과 4개의 열을 갖는 2차원 배열을 생성합니다. 모든 요소는 기본값으로 초기화 됩니다.</p>
<h4 id="3-선언과-동시에-초기화-1">3) 선언과 동시에 초기화</h4>
<pre><code class="language-java">int[][] matrix = new int[3][4];</code></pre>
<h4 id="4-선언과-동시에-값-할당-1">4) 선언과 동시에 값 할당</h4>
<pre><code class="language-java">int[][] matrix = {
    {1, 2, 3, 4},
    {5, 6, 7, 8},
    {9, 10, 11, 12}
};</code></pre>
<h3 id="예제-코드">예제 코드</h3>
<pre><code class="language-java">public class ArrayExample {

    public static void main(String[] args) {
        // 1차 배열 선언 및 초기화
        int[] oneDimArray = new int[5];  // 선언과 동시에 길이가 5인 배열 생성
        oneDimArray[0] = 1;
        oneDimArray[1] = 2;
        oneDimArray[2] = 3;
        oneDimArray[3] = 4;
        oneDimArray[4] = 5;

        // 1차 배열 선언과 값 할당
        int[] anotherOneDimArray = {1, 2, 3, 4, 5};

        // 2차 배열 선언 및 초기화
        int[][] twoDimArray = new int[3][4];  // 3x4 배열 생성
        twoDimArray[0][0] = 1;
        twoDimArray[0][1] = 2;
        twoDimArray[0][2] = 3;
        twoDimArray[0][3] = 4;
        twoDimArray[1][0] = 5;
        twoDimArray[1][1] = 6;
        twoDimArray[1][2] = 7;
        twoDimArray[1][3] = 8;
        twoDimArray[2][0] = 9;
        twoDimArray[2][1] = 10;
        twoDimArray[2][2] = 11;
        twoDimArray[2][3] = 12;

        // 2차 배열 선언과 값 할당
        int[][] anotherTwoDimArray = {
            {1, 2, 3, 4},
            {5, 6, 7, 8},
            {9, 10, 11, 12}
        };

        // 배열 요소 출력
        System.out.println(&quot;1차 배열 요소:&quot;);
        for (int i = 0; i &lt; oneDimArray.length; i++) {
            System.out.print(oneDimArray[i] + &quot; &quot;);
        }

        System.out.println(&quot;\n\n2차 배열 요소:&quot;);
        for (int i = 0; i &lt; twoDimArray.length; i++) {
            for (int j = 0; j &lt; twoDimArray[i].length; j++) {
                System.out.print(twoDimArray[i][j] + &quot; &quot;);
            }
            System.out.println();
        }
    }
}</code></pre>
<br>

<h2 id="8-타입-추론-var">8. 타입 추론, var</h2>
<p>&amp;nbsp 타입 추론과 &#39;var&#39;는 <U><strong>Java 10</strong></U>부터 도입된 기능으로, 코드를 간결하게 만들어주고 가독성을 향상시키는 데 도움을 줍니다.</p>
<br>

<h3 id="타입-추론type-inference">타입 추론(Type Inference)</h3>
<p>&amp;nbsp 타입 추론은 변수를 선언할 때 변수의 타입을 컴파일러가 자동으로 추론하여 할당하는 기능입니다. 이는 코드의 가독성을 향상시키고 타입 선언을 줄여줍니다.</p>
<pre><code class="language-java">// 타입 추론을 사용하지 않은 경우
Map&lt;String, List&lt;Integer&gt;&gt; myMap = new HashMap&lt;String, List&lt;Integer&gt;&gt;();

// 타입 추론을 사용한 경우
var myMap = new HashMap&lt;String, List&lt;Integer&gt;&gt;();</code></pre>
<p>&amp;nbsp 컴파일러는 <code>new HashMap&lt;String, List&lt;Integer&gt;&gt;()</code>를 보고 <code>HashMap&lt;String, List&lt;Integer&gt;&gt;</code> 타입을 추론하고, myMap의 타입을 설정합니다.</p>
<h3 id="var">var</h3>
<p>&amp;nbsp var 키워드는 <U><strong>변수의 타입을 컴파일러가 자동으로 추론하도록 지시합니다.</strong></U> 이를 통해 코드를 간결하게 만들 수 있습니다.</p>
<pre><code class="language-java">// 타입 추론을 사용한 경우
var number = 10;  // number의 타입은 int로 추론됨
var name = &quot;John&quot;;  // name의 타입은 String으로 추론됨

var myList = new ArrayList&lt;String&gt;();  
// myList의 타입은 ArrayList&lt;String&gt;으로 추론됨</code></pre>
<h3 id="제한사항">제한사항</h3>
<blockquote>
<ul>
<li>var는 지역 변수에 대해서만 사용할 수 있습니다. 클래스 멤버 변수, 메서드의 매개변수, 반환값의 타입으로는 사용할 수 없습니다.</li>
</ul>
</blockquote>
<ul>
<li>var로 선언된 변수는 반드시 초기값이 있어야 합니다. 초기값이 없는 경우 컴파일 에러가 발생합니다.</li>
<li>var로 선언된 변수의 타입은 컴파일 시점에 결정되며, 런타임 시에는 변하지 않습니다.</li>
</ul>
<br>

<h3 id="주의-사항">주의 사항</h3>
<blockquote>
<p>var를 남용하면 코드의 가독성을 떨어뜨릴 수 있으므로 적절하게 사용하는 것이 중요합니다. 변수명이나 초기화 값에서 타입을 명시하는것이 코드의 가독성을 높일 수 있는 경우에는 명시적인 타입 선언을 사용하는 것이 좋습니다.</p>
</blockquote>
<p><br><br><br><br></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[JVM의 개념과 JDK/JRE]]></title>
            <link>https://velog.io/@ha_bu/JVM%EC%9D%98-%EA%B0%9C%EB%85%90%EA%B3%BC-JDKJRE</link>
            <guid>https://velog.io/@ha_bu/JVM%EC%9D%98-%EA%B0%9C%EB%85%90%EA%B3%BC-JDKJRE</guid>
            <pubDate>Wed, 22 May 2024 06:19:37 GMT</pubDate>
            <description><![CDATA[<h3 id="목표">목표</h3>
<blockquote>
<p>자바 소스 파일(.java)을 JVM으로 실행하는 과정 이해하기.</p>
</blockquote>
<h3 id="목차">목차</h3>
<p><a href="#1-jvm%EC%9D%B4%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80">1. JVM이란 무엇인가</a>
<a href="#2-%EC%BB%B4%ED%8C%8C%EC%9D%BC-%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95">2. 컴파일 하는 방법</a>
<a href="#3-%EC%8B%A4%ED%96%89%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95">3. 실행하는 방법</a>
<a href="#4-%EB%B0%94%EC%9D%B4%ED%8A%B8%EC%BD%94%EB%93%9C%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80">4. 바이트코드란 무엇인가</a>
<a href="#5-jit-%EC%BB%B4%ED%8C%8C%EC%9D%BC%EB%9F%AC%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B4%EB%A9%B0-%EC%96%B4%EB%96%BB%EA%B2%8C-%EB%8F%99%EC%9E%91%ED%95%98%EB%8A%94%EC%A7%80">5. JIT 컴파일러란 무엇이며 어떻게 동작하는지</a>
<a href="#6-jvm-%EA%B5%AC%EC%84%B1%EC%9A%94%EC%86%8C">6. JVM 구성요소</a>
<a href="#7-jdk%EC%99%80-jre%EC%9D%98-%EC%B0%A8%EC%9D%B4">7. JDK와 JRE의 차이</a></p>
<br>

<h2 id="1-jvm이란-무엇인가">1. JVM이란 무엇인가?</h2>
<blockquote>
<p>Java Virtual Machine. 자바를 실행하기 위한 자바 가상머신</p>
</blockquote>
<p>.java 파일을 컴파일러를 통해 .class 파일(ByteCode)로 만들고, 이를 운영체제가 이해할 수 있는 기계어로 바꿔주는 역할을 합니다.</p>
<p>이러한 JVM은 <strong>운영체제에 영향을 받지 않고 실행이 가능</strong>하도록 해줍니다.
<br></p>
<p><img src="https://upload.wikimedia.org/wikipedia/commons/d/dd/JvmSpec7.png" alt="JVM Specification Image"></p>
<p align="center" style="font-size: 0.9em; color: #555; margin-top: -45px;">Java Virtual Machine (JVM) 구조(위키 백과)</p>

<br>

<h3 id="실행순서">실행순서</h3>
<ol>
<li>프로그램이 실행되면 JVM은 운영체제로부터 실행하려는 프로그램이 필요로 하는 메모리에 할당 받습니다.
 (JVM은 이 메모리를 용도에 맞게 여러 영역으로 나누어 관리합니다.) <br></li>
<li>자바의 컴파일러(javac)가 소스코드(.java)를 읽어들여 자바 바이트코드(.class) 형식으로 바꿔줍니다. <br></li>
<li>Class Loader를 통해 class 파일을 JVM Memory에 적재합니다.<br></li>
<li>JVM Memory 영역에 적재된 class 파일을 Excution Engine을 통해 해석합니다.<br>

</li>
</ol>
<h2 id="2-컴파일-하는-방법">2. 컴파일 하는 방법</h2>
<blockquote>
<p>준비물 : java.exe , javac.exc</p>
</blockquote>
<p>&amp;nbspjavac.exe는 자바 소스코드를 컴파일 할때 사용하는 프로그램 입니다. 이때 만들어진 .class(바이트코드 파일) 을 실행하는게 java.exe 입니다.</p>
<pre><code>$ javac 소스파일명.java</code></pre><p>&amp;nbsp위와 같이 명령어를 입력하여, .class 파일을 생성할 수 있습니다.
만들어진 .class 파일은 같은경로에 생성되며, 이름 또한 소스파일명.java의 소스파일 명을 따라갑니다.</p>
<h3 id="참고">참고</h3>
<blockquote>
<p>컴파일러(javac.exe)와 실행파일(java.exe)의 JDK/JRE 버전은 일치해야 합니다. 컴파일 옵션을 통해 해결하는 방법도 있긴합니다.</p>
</blockquote>
<br>

<h2 id="3-실행하는-방법">3. 실행하는 방법</h2>
<pre><code>$ java 소스파일명</code></pre><p>위와 같은 명령어를 통해 java.exe 를통해 바이트 코드로 컴파일된 .class를 실행 할 수 있습니다.
<br><br></p>
<h2 id="4-바이트코드란-무엇인가">4. 바이트코드란 무엇인가</h2>
<p>&amp;nbsp프로그램을 실행하는것은 컴퓨터이기 때문에, 컴퓨터가 이해할 수 있는 기계어를 전달해주어야 합니다.</p>
<br>

<p>1) 바이너리 코드란?</p>
<ul>
<li>0과 1로 구성되어 있는 코드 입니다.</li>
<li>C언어로 작성 된 .c 파일을 컴파일한 .obj 파일이 바이너리 코드입니다.<blockquote>
<p>하지만, .obj 파일은 완벽한 기계어는 아닙니다. 이 파일을 완벽한 기계어로 변환하려면 <strong>&quot;링커&quot;</strong>가 필요한데, 이 링커는 여러 개의 코드와 데이터를 모아 연결하여 메모리에서 실행 가능한 파일로 만드는 역할을 해줍니다.</p>
</blockquote>
</li>
</ul>
<p>※ 즉, 기계어는 컴퓨터가 이해할 수 있는 0과 1로 이루어져있는 바이너리 코드이지만, <U>기계어가 바이너리 코드로 이루어졌을 뿐이지, 모든 바이너리코드가 기계어인것은 아닙니다!</U></p>
<br>

<p>2) 바이트 코드</p>
<p>&amp;nbsp c언어와 다르게 Java에서는 컴파일러(javac)에 의해 소스파일(.java)이 바이트코드(.class)가 되는데, 컴퓨터는 이 바이트 코드를 바로 인식할 수는 없습니다.</p>
<br>
이 바이트 코드를 인식할 수 있는게 바로 가상머신입니다. JVM을 통해 컴퓨터에게 코드를 전달 할 수 있는것입니다.

<br>
<br>

<h3 id="그럼-왜-귀찮게-이러한-과정을-거치는가">그럼 왜? 귀찮게 이러한 과정을 거치는가.</h3>
<p>JVM이 설치되어있다면, 그게 어떤 플랫폼이라도 실행을 할 수 있게 되기 때문입니다. 즉, 이 JVM을 통해 운영체제의 종류나, 개발이 수행되는 환경의 종류에 구애받지 않고, 프로그램을 실행할 수 있게 됩니다.</p>
<p><br><br></p>
<h2 id="5-jit-컴파일러란-무엇이며-어떻게-동작하는지">5. JIT 컴파일러란 무엇이며 어떻게 동작하는지</h2>
<h3 id="jit">JIT?</h3>
<blockquote>
<p>C나 C++처럼 프로그램을 실행하기 전에 처음 한 번 컴파일 하는 대신, 프로그램을 실행하는 시점에서 필요한 부분을 즉석으로 컴파일 하는 방식을 말합니다. (Just-In-Time)</p>
</blockquote>
<p>&amp;nbsp JIT 컴파일러는 바이트코드를 읽어 빠른 속도로 기계어를 생성할 수 있습니다. 이런 기계어 변환은 코드가 실행되는 과정에 실시간으로 일어나며(Just-In-Time), 전체 코드의 필요한 부분만 변환합니다. 기계어로 변환된 코드는 캐시에 저장되기 때문에 재사용시 컴파일을 다시 할 필요는 없습니다.
<br><br></p>
<h2 id="6-jvm-구성요소">6. JVM 구성요소</h2>
<p><img src="https://upload.wikimedia.org/wikipedia/commons/d/dd/JvmSpec7.png" alt="JVM Specification Image"></p>
<p align="center" style="font-size: 0.9em; color: #555; margin-top: -45px;">Java Virtual Machine (JVM) 구조(위키 백과)</p>

<br>

<h3 id="1-class-loader">1) Class Loader</h3>
<p>클래스 로더는 자바 바이트코드(.class)를 읽고 JVM 내로 클래스를 로드하는 역할을 합니다. 클래스 파일을 찾고, 읽고, 검사한 후, JVM의 메모리 영역에 적재합니다. 주된 작업은 다음과 같습니다. <br></p>
<blockquote>
<ul>
<li>로딩(Loading): 클래스 파일을 찾아 읽어들입니다.</li>
<li>링킹(Linking): 클래스 파일의 유효성을 검증하고, 참조를 해결하며, 메모리를 할당합니다.</li>
<li>초기화(Initialization): 클래스 변수들을 초기화하고 static 블록을 실행합니다.</li>
</ul>
</blockquote>
<br> 

<h3 id="2-jvm-memory">2) JVM Memory</h3>
<p>JVM 메모리는 프로그램 실행 중에 필요한 데이터를 저장하는 여러 메모리 영역으로 나뉩니다.</p>
<blockquote>
<ul>
<li>Method Area(메소드 영역): 클래스 메타데이터, 상수 풀, 스태틱 변수, 메소드 코드 등이 저장됩니다. 일반적으로 퍼머넌트 제너레이션(PermGen) 또는 메타스페이스(Metaspace)로 구현됩니다.</li>
<li>Heap(힙): 모든 객체 인스턴스와 배열이 저장되는 영역입니다. <U>가비지 컬렉터</U>가 이 영역을 관리하며, Young Generation과 Old Generation으로 나뉩니다.</li>
<li>JVM Language Stacks(JVM 언어 스택): 각 스레드마다 존재하며, 메소드 호출 시 생성되는 프레임을 저장합니다. 프레임에는 지역 변수, 피연산자 스택, 메소드 호출/복귀 정보가 포함됩니다.</li>
<li>PC Resgisters(PC 레지스터): 각 스레드마다 존재하며, 현재 실행 중인 JVM 명령의 주소를 저장합니다.</li>
<li>Native Method Stacks(네이티브 메소드 스택): 네이티브 메소드(자바 이외의 언어로 작성된 메소드) 호출시 사용되는 스택입니다.</li>
</ul>
</blockquote>
<br>

<h3 id="3-execution-engine실행-엔진">3) Execution Engine(실행 엔진)</h3>
<p>실행 엔진은 바이트코드를 실제로 실행하는 역할을 합니다. 실행 엔진은 다음의 세 가지 주요 구성 요소로 이루어져 있습니다.</p>
<blockquote>
<ul>
<li>Interpreter : 바이트 코드를 한 줄씩 읽고 실행합니다. 처음에는 빠르게 실행할 수 있지만, 반복문 등에서 속도가 느려질 수 있습니다.</li>
<li>JIT Compiler : 인터프리터의 단점을 보완하기 위해, 자주 사용되는 코드(핫스팟)를 기계어로 변환하여 실행 속도를 높입니다. 컴파일된 코드는 캐시에 저장되어 이후 빠르게 실행됩니다.</li>
<li>Garbage Collector: 힙 영역을 관리하며, 사용되지 않는 객체를 자동으로 메모리에서 해제하여 메모리 누수를 방지합니다. </li>
</ul>
</blockquote>
<p>** ✨ Garbage Collector의 역할 **</p>
<ul>
<li><strong>객체 할당</strong>: 새 객체가 생성될 때 힙 영역에 메모리를 할당합니다.</li>
<li><strong>객체 수집</strong>: 더 이상 참조되지 않는 객체를 식별하고 메모리를 회수합니다.</li>
<li><strong>메모리 정리</strong>: 힙 영역의 단편화를 줄이기 위해 메모리를 정리하고 재배치합니다.</li>
</ul>
<br>

<h3 id="4-native-method-interface">4) Native Method Interface</h3>
<p>네이티브 메소드 인터페이스는 자바 코드에서 네이티브(비자바) 코드를 호출할 수 있도록 해주는 프레임워크입니다. 주로 C, C++로 작성된 네이티브 라이브러리와 상호작용할 때 사용됩니다.</p>
<br>

<h3 id="5-native-method-libraries">5) Native Method Libraries</h3>
<p>네이티브 메소드 라이브러리는 JVM이 네이티브 메소드 인터페이스를 통해 호출할 수 있는 네이티브 코드로 작성된 라이브러리입니다. 예를 들어, 자바에서 시스템 레벨의 기능을 사용하기 위해 운영체제 API를 호출할 때 사용됩니다. </p>
<h3 id="세줄요약">세줄요약</h3>
<ol>
<li>JVM은 자바 애플리케이션을 실행하기 위한 시스템</li>
<li>Class Loader는 클래스 파일을 로드하고, JVM Memory는 실행 중 필요한 데이터를 저장하며, Execution Engine은 바이트코드를 실제로 실행함.</li>
<li>Native Method Interface와 Native Method Libraries는 자바의 코드와 네이티브 코드를 연결하는 부가적이며 강력한 기능을 함.</li>
</ol>
<p><br> <br></p>
<h2 id="7-jdk와-jre의-차이">7. JDK와 JRE의 차이</h2>
<h3 id="1-jdk">1) JDK</h3>
<p>JDK는 자바 개발도구(Java Development Kit)의 약자입니다. Java로 애플리케이션을 개발하고 컴파일할 수 있도록 해주는 개발 환경의 세트를 의미합니다. JDK는 다음과 같은 구성 요소를 포함합니다:</p>
<ul>
<li><strong>javac</strong>: 자바 컴파일러로, 자바 소스 코드를 바이트코드로 컴파일합니다.</li>
<li><strong>java</strong>: 자바 애플리케이션을 실행하는 명령어입니다.</li>
<li><strong>jar</strong>: 자바 아카이브 도구로, 여러 클래스 파일을 하나의 압축 파일로 묶습니다.</li>
<li><strong>javadoc</strong>: 자바 소스 코드에서 API 문서를 생성하는 도구입니다.</li>
<li><strong>visualVM</strong>: 자바 애플리케이션의 모니터링, 디버깅, 프로파일링을 위한 도구입니다.</li>
<li><strong>기타 유틸리티</strong>: 다양한 개발 도구와 유틸리티를 포함하여 개발 과정에서 필요한 여러 기능을 제공합니다.</li>
</ul>
<p>JDK는 JRE(Java Runtime Environment)를 포함하며, 개발에 필요한 도구들을 추가적으로 제공합니다. 따라서, 자바 애플리케이션을 개발하고 실행할 수 있는 완전한 환경을 제공하는 것이 JDK입니다.</p>
<h3 id="jre">JRE</h3>
<p>JRE는 자바 실행환경(Java Runtime Environment)의 약자입니다. 자바 애플리케이션을 실행할 수 있는 환경을 제공합니다. JRE는 다음과 같은 구성 요소를 포함합니다:</p>
<ul>
<li><strong>JVM (Java Virtual Machine)</strong>: 자바 바이트코드를 실행하는 가상 머신으로, 플랫폼 독립적인 실행 환경을 제공합니다.</li>
<li><strong>클래스 라이브러리</strong>: 자바 표준 라이브러리로, 자바 애플리케이션이 사용하는 다양한 클래스와 인터페이스를 포함합니다. 예를 들어, 컬렉션 프레임워크, I/O, 네트워킹, GUI, 유틸리티 클래스 등이 포함됩니다.</li>
<li><strong>구성 파일 및 설정</strong>: JVM과 클래스 라이브러리의 동작을 제어하는 구성 파일과 설정을 포함합니다.</li>
</ul>
<p>JRE는 자바 애플리케이션을 개발할 필요는 없지만, 자바 애플리케이션을 실행할 수 있는 환경을 제공합니다. 따라서, 자바 애플리케이션을 실행하려는 사용자나 서버 환경에서는 JRE만 설치하면 충분합니다.</p>
]]></description>
        </item>
    </channel>
</rss>