<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>gxxmyx.x</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Wed, 03 Apr 2024 02:12:04 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>gxxmyx.x</title>
            <url>https://velog.velcdn.com/images/geumyi_/profile/254b52fc-fbe1-4001-bf07-bf97b8c69caa/image.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. gxxmyx.x. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/geumyi_" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[Java] 컬렉션 프레임워크_LIFO와 FIFO 컬렉션]]></title>
            <link>https://velog.io/@geumyi_/Java-%EC%BB%AC%EB%A0%89%EC%85%98-%ED%94%84%EB%A0%88%EC%9E%84%EC%9B%8C%ED%81%ACLIFO%EC%99%80-FIFO-%EC%BB%AC%EB%A0%89%EC%85%98</link>
            <guid>https://velog.io/@geumyi_/Java-%EC%BB%AC%EB%A0%89%EC%85%98-%ED%94%84%EB%A0%88%EC%9E%84%EC%9B%8C%ED%81%ACLIFO%EC%99%80-FIFO-%EC%BB%AC%EB%A0%89%EC%85%98</guid>
            <pubDate>Wed, 03 Apr 2024 02:12:04 GMT</pubDate>
            <description><![CDATA[<h3 id="✔️-lifo-fifo">✔️ LIFO, FIFO</h3>
<p>
<img src="https://velog.velcdn.com/images/geumyi_/post/3aa4a293-5dee-4665-980e-f2ef2292eefe/image.png">  
</p>

<p><strong>- LIFO(Last In First Out)</strong>
: 나중에 넣은 객체가 먼저 빠져나가는 구조</p>
<p><strong>- FIFO(First In First Out)</strong>
: 먼저 넣은 객체가 먼저 빠져나가는 자료구조</p>
<p>→ 컬렉션 프레임워크에는
<strong>LIFO(리포) 자료구조를 제공하는 Stack 클래스</strong>와
<strong>FIFO(피포) 자료구조를 제공하는 Queue 인터페이스</strong>를 
제공하고 있음</p>
<hr>
<h3 id="✔️-stack">✔️ Stack</h3>
<p>: Stack 클래스는 LIFO 자료구조를 구현한 클래스</p>
<p>
<img src="https://velog.velcdn.com/images/geumyi_/post/c3dc98b8-0751-489a-8c1c-b49e0a1de03d/image.png">  
</p>

<p>: Stack 객체를 생성하려면 
저장할 객체 타입을 E 타입 파라미터 자리에 표기하고
기본 생성자를 호출하면 됨</p>
<pre><code>ex) String을 저장하는 Stack
Stack&lt;E&gt; stack = new Stack&lt;E&gt;();
Stack&lt;E&gt; stack = new Stack&lt;&gt;();</code></pre><pre><code class="language-java">import java.util.*;

/*
 * 동전 케이스는 위에만 열려 있는 스택 구조를 가짐
 * 먼저 넣은 동전은 제일 밑에 깔리고 
 * 나중에 넣은 동전이 위에 쌓이기 때문에
 * Stack에서 동전을 빼면 마지막에 넣은 동전이
 * 먼저 나오게 됨
 */

// 동전 클래스
class Coin {
    private int value;

    public Coin(int value) {
        this.value = value;
    }

    public int getValue() {
        return value;
    }
}

// Stack을 이용한 동전 클래스
public class StackExample {
    public static void main(String[] args) {
        Stack&lt;Coin&gt; coinBox = new Stack&lt;Coin&gt;();

        coinBox.push(new Coin(100));
        coinBox.push(new Coin(50));
        coinBox.push(new Coin(500));
        coinBox.push(new Coin(10));

        while(!coinBox.isEmpty()) {
            Coin coin = coinBox.pop();
            System.out.println(&quot;꺼내온 동전: &quot; + coin.getValue() + &quot;원&quot;);
        }
    }
}

💻 결과
꺼내온 동전: 10원
꺼내온 동전: 500원
꺼내온 동전: 50원
꺼내온 동전: 100원</code></pre>
<hr>
<h3 id="✔️-queue">✔️ Queue</h3>
<p>: Queue 인터페이스는 FIFO 자료구조에서 사용되는 메소드를 정의하고 있음</p>
<p>
<img src="https://velog.velcdn.com/images/geumyi_/post/350f8f29-a0c2-4875-b363-05bd21a3847a/image.png" width="90%">  
</p>

<p>: Queue 인터페이스를 구현한
대표적인 클래스는 LinkedList임
LInkedList는 List 인터페이스를 구현했기 때문에
List 컬렉션이기도 함</p>
<p><strong>- LinkedList 객체를 Queue 인터페이스 타입으로 변환한 것</strong></p>
<pre><code>Queue&lt;E&gt; queue = new LinkedList&lt;E&gt;();
Queue&lt;E&gt; queue = new LinkedList&lt;&gt;();</code></pre><pre><code class="language-java">import java.util.*;

/*
 * 먼저 넣은 메시지가
 * 반대쪽으로 먼저 나오기 떄문에
 * 넣은 순서대로 메시지가 처리됨
 */

// Message 클래스
class Message {
    public String command;
    public String to;

    public Message(String command, String to) {
        this.command = command;
        this.to = to;
    }
}

// Queue를 이용한 메시지 큐
public class QueueExample {
    public static void main(String[] args) {
        Queue&lt;Message&gt; messageQueue = new LinkedList&lt;Message&gt;();

        messageQueue.offer(new Message(&quot;sendMail&quot;, &quot;홍길동1&quot;));
        messageQueue.offer(new Message(&quot;sendMail&quot;, &quot;홍길동2&quot;));
        messageQueue.offer(new Message(&quot;sendMail&quot;, &quot;홍길동3&quot;));

        while(!messageQueue.isEmpty()) {
            // 메시지 큐에서 1개의 메시지 꺼냄
            Message message = messageQueue.poll();
            switch(message.command) {
                case &quot;sendMail&quot;:
                    System.out.println(message.to 
                   + &quot;님에게 메일을 보냅니다.&quot;);
                    break;
                case &quot;sendSMS&quot;:
                    System.out.println(message.to 
                    + &quot;님에게 SMS를 보냅니다.&quot;);
                    break;
                case &quot;sendKaKaoTalk&quot;:
                    System.out.println(message.to 
                    + &quot;님에게 카카오톡을 보냅니다.&quot;);
                    break;
            }

        }
    }
}


💻 결과
홍길동1님에게 메일을 보냅니다.
홍길동2님에게 메일을 보냅니다.
홍길동3님에게 메일을 보냅니다.</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] 컬렉션 프레임워크_Map 컬렉션]]></title>
            <link>https://velog.io/@geumyi_/Java-%EC%BB%AC%EB%A0%89%EC%85%98-%ED%94%84%EB%A0%88%EC%9E%84%EC%9B%8C%ED%81%ACMap-%EC%BB%AC%EB%A0%89%EC%85%98</link>
            <guid>https://velog.io/@geumyi_/Java-%EC%BB%AC%EB%A0%89%EC%85%98-%ED%94%84%EB%A0%88%EC%9E%84%EC%9B%8C%ED%81%ACMap-%EC%BB%AC%EB%A0%89%EC%85%98</guid>
            <pubDate>Wed, 03 Apr 2024 02:06:05 GMT</pubDate>
            <description><![CDATA[<h3 id="✔️-map-컬렉션">✔️ Map 컬렉션</h3>
<p>
<img src="https://velog.velcdn.com/images/geumyi_/post/46f6c164-37f8-440f-b3c5-3cd71700cc73/image.png" width="90%">  
</p>

<p>: <strong>키(key)와 값(value)</strong>으로 구성된** Map.Entry 객체를 저장하는 구조**를 가지고 있음</p>
<p>: Entry는 <strong>Map 인터페이스 내부에 선언된 중첩 인터페이스</strong>임
여기서 <strong>키와 값은 모두 객체</strong>임</p>
<p>: 키는 중복 저장될 수 없지만 <strong>값은 중복 저장</strong>될 수 있음</p>
<p><strong>만약 기존에 저장된 키와 동일한 키로 값을 저장</strong>하면
기존의 값은 없어지고 <strong>새로운 값으로 대</strong>체됨</p>
<p>: Map 컬렉션에는
<strong>HashMap, Hashtable, LinkedHashMap, Properties, TreeMap</strong> 등이 있음</p>
<ul>
<li>Map 컬렉션에서 공통적으로 사용 가능한 Map 인터페이스의 메소드</li>
</ul>
<p>
<img src="https://velog.velcdn.com/images/geumyi_/post/edb9bb0f-4759-4d27-b387-aafd293ad9cd/image.png">  
</p>

<p>: 키로 객체들을 관리히기 때문에 <strong>키를 매개값으로 갖는 메소드가 많음</strong></p>
<p>: 메소드의 매개 변수 타입과 리턴 타입에 K와 V라는 타입 파라미터는
저장되는 키와 객체의 타입을 Map 컬렉션을 생성할 때 결정하라는 뜻</p>
<pre><code>ex)
키 타입이 String, 값 타입이 Integer인 Map 컬렉션을 생성하고,
put()메소드로 키와 값을 저장함

그리고 키로 값을 얻거나 제거하기 위해
get()과 remove() 메소드를 사용함

Map&lt;String, Integer&gt; map = ···;
map.put(&quot;홍길동&quot;, 30);
int score = map.get(&quot;홍길동&quot;);
map.remove(&quot;홍길동&quot;);

: Map&lt;String, Integer&gt;로 map 변수를 선언
이것은 Map 컬렉션에 저장되는 키 객체는 String 타입으로,
값 객체는 Integer 타입으로 하겠다는 뜻

따라서 K 타입 파라미터는 String이 되고,
V 타입 파라미터는 Integer가 되는 것

그래서 put() 메소드의 첫 번째 매개 값은 문자열이고,
두 번째 매개값은 30이 포장된 Integer 객체(자동 박싱)가 됨</code></pre><p><strong>- 저장된 전체 객체를 대상으로 하나씩 얻고 싶을 경우</strong></p>
<p>1) keySet() 메소드로 모든 키를 Set 컬렉션으로 얻은 다음,
반복자를 통해 키를 하나씩 얻고 get() 메소드를 통해 값을 얻는 방법</p>
<pre><code>Map&lt;K, V&gt; map = ···;
Set&lt;K&gt; keySet = map.keySet();
Iterator&lt;K&gt; keyIterator = keySet.iterator();
while(keyIterator.hasNext()) {
    K key = keyIterator.next();
    V value = map.get(key);
}</code></pre><p>2)  entrySet() 메소드로 모든 Map.Entry를 Set 컬렉션으로 얻은 다음,
반복자를 통해 Map.Entry를 하나씩 얻고 
getKey()와 getValue() 메소드를 이용해 키와 값을 얻는 방법</p>
<pre><code>Set&lt;Map.Entry&lt;K,V&gt;&gt; entrySet = map.entrySet();
Iterator&lt;Map.Entry&lt;K, V&gt;&gt; entryIterator = entrySet.iterator();
while(entryIterator.hasNext()) {
    Map.Entry&lt;K, V&gt; entry = entryIterator.next();
    K key = entry.getKey();
    V value = entry.getValue();
}</code></pre><hr>
<h3 id="✔️-hashmap">✔️ HashMap</h3>
<p>: Map 인터페이스를 구현한 대표적은 Map 컬렉션</p>
<p>: HashMap의 키로 사용할 객체는
hashCode()와 equals() 메소드를 재정의해서 
동등 객체가 될 조건을 정해야함</p>
<p>: 객체가 달라도 동등 객체라면 같은 키로 간주하고
중복 저장되지 않도록 하기 위함</p>
<p>: 동등 객체의 조건은 hashCode()의 리턴값이 같아야 하고,
 equalsd() 메소드가 true를 리턴해야함</p>
<p>: 주로 키 타입은 String을 많이 사용하는데,
String은 문자열이 같을 경우 동등 객체가 될 수 있도록
hashCode()와 equals() 메소드가 재정의되어 있음</p>
<p><strong>- HashMap 생성</strong></p>
<pre><code>Map&lt;K, V&gt; amp = new HasMap&lt;K, V&gt;();

키 타입과 값 타입을 타입 파라미터로 주고 기본 생성자를 호출하면됨</code></pre><p>: 키와 값의 타입은 
기본 타입(byte, short, int, float, double, boolean, char)을 사용할 수 없고 
<strong>클래스 및 인터페이스 타입만 사용 가능</strong>함</p>
<pre><code>ex) 키로 String 타입을 사용하고 값으로 Integer 타입을 사용시 HashMap 생성
Map&lt;String, Integer&gt; map = new HashMap&lt;String, Integer&gt;();
Map&lt;String, Integer&gt; map = new HashMap&lt;&gt;();</code></pre><pre><code>👩‍💻 이름을 키로 점수를 값으로 저장하기
import java.util.*;

public class HashMapExample {

    public static void main(String[] args) {
        //Map 컬렉션 생성
        Map&lt;String, Integer&gt; map = new HashMap&lt;String, Integer&gt;();

        //객체 저장
        //홍길동2는 키가 같기 떄문에 마지막 저장 값으로 대체
        map.put(&quot;홍길동1&quot;, 85);
        map.put(&quot;홍길동2&quot;, 90);
        map.put(&quot;홍길동3&quot;, 80);
        map.put(&quot;홍길동2&quot;, 95);
        System.out.println(&quot;총 Entry 수: &quot; + map.size());

        //객체 찾기
        //이름(키)으로 점수(값)를 검색
        System.out.println(&quot;\t홍길동2: &quot; + map.get(&quot;홍길동2&quot;));
        System.out.println();

        //객체를 하나씩 처리
        Set&lt;String&gt; keySet = map.keySet();
        Iterator&lt;String&gt; keyIterator = keySet.iterator();
        while(keyIterator.hasNext()) {
            String key = keyIterator.next();
            Integer value = map.get(key);
            System.out.println(&quot;\t&quot; + key + &quot;: &quot; + value);
        }
        System.out.println();

        //객체 삭제
        map.remove(&quot;홍길동2&quot;);
        System.out.println(&quot;총 Entry 수: &quot; + map.size());

        //객체를 하나씩 처리
        Set&lt;Map.Entry&lt;String, Integer&gt;&gt; entrySet = map.entrySet();
        Iterator&lt;Map.Entry&lt;String, Integer&gt;&gt; entryIterator = 
        entrySet.iterator();

        while(entryIterator.hasNext()) {
            Map.Entry&lt;String, Integer&gt; entry = entryIterator.next();
            String key = entry.getKey();
            Integer value = entry.getValue();
            System.out.println(&quot;\t&quot; + key + &quot;: &quot; + value);
        }
        System.out.println();

        //객체 전체 삭제
        map.clear();
        System.out.println(&quot;총 Entry 수: &quot; + map.size());
    }

}

💻 결과
총 Entry 수: 3
    홍길동2: 95

    홍길동2: 95
    홍길동3: 80
    홍길동1: 85

총 Entry 수: 2
    홍길동3: 80
    홍길동1: 85

총 Entry 수: 0</code></pre><pre><code class="language-import">
// 키로 사용할 객체
// hashCode()와 equals() 재정의
class Student {
    public int sno;
    public String name;

    public Student(int sno, String name) {
        this.sno = sno;
        this.name = name;
    }

    public boolean equals(Object obj) {
        if(obj instanceof Student) {
            Student student = (Student) obj;
            return (sno == student.sno) &amp;&amp; (name.equals(student.name));
        } else {
            return false;
        }
    }

    public int hashCode() {
        return sno + name.hashCode();
    }
}

// 학번과 이름이 동일한 경우 같은 키로 인식
public class HashMapExample2 {
    public static void main(String[] args) {
        Map&lt;Student, Integer&gt; map = new HashMap&lt;Student, Integer&gt;();

        map.put(new Student(1, &quot;홍길동&quot;), 95);
        map.put(new Student(1, &quot;홍길동&quot;), 95);

        System.out.println(&quot;총 Entry 수: &quot; + map.size());
    }
}

💻 결과
총 Entry 수: 1</code></pre>
<hr>
<h3 id="✔️-hashtable">✔️ Hashtable</h3>
<p>: HashMap과 동일한 내부 구조를 가짐
: 키로 사용할 객체는 <strong>hashCode()와 equals() 메소드를
재정의해서 동등 객체가 될 조건</strong>을 정해야함</p>
<p>: <strong>HashMap과 차이점</strong>은
Hashtable은 동기화된 메소드로 구성되어 있기 때문에
멀티 스레드가 동시에 Hashtable의 메소드들을 실행할 수 없고,
하나의 스레드가 실행을 완료해야만 다른 스레드를 실행할 수 있다는 것</p>
<p>그래서 멀티 스레드 환경에서 안전하게 객체를 추가, 삭제할 수 있기 때문에
Hashtable은 스레드에 안전함</p>
<p><strong>- 생성방법</strong></p>
<pre><code>Map&lt;K, V&gt; map = new Hashtable&lt;K, V&gt;();</code></pre><p>-방법</p>
<pre><code>ex) 키로 String 타입을 사용하고, 값으로 Integer 타입을 사용하는 Hashtable 생성
Map&lt;String, Integer&gt; map = new Hashtable&lt;String, Integer&gt;();
Map&lt;String, Integer&gt; map = new Hashtable&lt;&gt;();</code></pre><pre><code>👩‍💻 아이디와 비밀번호 검사하기
import java.util.*;

public class HashTableExample {
    public static void main(String[] args) {
        Map&lt;String, String&gt; map = new Hashtable&lt;String, String&gt;();

        map.put(&quot;spring&quot;, &quot;12&quot;);
        map.put(&quot;summer&quot;, &quot;123&quot;);
        map.put(&quot;fall&quot;, &quot;1234&quot;);
        map.put(&quot;winter&quot;, &quot;12345&quot;);

        Scanner scanner = new Scanner(System.in);

        while(true) {
            System.out.println(&quot;아이디와 비밀번호르 입력해주세요.&quot;);
            System.out.println(&quot;아이디: &quot;);
            String id = scanner.nextLine();

            System.out.println(&quot;비밀번호: &quot;);
            String password = scanner.nextLine();
            System.out.println();

            if(map.containsKey(id)) {
                if(map.get(id).equals(password)) {
                    System.out.println(&quot;로그인되었습니다.&quot;);
                    break;
                }else {
                    System.out.println(&quot;비밀번호가 일치하지 않습니다.&quot;);
                }
            } else {
                System.out.println(&quot;입력하신 아이디가 존재하지 않습니다.&quot;);
            }
        }
    }
}

💻 결과
아이디와 비밀번호르 입력해주세요.
아이디: 
summer
비밀번호: 
123

로그인되었습니다.</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] 컬렉션 프레임워크_Set 컬렉션]]></title>
            <link>https://velog.io/@geumyi_/Java-%EC%BB%AC%EB%A0%89%EC%85%98-%ED%94%84%EB%A0%88%EC%9E%84%EC%9B%8C%ED%81%ACSet-%EC%BB%AC%EB%A0%89%EC%85%98</link>
            <guid>https://velog.io/@geumyi_/Java-%EC%BB%AC%EB%A0%89%EC%85%98-%ED%94%84%EB%A0%88%EC%9E%84%EC%9B%8C%ED%81%ACSet-%EC%BB%AC%EB%A0%89%EC%85%98</guid>
            <pubDate>Wed, 03 Apr 2024 01:42:31 GMT</pubDate>
            <description><![CDATA[<h3 id="✔️-set-컬렉션">✔️ Set 컬렉션</h3>
<p>: List 컬렉션은 객체의 저장 순서를 유지할 수 있지만
<strong>Set 컬렉션은 저장 순서가 유지되지 않음</strong>
그리고 <strong>객체를 중복해서 저장할 수 없고</strong>,
<strong>하나의 null만 저장할 수 있음</strong></p>
<p>: Set 컬렉션은 
&amp;nbsp&amp;nbsp <strong>= 수학의 집합과 비슷함</strong>
&amp;nbsp&amp;nbsp → 집합은 순서와 상관없고 중복이 허용되지 않기 때문</p>
<p>&amp;nbsp&amp;nbsp <strong>= 구슬 주머니와도 같음</strong>
&amp;nbsp&amp;nbsp → 동일한 구슬을 2개 넣을 수 없고,
&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp 들어갈(저장할) 때의 순서와
&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp 나올(찾을) 때의 순서가 다를 수도 있기 때문</p>
<p>: Set 컬렉션에는 <strong>HashSet, LinkedHashSet, TreeSet</strong> 등이 있음</p>
<p><strong>- Set 인터페이스의 메소드</strong></p>
<p>
<img src="https://velog.velcdn.com/images/geumyi_/post/ea07726a-4776-4d18-86b5-d24bbce40876/image.png">  
</p>

<p>: 인덱스로 관리하지 않기 때문에 인덱스를 매개값으로 갖는 메소드가 없음</p>
<p>: 메소드의 매개 변수 타입과 리턴 타입에  E라는 타입 파라미터가 있는데,
이것은 저장되는 객체의 타입을 Set 컬렉션을 생성할 때 결정하라는 뜻</p>
<pre><code>ex)
Set컬렉션에 String 객체를 저장하고 삭제하는 방법

Set&lt;String&gt; set = ···;
set.add(&quot;홍길동&quot;);        // 객체 추가
set.add(&quot;홍길동2&quot;);    
set.remove(&quot;홍길동&quot;);    // 객체 삭제

→ Set&lt;String&gt;으로 set 변수를 선언함
이것은 Set 컬렉션에 저장되는 객체를 String으로 하겠단 의미

따라서 E 타입 파라미터는 String 타입이 되는 것임

그래서 add() 메소드와 remove() 메소드의 매개값은 문자열이 됨</code></pre><p>: Set 컬렉션은 인덱스로 객체를 검색해서 가져오는 메소드가 없음</p>
<p>대신, 전체 객체를 대상으로 한 번씩 반복해서 가져오는 <strong>반복자(Iterator)를 제공</strong>함</p>
<p>반복자는 <strong>Iterator 인터페이스를 구현한 객체</strong>를 말하는데,
iterator() 메소드를 호출하면 얻을 수 있음</p>
<pre><code>Set&lt;String&gt; set = ···;
Iterator&lt;String&gt; iterator = set.iterator();

: Iterator&lt;String&gt; 타입의 iterator 변수에 대입한 이유는
반복해서 가져올 객체가 String 타입이기 때문임</code></pre><p><strong>- Iterator 인터페이스에 선언된 메소드</strong></p>
<p>
<img src="https://velog.velcdn.com/images/geumyi_/post/53668408-1cef-4dec-9570-2956bd52c482/image.png">  
</p>

<p><strong>· next() , hasNext()</strong>
: <strong>하나의 객체를 가져올 때는 next() 메소드를 사용</strong>함
: 메소드를 사용하기 전에 먼저 가져올 객체가 있는지 확인하는 것이 좋음</p>
<p>: hasNext() 메소드는
<strong>가져올 객체가 있으면 true를 리턴</strong>하고
<strong>더이상 가져올 객체가 없으면 false를 리턴</strong>함</p>
<p>따라서 true가 리턴하고
더 이상 가져올 객체가 없으면 false를 리턴함
따라서 <strong>true가 리턴될 때 next() 메소드를 사용</strong>해야함</p>
<pre><code>- Set 컬렉션에서 String 객체들을 반복해서 하나씩 가져오는 코드

Set&lt;String&gt; set = ···;
Iterator&lt;String&gt; iterator = set.iterator();
while(iterator.hasNext()) {
    //String 객체 하나를 가져옴
    String str = iterator.next();
}

- Iterator를 사용하지 않더라도 향상된 for문을 이용해서
전체 객체를 대상으로 반복할 수 있음

Set&lt;String&gt; set = ···;
for(String str : set) {
}</code></pre><p>: Set 컬렉션에서 Iterator의 next() 메소드로
가져온 객체를 제거하고 싶다면 remove()메소드를 호출하면 됨</p>
<p>Iterator의 메소드이지만, 실제 Set 컬렉션에서 객체가 제거됨을 알아야함</p>
<pre><code>- Set 컬렉션에서 &quot;홍길동&quot;을 제거하기

while(iterator.hasNext()) {
    String str = iterator.next();
    if(str.equals(&quot;홍길동&quot;)) {
        iterator.remove();
    }
}</code></pre><hr>
<h3 id="✔️-hashset">✔️ HashSet</h3>
<p>: Set 인터페이스의 구현 클래스임</p>
<pre><code>Set&lt;E&gt; set = new HashSet&lt;E&gt;();

: 타입 파라미터 E에는 컬렉션에 저장할 객체 타입을 지정하면 됨</code></pre><p><strong>- String 객체를 저장하는 HashSet 생성하기</strong></p>
<pre><code>Set&lt;String&gt; set = new HashSet&lt;String&gt;();
Set&lt;String&gt; set = new HashSet&lt;&gt;();</code></pre><p>: HashSet은 <strong>객체들을 순서 없이 저장</strong>하고 <strong>동일한 객체는 중복 저장하지 않음</strong></p>
<p>: HashSet이 판단하는 동일한 객체란 <strong>꼭 같은 인스턴스를 뜻하지는 않음</strong></p>
<p>: HashSet은 객체를 저장하기 전에
먼저 객체의 hashCode() 메소드를 호출해서 해시코드를 얻어내고, 
이미 저장되어 있는 객체들의 해시코드와 비교함</p>
<p>만약 동일한 해시코드가 있다면 다시 equals() 메소드로 
두 객체를 비교해서 true가 나오면 동일한 객체로 판단하고 중복 저장을 하지 않음</p>
<p>: 문자열을 HashSet에 저장할 경우에
같은 문자열을 갖는 String 객체는 동등한 객체로 간주되고
다른 문자열을 갖는 String 객체는 다른 객체로 간주됨</p>
<p>그 이유는 String 클래스가 hashCode()와 equals() 메소드를
재정의해서 같은 문자열일 경우 
hashCode()의 리턴값은 같게,
equals()의 리턴값은 true가 나오도록 했기 때문임</p>
<pre><code>👩‍💻 String 객체를 중복 없이 저장하는 HashSet

import java.util.*;

public class HashSetExample {
    public static void main(String[] args) {
        Set&lt;String&gt; set = new HashSet&lt;String&gt;();

        // &quot;Java&quot;는 한번만 저장됨
        set.add(&quot;Java&quot;);
        set.add(&quot;JDBC&quot;);
        set.add(&quot;Servlet/JSP&quot;);
        set.add(&quot;Java&quot;);
        set.add(&quot;iBATIS&quot;);

        // 저장된 객체 수 얻기
        int size = set.size();
        System.out.println(&quot;총 객체수: &quot; + size);

        // 반복자 얻기
        Iterator&lt;String&gt; iterator = set.iterator();
        while(iterator.hasNext()) {
            // 1개의 객체를 가져옴
            String element = iterator.next();
            System.out.println(&quot;\t&quot; + element);
        }

        // 1개의 객체 삭제
        set.remove(&quot;JDBC&quot;);
        set.remove(&quot;iBATIS&quot;);

        System.out.println(&quot;총 객체수: &quot; + set.size());

        // 반복자 얻기
        iterator = set.iterator();
        for(String element : set) {
            System.out.println(&quot;\t&quot; + element);
        }

        // 모든 객체를 제거하고 비움
        set.clear();
        if(set.isEmpty()) {
            System.out.println(&quot;비어 있음&quot;);
        }
    }
}

💻 결과
총 객체수: 4
    Java
    JDBC
    Servlet/JSP
    iBATIS
총 객체수: 2
    Java
    Servlet/JSP
비어 있음</code></pre><pre><code>👩‍💻
import java.util.*;

// hashCode()와 equals()메소드 재정의
class Member {
    public String name;
    public int age;

    public Member(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public boolean equals(Object obj) {
        if(obj instanceof Member) {
            Member member = (Member) obj;
            return member.name.equals(name) &amp;&amp; (member.age == age);
        } else {
            return false;
        }
    }

    @Override
    // name과 age 값이 같으면 동일한 hashCode를 리턴
    public int hashCode() {
        // name.hashCode()
        // String의 hashCode() 이용
        return name.hashCode() + age;
    }
}

// Member 객체를 중복 없이 저장하는 HashSet
public class HashSetExample2 {
    public static void main(String[] args) {
        Set&lt;Member&gt; set = new HashSet&lt;Member&gt;();

        // 인스턴스는 다르지만 내부 데이터가
        // 동일하므로 객체 1개만 저장
        set.add(new Member(&quot;홍길동&quot;, 30));
        set.add(new Member(&quot;홍길동&quot;, 30));

        System.out.println(&quot;총 객체수: &quot; + set.size());
    }
}

💻 결과
총 객체수: 1</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] 컬렉션 프레임워크_List 컬렉션]]></title>
            <link>https://velog.io/@geumyi_/Java-%EC%BB%AC%EB%A0%89%EC%85%98-%ED%94%84%EB%A0%88%EC%9E%84%EC%9B%8C%ED%81%ACList-%EC%BB%AC%EB%A0%89%EC%85%98</link>
            <guid>https://velog.io/@geumyi_/Java-%EC%BB%AC%EB%A0%89%EC%85%98-%ED%94%84%EB%A0%88%EC%9E%84%EC%9B%8C%ED%81%ACList-%EC%BB%AC%EB%A0%89%EC%85%98</guid>
            <pubDate>Wed, 03 Apr 2024 01:33:22 GMT</pubDate>
            <description><![CDATA[<h3 id="✔️-list-컬렉션">✔️ List 컬렉션</h3>
<p>: 배열과 비슷하게 객체를 인덱스로 관리함</p>
<p><strong>- 배열과 차이점</strong>
: 저장 용량이 자동으로 증가
: 객체를 저장할 때 자동 인덱스가 부여됨
: 추가, 삭제, 검색을 위한 다양한 메소드들이 제공됨</p>
<p>
<img src="https://velog.velcdn.com/images/geumyi_/post/00aa823c-5809-4f84-80dc-476302776284/image.png
" width="90%">  
</p>

<p>: 객체 자체를 저장하는 것이 아니라 <strong>객체의 번지를 참조</strong>함
→ 그렇기 때문에 동일한 객체를 중복 저장할 수 있는데,
이 경우 동일한 번지가 참조됨
: null도 저장이 가능하며, 
이 경우 해당 인덱스는 객체를 참조하지 않음</p>
<p>: List 컬렉션에는 <strong>ArrayList, Vector, LinkedList</strong> 등이 있음</p>
<p><strong>- List 컬렉션에서 공통적으로 사용 가능한 List 인터페이스의 메소드</strong></p>
<p>
<img src="https://velog.velcdn.com/images/geumyi_/post/fd113d4c-79f8-42d0-8559-a7d2e3249056/image.png
" width="90%">  
</p>

<p>: 인덱스로 객체를 관리하기 때문에 인덱스를 매개값으로 갖는 메소드가 많음</p>
<p>: 메소드의 매개 변수 타입과, 리턴 타입에 <strong>E라는 타입 파라미터</strong>가 있는데,
이것은 <strong>저장되는 객체의 타입을 List 컬렉션을 생성할 때 결정</strong>하라는 뜻</p>
<pre><code>ex)
List 컬렉션에 객체를 추가할 때에는 add() 메소드를 사용하고,
객체를 찾아올 때에는 get() 메소드를 사용함
객체 삭제는 remove() 메소드를 사용함

List컬렉션에 
String 객체를 추가, 삽입, 검색, 삭제하는 방법

List&lt;String&gt; list = ···;
list.add(&quot;홍길동1&quot;);        //맨 끝에 객체 추가
list.add(1, &quot;홍길동2&quot;);    //지정된 인덱스에 객체 삽입

String str = list.get(1);    //인덱스로 객체 검색
list.remove(0);                //인덱스로 객체 삭제
list.remove(&quot;홍길동2&quot;);      //객체 삭제

→ List&lt;String&gt;으로 list 변수를 선언함
이것은 List 컬렉션에 저장되는 객체를 String타입으로 하겠다는 의미
따라서 E 타입 파라미터는 String 타입이 되는 것

그래서 add() 메소드의 매개값은 문자열이 되고
get() 메소드의 리턴값은 문자열이 됨</code></pre><p>: List 컬렉션에 저장된 모든 객체를 대상으로
하나씩 가져와 처리하고 싶다면 인덱스를 이용하는 방법과
향상된 for문을 이용하는 방법이 있음</p>
<p><strong>1) 인덱스를 이용하는 방법</strong></p>
<pre><code>List 컬렉션의 size() 메소드는
현재 저장되어 있는 객체 수를 리턴함

List&lt;String&gt; list = ···;

//저장된 총 객체 수만큼 루핑
for(int i=0; i&lt;list.size(); i++) {
    // i 인덱스에 저장된 String 객체를 가져옴
    String str = list.get(i);
}</code></pre><p><strong>2) 향상된 for문을 이용하는 방법</strong></p>
<pre><code>List 컬렉션에 저장된 객체 수만큼 반복하면서
객체를 하나씩 str 변수에 대입

//저장된 총 객체 수만큼 루핑
for(String str : list) {
    // list → str : String 객체를 하나씩 가져옴
}</code></pre><hr>
<h3 id="✔️-arraylist">✔️ ArrayList</h3>
<p>: List 인터페이스의 대표적인 구현 클래스</p>
<p><strong>- ArrayList 객체를 생성하는 방법</strong></p>
<p><code>List&lt;E&gt; list = new ArrayList&lt;E&gt;();</code>+</p>
<p>: ArrayList를 생성하기 위해서는 
저장할 객체 타입을 E 타입 파라미터 자리에 표기하고
기본 생성자를 호출하면됨</p>
<pre><code>ex) 
String을 저장하는 ArrayList

List&lt;String&gt; list = new ArrayList&lt;String&gt;();
List&lt;String&gt; list = new ArrayList&lt;&gt;();

: 두 번째 코드와 같이 ArrayList의 E 타입 파라미터를
생략하면 왼쪽 List에 지정된 타입을 따라감

따라서 위 두 코드는 동일하게
String을 저장하는 ArrayList 객체를 생성함</code></pre><p>
<img src="https://velog.velcdn.com/images/geumyi_/post/335ca934-b080-4628-a028-cb36b5de3408/image.png" width="90%">  
</p>

<p>: 기본 생성자로 ArrayList 객체를 생성하면 
내부에 10개의 객체를 저장할 수 있는 초기 용량을 가지게 됨</p>
<p>: 저장되는 객체 수가 늘어나면 용량이 자동으로 증가함</p>
<p>: ArrayList에 객체를 추가하면 0번 인덱스부터 차례대로 저장됨</p>
<p>: ArrayList에서 특정 인덱스의 객체를 제거하면
바로 뒤 인덱스부터 마지막 인덱스 까지 모두 앞으로 1씩 당겨짐</p>
<p>마찬가지로 특정 인덱스에 객체를 삽입하면 해당 인덱스부터
마지막 인덱스까지 모두 1씩 밀려남</p>
<p>: 저장된 객체 수가 많고, 특정 인덱스에 객체를 추가하거나
제거하는 일이 빈번하다면 ArrayList보다는 LinkedList를 사용하는 것이 좋음</p>
<p>하지만 인덱스를 이용해서 객체를 찾거나 맨 마지막에 객체를 추가하는 경우에는
ArrayList가 더 좋은 성능을 발휘함</p>
<pre><code class="language-java">👩‍💻 String 객체를 저장하는 ArrayList
import java.util.*;

public class ArrayListExample {
    public static void main(String[] args) {
        List&lt;String&gt; list = new ArrayList&lt;String&gt;();

        // Stirng 객체를 저장
        list.add(&quot;Java&quot;);
        list.add(&quot;JDBC&quot;);
        list.add(&quot;Servlet/JSP&quot;);
        list.add(2, &quot;Database&quot;);
        list.add(&quot;iBATIS&quot;);

        // 저장된 총 객체 수 얻기
        int size = list.size();
        System.out.println(&quot;총 객체수: &quot; + size);
        System.out.println();

        // 2번 인덱스의 객체 얻기
        String skill = list.get(2);
        System.out.println(&quot;2: &quot; + skill);
        System.out.println();

        // 저장된 총 객체 수만큼 루핑
        for(int i=0; i&lt;list.size(); i++) {
            String str = list.get(i);
            System.out.println(i + &quot;:&quot; + str);
        }
        System.out.println();

        // 2번 인덱스 객체(Database) 삭제됨
        list.remove(2);
        // 2번 인덱스 객체(Servlet/JSP) 삭제됨
        list.remove(2);
        list.remove(&quot;iBATIS&quot;);

        // 저장된 총 객체 수만큼 루핑
        for(int i=0; i&lt;list.size(); i++) {
            String str = list.get(i);
            System.out.println(i + &quot;:&quot; + str);
        }
    }
}

💻 결과
총 객체수: 5

2: Database

0:Java
1:JDBC
2:Database
3:Servlet/JSP
4:iBATIS

0:Java
1:JDBC</code></pre>
<hr>
<h3 id="✔️-vector">✔️ Vector</h3>
<pre><code>List&lt;E&gt; list = new Vector&lt;E&gt;();
List&lt;E&gt; list = new Vector&lt;&gt;();</code></pre><p>: ArrayList와 동일한 내부 구조를 가지고 있음
: Vector를 생성하기 위해서는
저장할 객체 타입을 타입 파라미터로 표기하고 
기본 생성자를 호출하면 됨</p>
<p>: <strong>ArrayList와 다른 점</strong>은
Vector는 동기화된 메소드로 구성되어 있기 떄문에
멀티 스레드가 동시에 Vector의 메소드들을 실행할 수 없고,
하나의 스레드가 메소드를 실행을 완료해야만
다른 스레드가 메소드를 실행할 수 있음</p>
<p>그래서 멀티 스레드 환경에서 안전하게 객체를 추가, 삭제할 수 있음
→ 이것을 스레드에 안전하다고 표현함</p>
<pre><code class="language-java">import java.util.*;

// 게시물 정보 객체
class Board {
    String subject;
    String content;
    String writer;

    public Board(String subject, String content, String writer) {
        this.subject = subject;
        this.content = content;
        this.writer = writer;
    }
}

// Board 객체를 저장하는 Vector
public class VectorExample {
    public static void main(String[] args) {
        List&lt;Board&gt; list = new Vector&lt;Board&gt;();

        //Board 객체를 저장
        list.add(new Board(&quot;제목1&quot;, &quot;내용1&quot;, &quot;글쓴이1&quot;));
        list.add(new Board(&quot;제목2&quot;, &quot;내용2&quot;, &quot;글쓴이2&quot;));
        list.add(new Board(&quot;제목3&quot;, &quot;내용3&quot;, &quot;글쓴이3&quot;));
        list.add(new Board(&quot;제목4&quot;, &quot;내용4&quot;, &quot;글쓴이4&quot;));
        list.add(new Board(&quot;제목5&quot;, &quot;내용5&quot;, &quot;글쓴이5&quot;));

        //2번 인덱스 객체(제목3) 삭제
        //뒤의 인덱스는 1씩 앞으로 당겨짐
        list.remove(2);
        //3번 인덱스 객체(제목5) 삭제
        list.remove(3);

        for(int i=0; i&lt;list.size(); i++) {
            Board board = list.get(i);
            System.out.println(board.subject +
                    &quot;\t&quot; + board.content +
                    &quot;\t&quot; + board.writer);
        }
    }
}

💻 결과
제목1    내용1    글쓴이1
제목2    내용2    글쓴이2
제목4    내용4    글쓴이4</code></pre>
<hr>
<h3 id="✔️-linkedlist">✔️ LinkedList</h3>
<p>: List 구현 클래스임
: ArrayList와 사용 방법은 똑같은데,
내부 구조는 완전히 다름</p>
<p>
<img src="https://velog.velcdn.com/images/geumyi_/post/ee7ff820-3ad4-49e6-93e7-7d45e422bb6d/image.png" width="90%">  
</p>

<p>: ArrayList는 내부 배열에 객체를 저장해서 관리하지만,
<strong>LinkedList는 인접 참조를 링크해서 체인처럼 관리</strong>함</p>
<p>: LinkedList에서 특정 인덱스의 객체를 제거하면 <strong>앞뒤 링크만 변경</strong>되고
나머지 링크는 변경되지 않음
특정 인덱스에 객체를 삽일할 때에도 마찬가지임</p>
<p><strong>- 객체를 제거할 경우 앞뒤 링크의 수정이 일어나는 모습</strong></p>
<p>
<img src="https://velog.velcdn.com/images/geumyi_/post/52aa1eda-a4fa-4bca-85e6-8b747452386f/image.png" width="90%">  
</p>

<p>: ArrayList는 중간 인덱스의 객체를 제거하면
뒤에 있는 객체의 인덱스가 1씩 앞으로 당겨지기 때문에
<strong>빈번한 객체 삭제와 삽입이 일어나는 곳</strong>에서는
ArrayList보다 <strong>LinkedList가 좋은 성능을 발휘함</strong></p>
<pre><code>List&lt;E&gt; list = new LinkedList&lt;E&gt;();
List&lt;E&gt; list = new LinkedList&lt;&gt;();</code></pre><p>: LinkedList를 생성하기 위해서는 
저장할 객체 타입을 타입 파라미터(E)에 표기하고
기본 생성자를 호출하면됨</p>
<p>LinkedList가 처음 생성될 때에는 어떠한 링크도
만들어지지 않기 때문에 내부는 비어 있음</p>
<pre><code class="language-java">👩‍💻 ArrayList와 LinkedList의 실행 성능 비교
import java.util.*;


/*
 * ArrayList와 LinkedList에
 * 10,000개의 객체를 삽입하는 데 걸린 시간을 측정한 것
 * 
 * 0번 인덱스에 String 객체를 10,000번 추가하기 위해
 * List 인터페이스의 add(int index, Element) 메소드를 이용함
 */
public class LinkedListExample {
    public static void main(String[] args) {
        List&lt;String&gt; list1 = new ArrayList&lt;String&gt;();
        List&lt;String&gt; list2 = new ArrayList&lt;String&gt;();

        long startTime;
        long endTime;

        startTime = System.nanoTime();
        for(int i=0; i&lt;10000; i++) {
            list1.add(0, String.valueOf(i));
        }
        endTime = System.nanoTime();
        System.out.println(&quot;ArrayList 걸린시간: &quot; + 
                (endTime-startTime) + &quot;ns&quot;);
        startTime = System.nanoTime();
        for(int i=0; i&lt;10000; i++) {
            list2.add(0, String.valueOf(i));
        }

        endTime = System.nanoTime();
        System.out.println(&quot;LinkedList 걸린시간: &quot; + 
                (endTime-startTime) + &quot;ns&quot;);
    } 
}

 💻 결과
ArrayList 걸린시간: 3824900ns
LinkedList 걸린시간: 3742299ns

→ 끝에서부터(순차적으로) 추가 또는 삭제하는 경우는
ArrayList가 빠르지만,
중간에 추가, 삭제하는 경우에는 앞뒤 링크 정보만 변경하므로
LinkedList가 더 빠름

ArrayLIst는 뒤쪽 인덱스들을 모두
1씩 증가 또는 감소시키는 시간이 필요하므로 처리 속도가 느림</code></pre>
<p>
<img src="https://velog.velcdn.com/images/geumyi_/post/c5476c1c-04c1-46f8-a66f-50aba6eb3cfe/image.png" width="90%">  
</p>

]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] 컬렉션 프레임워크]]></title>
            <link>https://velog.io/@geumyi_/Java-%EC%BB%AC%EB%A0%89%EC%85%98-%ED%94%84%EB%A0%88%EC%9E%84%EC%9B%8C%ED%81%AC</link>
            <guid>https://velog.io/@geumyi_/Java-%EC%BB%AC%EB%A0%89%EC%85%98-%ED%94%84%EB%A0%88%EC%9E%84%EC%9B%8C%ED%81%AC</guid>
            <pubDate>Wed, 03 Apr 2024 01:12:02 GMT</pubDate>
            <description><![CDATA[<h3 id="✔️-컬렉션-프레임워크collection-framework">✔️ 컬렉션 프레임워크(Collection Framework)</h3>
<p>: 자료구조(Data Structure)를 사용해서 객체들을 효율적으로
추가, 삭제, 검색할 수 있또록 인터페이스와 구현 클래스를
java.util 패키지에서 제공함 이들을 총칭한 것</p>
<p>: <strong>컬렉션(Collection)</strong> - 객체의 저장
: <strong>프레임워크(Frame)</strong> - 사용 방법을 정해놓은 라이브러리</p>
<p>: 컬렉션 프레임워크는 사용 방법을 정의한 인터페이스와
실제 객체를 저장하는 다양한 컬렉션 클래스(구현 클래스)를 제공함</p>
<p>: 주요 인터페이스로는 <strong>List, Set, Map</strong>이 있음
이 인터페이스들은 컬렉션 클래스를 사용하는 방법을 정의한 것</p>
<p><strong>- 인터페이스로 사용 가능한 컬렉션 클래스(구현 클래스)</strong></p>
<p>
<img src="https://velog.velcdn.com/images/geumyi_/post/938e1dc0-2ebe-4887-87bc-6afe3a7a5baf/image.png" width="90%">  
</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] 데몬 스레드]]></title>
            <link>https://velog.io/@geumyi_/Java-%EB%8D%B0%EB%AA%AC-%EC%8A%A4%EB%A0%88%EB%93%9C</link>
            <guid>https://velog.io/@geumyi_/Java-%EB%8D%B0%EB%AA%AC-%EC%8A%A4%EB%A0%88%EB%93%9C</guid>
            <pubDate>Mon, 01 Apr 2024 01:05:59 GMT</pubDate>
            <description><![CDATA[<h3 id="✔️-데몬-스레드">✔️ 데몬 스레드</h3>
<p>: 주 스레드의 작업을 돕는 보조적인 역할을 수행하는 스레드
: 주 스레드가 종료되면 데몬 스레드는 강제적으로 자동 종료되는데,
그 이유는 주 스레드의 보조 역할을 수행하므로
주 스레드가 종료되면 데몬 스레드의 존재 의미가 사라지기 때문</p>
<p>이 점을 제외하면 데몬 스레드는 일반 스레드와 큰 차이가 없음</p>
<pre><code>ex)
워드프로세서의 자동 저장, 
미디어 플레이어의 동영상 및 음악 재생,
쓰레기 수집기 등이 있는데
이 기능들은 주 스레드가 종료되면 같이 종료됨</code></pre><p>: 스레드를 데몬으로 만들기 위해서는
주 스레드가 데몬이 될 스레드의 setDaemon(true)를 호출하면 됨</p>
<pre><code>public static void main(String[] args) {
    AutoSaveThread thread = new AutoSaveThread();
    thread.setDaemon(true);
    thread.start();
    ...
}

주의할 점
start() 메소드가 호출되고 나서
setDaemon(true)를 호출하면
IllegalThreadStateException이 발생하기 때문에

start() 메소드 호출 전에
setDaemon(true)를 호출해야 한다는 것</code></pre><p>: 현재 실행 중인 스레드가 데몬 스레드인지 아닌지 구별하려면
isDaemon() 메소드의 리턴값을 조사해보면 됨
데몬 스레드일 경우 true를 리턴함</p>
<pre><code class="language-java">1초 주기로 save() 메소드를 자동 호출하도록
AutoSaveThread를 작성하고,  메인 스레드가 3초 후 종료되면
AutoSaveThread도 같이 종료되도록
AutoSaveThread를 데몬 스레드로 만들기

👩‍💻 1초 주기로 save() 메소드를 호출하는 데몬 스레드
public class AutoSaveThread extends Thread {
    public void save() {
        System.out.println(&quot;작업 내용을 저장함&quot;);
    }

    @Override
    public void run() {
        while(true) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                break;
            }

            save();
        }
    }
}

👩‍💻 메인 스레드가 실행하는 코드
public class DaemonExample {
    public static void main(String[] args) {
        AutoSaveThread autoSaveThread = new AutoSaveThread();

        //AutoSaveThread를 데몬 스레드로 만듦
        autoSaveThread.setDaemon(true);
        autoSaveThread.start();

        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {

        }

        System.out.println(&quot;메인 스레드 종료&quot;);
    }
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] 스레드 제어]]></title>
            <link>https://velog.io/@geumyi_/Java-%EC%8A%A4%EB%A0%88%EB%93%9C-%EC%A0%9C%EC%96%B4</link>
            <guid>https://velog.io/@geumyi_/Java-%EC%8A%A4%EB%A0%88%EB%93%9C-%EC%A0%9C%EC%96%B4</guid>
            <pubDate>Mon, 01 Apr 2024 01:03:58 GMT</pubDate>
            <description><![CDATA[<p>
<img src="https://velog.velcdn.com/images/geumyi_/post/444d0b21-a5e4-4fdf-aa41-11bdff101cab/image.png">
</p>

<p>: 스레드 객체를 생성하고 start() 메소드를 호출하면
바로 실행되는 것이 아니라 실행 대기 상태가 됨</p>
<p>: 실행대기 상태란 언제든지 실행할 준비가 되어 있는 상태를 말함</p>
<p>: 운영체제는 실행 대기 상태에 있는 
스레드 중에서 하나를 선택해서 실행 상태로 만듦</p>
<p>: 실행 상태의 스레드는 run() 메소드를 모두 실행하기 전에
다시 실행 대기 상태로 돌아갈 수 있으며,
실행 대기 상태에 있는 다른 스레드가 선택되어 실행 상태가 되기도 함</p>
<p>: 실행 상태에서 run() 메소드의 내용이 모두 실행되면
스레드의 실행이 멈추고 종료 상태가 됨</p>
<hr>
<h3 id="✔️-스레드-상태">✔️ 스레드 상태</h3>
<p><strong>- 실행 상태</strong>
: 실행 대기 상태에 있는 스레드 중에서
운영체제는 하나의 스레드를 선택하고 CPU(코어)가
run() 메소드를 실행하도록 함</p>
<p>: 실행 상태의 스레드는 run() 메소드를
모두 실행하기 전에 다시 실행 대기 상태로 돌아갈 수 있음</p>
<p>: 스레드는 실행 대기 상태와 실행 상태를 번갈아가며
자신의 run() 메소드를 조금씨 실행함</p>
<p><strong>- 종료 상태</strong>
: 실행 상태에서 run() 메소드가 종료되면,
더 이상 실행할 코드가 없기 때문에
스레드의 실행은 멈추게 됨</p>
<p>→ 이처럼 스레드는
실행 대기상태와 실행 상태로 번갈아 변하면서,
경우데 따라 실행 상태에서 일시 정지 상태로 가기도 함</p>
<p>일시 정지 상태는 스레드가 실행할 수 없는 상태를 말함</p>
<p>일시 정지 상태에서는 바로 실행 상태로 돌아갈 수 없고,
일시 정지 상태에서 빠져나와 실행 대기 상태로 가야함</p>
<hr>
<h3 id="✔️-스레드-상태-제어">✔️ 스레드 상태 제어</h3>
<p><strong>- 스레드 상태 제어</strong>
: 실행 중인 스레드의 상태를 변경하는 것</p>
<pre><code>ex)
사용자는 미디어 플레이어에서
동영상을 보다가 일시 정지할 수도 있고,
종료할 수도 있음

일시 정지는 조금 후 다시 동영상을 보겠다는 의미이므로
미디어 플레이어는 동영상 스레드를 일시 정지 상태로 만들어야함

그리고 종료는 더 이상 동영상을 보지 않겠다는 의미로
미디어 플레이어는 스레드를 종료 상태로 만들어야함</code></pre><p>: 스레드 상태 제어는 주어진 시간 동안
일시 정지시키는  sleep() 메소드와 스레드를
안전하게 종료 시키는 stop 플래스,
interrupt() 메소드를 사용함</p>
<p>
<img src="https://velog.velcdn.com/images/geumyi_/post/7beb1b3b-a88b-4380-86d8-abfcd825467d/image.png">
</p>
→ 취소선으로 표시한 메소드는
스레드의 안전성을 해친다고 하여
더 이상 사용하지 않도록 권장된 Deprecated 메소드 임


<p><strong>- 상태 변화를 가져오는 메소드의 종류</strong>
<img src="https://velog.velcdn.com/images/geumyi_/post/25b9f26f-c2b7-45e9-a93d-5ee52b08910e/image.png"></p>
</p>

<hr>
<h3 id="✔️-주어진-시간-동안-일시-정지">✔️ 주어진 시간 동안 일시 정지</h3>
<pre><code>try {
    Thread.sleep(1000);
} catch(InterruptedException e) {
    //interrupt() 메소드가 호출되면 실행
}</code></pre><p>: 실행 중인 스레드를 일정 시간 멈추게 하고 싶다면
Thread 클래스의 정적 메소드인 sleep()을 사용하면 됨</p>
<p>: Thread.sleep() 메소드를 호출한 스레드는
주어진 시간 동안 일시 정지 상태가 되고,
다시 실행 대기 상태로 돌아감</p>
<p>: 매개값에는 얼마 동안 일시 정지 상태로 있을 것인지
밀리세컨드(1/1000초) 단위로 시간을 주면 됨</p>
<p>: 일시 정지 상태에서 주어진 시간이 되기 전에
interrupt() 메소드가 호출되면
InterruptedException이 발생하기 때문에
예외 처리가 필요함</p>
<pre><code class="language-java"> 👩‍💻3초 주기로 10번 비프음 발생
import java.awt.Toolkit;

public class SleepExample {
    public static void main(String[] args) {
        Toolkit toolkit = Toolkit.getDefaultToolkit();
        for(int i=0; i&lt;10; i++) {
            toolkit.beep();
            try {
                // 3초 동안 메인 스레드를
                // 일시 정지 상태로 만듦
                Thread.sleep(3000);
            } catch(InterruptedException e) {}
        }
    }
}</code></pre>
<hr>
<h3 id="✔️-스레드의-안전한-종료">✔️ 스레드의 안전한 종료</h3>
<p>: 스레드는 자신의 run() 메소드가 모두 실행되면
자동적으로 종료됨</p>
<p>: 하지만 경우에 따라 실행 중인 스레드를
즉시 종료해야 할 때가 있음</p>
<pre><code>ex) 동영상을 끝까지 보지 않고,
사용자가 멈춤을 요구할 때</code></pre><p>: Thread는 스레드를 즉시 종료하기 위해서
stop() 메소드를 제공하고 있는데,
이 메소드는 deprecated(중요도가 떨어져
이제 사용되지 않음) 되었습니다.
→ 그 이유는 stop() 메소드로 스레드를
갑자기 종료하게 되면 스레드가 사용 중이던
자원들이 불안전한 상태로 남겨지기 때문</p>
<p><strong>- 안전하게 종료하는 방법</strong>
<strong>1) stop 플래그를 이용하는 방법</strong>
: 스레드는 run()메소드가 끝나면 자동적으로 종료되므로,
run() 메소드가 정상적으로 종료되도록 유도하는 것이 중요함</p>
<pre><code>public class XXXThread extends Thread {
    //stop 플래그 필드
    private boolean stop;

    public void run() {
        // stop이 true가 되면 run()이 종료
        while( !stop ) {
            스레드가 반복 실행하는 코드;
        }
        // 스레드가 사용한 자원 정리
    }
}

: stop 필드가 false일 경우에는
while문의 조건식이 true가 되어 반복 실행하지만,

stop 필드가 true일 경우에는 
while문의 조건식이 false가 되어 while문으로 빠져나옴

그리고 스레드가 사용한 자원을 정리하고,
run() 메소드가 끝나게 됨으로써 스레드는 안전하게 종료함</code></pre><pre><code class="language-java"> 👩‍💻무한 반복해서 출력하는 스레드
public class PrintThread1 extends Thread { 
    private boolean stop;

    public void setStop(boolean stop) {
        this.stop = stop;
    }

    public void run() {
        while(!stop) {
            System.out.println(&quot;실행 중&quot;);
        }
        //stop이 true가 될때 
        System.out.println(&quot;자원 정리&quot;);
        System.out.println(&quot;실행 종료&quot;);
    }
}

👩‍💻 1초 후 출력 스레드를 중지
public class StopFlagExample {
    public static void main(String[] args) {
        PrintThread1 printThread = new PrintThread1();
        printThread.start();

        try { Thread.sleep(1000); }
        catch(InterruptedException e) {}

        // 스레드를 종료하기 위해
        // stop 필드롤 true로 변경
        printThread.setStop(true);
    }
}</code></pre>
<p><strong>2) interrupt() 메소드를 이용하는 방법</strong>
: interrupt() 메소드는 스레드가 일시 정지 상태에 있을 때
InterruptedException을 발생시키는 역할을 함</p>
<p>이를 이용하면 run() 메소드를 정상 종료할 수 있음</p>
<pre><code class="language-java">👩‍💻 1초 후 출력 스레드를 중지
public class PrintThread2 extends Thread {
    public void run() {
        try {
            while(true) {
                System.out.println(&quot;실행 중&quot;);
                Thread.sleep(1);
            }
        } // Thread.sleep(1)에서 
        // InterruptedException 발생시 예외처리 이동  
        catch(InterruptedException e) {}

        System.out.println(&quot;자원 정리&quot;);
        System.out.println(&quot;실행 종료&quot;);
    }
}

👩‍💻 무한 반복해서 출력하는 스레드
public class StopFlagExample {
    public static void main(String[] args) {        
        Thread thread = new PrintThread2();
        thread.start();

        try { Thread.sleep(1000); }
        catch(InterruptedException e) {}

        // 스레드를 종료하기 위해
        // InterruptedException을 발생시킴
        thread.interrupt();
    }
}

→ 스레드가 실행 대기 또는 실행 상태에 있을 때
interrupt() 메소드가 실행되면
즉시 InterruptedException이 발생한다는 것

따라서 스레드가 일시 정지 상태가 되지 않으면
interrupt() 메소드 호출은 아무런 의미가 없음

그래서 짧읍 시간이나마 일시 정지시키기 위해
Thread.sleep(1)을 사용한 것</code></pre>
<p><strong>- 일시 정지를 만들지 않고도 interrupt()의 호출 여부를 알 수 있는 방법</strong></p>
<blockquote>
</blockquote>
<p>boolean status = Thread.interrupted();
boolean status = objThread.isInterrupted();</p>
<p>: interrupt() 메소드가 호출되었다면
스레드의 interrupted()와 isInterrupted() 메소드는
true를 리턴함</p>
<p>interrupted()는 <strong>정적 메소드</strong>로 현재 스레드가
interrupted 되었는지 확인하는 것이고,</p>
<p>isInterrupted()는 <strong>인스턴스 메소드</strong>로 현재 스레드가
interrupted 되었는지 확인함</p>
<pre><code class="language-java">👩‍💻 Thread.sleep(1)을 사용하지 않고,
Thread.interrupted()를 사용해서
PrintThread의 interrupt()가 호출되었는지 확인한 다음
while문 빠져나가기

public class PrintThread2 extends Thread {

    public void run() {

        while(true) {
            System.out.println(&quot;실행 중&quot;);

            if(Thread.interrupted()) {
                break;
            }
        }


        System.out.println(&quot;자원 정리&quot;);
        System.out.println(&quot;실행 종료&quot;);
    }
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] 멀티 스레드]]></title>
            <link>https://velog.io/@geumyi_/Java-%EB%A9%80%ED%8B%B0-%EC%8A%A4%EB%A0%88%EB%93%9C</link>
            <guid>https://velog.io/@geumyi_/Java-%EB%A9%80%ED%8B%B0-%EC%8A%A4%EB%A0%88%EB%93%9C</guid>
            <pubDate>Mon, 01 Apr 2024 00:35:00 GMT</pubDate>
            <description><![CDATA[<h3 id="✔️-프로세스process">✔️ 프로세스(Process)</h3>
<p>: 운영체제에서는 실행 중인 하나의 애플리케이션을 프로세스라고 함
: 사용자가 애플리케이션을 실행하면 
운영체제로부터 실행에 필요한 메모리를 할당받아
애플리케이션의 코드를 실행하는 것</p>
<p>
<img src="https://velog.velcdn.com/images/geumyi_/post/a72af9bd-c579-4b61-ad63-5b6ebb769963/image.png" width="80%">
</p>

<p>: 하나의 애플리케이션은 멀티 프로세스(multi process)를
만들기도 함</p>
<pre><code>ex)
메모장 애플리케이션을 2개 실행했다면
2개의 메모장 프로세스가 생성된 것</code></pre><hr>
<h3 id="✔️-스레드thread">✔️ 스레드(thread)</h3>
<p>: 사전적 의미로 한 가닥의 실이라는 뜻
: 한 가지 작업을 실행하기 위해 순차적으로
실행할 코드를 실처럼 이어놓았다고 해서 유래된 이름
: 하나의 스레드는 하나의 코드 실행 흐름이기 때문에
한 프로세스 내에 스레드가 2개라면 2개의 코드 실행 흐름이
생긴다는 의미</p>
<p>
<img src="https://velog.velcdn.com/images/geumyi_/post/188e2704-1969-4919-8eab-92e525e19b97/image.png" width="90%">
</p>

<pre><code>운영체제는 두 가지 이상의 작업을 동시에 처리하는
멀티 태스킹(multi tasking)을 할 수 있도록 CPU 및 메모리 자원을
프로세스마다 적절히 할당해주고, 병렬로 실행시킴

ex)  원서로 문서 작업을 하면서 동시에
윈도우 미디어 플레이어로 음악을 들을 수 있다.

멀티 태스킹은 꼭 멀티 프로세스를 뜻하는건 아님
한 프로세스 내에서 멀티 태스킹을 할 수 있도록 만들어진
애플리케이션도 있음

ex) 미디어 플레이어와 메신저
미디어 플레이어는 동영상 재생과 음악 재생이라는
두 가지 작업을 동시에 처리하고,
메신저는 채팅 기능을 제공하면서 동시에 파일 전송 기능을
수행하기도 함</code></pre><p>→ 하나의 프로세스가 두 가지 이상의 작업을 처리하는 것
&#39;멀티 스레드&#39;</p>
<p><strong>- 멀티 프로세스 vs 멀티 스레드</strong>
<strong>• 멀티 프로세스</strong>
: 자신의 메모리를 가지고 실행하므로 서로 독립적
따라서 하나의 프로세스에서 오류가 발생해도
다른 프로세스에 영향을 미치지 않음</p>
<p><strong>• 멀티 스레드</strong>
: 하나의 프로세스 내부에 생성되기 때문에
하나의 스레드가 예외를 발생시키면
프로세스 자체가 종료될 수 있어 다른 스레드에 영향을 미침</p>
<pre><code>ex) 멀티 프로세스인 워드와 엑셀을 동시에 사용하던 도중,
워드에 오류가 생겨 먹통이 되더라도 엑셀은 여전히 사용 가능함

그러나 멀티 스레드로 동작하는 메신저의 경우
파일을 전송하는 스레드에서 예외가 발생하면
메신저 프로세스 자체가 종료되므로 채팅 스레드도 같이 종료됨

그렇기 때문에 멀티 스레드에서는 예외 처리에 만전을 기해야 함</code></pre><p>- 멀티 스레드는 다양한 곳에서 사용됨
대용량 데이터의 처리 시간을 줄이기 위해 
데이터 분할해서 병렬로 처리하기도 하고,
UI를 가지고 있는 애플리케이션에서 네트워크 통신을
하기 위해 사용되기도 함. 
또한 다수 클라이언트의 요청을 처리하는 서버를 개발할 때에도 사용됨</p>
<hr>
<h3 id="✔️-메인-스레드main-thread">✔️ 메인 스레드(main thread)</h3>
<p>: 자바의 모든 애플리케이션은
메인 스레드가 main()메소드를 실행하면서 시작함</p>
<p>: 메인 스레드는 main() 메소드의 첫 코드부터 아래로 순차적으로 실행하고,
main() 메소드의 마지막 코드를 실행하거나 return문을 만나면 실행이 종료됨</p>
<pre><code>public static void main(String[] args) {
    // 코드의 실행 흐름 → 스레드
    String data = null;
    if(...) {
    }
    while(...) {
    }
    System.out.println(&quot;...&quot;);
}</code></pre><p>→ 메인 스레드는 필요에 따라 작업 스레드들을 만들어서
병렬로 코드를 실행할 수 있음</p>
<p>즉, 멀티 스레드를 생성해서 멀티 태스킹을 수행함</p>
<p>
<img src="https://velog.velcdn.com/images/geumyi_/post/3eba7f60-d343-4d08-9e71-585147c141b9/image.png" width="90%">
</p>

<p>: 오른쪽 멀티 스레드 애플리케이션을 보면
메인 스레드가 작업 스레드1을 생성하고 실행한 다음,
곧이어 작업 스레드2를 생성하고 실행함</p>
<p>: 싱글 스레드 애플리케이션에서는 메인 스레드가 종료하면
프로세스도 종료됨</p>
<p>: 멀티 스레드 애플리케이션에서는 실행 중인 스레드가 하나라도 있다면,
프로세스는 종료되지 않음</p>
<p>: 메인 스레드가 작업 스레드보다 먼저 종료되더라도
작업 스레드가 계속 실행 중이라면 프로세스는 종료되지 않음</p>
<hr>
<h3 id="✔️-작업-스레드-생성과-실행">✔️ 작업 스레드 생성과 실행</h3>
<p>
<img src="https://velog.velcdn.com/images/geumyi_/post/db117386-3f3f-49ca-b2d5-74b22b08b530/image.png" width="90%">
</p>

<p>: 멀티 스레드로 실행하는 애플리케이션을 개발하려면
먼저 몇 개의 작업을 병렬로 실행할지 결정하고
각 작업별로 스레드를 생성해야함</p>
<p>: 어떤 자바 애플리케이션이건 메인 스레드는 반드시 존재하기 때문에
메인 작업 이외에 추가적인 병렬 작업의 수만큼 스레드를 생성하면 됨</p>
<p>: 자바에서는 작업 스레드도 객체로 생성되기 때문에
클래스가 필요함</p>
<p>: java.lang.Thread 클래스를 직업 객체화해서 생성해도 되지만,
Thread 클래스를 상속해서 하위 클래스를 만들어 생성할 수도 있음</p>
<hr>
<h3 id="✔️-thread클래스로부터-직접-생성">✔️ Thread클래스로부터 직접 생성</h3>
<blockquote>
</blockquote>
<p>Thread thread = new Thread(Runnable target);</p>
<p>: java.lang.Thread 클래스로부터 작업 스레드 객체를 직접 생성하려면
Runnable을 매개값으로 갖는 생성자를 호출해야함</p>
<p><strong>- Runnable</strong>
: 작업 스레드가 실행할 수 있는 코드를 가지고 있는 객체
: 인터페이스 타입이기 때문에 구현 객체를 만들어 대입해야함
: run() 메소드 하나가 정의되어 있는데,
구현 클래스는 run()을 재정의해서 작업 스레드가 실행할 코드를 작성해야함</p>
<pre><code>- Runnable 구현 클래스
class Task implements Runnable {
    public void run() {
        스레드가 실행할 코드;
    }
}</code></pre><p>: Runnable은 작업 내용을 가지고 있는 객체이지 실제 스레드는 아님
: Runnable 구현 객체를 생성한후,
이것을 매개값으로 해서 Thread 생성자를 호출해야 비로소 작업 스레드가 생성됨</p>
<pre><code>Runnable task = new Task();
Thread thread = new Thread(task);</code></pre><p>: 코드를 좀 더 절약하기 위해
Thread 생성자를 호출할 때 Runnable 익명 객체를 
매개값으로 사용할 수 있음</p>
<pre><code>→ 이 방법이 더 많이 사용됨
Thread thread = new Thread( new Runnable() {
    //익명 구현 객체
    public void run() {
        스레드가 실행할 코드;
    }
}</code></pre><p>: 작업 스레드는 생성되는 즉시 실행되는 것이 아니라,
start() 메소드를 호출해야만 실행됨</p>
<blockquote>
</blockquote>
<p>thread.start();</p>
<p>: start() 메소드가 호출되면,
작업 스레드는 매개값으로 받은 Runnable의 run() 메소드를
실행하면서 자신의 작업을 처리함</p>
<p>
<img src="https://velog.velcdn.com/images/geumyi_/post/e6232f47-5416-4205-8496-f5ebce5bf73e/image.png">
</p>

<pre><code class="language-java">👩‍💻 메인 스레드만 이용한 경우
import java.awt.Toolkit;

/*
 * 0.5초 주기로 비프(beep)음을 발생시키면서
 * 동시에 출력하는 작업이 있다고 가정
 * 
 * 비프음 발생과 출력은 서로 다른 작업이므로
 * 메인 스레드가 동시에 두 가지 작업을 처리할 수 없음
 * 
 * 아래 코드와 같이 작성시
 * 메인 스레드는 비프음을 모두 발생한 다음, 출력을 시작함
 */
public class BeepPrintExample1 {

    public static void main(String[] args) {
        //Toolkit 객체 얻기
        Toolkit toolkit = Toolkit.getDefaultToolkit();
        for(int i=0; i&lt;5; i++) {
            //비프음 발생
            toolkit.beep();
            try { Thread.sleep(500); /*0.5초간 일시 정지*/
            } catch(Exception e) {}
        }

        for(int i=0; i&lt;5; i++) {
            System.out.println(&quot;띵&quot;);
            try {Thread.sleep(500); /*0.5초간 일시 정지*/
            } catch(Exception e) {}
        }
    }

}

💻 결과
띵
띵
띵
띵
띵</code></pre>
<p>→ 비프음을 발생시키면서
동시에 출력을 하려면 두 작업 중 하나를
메인 스레드가 아닌 다른 스레드에서 실행해야 함</p>
<p>출력은 메인 스레드가 담당하고
비프음을 들려주는 것은 작업 스레드가 담당하도록 수정</p>
<pre><code>👩‍💻 비프음을 들려주는 작업 정의
import java.awt.Toolkit;

public class BeepTask implements Runnable {
    public void run() {
        //스레드 실행 내용
        Toolkit toolkit = Toolkit.getDefaultToolkit();
        for(int i=0; i&lt;5; i++) {
            toolkit.beep();
            try { Thread.sleep(500); }
            catch(Exception e) {}
        }
    }
}

👩‍💻 메인 스레드와 작업 스레드가 동시에 실행
public class BeepPrintExample2 {
    public static void main(String[] args) {
        //BeepTask 객체를 생성
        Runnable beepTask = new BeepTask();
        //작업 스레드 생성
        Thread thread = new Thread(beepTask);
        //작업 스레드의 start()메소드를 호출
        //작업 스레드에 의해 
        //BeepTask  객체의 run() 메소드가 실행되어
        //비프음이 발생
        thread.start();

        //그와 동시에 메인 스레드는
        //for문을 실행시켜 0.5초 간격으로 &quot;띵&quot;을 출력
        for(int i=0; i&lt;5; i++) {
            System.out.println(&quot;띵&quot;);
            try {Thread.sleep(500);}
            catch(Exception e) {}
        }

    }
}</code></pre><pre><code>👩‍💻 Runnable 익명 구현 객체로 대체하여
작업 스레드를 만들 수 있는 방법
import java.awt.Toolkit;

public class BeepPrintExample3 {
    public static void main(String[] args) {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                Toolkit toolkit = Toolkit.getDefaultToolkit();
                for(int i=0; i&lt;5; i++) {
                    toolkit.beep();
                    try { Thread.sleep(500); }
                    catch(Exception e) {}
                }
            }
        });
        thread.start();

        for(int i=0; i&lt;5; i++) {
            System.out.println(&quot;띵&quot;);
            try {Thread.sleep(500);}
            catch(Exception e) {}
        }
    }
}</code></pre><hr>
<h3 id="✔️-thread-하위-클래스로부터-생성">✔️ Thread 하위 클래스로부터 생성</h3>
<p>: 작업 스레드가 실행할 작업을 Runnable로 만들지 않고,
Thread의 하위 클래스로 작업 스레드를 정의하면서 작업 내용을
포함시킬 수도 있음</p>
<p><strong>- 작업 스레드 클래스 정의하는 방법</strong>
:Thread 클래스를 상속한 후 run() 메소드를
재정의(overriding)해서 스레드가 실행할 코드를 작성하면됨</p>
<p>: 작업 스레드 클래스로부터 작업 스레드 객체를 생성하는 방법은
일반적인 객체를 생성하는 방법과 동일함</p>
<pre><code>public class WorkerThread extends Thread {
    //run() 메소드 재정의
    @Override
    public void run() {
        스레드가 실행할 코드;
    }
}
Thread thread = new WorkerThread();</code></pre><p>→ 코드를 좀 더 절약하기 위해
Thread 익명 객체로 작업 스레드 객체를 생성할 수도 있음</p>
<pre><code>Thread thread = new Thread() {
    // 익명 자식 객체
    public void run() {
        스레드가 실행할 코드;
    }
};</code></pre><p>: 이렇게 생성된 작업 스레드 객체에서
start() 메소드를 호출하면
작업 스레드는 자신의 run() 메소드를 실행하게 됨</p>
<blockquote>
</blockquote>
<p>thread.start();</p>
<p>
<img src="https://velog.velcdn.com/images/geumyi_/post/e738cc30-73ec-4381-a237-b541c89adc14/image.png">
</p>

<pre><code>👩‍💻 비프음 들려주는 스레드
/*
 * Runnable을 생성하지 않고
 * Thread의 하위 클래스로 작업 스레드를 정의한 것
 */

public class BeepThread extends Thread {
    @Override
    public void run() {
        //스레드 실행내용
        Toolkit toolkit = Toolkit.getDefaultToolkit();
        for(int i=0; i&lt;5; i++) {
            toolkit.beep();
            try { Thread.sleep(500); }
            catch(Exception e) {}
        }
    }
}

👩‍💻 메인 스레드와 작업 스레드가 동시에 실행
/*
 * BeepThread 클래스를 이용해서
 * 작업 스레드 객체를 생성하고 실행함
 */
public class BeepPrintExample4 {

    public static void main(String[] args) {
        //BeepThread 객체를 생성
        Thread thread = new BeepThread();
        //start() 메소드 호출
        thread.start();

        /*
        그와 동시에 메인 스레드는
        for문을 실행시켜 0.5초 간격으로
        &quot;띵&quot;을 출력함
        */    
        for(int i=0; i&lt;5; i++) {
            System.out.println(&quot;띵&quot;);
            try { Thread.sleep(500); }
            catch(Exception e) {}
        }


    }

}</code></pre><pre><code>👩‍💻 Thread 익명 자식 객체를 이용해서
작업 스레드를 만들 수 있는 또 다른 방법

import java.awt.Toolkit;

public class BeepPrintExample5 {
    public static void main(String[] args) {
        Thread thread = new Thread() {
            @Override
            public void run() {
                Toolkit toolkit = Toolkit.getDefaultToolkit();
                for(int i=0; i&lt;5; i++) {
                    toolkit.beep();
                    try { Thread.sleep(500); }
                    catch(Exception e) {}
                }
            }
        };

        thread.start();

        for(int i=0; i&lt;5; i++) {
            System.out.println(&quot;띵&quot;);
            try { Thread.sleep(500); }
            catch(Exception e) {}
        }
    }
}</code></pre><hr>
<h3 id="✔️-스레드-이름">✔️ 스레드 이름</h3>
<p>: 스레드는 자신의 이름을 가지고 있음
: 디버깅할때 어떤 스레드가 어떤 작업을 하는지
조사할 목적으로 가끔 사용됨</p>
<p>: 메인 스레드는 &#39;main&#39;이라는 이름을 가지고 있고,
직접 생성한 스레드는 자동적으로 &#39;Thread-n&#39;이라는 이름으로 설정됨</p>
<p>→ n은 스레드의 번호를 말함
→ Thread-n 대신 다른 이름으로 설정하고 싶다면
Thread 클래스의 setName() 메소드로 변경하면 됨</p>
<blockquote>
</blockquote>
<p>thread.setName(&quot;스레드 이름&quot;);</p>
<p>→ 스레드 이름을 알고 싶을 경우에는 getName() 메소드로 변경하면됨</p>
<blockquote>
</blockquote>
<p>thread.getName();</p>
<p>: setName()과 getName()은 Thread 클래스의 인스턴스 메소드이므로
스레드 객체의 참조가 필요함</p>
<p>: 만약 스레드 객체의 참조를 가지고 있지 않다면,
Thread 클래스의 정적 메소드인 currentThread()을 이용해서
현재 스레드의 참조를 얻을 수 있음</p>
<blockquote>
</blockquote>
<p>Thread thread = Thread.currentThread();</p>
<pre><code>👩‍💻 ThreadA 클래스
public class ThreadA extends Thread {
    public ThreadA() {
        //스레드 이름 설정
        setName(&quot;ThreadA&quot;);
    }

    public void run() {
        //ThreadA 실행내용
        for(int i=0; i&lt;2; i++) {
            //getName() - 스레드 이름 얻기
            System.out.println(getName() + &quot;가 출력한 내용&quot;);
        }
    }

}

👩‍💻 ThreadB 클래스
public class ThreadB extends Thread{
    public void run() {
        //ThreadB 실행내용
        for(int i=0; i&lt;2; i++) {
            //getName() - 스레드 이름 얻기
            System.out.println(getName() + &quot;가 출력한 내용&quot;);
        }
    }
}

👩‍💻 메인 스레드 이름 출력 및 UserThread 생성 및 시작
/*
 * 메인 스레드의 참조를 얻어
 * 스레드 이름을 콘솔에 출력하고
 * 새로 생성한 스레드의 이름을
 * setName() 메소드로 설정한 후,
 * getName() 메소드로 읽어오기
 */
public class ThreadNameExample {
    public static void main(String[] args) {
        //이 코드를 실행하는 스레드 객체 얻기
        Thread mainThread = Thread.currentThread();
        System.out.println(&quot;프로그램 시작 스레드 이름: &quot; +
                mainThread.getName());

        //ThreadA 생성
        ThreadA threadA = new ThreadA();
        System.out.println(&quot;작업 스레드 이름: &quot; +
                threadA.getName());
        //ThreadA시작
        threadA.start();

        //ThreadB생성
        ThreadB threadB = new ThreadB();
        System.out.println(&quot;작업 스레드 이름: &quot; + 
                threadB.getName());
        threadB.start();
    }
}

💻 결과
프로그램 시작 스레드 이름: main
작업 스레드 이름: ThreadA
ThreadA가 출력한 내용
ThreadA가 출력한 내용
작업 스레드 이름: Thread-1
Thread-1가 출력한 내용
Thread-1가 출력한 내용</code></pre><hr>
<h3 id="✔️-동기화-메소드">✔️ 동기화 메소드</h3>
<p>: 싱글 스레드 프로그램에서는 1개의 스레드가
객체를 독차지해서 사용하면 되지만,</p>
<p>멀티 스레드 프로그램에서는 스레드들이 객체를
공유해서 작업해야하는 경우가 있음</p>
<p>이 경우에 주의해야할 점이 있음</p>
<p><strong>- 공유 객체를 사용할 때의 주의할 점</strong></p>
<p>: 멀티 스레드 프로그램에서 
스레드들이 객체를 공유해서 작업해야 하는 경우,
스레드 A가 사용하던 객체를 
스레드 B가 상태를 변경할 수 있기 때문에
스레드 A가 의도했던 거소가는 다른 결과를 산출할 수도 있음</p>
<pre><code>ex)
여러 사람이 계산기를 함께 나눠 쓰는 상황이라면

사람 A가 계산기로 작업을 하다가
계산 결과를 메모리에 저장한 뒤 잠시 자리를 비웠는데,

이때 사람 B가 계산기를 만져서 사람 A가 메모리에
저장한 값을 다른 값으로 변경하는 것과 동일함

그런 다음 사람 A가 돌아와 계산기에 저장된 값을
이용해서 이후 작업을 진행한다면 결국 사람 A는
엉터리 값을 이용하게 됨</code></pre><pre><code class="language-java">👩‍💻 공유객체
public class Calculator {
    private int memory;

    public int getMemory() {
        return memory;
    }

    //계산기 메모리에 값을 저장하는 메소드
    public void setMemory(int memory) {
        //매개값을 memory 필드에 저장
        this.memory = memory;
        //스레드를 2초간 일시 정지시킴
        try {
            Thread.sleep(2000);
        } catch(InterruptedException e) {}
        //Thread.currentThread().getName() - 스레드 이름 얻기
        //this.memory - 메모리값
        System.out.println(Thread.currentThread().getName() + &quot;: &quot; + 
                this.memory);
    }
}

👩‍💻 User1 스레드
public class User1 extends Thread {
    private Calculator calculator;

    public void setCalculator(Calculator calculator) {
        //스레드 이름을 user1로 설정
        this.setName(&quot;User1&quot;);
        //공유 객체인 calculator를 필드에 저장
        this.calculator = calculator;
    }

    public void run() {
        //공유 객체인 calculator의 메모리에 100을 저장
        calculator.setMemory(100);
    }

}

👩‍💻 User2 스레드
public class User2 extends Thread {
    private Calculator calculator;

    public void setCalculator(Calculator calculator) {
        //스레드 이름을 user1로 설정
        this.setName(&quot;User2&quot;);
        //공유 객체인 calculator를 필드에 저장
        this.calculator = calculator;
    }

    public void run() {
        //공유 객체인 calculator의 메모리에 100을 저장
        calculator.setMemory(50);
    }
}

👩‍💻 메인 스레드가 실행하는 코드
public class MainThreadExample {
    public static void main(String[] args) {
        Calculator calculator = new Calculator();

        // User1 스레드 생성
        User1 user1 = new User1();
        // 공유 객체 설정
        user1.setCalculator(calculator);
        // User1 스레드 시작
        user1.start();

        // User2 스레드 생성
        User2 user2 = new User2();
        // 공유 객체 설정
        user2.setCalculator(calculator);
        // user2 스레드 시작
        user2.start();

    }
}

💻 결과
User2: 50
User1: 50</code></pre>
<p>
<img src="https://velog.velcdn.com/images/geumyi_/post/4c3fdbca-b6e7-498f-a68e-957261f6a7ef/image.png">
</p>

<p>: User1 스레드가 Calculator 객체의 memory 필드에 
100을 먼저 저장하고 2초간 일시 정지 상태가 됨</p>
<p>그동안에 User2 스레드가 memory 필드값을 50으로 변경</p>
<p>2초가 지나 User1 스레드가 다시 실행 상태가 되어
memory 필드값을 출력하면 User2 스레드가 저장한 50이 출력됨</p>
<p><strong>- 동기화 메소드</strong>
: 스레드가 사용 중인 객체를 다른 스레드가 변경할 수 없게 하려면
스레드 작업이 끝날 때까지 객체에 잠금을 걸어서 
다른 스레드가 사용할 수 없도록 해야함</p>
<p>: 자바는 임계 영역을 지정하기 위해 동기화 메소드를 제공함</p>
<pre><code>+) 임계 영역
: 멀티 스레드 프로그램에서 단 하나의 스레드만 실행할 수 있는 코드 영역</code></pre><p>: 스레드가 내부의 동기화 메소드를 실행하면
즉시 객체에 잠금을 걸어 다른 스레드가 동기화 메소드를 
실행하지 못하도록 해야함</p>
<pre><code>public synchronized void method() {
    //단 하나의 스레드만 실행
    임계 영역; 
}</code></pre><p>: 동기화 메소드를 만들려면
메소드 선언에 synchronized 키워드를 붙이면 됨
, 인스턴스와 정적 메소드 어디든 붙일 수 있음</p>
<p>: 동기화 메소드는 메소드 전체 내용이 임계 영역이므로
스레드가 동기화 메소드를 실행하는 즉시
객체에는 잠금이 일어나고,
스레드가 동기화 메소드를 실행 종료하면 잠금이 풀림</p>
<p>: 만약 동기화 메소드가 여러 개 있을 경우,
스레드가 이들 중 하나를 실행할 때 다른 스레드는 
해당 메소드는 물론이고 다른 동기화 메소드도 실행할 수 없음</p>
<p>하지만 이때 다른 스레드에서 일반 메소드는 실행이 가능함</p>
<pre><code>👩‍💻 동기화 메소드로 수정된 공유 객체
public class Calculator {
    private int memory;

    public int getMemory() {
        return memory;
    }

    //계산기 메모리에 값을 저장하는 메소드
    public synchronized void setMemory(int memory) {
        //매개값을 memory 필드에 저장
        this.memory = memory;
        //스레드를 2초간 일시 정지시킴
        try {
            Thread.sleep(2000);
        } catch(InterruptedException e) {}
        //Thread.currentThread().getName() - 스레드 이름 얻기
        //this.memory - 메모리값
        System.out.println(Thread.currentThread().getName() + &quot;: &quot; + 
                this.memory);
    }

}

→ 위 코드 수정하여
실행해보면 User1은 100,
User2는 50 이라는 출력값을 얻을 수 있음

→ User1 스레드는 Calculator 객체의 동기화 메소드인
setMemory()를 실행하는 순간 Calculator 객체를 잠금 처리함

메인 스레드가 User2 스레드를 실행하지만,
동기화 메소드인 setMemory()를 실행하지는 못하고
User1이 setMemory()를 모두 실행할 동안 대기해야함

→ User1 스레드가 setMemory() 메소드를 모두 실행하고 나면
User2 스레드가 setMemory() 메소드를 실행함

결국 User1 스레드가 Calculator 객체를 사용할 동안
User2 스레드는 Calculator 객체를 사용하지 못하므로
User1 스레드는 방해받지 않고 안전하게
Calculator 객체를 사용할 수 있게 되는 것</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] java.util 패키지]]></title>
            <link>https://velog.io/@geumyi_/Java-java.util-%ED%8C%A8%ED%82%A4%EC%A7%80</link>
            <guid>https://velog.io/@geumyi_/Java-java.util-%ED%8C%A8%ED%82%A4%EC%A7%80</guid>
            <pubDate>Thu, 28 Mar 2024 08:41:42 GMT</pubDate>
            <description><![CDATA[<h3 id="✔️-date-클래스">✔️ Date 클래스</h3>
<blockquote>
</blockquote>
<p>Date now = new Date();</p>
<p>: 특정 시점의 날짜를 표현하는 클래스
: Date 객체 안에는 특정 시점의 연도, 월, 일, 시간 정보가 저장됨</p>
<p>: Date는 객체 간의 날짜 정보를 주고받을 때 
매개 변수나 리턴 타입으로 주로 사용됨</p>
<blockquote>
</blockquote>
<p>SimpleDateFormat sdf = new SimpleDateFormat(&quot;yyyy년 MM월 dd일 hh시 mm분 ss초&quot;)</p>
<p>: Date 객체의 toString() 메소드는 영문으로 된 날짜를 리턴하기 때문에
원하는 날짜 형식의 문자열을 얻고 싶다면 java.text 패키지의
SimpleDateFormat 클래스와 함께 사용하는 것이 좋음</p>
<p>: SimpleDateFormat 생성자의 매개값은 형식 문자열임
yyy는 4자리연도, MM은 2자리 월, dd는 2자리 일을 뜻함</p>
<blockquote>
</blockquote>
<p>String strNow = sdf.format(now);</p>
<p>:SimpleDateFormat 객체를 얻었다면,
format() 메소드를 호출해서 원하는 형식의 날짜 정보를 얻을 수 있음
format() 메소드의 매개값은 Date 객체임</p>
<hr>
<h3 id="✔️-calendar-클래스">✔️ Calendar 클래스</h3>
<p>: 달력을 표현한 클래스
: 해당 운영체제의 Calendar 객체를 얻으면,
연도, 월, 일, 요일, 오전/오후, 시간 등의 정보를 얻을 수 있음</p>
<p>: Calendar 클래스는 추상 클래스 이므로
new 연산자를 사용해서 인스턴스를 생성할 수 없음</p>
<blockquote>
</blockquote>
<p>Calendar now = Calendar.getInstance();</p>
<p>: Calendar 클래스의 정적 메소드인 getInstance() 메소드를 이용하면
현재 운영체제에 설정되어 있는 시간대를 기준으로 한 
Calendar 하위 객체를 얻을 수 있음</p>
<pre><code>Calendar 객체를 얻었다면
get()메소드를 이용해서 날짜와 시간에 대한 정보를 읽을 수 있음

int year    = now.get(Calendar.YEAR);            //연도를 리턴
int month    = now.get(Calendar.MONTH) + 1;        //월을 리턴
int day    = now.get(Calendar.DAY_OF_MONTH);    //일을 리턴
int week    = now.get(Calendar.DAY_OF_WEEK);    //요일을 리턴
int amPm    = now.get(Calendar.AM_PM);            //오전/오후를 리턴
int hour    = now.get(Calendar.HOUR);            //시를 리턴
int minute    = now.get(Calendar.MINUTE);        //분을 리턴
int second    = now.get(Calendar.SECOND);        //초를 리턴</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] Math 클래스]]></title>
            <link>https://velog.io/@geumyi_/Java-Math-%ED%81%B4%EB%9E%98%EC%8A%A4</link>
            <guid>https://velog.io/@geumyi_/Java-Math-%ED%81%B4%EB%9E%98%EC%8A%A4</guid>
            <pubDate>Thu, 28 Mar 2024 08:39:37 GMT</pubDate>
            <description><![CDATA[<h3 id="✔️-math-클래스">✔️ Math 클래스</h3>
<p>: java.lang.Math 클래스는
수학 계산에 사용할 수 있는 메소드를 제공함</p>
<p>: Math 클래스가 제공하는 메소드는
모두 <strong>정적 메소드</strong>이므로
Math 클래스로 바로 사용 가능</p>
<hr>
<h3 id="✔️-math-클래스-메소드">✔️ Math 클래스 메소드</h3>
<p>
<img src="https://velog.velcdn.com/images/geumyi_/post/1f55e61b-9650-40fc-bd60-d52f2780b371/image.png
">  
</p>

<p><strong>- round() 메소드</strong>
: 항상 소수점 첫째 자리에서 반올림해서 정수값을 리턴</p>
<p><strong>- Math.random() 메소드</strong>
: 0.0관 1.0사이의 범위에 속하는 하나의 double 타입의 값을 리턴
0.0은 범위에 포함되고 1.0은 포함되지 않음</p>
<blockquote>
</blockquote>
<p>0.0 &lt;= Math.random() &lt; 1.0</p>
<p>ex) 1부터 10까지의 정수 난수 얻기</p>
<p>① 각 변에 10을 곱하면
다음과 같이 0.0 &lt;= ··· &lt; 10.0 사이의
범위에 속하는 하나의 double 타입의 값을 얻을 수 있음</p>
<blockquote>
</blockquote>
<p>0.0 * 10 &lt;= Math.random() * 10 &lt; 1.0 * 10</p>
<p>② 각 변을 int 타입으로 강제 타입 변환하면 다음과 같이
0 &lt;= ··· &lt; 10 사이의 범위에 속하는 하나의 int 타입의 값을 얻을 수 있음</p>
<blockquote>
</blockquote>
<p>(int) (0.0 * 10) &lt;= (int) (Math.random() * 10) &lt; (int) (1.0 * 10)</p>
<p>③ 각 변에 1을 더하면 다음과 같이 1&lt;= ··· &lt;11 사이의 
범위에 속하는 하나의 정수를 얻게 됨</p>
<blockquote>
</blockquote>
<p>(int) (0.0*10)+1 &lt;= (int) (Math.random() * 10) + 1 &lt; (int) (1.0 * 10) + 1</p>
<p>④ 자바 코드로 표현
int num = (int) (Math.rnadom() * 10) + 1</p>
<pre><code>- 만약 시작이 1이 아닌 start일 경우,
start &lt;= ··· &lt; (start+n) 범위에 속하는 
하나의 정수를 얻기 위한 연산식

ex)
주사위 번호 뽑기
int num = (int) (Math.random() * 6) + 1;

로또 번호 뽑기
int num = (int) (Math.random() * 45) + 1;</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] Wrapper(포장) 클래스]]></title>
            <link>https://velog.io/@geumyi_/Java-Wrapper%ED%8F%AC%EC%9E%A5-%ED%81%B4%EB%9E%98%EC%8A%A4</link>
            <guid>https://velog.io/@geumyi_/Java-Wrapper%ED%8F%AC%EC%9E%A5-%ED%81%B4%EB%9E%98%EC%8A%A4</guid>
            <pubDate>Thu, 28 Mar 2024 08:34:44 GMT</pubDate>
            <description><![CDATA[<h3 id="✔️-wrapper포장-클래스">✔️ Wrapper(포장) 클래스</h3>
<p>: 자바는 기본 타입(byte, char, short, int, long, float, double, boolean)의 값을
갖는 객체를 생성할 수 있음 → 이런 객체를 <strong>포장(Wrapper) 객체</strong>라고 함</p>
<p>→ 그 이유는 기본 타입의 값을 내부에 두고 포장하기 때문</p>
<blockquote>
</blockquote>
<p>· 포장 객체의 특징
: 포장하고 있는 기본 타입 값은 외부에서
변경할 수 없음
→ 만약 내부의 값을 변경하고 싶으면
새로운 포장 객체를 만들어야함</p>
<p>: 포장 객체는 주로 컬렉션 프라임워크에서 기본 타입 값을
객체로 생성해서 관리할 때 사용됨</p>
<p>: 포장 객체의 설계도인 포장 클래스는 java.lang 패키지에 포함되어 있음</p>
<p>
<img src="https://velog.velcdn.com/images/geumyi_/post/ef8a7d52-587a-42d2-a0aa-ee73a919f7f3/image.png
" width="80%">  
</p>

<p>: 다음과 같이 기본 타입에 대응되는 클래스들이 있음
char 타입과 int타입이 각각 Character와 Integer로 변경되고,
기본 타입의 첫 문자를 대문자로 바꾼 이름을 가지고 있음</p>
<hr>
<h3 id="✔️-박싱boxing과-언박싱unboxing">✔️ 박싱(Boxing)과 언박싱(Unboxing)</h3>
<p>· 박싱(Boxing)
: 기본 타입의 값을 포장 객체로 만드는 과정</p>
<p>· 언박싱(Unboxing)
: 포장 객체에서 기본 타입의 값을 얻어내는 과정</p>
<p>
<img src="https://velog.velcdn.com/images/geumyi_/post/ef8a7d52-587a-42d2-a0aa-ee73a919f7f3/image.png
" width="80%">  
</p>

<p>→ 8개의 기본 타입의 값을 박싱하는 방법을 보여주고 있음
간단하게 포장 클래스의 생성자 매개값으로 
기본 타입의 값 또는 문자열로 넘겨주면 됨</p>
<blockquote>
</blockquote>
<p>Integer obj = Integer.valueOf(1000);
Integer obj = Integer.valueOf(&quot;1000&quot;);</p>
<p>: 생성자를 이용하지 않아도
각 포장 클래스마다 가지고 있는 
정적 valueOf() 메소드를 사용할 수도 있음</p>
<p>
<img src="https://velog.velcdn.com/images/geumyi_/post/c81f4fd7-24f0-41cc-8fae-b818d3274940/image.png
" width="80%">  
</p>

<p>→ 박싱된 포장 객에에서 다시 
기본 타입의 값을 얻어내기 위해서는(언박싱하기 위해서는)
각 포장 클래스마다 가지고 있는 
<strong>&#39;기본 타입 이름 + Value()&#39;</strong> 메소드를 호출하면 됨</p>
<pre><code class="language-java">👩‍💻 기본 타입의 값을 박싱하고 언박싱하기
public class BoxingUnBoxingExample {
    public static void main(String[] args) {
        //박싱
        Integer obj1 = new Integer(100);
        Integer obj2 = new Integer(&quot;200&quot;);
        Integer obj3 = Integer.valueOf(&quot;300&quot;);

        //언박싱
        int value1 = obj1.intValue();
        int value2 = obj2.intValue();
        int value3 = obj3.intValue();

        System.out.println(value1);
        System.out.println(value2);
        System.out.println(value3);
    }
}

💻 결과
100
200
300</code></pre>
<hr>
<h3 id="✔️-자동-박싱과-언박싱">✔️ 자동 박싱과 언박싱</h3>
<p><strong>· 자동 박싱</strong>
: 기본 타입 값을 직접 박싱, 언박싱하지 않아도 자동적으로
박싱과 언박싱이 일어나는 경우가 있음
: 포장 클래스 타입에 기본값이 대입될 경우에 발생</p>
<pre><code>ex)
int 타입의 값을 Integer 클래스 변수에 대입하면
자동 박싱이 일어나 힙 영역에 Integer 객체가 생성됨

Integer obj = 100; //자동 박싱</code></pre><p><strong>· 자동 언박싱</strong>
: 기본 타입에 포장 객체가 대입되는 경우와 연산에서 발생</p>
<pre><code>ex)
Integer 객체를 int 타입 변수에 대입하거나,
Integer 객체와 int 값을 연산하면 Integer 객체로부터
int값이 자동 언박싱되어 연산됨

Integer obj = new Integer(200);
int value1 = obj; //자동 언박싱
int value2 = ojb + 100; //자동 언박싱</code></pre><pre><code class="language-java">👩‍💻 자동 박싱과 언박싱
public class AutoBoxingUnBoxingExample {
    public static void main(String[] args) {
        //자동 박싱
        Integer obj = 100;
        System.out.println(&quot;value: &quot; + obj.intValue());

        //대입 시 자동 언박싱
        int value = obj;
        System.out.println(&quot;value: &quot; + value);

        //연산 시 자동 언박싱
        int result = obj + 100;
        System.out.println(&quot;result: &quot; + result);
    }
}

💻 결과
value: 100
value: 100
result: 200</code></pre>
<hr>
<h3 id="✔️-문자열을-기본-타입-값으로-변환">✔️ 문자열을 기본 타입 값으로 변환</h3>
<p>
<img src="https://velog.velcdn.com/images/geumyi_/post/108c563b-868d-4249-81c7-d7a4a1469621/image.png
" width="80%">  
</p>

<p>: 포장 글래스의 주요 용도는
기본 타입의 값을 박싱해서 포장 객체로 만드는 것이지만,
문자열을 기본 타입 값으로 변환할 때에도 많이 사용됨</p>
<p>: 대부분의 포장 클래스에는 
<strong>&#39;parse+기본 타입 이름&#39;</strong>으로 되어 있는 정적 메소드가 있음
정적 메소드는 문자열을 매개값으로 받아 기본 타입 값으로 변환함</p>
<pre><code class="language-java">👩‍💻 문자열을 기본 타입 값으로 변환
public class StringToPrimitiveValueExample {
    public static void main(String[] args) {
        int value1 = Integer.parseInt(&quot;10&quot;);
        double value2 = Double.parseDouble(&quot;3.14&quot;);
        boolean value3 = Boolean.parseBoolean(&quot;true&quot;);

        System.out.println(&quot;value1: &quot; + value1);
        System.out.println(&quot;value2: &quot; + value2);
        System.out.println(&quot;value3: &quot; + value3);
    }
}

💻 결과
value1: 10
value2: 3.14
value3: true</code></pre>
<hr>
<h3 id="✔️-포장-값-비교">✔️ 포장 값 비교</h3>
<p>: 포장 객체는 내부의 값을 비교하기 위해 
==와 !=연산자를 사용하지 않는 것이 좋음</p>
<p>이 연산자는 내부의 값을 비교하는 것이 아니라
포장 객체의 참조를 비교하기 때문</p>
<pre><code>ex)
Integer obj1 = 300;
Integer obj2 = 300;
System.out.println(obj1 == obj2);

동일한 값을 갖고 있지만
== 연산의 결과는 false가 나옴</code></pre><p>: 포장 객체에 정확히 어떤 값이 저장될지 모르는 상황이라면
직접 내부 값을 언박싱해서 비교하거나,
equals()메소드로 내부 값을 비교하는 것이 좋음</p>
<pre><code class="language-java"> 👩‍💻 포장 객체 비교
public class ValueCompareExample {
    public static void main(String[] args) {
        System.out.println(&quot;[-128~127 초과값일 경우]&quot;);
        Integer obj1 = 300;
        Integer obj2 = 300;
        System.out.println(&quot;==결과: &quot; + (obj1 == obj2));
        System.out.println(&quot;언박싱후 ==결과: &quot; + (obj1.intValue()
                == obj2.intValue()));
        System.out.println(&quot;equals() 결과: &quot; + obj1.equals(obj2));
        System.out.println();

        System.out.println(&quot;[-128~127 범위값일 경우]&quot;);
        Integer obj3 = 10;
        Integer obj4 = 10;
        System.out.println(&quot;==결과: &quot; + (obj3 == obj4));
        System.out.println(&quot;언박싱후 ==결과: &quot; + 
                (obj3.intValue() == obj4.intValue()));
        System.out.println(&quot;equals() 결과: &quot; + obj3.equals(obj4));

    }
}

💻 결과
[-128~127 초과값일 경우]
==결과: false
언박싱후 ==결과: true
equals() 결과: true

[-128~127 범위값일 경우]
==결과: true
언박싱후 ==결과: true
equals() 결과: true</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] String 클래스]]></title>
            <link>https://velog.io/@geumyi_/Java-String-%ED%81%B4%EB%9E%98%EC%8A%A4</link>
            <guid>https://velog.io/@geumyi_/Java-String-%ED%81%B4%EB%9E%98%EC%8A%A4</guid>
            <pubDate>Thu, 28 Mar 2024 08:30:11 GMT</pubDate>
            <description><![CDATA[<h3 id="✔️-string-생성자">✔️ String 생성자</h3>
<p>
<img src="https://velog.velcdn.com/images/geumyi_/post/3d527961-6d45-4ce7-80b8-04325ccbc1d3/image.png">  
</p>

<p>: 문자열은 java.lang 패키지의 
String 클래스의 인스턴스로 관리됨</p>
<p>: 소스상에서 문자열 리터럴은 String 객체로 자동 생성되지만
String 클래스의 다양한 생성자를 이용해서
직접 String 객체를 생성할 수도 있음</p>
<p>: 어떤 생성자를 이용해서 String 객체를 생성할지는
제공되는 매개값의 타입에 달려있음</p>
<pre><code>네트워크를 통해 받은 데이터는
보통 byte[] 배열이므로 이것을 문자열로
변환하기 위해 사용됨

//배열 전체를 String 객체로 생성
String str = new String(byte[] bytes);

//지정한 문자셋으로 디코딩
String str = new String(byte[] bytes, String charsetName);

//배열의 offset 인덱스 위치부터 length만큼 String 객체로 생성
String str = new String(byte[] bytes, int offset, int lenght);

//지정한 문자셋으로 디코딩
String str = new String(byte[] bytes, int offset, 
        int length, String charsetName)</code></pre><pre><code>👩‍💻 바이트 배열을 문자열로 변환
public class ByteToStringExample {
    public static void main(String[] args) {
        byte[] bytes = {72, 101, 108, 108, 
                111, 32, 74, 97,
                118, 97};

        String str1 = new String(bytes);
        System.out.println(str1);

        // String(bytes, 6, 4) 74의 인덱스위치, 4개
        String str2 = new String(bytes, 6, 4);
        System.out.println(str2);
    }
}

💻 결과
Hello Java
Java</code></pre><p><strong>- 키보드로부터 읽은 바이트 배열을 문자열로 변환하는 방법</strong>
System.in.read() 메소드는
키보드에서 입력한 내용을 매개값으로 주어진 바이트 배열에
저장하고 읽은 바이트 수를 리턴함</p>
<pre><code>ex)
Hello를 입력하고 enter키를 눌렀다면
Hello+캐리지리턴(\r)+라인피드(\n)의
코드값이 바이트 배열에 저장되고
총 7개의 바이트를 읽었기 때문에
7을 리턴함</code></pre><p>
<img src="https://velog.velcdn.com/images/geumyi_/post/079c786d-7918-4f0f-ab16-8d7aa54e4929/image.png
" width="80%">  
</p>

<pre><code>👩‍💻 바이트 배열을 문자열로 변환
import java.io.IOException;

public class KeyboardToStringExample {
    public static void main(String[] args) throws IOException {
        //읽은 바이트를 저장하기 위한 배열 생성
        byte[] bytes = new byte[100];

        System.out.print(&quot;입력: &quot;);
        //배열에 읽은 바이트를 저장하고
        //읽은 바이트 수를 리턴
        int readByteNo = System.in.read(bytes);

        String str = new String(bytes, 0, readByteNo-2);
        System.out.println(str);
    }
}

/*
 * String(byte[] bytes, int offset, int length)
 * 형태로 바이트 배열을 문자열로 변환하였는데,
 * length 매개값으로 배열 길이에서 2를 빼준 이유는
 * 캐리지리턴(\r)+라인피트(\n)부분은 문자열로 만들 필요가
 * 없기 때문
 */

💻 결과
입력: Hello
Hello</code></pre><hr>
<h3 id="✔️-string-메소드">✔️ String 메소드</h3>
<p><strong>- 문자 추출(charAt())</strong>
[ 리턴 타입 = char ] 
형태- charAt(int index)
: 특정 위치의 문자를 리턴함</p>
<p>: 매개값으로 주어진 인덱스의 문자를 리턴함</p>
<p>+ 인덱스 : 0에서부터 &#39;문자열 길이-1&#39;까지의 번호</p>
<pre><code>String subject = &quot;자바 프로그래밍&quot;;
char charValue = subject.charAt(3);

→ charAt(3)은 3번 인덱스 위치에 있는 문자를 뜻함</code></pre><pre><code>public class StringCharAtExample {

    public static void main(String[] args) {
        String ssn = &quot;010624-1230123&quot;;
        char sex = ssn.charAt(7);
        switch (sex) {
            case &#39;1&#39;:
            case &#39;3&#39;:
                System.out.println(&quot;남자 입니다.&quot;);
                break;
            case &#39;2&#39;:
            case &#39;4&#39;:
                System.out.println(&quot;여자 입니다.&quot;);
                break;
        }
    }

}

💻 결과
남자 입니다.</code></pre><p><strong>- 문자열 비교(equals())</strong>
[ 리턴 타입 = boolean ]
형태- equals(Object anObject)
: 두 문자열을 비교함</p>
<p>: 기본 타입(byte, char, short, int, long, float,double, boolean) 변수의 값을 
비교할 때에는== 연산자를 사용함 
그러나 문자열을 비교할 때에는
== 연산자를 사용하면 원하지 않는 결과가 나올 수 있음</p>
<pre><code>String strVar1 = new String(&quot;홍길동&quot;);
String strVar2 = &quot;홍길동&quot;;
String strVar3 = &quot;홍길동&quot;;

: 문자열 리터럴이 동일하다면 
동일한 String 객체를 참조하도록 되어 있음

그래서 strVar2와 strVar3은 동일한 String객체를 참조함

그러나 strVar1은 new 연산자로 생성된
다른 String객체를 참조함

== 연산자는 각 변수에 저장된 번지를 비교하기 떄문에
strVar1 == strVar2 //false
strVar2 == strVar3 //true

결과가 나옴

→ 만약 String 객체의 문자열만 비교하고 싶다면
equals() 메소드를 사용하면 됨
strVar1.equals(strVar2) //true
strVar2.equals(strVar3) </code></pre><p>: equalse()는 Object 클래스의 번지 비교 메소드지만,
String 클래스가 재정의해서 문자열을 비교하도록 함</p>
<pre><code>👩‍💻 문자열 비교
public class StringEqualsExample {

    public static void main(String[] args) {
        String strVar1 = new String(&quot;홍길동&quot;);
        String strVar2 = &quot;홍길동&quot;;

        if(strVar1 == strVar2) {
            System.out.println(&quot;같은 String 객체를 참조&quot;);
        } else {
            System.out.println(&quot;다른 String 객체를 참조&quot;);
        }

        if(strVar1.equals(strVar2)) {
            System.out.println(&quot;같은 문자열을 가짐&quot;);
        } else {
            System.out.println(&quot;다른 문자열을 가짐&quot;);
        }

    }

}

💻 결과
다른 String 객체를 참조
같은 문자열을 가짐</code></pre><p><strong>- 바이트 배열로 변환(getBytes())</strong>
[ 리턴 타입 = byte[] ]
형태- getBytes()
: byte[]로 리턴함</p>
<p>: 문자열을 바이트 배열로 변환하는 경우가 있음</p>
<pre><code>ex)
네트워크로 문자열을 전송하거나,
문자열을 암호화할 때 문자열을 바이트 배열로 변환하는 경우</code></pre><p>· 문자열을 바이트 배열로 변환하는 메소드</p>
<blockquote>
</blockquote>
<p>byte[] bytes = &quot;문자열&quot;.getBytes();
byte[] bytes = &quot;문자열&quot;.getBytes(Charset charset);</p>
<p>: getBytes() 메소드는 시스템의 기본 문자셋으로
인코딩된 바이트 배열을 리턴함</p>
<p>: 만약 특정 문자셋으로 인코딩된 바이트 배열을 얻으려면
두 번째 메소드를 사용하면 됨</p>
<p>: 어떤 문자셋으로 인코딩하느냐에 따라
바이트 배열의 크기가 달라지는데,
EUC-KR은 getBytes()와 마찬가지로
알파벳은 1바이트, 한글은 2바이트로 변환
UTF-8은 알파벳 1바이트, 한글 3바이트로 변환</p>
<p>: getBytes(Charset charset) 메소드는 잘못된 문자셋을
매개값으로 줄 경우,
java.io.UnsupportedEncodeingException이 발생하므로 예외처리가 필요</p>
<p>: 바이트 배열을 다시 문자열로 변환(디코딩)할 때에는
어떤 문자셋으로 인코딩된 바이트 배열이냐에 따라서
디코딩 방법이 다름.</p>
<p>단순하게 String(byte[] bytes) 생성자를 이용해서
디코딩하면 시스템의 기본 문자셋을 이용함</p>
<p>시스템 기본 문자셋과 다른 문자셋으로 인코딩된
바이트 배열일 경우 </p>
<blockquote>
</blockquote>
<p>String str = new String(byte[] bytes, String charsetName);</p>
<p>String 생성자를 이용해서 디코딩해야함</p>
<pre><code class="language-java">👩‍💻 바이트 배열로 변환
import java.io.UnsupportedEncodingException;

/*
 * 문자열을 바이트 배열로 인코딩하고 길이 출력,
 * 다시 String 생성자를 이용해서 문자열로 디코딩하기
 */
public class StringGetBytesExample {
    public static void main(String[] args) {
        String str = &quot;안녕하세요&quot;;

        // 기본 문자셋으로 인코딩과 디코딩
        byte[] bytes1 = str.getBytes();
        System.out.println(&quot;bytes1.length: &quot; +
                bytes1.length);
        String str1 = new String(bytes1);
        System.out.println(&quot;bytes1-&gt;String: &quot; +
                str1);

         try {

             //EUC-KR을 이용해서 인코딩 및 디코딩
             byte[] bytes2 = str.getBytes(&quot;EUC-KR&quot;);
             System.out.println(&quot;bytes2.length: &quot; +
                        bytes2.length);
             String str2 = new String(bytes2, &quot;EUC-kR&quot;);
                System.out.println(&quot;bytes2-&gt;String: &quot; +
                        str2);

             //UTF-8을 이용해서 인코딩 및 디코딩
             byte[] bytes3 = str.getBytes(&quot;UTF-8&quot;);
             System.out.println(&quot;bytes3.length: &quot; +
                     bytes3.length);
             String str3 = new String(bytes3, &quot;UTF-8&quot;);
                System.out.println(&quot;bytes3-&gt;String: &quot; +
                        str3);    

         } catch (UnsupportedEncodingException e) {
             e.printStackTrace();
         }
    }
}

💻 결과
bytes1.length: 15
bytes1-&gt;String: 안녕하세요
bytes2.length: 10
bytes2-&gt;String: 안녕하세요
bytes3.length: 15
bytes3-&gt;String: 안녕하세요</code></pre>
<p><strong>- 문자열 찾기(indexOf())</strong>
[ 리턴 타입 =int ]
형태- indexOf(String str)
: 문자열 내에서 주어진 문자열의 위치를 리턴함</p>
<p>: 매개값으로 주어진 문자열이 시작되는 인덱스를 리턴
만약 주어진 문자열이 포함되어 있지 않으면 -1을 리턴함</p>
<pre><code>String subject = &quot;자바 프로그래밍&quot;;
int index = subject.indexOf(&quot;프로그래밍&quot;);

→ index변수에는 3이 저장되는데
&quot;자바 프로그래밍&quot;에서
&quot;프로그래밍&quot; 문자열의 인덱스 위치가 3이기 때문</code></pre><p>: indexOf() 메소드는 if문의 조건식에서 특정 문자열이
포함되어 있는지 여부에 따라 실행 코드를 달리할 때 자주 사용됨
-1 값을 리턴하면 특정 문자열이 포함되어 있지 않다는 뜻</p>
<pre><code>if( 문자열.indexOf(&quot;찾는문자열&quot;) != -1 ) {
    //포함되어 있는 경우
} else {
    //포함되어 있지 않은 경우
}</code></pre><pre><code class="language-java">👩‍💻 문자열 포함 여부 조사
public class StringIndexOfExample {

    public static void main(String[] args) {
        String subject = &quot;자바 프로그래밍&quot;;

         int location = subject.indexOf(&quot;프로그래밍&quot;);
         System.out.println(location);

         if(subject.indexOf(&quot;자바&quot;) != -1) {
             System.out.println(&quot;자바와 관련된 책이군요&quot;);
         } else { 
             System.out.println(&quot;자바와 관련없는 책이군요&quot;);
         }
    }

}

💻 결과
3
자바와 관련된 책이군요</code></pre>
<p><strong>- 문자열 길이(length())</strong>
[ 리턴 타입 =int ]
형태- length()
: 문자열 내에서 주어진 문자열의 위치를 리턴함</p>
<p>: 문자열의 길이(문자의 수)를 리턴</p>
<pre><code>String subject = &quot;자바 프로그래밍&quot;;
int length = subject.length();

legnth변수에는 8이 저장됨
공백을 포함해서 8개이기 때문</code></pre><pre><code class="language-java">👩‍💻 문자열의 문자 수 얻기
public class StringLengthExample {

    public static void main(String[] args) {
        String ssn = &quot;7306241230123&quot;;
        int length = ssn.length();

        if(length == 13) {
            System.out.println(&quot;주민번호 자리수가 맞습니다.&quot;);
        } else { 
            System.out.println(&quot;주민번호 자리수가 틀립니다.&quot;);
        }

    }

}

💻 결과
주민번호 자리수가 맞습니다.</code></pre>
<p><strong>- 문자열 대치(replace())</strong>
[ 리턴 타입 = String ]
형태- replace(CharSequence target, CharSequence replacement)
: target 부분을 replacement로 대치한 새로운 문자열을 리턴</p>
<p>: 첫 번째 매개값인 문자열을 찾아
두 번째 매개값인 문자열로 대치한 새로운 문자열을 생성하고 리턴</p>
<pre><code>String oldStr = &quot;자바 프로그래밍&quot;;
String newStr = oldStr.replace(&quot;자바&quot;, &quot;JAVA&quot;);</code></pre><p>: String 객체의 문자열은 변경이 불가능한 특성을 갖기 때문에
replace() 메소드가 리턴하는 문자열은
원래 문자열의 수정본이 아니라 완전히 새로운 문자열임</p>
<pre><code class="language-java">👩‍💻 문자열 대치하기
public class StringReplaceExample {

    public static void main(String[] args) {
        String oldStr = &quot;자바는 객체 지향 언어입니다.&quot;
                + &quot; 자바는 풍부한 API를 지원합니다.&quot;;
        String newStr = oldStr.replace(&quot;자바&quot;, &quot;JAVA&quot;);
        System.out.println(oldStr);
        System.out.println(newStr);

    }

}

💻 결과
자바는 객체 지향 언어입니다. 자바는 풍부한 API를 지원합니다.
JAVA는 객체 지향 언어입니다. JAVA는 풍부한 API를 지원합니다.</code></pre>
<p><strong>- 문자열 잘라내기(substring())</strong>
[ 리턴 타입 = String ]
형태- substring(int beginIndex, int endIndex)
: beginIndex 위치에서
endIndex 전까지 잘라낸 새로운 문자열을 리턴함</p>
<p>: 주어진 인덱스에서 문자열을 추출함</p>
<p><code>substring(int beginIndex, int endInedx)</code>
는 주어진 시작과 끝 인덱스 사이의 문자열을 추출</p>
<p><code>substring(int beginIndex)</code>
는 주어진 인덱스부터 끝까지 문자열을 추출</p>
<pre><code>String ssn = &quot;880815-1234567&quot;;
String firstNum = ssn.substring(0, 6);
String secondNum = ssn.substring(7);

firstNum 변수값은 &quot;880815&quot;
secondNum 변수값은 &quot;1234567&quot;

ssn.substring(0.6)은
인덱스 0(포함) ~ 6(제외) 문자열을 추출

substring(7)은
인덱스 7부터 끝까지 문자열을 추출</code></pre><pre><code class="language-java">👩‍💻 문자열 추출하기
public class StringSubstringExample {

    public static void main(String[] args) {
        String ssn = &quot;880815-1234567&quot;;

        String firstNum = ssn.substring(0, 6);
        System.out.println(firstNum);

        String secondNum = ssn.substring(7);
        System.out.println(secondNum);

    }

}

💻 결과
880815
1234567</code></pre>
<p><strong>- 알파벳 소·대문자 변경(toLowerCase(), toUpperCase())</strong>
[ 리턴 타입 = String ]
형태- toLowerCase()
: 알파벳 소문자로 변환한 새로운 문자열을 리턴
형태- toUpperCase()
: 알파벳 대문자로 변환한 새로운 문자열을 리턴</p>
<p>toLowerCase() 메소드는
문자열을 모두 소문자로 바꾼
새로운 문자열을 생성한 후 리턴함</p>
<p>toUpperCase() 메소드는
문자열을 모두 대문자로 바꾼
새로운 문자열을 생성한 후 리턴함</p>
<pre><code>String original = &quot;Java Programming&quot;;
String lowerCase = original.toLowerCase();
String upperCase = original.toUpperCase();

: lowerCase 변수는 새로 생성된 &quot;java programming&quot; 문자열을 참조하고
upperCase 변수는 새로 생성된 &quot;JAVA PROGRMMING&quot; 문자열을 참조함

: 문자열이 변경된 것은 아님</code></pre><p>: 영어로 된 두 문자열을 대소문자와 관계없이
비교할때 주로 이용됨</p>
<p>: equals() 메소드를 사용하려면 사전에
toLowerCase()와 toUpperCase()로 대소문자를 맞춰야 하지만,
equalsIgnoreCase() 메소드를 사용하면
이 작업이 생략됨</p>
<pre><code class="language-java">👩‍💻 전부 소문자 또는 대문자 변경
public class StringToLowerUpperCaseExample {

    public static void main(String[] args) {
        String str1 = &quot;Java Programming&quot;;
        String str2 = &quot;JAVA Programming&quot;;

        System.out.println(str1.equals(str2));

        String lowerStr1 = str1.toLowerCase();
        String lowerStr2 = str2.toLowerCase();
        System.out.println(lowerStr1.equals(lowerStr2));

        System.out.println(str1.equalsIgnoreCase(str2));

    }

}

💻 결과
false
true
true</code></pre>
<p><strong>- 문자열 암뒤 공백 잘라내기(trim())</strong>
[ 리턴 타입 = String ]
형태- trim()
: 앞뒤 공백을 제거한 새로운 문자열을 리턴</p>
<p>: 문자열의 앞뒤 공백을 제거한 새로운 문자열을 생성하고 리턴함</p>
<pre><code>String oldStr = &quot;    자바 프로그래밍     &quot;;
String newStr = oldStr.trim();

:newStr 변수는 앞뒤 공백이 제거된
새로 생성된 &quot;자바 프로그래밍&quot; 문자열을 참조함

: 원래 문자열의 공백이 제거되는 것은 아님</code></pre><pre><code class="language-java">👩‍💻 문자열 앞뒤 공백 제거
public class StringTrimExample {
    public static void main(String[] args) {
        String tel1 = &quot;  02&quot;;
        String tel2 = &quot;123  &quot;;
        String tel3 = &quot;   1234   &quot;;

        String tel = tel1.trim() + tel2.trim() +
                tel3.trim();

        System.out.println(tel);
    }
}

💻 결과
021231234</code></pre>
<p><strong>- 문자열 변환(valueOf())</strong>
[ 리턴 타입 = String ]
형태- valueOf(int i) / valueOf(double d)
: 기본 타입 값을 문자열로 리턴</p>
<p>: 기본 타입의 값을 문자열로 변환하는 기능</p>
<p>· String 클래스에는 매개 변수의 타입별로 valueOf()
메소드가 오버로딩 되어있음</p>
<pre><code>static String valueOf(boolean b)
static String valueOf(char c)
static String valueOf(int i)
static String valueOf(long l)
static String valueOf(double d)
static String valueOf(float f)</code></pre><pre><code class="language-java">👩‍💻 기본 타입 값을 문자열로 변환
public class StringValueOfExample {
    public static void main(String[] args) {
        String str1 = String.valueOf(10);
        String str2 = String.valueOf(10.5);
        String str3 = String.valueOf(true);

        System.out.println(str1);
        System.out.println(str2);
        System.out.println(str3);
    }
}

💻 결과
10
10.5
true</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] Class 클래스]]></title>
            <link>https://velog.io/@geumyi_/Java-Class-%ED%81%B4%EB%9E%98%EC%8A%A4</link>
            <guid>https://velog.io/@geumyi_/Java-Class-%ED%81%B4%EB%9E%98%EC%8A%A4</guid>
            <pubDate>Wed, 27 Mar 2024 02:05:51 GMT</pubDate>
            <description><![CDATA[<h3 id="✔️-class-클래스">✔️ Class 클래스</h3>
<p>: 클래스와 인터페이스의 메타 데이터를
java.lang 패키지에 소속된 Class 클래스로 관리함</p>
<ul>
<li>메타 데이터란?
: 클래스의 이름, 생성자 정보, 필드 정보, 메소드 정보를 말함</li>
</ul>
<hr>
<h3 id="✔️-class-객체-얻기getclass-forname">✔️ Class 객체 얻기(getClass(), forName())</h3>
<p>1) 클래스로부터 얻는 방법
① Class clazz = 클래스이름.class
② Class clazz = Class.forName(&quot;패키지. . .클래스이름&quot;)</p>
<p>→ 객체 없이 클래스 이름만 가지고
Class객체를 얻는 방법</p>
<p>2) 객체로부터 얻는 방법
③ Class clazz = 참조변수.getClass();</p>
<p>→ 클래스로부터 객체가 이미 생성되어 있을 경우에
사용하는방법</p>
<pre><code>ex) 
String 클래스의 Class 객체 얻기
① Class clazz = String.class;
② Class clazz = Class.forName(&quot;java.lang.String&quot;);
    String str = &quot;감자바&quot;;
③ Class clazz = str.getClass();</code></pre><pre><code class="language-java">import sec06.exam06.Car;

public class ClassExample {
    public static void main(String[] args) {
        //첫 번째 방법
        Class clazz = Car.class;

        //두 번째 방법
        //Class clazz = Class.forName(&quot;sec06.exam06.Car&quot;);

        //세 번째 방법
        //Car car = new Car();
        //Class clazz = car.getClass();

        System.out.println(clazz.getName());
        System.out.println(clazz.getSimpleName());
        System.out.println(clazz.getPackage().getName());
    }
}

💻 결과
sec06.exam06.Car
Car
sec06.exam06</code></pre>
<hr>
<h3 id="✔️-클래스-경로를-활용해서-리소스-절대-경로-얻기">✔️ 클래스 경로를 활용해서 리소스 절대 경로 얻기</h3>
<p>: Class 객체는 해당 클래스의 파일 경로 정보를 가지고 있기 때문에
이 경로를 활용해서 다른 리소스 파일(이미지, XML, Property 파일)의
경로를 얻을 수 있음</p>
<p>→ 이 방법은 UI 프로그램에서 많이 활용됨</p>
<pre><code>ex)
Car 클래스가 위치하는 경로에 photo.jpg파일이 있다고 가정

파일
C:\SelfJavaStudy\chap11\bin\sec01
                      | - exam09
                               | - Car.class
                             | - photo1.jpg
                             | - images
                               | - photo2.jpg

- 프로그램 실행 중 이미지 파일(photo1.jpg, photo2.jpg)의
절대 경로가 필요할 경우에 Car.class를 기준으로
한 상대 경로를 이용해서 절대 경로를 얻을 수 있음

String photo1Path = clazz.getResource(&quot;photo1.jpg&quot;).getPath();
String photo2Path = clazz.getResource(&quot;images/photo2.jpg&quot;).getPath();</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] System 클래스]]></title>
            <link>https://velog.io/@geumyi_/Java-System-%ED%81%B4%EB%9E%98%EC%8A%A4</link>
            <guid>https://velog.io/@geumyi_/Java-System-%ED%81%B4%EB%9E%98%EC%8A%A4</guid>
            <pubDate>Wed, 27 Mar 2024 02:05:05 GMT</pubDate>
            <description><![CDATA[<h3 id="✔️-system-클래스">✔️ System 클래스</h3>
<p>: 자바 프로그램은 운영체제에서 바로 실행되는 것이 아니라
JVM위에서 실행됨</p>
<p>: java.lang 패키지에 속하는 System 클래스를 이용하면
운영체제의 일부 기능을 이용할 수 있음
즉, 프로그램 종료, 키보드로부터 입력, 
모니터로 출력, 현재 시간 읽기등이 가능함</p>
<p>: System 클래스의 모든 필드와 메소드는
정적 필드와 정적 메소드로 구성되어 있음</p>
<hr>
<h3 id="✔️-exit-메소드">✔️ exit() 메소드</h3>
<p>: 강제적으로JVM을 종료시킬 때도 있음
: System 클래스의 exit() 메소드를 호출하면
현재 실행하고 있는 프로세스를 
강제로 종료시키는 역할을 함</p>
<p>: exit() 메소드는 int 매개값을 지정하도록 되어 있는데,
이 값을 종료 상태값이라고함
→ 일반적으로 정상 종료일 경우 0 값을 줌</p>
<blockquote>
</blockquote>
<p>System.exit(0);</p>
<pre><code class="language-java">public class ExitExample {
    public static void main(String[] args) {
        for(int i=0; i&lt;10; i++) {
            if(i == 5) {
                System.exit(0);
                //break;
            }
        }


        System.out.println(&quot;마무리 코드&quot;);
    }
}

→ System.exit(0)은 프로그램을 강제 종료하므로
&quot;마무리 코드&quot;는 출력되지 않음

출력 코드를 사용하고 싶다면
System.exit(0) 대신에 for문을 빠져나오는 
break문을 사용하는 것이 좋음</code></pre>
<hr>
<h3 id="✔️-currenttimemillis-nanotime-메소드">✔️ currentTimeMillis(), nanoTime() 메소드</h3>
<p>: System 클래스의
currentTimeMillis() 메소드와
nanoTime() 메소드는
컴퓨터 시계로부터 현재 시간을 읽어서
밀리세컨드(1/1000초) 단위와
나노세컨드(1/10의 9승 초) 단위의 
long 값을 리턴함</p>
<blockquote>
</blockquote>
<p>long time = System.currentTimeMillis();
long time = System.nanoTime();</p>
<p>: 리턴값은 주로 프로그램의 실행 소요 시간 측정에 사용됨
: 프로그램 시작 시 시각을 읽고,
프로그램이 끝날 때 시각을 읽어서 차이를 구하면 
프로그램 실행 소요 시간이 나옴</p>
<pre><code class="language-java">public class SystemTimeExample {

    public static void main(String[] args) {
        //시작 시간 읽기
        long time1 = System.nanoTime();

        int sum = 0;
        for(int i=1; i&lt;=1000000; i++) {
            sum += i;
        }

        //끝 시간 읽기
        long time2 = System.nanoTime();

        System.out.println(&quot;1~1000000까지의 합: &quot; + sum);
        System.out.println(&quot;계산에 &quot; + (time2-time1) 
                + &quot; 나노초가 소요되었습니다.&quot;);
    }

}

💻 결과
1~1000000까지의 합: 1784293664
계산에 3491600 나노초가 소요되었습니다.</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] Object 클래스_toString()]]></title>
            <link>https://velog.io/@geumyi_/Java-Object-%ED%81%B4%EB%9E%98%EC%8A%A4toString</link>
            <guid>https://velog.io/@geumyi_/Java-Object-%ED%81%B4%EB%9E%98%EC%8A%A4toString</guid>
            <pubDate>Wed, 27 Mar 2024 02:04:19 GMT</pubDate>
            <description><![CDATA[<h3 id="✔️-객체-문자-정보tostring">✔️ 객체 문자 정보(toString())</h3>
<p>: 객체의 문자 정보를 리턴함
: 객체의 문자 정보란 
객체를 문자열로 표현한 값</p>
<p>: 기본적으로 Object 클래스의 toString() 메소드는
&#39;클래스이름@16진수해시코드&#39;로 구성된 문자 정보를 리턴함</p>
<pre><code>Object obj = new Object();
System.out.println( obj.toString() );

💻결과
java.lang.Object@de6ced</code></pre><p>: Object의 toString() 메소드의 리턴값은
자바 애플리케이션에서 별 값어치 없는 정보임</p>
<p>: Object 하위 클래스는 toString() 메소드를
재정의(오버라이딩)하여 간결하고 유익한 정보를 리턴 하도록 되어 있음</p>
<pre><code>ex)
java.util 패키지의 Date 클래스는 toString() 메소드를 재정의하여
현재 시스템의 날짜와 시간 정보를 리턴함

String 클래스는 toString() 메소드를 재정의해서
저장하고 있는 문자열을 리턴함</code></pre><pre><code class="language-java">import java.util.Date;

public class ToStringExample {
    public static void main(String[] args) {
        Object obj1 = new Object();
        Date obj2 = new Date();
        System.out.println(obj1.toString());
        System.out.println(obj2.toString());
    }
}

💻 결과
java.lang.Object@5594a1b5
Tue Mar 26 16:35:17 KST 2024</code></pre>
<p>• SmartPhone 클래스에서 toString() 메소드를 오버라이딩하여
제작회사와 운영체제를 리턴하기</p>
<pre><code class="language-java">class SmartPhone {
    private String company;
    private String os;

    public SmartPhone(String company, String os) {
        this.company = company;
        this.os = os;
    }

    @Override
    public String toString() {
        return company + &quot;, &quot; + os;
    }
}


public class SmartPhoneExample {

    public static void main(String[] args) {
        SmartPhone myPhone = new SmartPhone(&quot;구글&quot;, &quot;안드로이드&quot;);

        // 재정의된 toString() 호출
        String strObj = myPhone.toString();
        System.out.println(strObj);

        /*
         * 재정의된 toString()을
         * 호출하고 리턴값을 받아 출력
         */
        System.out.println(myPhone);

    }

}

💻 결과
구글, 안드로이드
구글, 안드로이드</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] Object 클래스_hashCode() 메소드]]></title>
            <link>https://velog.io/@geumyi_/Java-Object-%ED%81%B4%EB%9E%98%EC%8A%A4hashCode-%EB%A9%94%EC%86%8C%EB%93%9C</link>
            <guid>https://velog.io/@geumyi_/Java-Object-%ED%81%B4%EB%9E%98%EC%8A%A4hashCode-%EB%A9%94%EC%86%8C%EB%93%9C</guid>
            <pubDate>Wed, 27 Mar 2024 02:03:28 GMT</pubDate>
            <description><![CDATA[<h3 id="✔️-객체-해시코드hashcode">✔️ 객체 해시코드(hashCode())</h3>
<p>: 객체를 식별하는 하나의 정수값
: Object 클래스의 hashCode() 메소드는
객체의 메모리 번지를 이용해서 해시코드를 만들어
리턴하기 때문에 객체마다 다른 값을 가지고 있음</p>
<p>: 논리적 동등 비교 시 hashCoe()를 오버라이딩할 필요가 있음
컬렉션 프레임워크에서 HastSet, HashMap, Hashtable은
다음과 같은 방법으로 두 객체가 동등한지 비교함</p>
<p>
<img src="https://velog.velcdn.com/images/geumyi_/post/be85cba9-bf08-489c-9554-6c875a3765a7/image.png">  
</p>

<p>1) hashCode() 메소드를 실행해서 리턴된 해시코드 값이 같은지 확인
2) 해시코드 값이 다르면 다른 객체로 판단하고,
해시코드 값이 같으면 equals() 메소드로 다시 비교함</p>
<p>그렇기 때문에 hashCode() 메소드가 true가 나와도
equals()의 리턴값이 다르면 다른 객체가 됨</p>
<pre><code>ex)
Key 클래스는 equals() 메소드를 재정의해서
number 필드값이 같으면 true를 리턴

그러나 hashCode() 메소드는 재정의하지 않았기 때문에
Object의 hashCode() 메소드가 사용됨</code></pre><pre><code class="language-java">import java.util.HashMap;


class Key{
    public int number;

    public Key(int number) {
        this.number = number;
    }

    @Override
    public boolean equals(Object obj) {
        if(obj instanceof Key) {
            Key compareKey = (Key) obj;
            if(this.number == compareKey.number) {
                return true;
            }
        }

        return false;
    }

}

public class KeyExample {
    public static void main(String[] args) {
        //Key 객체를 식별키로 사용해서 String 값을 저장하는 HashMap 객체 생성
        HashMap&lt;Key, String&gt; hashMap = new HashMap&lt;Key,String&gt;();

        //식별키 new Key(1)로 &quot;홍길동&quot;을 저장함
        hashMap.put(new Key(1), &quot;홍길동&quot;);

        //식별키 new Key(1)로 &quot;홍길동&quot;을 읽어옴
        String value = hashMap.get(new Key(1));
        System.out.println(value);
    }
}

💻 결과
null

/*
 * 이런 경우 HashMap의 식별키로 Key 객체를 사용하면
 * 저장된 값을 찾아오지 못함
 * 
 * 왜냐하면 number 필드값이 같더라도 hashCode() 메소드에서
 * 리턴하는 해시코드가 다르므로 다른 식별키로 인식하기 때문
 * 
 * new Key(1) 객체로 &quot;홍길동&quot;을 저장하고,
 * 다시 new Key(1) 객체로 저장된 &quot;홍길동&quot;을 읽으려고 했지만
 * 결과는 null 나옴
 */</code></pre>
<p>→ 의도한 대로 &quot;홍길동&quot;을 읽으려면
다음과 같이 재정의한 hashCode()의
리턴값을 number 필드값으로 했기 때문에
저장할 때의 new Key(1)과
읽을 때의 new Key(1)로 같은 해시코드가 리턴됨</p>
<pre><code class="language-java">class Key{
    public int number;

    public Key(int number) {
        this.number = number;
    }

    @Override
    public boolean equals(Object obj) {
        if(obj instanceof Key) {
            Key compareKey = (Key) obj;
            if(this.number == compareKey.number) {
                return true;
            }
        }

        return false;
    }

    @Override
    public int hashCode() {
        return number;
    }

}

public class KeyExample {
    public static void main(String[] args) {
        //Key 객체를 식별키로 사용해서 String 값을 저장하는 HashMap 객체 생성
        HashMap&lt;Key, String&gt; hashMap = new HashMap&lt;Key,String&gt;();

        //식별키 new Key(1)로 &quot;홍길동&quot;을 저장함
        hashMap.put(new Key(1), &quot;홍길동&quot;);

        //식별키 new Key(1)로 &quot;홍길동&quot;을 읽어옴
        String value = hashMap.get(new Key(1));
        System.out.println(value);
    }
}

💻 결과
홍길동</code></pre>
<p>→ 저장할 떄의 new Key(1)과 
읽을 때의 new Key(1)은 사실 서로 다른 객체이지만
HashMap은 hashCode()의 리턴값이 같고,
equals()의 리턴값이 true가 되기 때문에
동등한 객체로 평가함</p>
<p>즉, 같은 식별키로 인식한다는 뜻</p>
<p>결론적으로 말해서 객체의 동등 비교를 위해서는
Object의 equals() 메소드만 재정의하지 말고
hashCode() 메소드도 재정의해서
논리적으로 동등한 객체일 경우
동일한 해시코드가 리턴되도록 해야함</p>
<pre><code>ex) id 필드값이 같을 경우
같은 해시코드를 리턴하도록 하기 위해
String의 hashCode() 메소드를 리턴값을 활용함

String의 hashCode()는 같은 문자열일 경우
동일한 해시코드를 리턴함</code></pre><pre><code class="language-java">class Member {
    public String id;

    public Member(String id) {
        this.id = id;
    }

    @Override
    public boolean equals(Object obj) {
        // 매개값이 Member 타입인지 확인
        if(obj instanceof Member) {
            //Memeber 타입으로 강제 타입 변환하고
            //id필드값이 동일하니 검사한 후,
            //동일하다면 true를 리턴
            Member member = (Member) obj;
            if(id.equals(member.id)) {
                return true;
            }
        }
        //매개값이 Member 타입이 아니거나
        //id필드값이 다른 경우 false를 리턴
        return false;
    }

    //id가 동일한 문자열인 경우
    //같은 해시 코드를 리턴
    @Override
    public int hashCode() {
        return id.hashCode();
    }
}


public class MemberExample {
    public static void main(String[] args) {
        Member obj1 = new Member(&quot;blue&quot;);
        Member obj2 = new Member(&quot;blue&quot;);
        Member obj3 = new Member(&quot;red&quot;);

        //매개값이 Member타입이고
        //id필드값도 동일하므로 true
        if(obj1.equals(obj2)) {
            System.out.println(&quot;obj1과 obj2는 동등합니다.&quot;);
        } else {
            System.out.println(&quot;obj1과 obj2는 동등하지 않습니다.&quot;);
        }

        //매개값이 Member타입이지만
        //id필드값이 다르므로 false
        if(obj1.equals(obj3)) {
            System.out.println(&quot;obj1과 obj3은 동등합니다.&quot;);
        } else {
            System.out.println(&quot;obj1과 obj3은 동등하지 않습니다.&quot;);
        }
    }
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] Object 클래스_equals() 메소드]]></title>
            <link>https://velog.io/@geumyi_/Java-Object-%ED%81%B4%EB%9E%98%EC%8A%A4equals-%EB%A9%94%EC%86%8C%EB%93%9C</link>
            <guid>https://velog.io/@geumyi_/Java-Object-%ED%81%B4%EB%9E%98%EC%8A%A4equals-%EB%A9%94%EC%86%8C%EB%93%9C</guid>
            <pubDate>Wed, 27 Mar 2024 02:02:01 GMT</pubDate>
            <description><![CDATA[<h3 id="✔️-객체-비교equals">✔️ 객체 비교(equals())</h3>
<blockquote>
</blockquote>
<p>public boolean equals(Object obj) { ··· }</p>
<p>: equals() 메소드의 매개 타입은 Object인데,
이것은 모든 객체가 매개값으로 대입될 수 있음을 말함
→ 왜냐하면 모든 객체는 Object 타입으로 자동 타입 변환될 수 있기 때문</p>
<p>: Object 클래스의 equals() 메소드는 비교 연산자인 ==과 동일한 결과를 리턴함</p>
<pre><code>Object obj1 = new Object();
Object obj2 = new Object();

//obj1(기준 객체).equals(obj2(비교 객체));
boolean result = obj1.equals(obj2);

// equals 와 결과가 동일함
boolean result = (obj1 == obj2)</code></pre><p>: 동등 비교할 때 equals() 메소드를 흔히 사용함
두 객체를 비교해서 논리적으로 동등하면 true를 리턴,
그렇지 않으면 false를 리턴함</p>
<p>: 논리적으로 동등하다는 것은 같은 객체이건 다른 객체이건
상괎없이 객체가 저장하고 있는 데이터가 동일함을 뜻함</p>
<pre><code>ex)
String 객체의 equals() 메소드는 String 객체의 번지를 비교하는 것이 아니고,
문자열이 동일한지 조사해서 같다면 true를 리턴하고,
그렇지 않다면 false를 리턴함

이것이 가능한 이유는
String 클래스가 Object의 equals() 메소드를 재정의(오버라이딩)해서
번지 비교가 아닌 문자열 비교로 변경했기 때문

일반적으로 Object의 equals() 메소드는
직접 사용되지 않고 하위 클래스에서 재정의하여
논리적으로 동등 비교할 때 이용됨</code></pre><p>: equals() 메소드를 재정의할 때에는
매개값(비교 객체)이 기준 객체와 동일한 타입의 객체인지 먼저 확인</p>
<p>Object 타입의 매개 변수는 모든 객체가 매개값으로 제공될 수 있기 때문에
instanceof 연산자로 기준 객체와 동일한 타입인지 제일 먼저 확인해야 함</p>
<pre><code class="language-java">class Member {
    public String id;

    public Member(String id) {
        this.id = id;
    }

    @Override
    public boolean equals(Object obj) {
        // 매개값이 Member 타입인지 확인
        if(obj instanceof Member) {
            //Memeber 타입으로 강제 타입 변환하고
            //id필드값이 동일하니 검사한 후,
            //동일하다면 true를 리턴
            Member member = (Member) obj;
            if(id.equals(member.id)) {
                return true;
            }
        }
        //매개값이 Member 타입이 아니거나
        //id필드값이 다른 경우 false를 리턴
        return false;
    }
}

public class MemberExample {
    public static void main(String[] args) {
        Member obj1 = new Member(&quot;blue&quot;);
        Member obj2 = new Member(&quot;blue&quot;);
        Member obj3 = new Member(&quot;red&quot;);

        //매개값이 Member타입이고
        //id필드값도 동일하므로 true
        if(obj1.equals(obj2)) {
            System.out.println(&quot;obj1과 obj2는 동등합니다.&quot;);
        } else {
            System.out.println(&quot;obj1과 obj2는 동등하지 않습니다.&quot;);
        }

        //매개값이 Member타입이지만
        //id필드값이 다르므로 false
        if(obj1.equals(obj3)) {
            System.out.println(&quot;obj1과 obj3은 동등합니다.&quot;);
        } else {
            System.out.println(&quot;obj1과 obj3은 동등하지 않습니다.&quot;);
        }
    }
}

💻 결과
obj1과 obj2는 동등합니다.
obj1과 obj3은 동등하지 않습니다.</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] java.lang 패키지]]></title>
            <link>https://velog.io/@geumyi_/Java-java.lang-%ED%8C%A8%ED%82%A4%EC%A7%80</link>
            <guid>https://velog.io/@geumyi_/Java-java.lang-%ED%8C%A8%ED%82%A4%EC%A7%80</guid>
            <pubDate>Wed, 27 Mar 2024 02:00:46 GMT</pubDate>
            <description><![CDATA[<h3 id="✔️-javalang-패키지">✔️ java.lang 패키지</h3>
<p>: 자바 프로그램의 기본적인 클래스를 담고 있는 패키지
: java.lang 패키지에 있는 클래스와 인터페이스는
 import 없이 사용할 수 있음</p>
<pre><code>ex)
String, System 클래스도
java.lnag 패키지에 포함되어 있기 때문에
import하지 않고 사용함</code></pre><p><strong>• java.lang 패키지에 속하는 주요 클래스 와 간략한 용도</strong></p>
<p>
<img src="https://velog.velcdn.com/images/geumyi_/post/74f74b47-3187-4135-be16-fdf2184af657/image.png">  
</p>

<hr>
<h3 id="✔️-자바-api-도큐먼트">✔️ 자바 API 도큐먼트</h3>
<p>- API(Application Programming Interface)
: 라이브러리(library)라고 부르기도함
: 프로그램 개발에 자주 사용되는 클래스 및 인터페이스 모음
: String 클래스와 System 클래드소 모두 API에 속하는 클래스임</p>
<p>- 이클립스에서 API 도큐먼트 보는 방법</p>
<p>1) 코드 편집 뷰에서 String 클래스를 마우스로 선택
2) F1키를 누르면 자동으로 API 도큐먼트를 보여주는 Help뷰가 나타남
3) Help뷰에서 Javadoc for &#39;java.lang.String&#39; 링크를 클릭
4) Class String 페이지로 이동</p>
<hr>
<h3 id="✔️-api-도큐먼트에서-클래스-페이지-읽는-방법">✔️ API 도큐먼트에서 클래스 페이지 읽는 방법</h3>
<p>
<img src="https://velog.velcdn.com/images/geumyi_/post/8d64be37-1cb5-4734-af97-bead754055cf/image.png
">  
</p>

<p>1) 최상단의 SUMMARY: NESTED | FIELD | CONSTR | METHOD
에서 SUMMARY는 클래스 내에 선언된 멤버가 무엇이 있는지 알려줌</p>
<p>링크가 있다면 해당 멤버가 있다는 뜻
링크가 없으면 해당 멤버가 없다는 뜻</p>
<p>String 클래스는 NESTED에 링크가 없으므로
중첩 클래스나 중첩 인터페이스가 없다는 의미</p>
<p>반면에 FIELD, CONSTR, METHOD는 모두 링크가 있으므로
public 또는 protected로 선언된 필드, 생성자, 메소드는 있다는 뜻</p>
<p>2) 
① 클래스의 선언부
: 클래스가 final 또는 abstract 키워드가 있는지 확인함
String 클래스는 final 키워드가 있으므로 부모 클래스로는 사용할 수 없음</p>
<p>그리고 extends 뒤에 언급된 부모 클래스를 보면
String 클래스는 Object를 상속 받고 있음
상속 관계에 있는 모든 클래스를 보려면 ②의 상속 계층도를 보면 됨</p>
<p>마지막으로 implemets 키워드 뒤에 언급된 인터페이스가 무엇인지 보면
String 클래스는 Serializable, Comparable<String>, CharSequence와 같이
3개의 인터페이스를 구현하고 있음</p>
<p>3) 클래스에 선언된 필드 목록
SUMMARY: NESTED | FIELD | CONSTR | METHOD</p>
<p>3-1) FIELD 링크</p>
<p>
<img src="https://velog.velcdn.com/images/geumyi_/post/9e20be31-3cfd-4e8f-9c28-18403b0bcb09/image.png">  
</p>

<p>Modifier and Type 컬럼에는 static 또는 protected여부와 타입이 표시됨
Field와 Description 컬럼에는 필드 이름이 굵은 글씨고 표시되어 있고,
아래에는 필드에 대한 간단한 설명이 있음</p>
<p>필드 이름을 클릭하면 상세 설명 페이지로 이동함</p>
<p>3-2) CONSTR 링크</p>
<p>
<img src="https://velog.velcdn.com/images/geumyi_/post/eacff03c-dd64-4e5f-906f-aab3cd088ea6/image.png">  
</p>

<p>CONSTR 링크를 클릭하면 생성자 목록으로 이동함</p>
<p>String 클래스에는 매개 변수의 타입 또는 개수를 달리해서
10개가 넘는 생성자들이 오버로딩되어 있음</p>
<p>모두 new 연산자로 호출해서 String 객체를 생성할 수 있음
굵제 표시된 것이 생성자이름이고, 옆에 간단한 설명이 있음
생성자 이름을 클릭하면 상세 설명 페이지로 이동함</p>
<p>3-3) METHOD 링크</p>
<p>
<img src="https://velog.velcdn.com/images/geumyi_/post/d43a849a-ad74-49ab-a7da-779355f29632/image.png">  
</p>

<p>[All Methods] 탭은 전체 메소드 목록을 보여줌
[Static Methods] 탭은 정적 메소드 목록을 보여줌
[Instance Methods] 탭은 인스턴스 메소드 목록을 보여줌</p>
<p>Modifier and Type 컬럼에는
static 또는 protected여부와 리턴 타입이 표시됨
static이 없다면 인스턴스 메소드라는 뜻이고,
protected가 없다면 기본이 public임</p>
<p>Method와 Description 컬럼에는
메로드 이름과 굵은 글씨로 표시되어 있고,
옆에는 메소드에 대해 간단한 설명이 있음</p>
<p>메소드 이름을 클릭하면 상세 설명 페이지로 이동함</p>
<hr>
<p>✔️ Object 클래스</p>
<p>: 클래스를 선언할 때 extends 키워드로 다른 클래스를
상속하지 않으면 암시적으로 java.lang.Object 클래스를 상속하게 됨</p>
<p>: 자바의 모든 클래스는 Object 클래스의
자식이거나 자손 클래스임</p>
<p>: Object는 자바의 최상위 부모 클래스에 해당함</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java]예외 처리]]></title>
            <link>https://velog.io/@geumyi_/Java%EC%98%88%EC%99%B8-%EC%B2%98%EB%A6%AC</link>
            <guid>https://velog.io/@geumyi_/Java%EC%98%88%EC%99%B8-%EC%B2%98%EB%A6%AC</guid>
            <pubDate>Mon, 25 Mar 2024 07:01:20 GMT</pubDate>
            <description><![CDATA[<h3 id="✔️-예외-처리-코드">✔️ 예외 처리 코드</h3>
<p><strong>- try-catch-finally 블록</strong>
: 생성자 내부와 메소드 내부에서 작성되어
&amp;nbsp&amp;nbsp 일반 예외와 실행 예외가 발생할 경우
&amp;nbsp&amp;nbsp 예외 처리를 할 수 있도록 해줌</p>
<pre><code>try {
    예외 발생가능 코드
} catch(예외클래스 e) {
    예외 처리
} finally {
    /*생략 가능*/
    //예외 발생 여부와 상관없이
    //항상 실행할 내용이 있을 경우에만
    //finally 블록을 작성하면 됨
    항상 실행;
}</code></pre><p>
<img src="https://velog.velcdn.com/images/geumyi_/post/c6a6bfbf-1489-41d9-ad6f-0f4099525cd9/image.png" width="80%">  
</p>

<p>: Class.forName() 메소드는 매개값으로 주어진
&amp;nbsp&amp;nbsp 클래스가 존재하면 Class객체를 리턴하지만,
&amp;nbsp&amp;nbsp 존재하지 않으면 ClassNotFoundException을 발생시킴</p>
<pre><code class="language-java">👩‍💻 일반 예외 처리
public class TryCatchFinallyExample {
    public static void main(String[] args) {

        try {
            Class clazz = Class.forName(&quot;java.lang.String2&quot;);
        } catch(ClassNotFoundException e){
            System.out.println(&quot;클래스가 존재하지 않습니다.&quot;);
        }
    }
}

💻 결과
클래스가 존재하지 않습니다.

→ java.lang.String2 클래스가 존재하지 않기 때문에
   예외가 발생함</code></pre>
<p>→ ArrayIndexOutOfBoundsException이나 NumberFormatException과
&amp;nbsp&amp;nbsp 같은 실행 예외는 컴파일러가 예외 처리 코드를 체크하지 않기 때문에
&amp;nbsp&amp;nbsp 이클립스에서도 빨간 밑줄이 생기지 않음</p>
<pre><code class="language-java">👩‍💻 실행 예외 처리
public class TryCatchFinallyRuntimeExceptionExample {

    public static void main(String[] args) {
        String data1 = null;
        String data2 = null;
        try {
            data1 = args[0];
            data2 = args[1];
        } catch (ArrayIndexOutOfBoundsException e) {
            System.out.println(&quot;실행 매개값의 수가 부족합니다.&quot;);
            return;
        }

        try {
            int value1 = Integer.parseInt(data1);
            int value2 = Integer.parseInt(data2);
            int result = value1 + value2;
            System.out.println(data1 + &quot;+&quot; + data2
                    + &quot;=&quot; + result);
        } catch(NumberFormatException e) {
            System.out.println(&quot;숫자로 변환할 수 없습니다.&quot;);
        } finally {
            System.out.println(&quot;다시 실행하세요.&quot;);
        }
    }

}

💻 결과
실행 매개값의 수가 부족합니다.</code></pre>
<hr>
<h3 id="✔️-예외-종류에-따른-처리-코드">✔️ 예외 종류에 따른 처리 코드</h3>
<p><strong>- 다중 catch</strong>
: try 블록 내부에는 다양한 예외가 발생할 수 있음
&amp;nbsp&amp;nbsp 이럴경우, 다중 catch블록을 작성해야함</p>
<pre><code>try {

} catch(예외클래스 e) {
    예외처리1
} catch(예외클래스 e) {
    예외처리2
}</code></pre><p>: catch 블록이 여러 개라 할지라도 
&amp;nbsp&amp;nbsp 단 하나의 catch블록만 실행됨
→ try블록에서 동시 다발적으로 예외가 발생하지 않고,
&amp;nbsp&amp;nbsp 하나의 예외가 발생하면 즉시 실행을 멈추고
&amp;nbsp&amp;nbsp 해당 catch블록으로 이동하기 때문</p>
<pre><code class="language-java">👩‍💻 다중 catch
public class CatchByExceptionKindExample {

    public static void main(String[] args) {
        try {
            String data1 = args[0];
            String data2 = args[1];
            int value1 = Integer.parseInt(data1);
            int value2 = Integer.parseInt(data2);
            int result = value1 + value2;
            System.out.println(data1 + &quot;+&quot; + data2 + &quot;=&quot; + result);
        } catch (ArrayIndexOutOfBoundsException e) {
            System.out.println(&quot;실행 매개값의 수가 부족합니다.&quot;);
        } catch (NumberFormatException e) {
            System.out.println(&quot;숫자로 변환할 수 없습니다.&quot;);
        } finally {
            System.out.println(&quot;다시 실행하세요.&quot;);
        }
    }

}
💻 결과
실행 매개값의 수가 부족합니다.
다시 실행하세요.</code></pre>
<p><strong>- catch 순서</strong>
: 다중 catch 블록을 작성할 떄는
&amp;nbsp&amp;nbsp 상위 예외 클래스가 하위 예외 클래스보다 아래 있어야함</p>
<pre><code>- 잘못된 코딩 예
try {
    ArrayIndexOutOfBoundsException 발생

    Number FormatException 발생
} catch(Exception e) {
    에외 처리1
} catch(ArrayIndexOutOfBoundsException e){
    예외 처리2
}

→ ArrayIndexOutOfBoundsException과
   NumberFormatException은 모두 Exception을
  상속값을 받기 때문에 첫번째 catch블록만 선택되어 실행됨

→ 두 번째 catch 블록은 어떤 경우에라도 실행되지 않음

- 올바른 코딩 예

try {
    ArrayIndexOutOfBoundsException 발생

    Number FormatException 발생    
} catch(ArrayIndexOutOfBoundsException e) {
    예외 처리1
} catch(Exception e) {
    예외 처리2
}

→ try 블록에서 ArrayIndexOutOfBoundsException이 발생하면
  첫 번째 catch블록을 실행하고, 그 밖의 다른 예외가 발생하면
  두 번째 catch블록을 실행함</code></pre><pre><code class="language-java">👩‍💻 catch 블록의 순서
public class CatchOrderExample {
    public static void main(String[] args) {
        try {
            String data1 = args[0];
            String data2 = args[1];
            int value1 = Integer.parseInt(data1);
            int value2 = Integer.parseInt(data2);
            int result = value1 + value2;
            System.out.println(data1 + &quot;+&quot; + data2 +
                    &quot;=&quot; + result);
        } catch(ArrayIndexOutOfBoundsException e) {
            System.out.println(&quot;실행 매개값의 수가 부족합니다.&quot;);
        } catch(Exception e) {
            System.out.println(&quot;실행에 문제가 있습니다.&quot;);
        } finally {
            System.out.println(&quot;다시 실행하세요.&quot;);
        }
    }
}

💻 결과
실행 매개값의 수가 부족합니다.
다시 실행하세요.</code></pre>
<hr>
<h3 id="✔️-예외-떠넘기기">✔️ 예외 떠넘기기</h3>
<p>: 메소드를 호출한 곳으로 예외를 떠넘길 수도 있음
: 이떄 사용하는 키워드가 throws임</p>
<p><strong>- throws 키워드</strong></p>
<blockquote>
</blockquote>
<p>리턴타입 메소드이름(매개변수, ···) throws 예외클래스1, 예외클래스2, ··· {
}</p>
<p>: 메소드 선언부 끝에 작성되어 메소드에서 처리하지 않은
&amp;nbsp&amp;nbsp 예외를 호출한 곳으로 떠넘기는 역할
: throws 키워드 뒤에는 떠넘길 예외 클래스를
&amp;nbsp&amp;nbsp 쉼표로 구분해서 나열해주면 됨</p>
<blockquote>
</blockquote>
<p>리턴타입 메소드이름(매개변수, ···) throws Exception {
}</p>
<p>: throws Exception만으로도 모든 예외를 간단히
&amp;nbsp&amp;nbsp 떠넘길 수도 있음</p>
<p>: thorws 키워드가 붙어 있는 메소드는
&amp;nbsp&amp;nbsp 반드시 try 블록 내에서 호출되어야 함 그리고
&amp;nbsp&amp;nbsp catch 블록에서 떠넘겨 받은 예외를 처리해야함</p>
<pre><code>ex)
throws 키워드가 있는 method2()를
method1()에서 호출하는 방법

public void method1() {
    try {
        method2();
    } catch(ClassNotFoundException e) {
        //예외 처리 코드
        System.out.println(&quot;클래스가 존재하지 않습니다.&quot;);
    }
}

public void method2() throws ClassNotFoundException {
    Class clazz = Class.forName(&quot;java.lang.String2&quot;);
}

- method1()에서도 try-catch 블록으로 예외를 처리하지 않고
  다음과 같이 throws 키워드로 다시 예외를 떠넘길 수 있음
- 그러면 method1()을 호출하는 곳에서 
  try-catch블록을 사용해서 예외를 처리해야함

public void method1() throws ClassNotFoundException {
    method2();
}</code></pre><pre><code class="language-java">👩‍💻 예외 처리 떠넘기기
버전1)
public class ThrowsExample {

    public static void main(String[] args) {
        try {
            findClass();
        } catch(ClassNotFoundException e) {
            System.out.println(&quot;클래스가 존재하지 않습니다.&quot;);
        }
    }

    public static void findClass() throws ClassNotFoundException {
        Class clazz = Class.forName(&quot;java.lang.String2&quot;);
    }

}

💻 결과
클래스가 존재하지 않습니다.

버전2)
public static void main(String[] args) throws ClassNotFoundException {
    findClass();
}

→ main()메소드에서도 throws 키워드를 사용해서 예외를 떠넘길 수 있음
결국 JVM이 최족적으로 예외 처리를 하게 됨
JVM은 예외의 내용을 콘솔에 출력하는 것으로 예외 처리함</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java]익명 객체]]></title>
            <link>https://velog.io/@geumyi_/Java%EC%9D%B5%EB%AA%85-%EA%B0%9D%EC%B2%B4</link>
            <guid>https://velog.io/@geumyi_/Java%EC%9D%B5%EB%AA%85-%EA%B0%9D%EC%B2%B4</guid>
            <pubDate>Fri, 22 Mar 2024 04:26:46 GMT</pubDate>
            <description><![CDATA[<h3 id="✔️-익명-객체">✔️ 익명 객체</h3>
<blockquote>
<p>일반적인 경우
<strong>[상속]</strong>
class 클래스이름1 extends 부모클래스 { ··· }
부모클래스 변수 = new 클래스이름1();
→ 부모 클래스 변수는 클래스1의 객체를 참조<br><br>
<strong>[구현]</strong> 
class 클래스이름2 implements 인터페이스 { ··· }
인터페이스 변수 = new 클래스이름2(); 
→ 인터페이스 변수는 클래스이름2의 객체를 참조 </p>
</blockquote>
<blockquote>
<p>익명 객체 생성
<strong>[상속]</strong>
부모클래스 변수 = new 부모클래스()  { ··· }; 
→ 부모 클래스 변수는 이름이 없는 자식 객체를 참조
<strong>[구현]</strong>
부모클래스 변수 = new 부모클래스()  { ··· };
→ 인터페이스 변수는 이름이 없는 구현객체를 참조</p>
</blockquote>
<p>: 클래스를 선언할 때 일반적으로 클래스 이름과
&amp;nbsp&amp;nbsp 동일한 소스 파일을 생성하고 클래스 선언함
: 한번 선언 선언해놓고 여러 곳에서 객체를 만들어 사용하고 싶을때
&amp;nbsp&amp;nbsp 간단히 클래스 이름으로 생성자를 호출할 수 있기 때문
: 클래스 이름이 없는 객체도 있음 → <strong>익명 객체</strong>
: 어떤 클래스를 상속하거나 인터페이스를 구현해야만 함</p>
<hr>
<h3 id="✔️-익명-자식-객체-생성">✔️ 익명 자식 객체 생성</h3>
<p>• <strong>부모 타입의 필드 또는 변수를 선언</strong>하고
&amp;nbsp&amp;nbsp <strong>자식 객체를 초기값으로 대입</strong>하는 경우</p>
<p>1) 부모 클래스를 상속해서 자식 클래스를 선언함
2) new 연산자를 이용해서 자식 객체를 생성한 후
&amp;nbsp&amp;nbsp 부모 타입의 필드 또는 변수에 대입하는 것</p>
<pre><code>/** 자식 클래스 선언 **/
class Child extends Parent { }  

class A { 
    /** 필드에 자식 객체를 대입 **/
    Parent field = new Childe();

    void method() {
        /** 로컬 변수에 자식 객체를 대입 **/
        Parent localVar = new Child();
    }
}</code></pre><p><strong>• 자식 클래스를 명시적으로 선언하는 이유</strong>
→ 어디서건 이미 선언된 자식 클래스로 간단히 
&amp;nbsp&amp;nbsp 객체를 생성해서 사용할 수 있기 때문
→ 이것을 재사용성이 높다고 말함</p>
<p><strong>• 익명 자식 객체를 생성해야 하는 경우</strong>
→ 자식 클래스가 재사용 되지 않고
&amp;nbsp&amp;nbsp 오로지 특정 위치에서 사용할 경우라면
&amp;nbsp&amp;nbsp 자식 클래스를 명시적으로 선언해야할 때
&amp;nbsp&amp;nbsp 사용 함</p>
<blockquote>
</blockquote>
<p><strong>[익명 자식 객체를 생성하는 방법]</strong>
부모클래스 [필드|변수] = new 부모클래스(매개값, ···) {
&amp;nbsp&amp;nbsp //필드
&amp;nbsp&amp;nbsp //메소드
};</p>
<p>: &#39;부모 클래스(매개값, ···) {···}&#39;은 
&amp;nbsp&amp;nbsp 부모 클래스를 상속해서 중괄호 {}와 같이 
&amp;nbsp&amp;nbsp 자식 클래스를 선언하라는 의미
: new연산자는 이렇게 선언된
&amp;nbsp&amp;nbsp 자식 클래스를 객체로 생성함
: &#39;부모 클래스(매개값, ···) {···}&#39;은 부모 생성자를 호출하는 코드로
&amp;nbsp&amp;nbsp 매개값은 부모 생성자의 매개 변수에 맞게 입력하면 됨
: 중괄호 { } 내부에는 필드나 메소드를 선언하고나
&amp;nbsp&amp;nbsp 부모 클래스의 메소드를 재정의(오버라이딩)하는 내용을 작성
: 일반 클래스와의 차이점은 생성자를 선언할 수 없음</p>
<pre><code>- 필드를 선언할 때 초기값으로 익명 자식 객체를 생성해서 대입하는 예
ex)
class A {
    // A클래스의 필드 선언
    Parent field = new Parent() {
        int childField;
        void childMethod() { }
        // Parent의 메소드를 재정의
        @Override
        void parentMethod() { }
    };
}

- 메소드 내에서 로컬 변수를 선언할 때 초기값으로
  익명 자식 객체를 생성해서 대입하는 예
ex)
class A {
    void method() {
        // 로컬 변수 선언
        Parent localVar = new Parent() {
            int childField;
            void childMethod() { }
            // Parent의 메소드를 재정의
            @Override
            void parentMethod() { }
        };
    }
}

- 메소드의 매개 변수가 부모 타입일 경우
  메소드를 호출하는 코드에서 익명 자식 객체를 
  생성해서 매개값으로 대입하는 예
class A {
    void method1(Parent parent) { }

    void method2() {
        //method1()메소드를 호출
        method1(
            //method1()의 매개값으로
              익명 자식 객체를 대입
            new Parent() {
                int childField;
                void childMethod()() { }
                @Override
                void parentMethod() { }
            }
        };
    }
}</code></pre><p>- 익명 자식 객체에 새롭게 정의된 필드와 메소드는
&amp;nbsp&amp;nbsp 익명 자식 객체 내부에서만 사용됨
&amp;nbsp&amp;nbsp  외부에서는 접근할 수 없음
→ 왜냐하면 익명 자식 객체는 부모 타입 변수에 대입되므로
&amp;nbsp&amp;nbsp 부모 타입에 선언된것만 사용할 수 있기 때문</p>
<pre><code>ex)
childField 필드와 childMethod()메소드는
parentMethod()메소드내에서 사용이 가능하나,
A 클래스의 필드인 field로는 접근할 수 없음

class A {
    Parent field = nw Parent() {
        int childField;
        void childMethod() { }
        @Override
        void parentMethod() {
            childField = 3;
            childMethod();
        }
    };

    void method() {
        field,childField = 3;
        field.childMethod();
        field.parentMethod();
    }
}</code></pre><pre><code class="language-java">//부모클래스
class Person {
    void wake() {
        System.out.println(&quot;7시에 일어납니다.&quot;);
    }
}

//익명 자식 객체 생성
class Anonymous {
    //필드 초기값으로 대입
    //필드값으로 익명 객체 대입
    Person field = new Person() {
        void work() {
            System.out.println(&quot;출근합니다.&quot;);
        }

        @Override
        void wake() {
            System.out.println(&quot;6시에 일어납니다.&quot;);
            work();
        }
    };

    void method1() {
        //로컬 변수값으로 대입
        //로컬 변수값으로 익명 객체 대입
        Person localVar = new Person() {
            void walk() {
                System.out.println(&quot;산책합니다.&quot;);
            }
            @Override
            void wake() {
                System.out.println(&quot;7시에 일어납니다.&quot;);
                walk();
            }
        };

        //로컬 변수 사용
        localVar.wake();
    }

    void method2(Person person) {
        person.wake();
    }
}

//익명 자식 객체 생성
public class AnonymousExample {
    public static void main(String[] args) {
        Anonymous anony = new Anonymous();
        //익명 객체 필드 사용
        anony.field.wake();
        //익명 객체 로컬 변수 사용
        anony.method1();
        //익명 객체 매개값 사용
        anony.method2(
                //매개값으로 익명 객체 대입
                new Person() {
                    void study() {
                        System.out.println(&quot;공부합니다.&quot;);
                    }
                    @Override
                    void wake() {
                        System.out.println(&quot;8시에 일어납니다.&quot;);
                        study();
                    }
                }
        );
    }
}

💻 결과
6시에 일어납니다.
출근합니다.
7시에 일어납니다.
산책합니다.
8시에 일어납니다.
공부합니다.</code></pre>
<hr>
<h3 id="✔️-익명-구현-객체-생성">✔️ 익명 구현 객체 생성</h3>
<p>- 일반적으로 인터페이스 타입의 필드 또는 변수를 선언하고,
&amp;nbsp&amp;nbsp 구현 객체를 초기값으로 대입하는 경우를 생각해보면</p>
<p>1) 구현 클래스를 선언함
2) new 연산자를 이용해서 구현 객체를 생성
3) 인터페이스 타입의 필드 또는 로컬 변수에 대입</p>
<pre><code>class TV implements RemoteControl { }

class A {
    //필드에 구현 객체를 대입
    RemoteControl field = new TV(); 
    void method() {
        //로컬 변수에 구현 객체를 대입
        RemoteControl localVar = new TV();
       }
}</code></pre><p>• 자식 클래스를 명시적으로 선언하는 이유
→ 어디서건 이미 선언된 구현 클래스로
&amp;nbsp&amp;nbsp 간단히 객체를 생성해서 사용할 수 있기 때문
→ 이것을 재사용성이 높다고 말함</p>
<p>• 익명 구현 객체를 생성해야 하는 경우
→ 구현 클래스가 재사용되지 않고,
&amp;nbsp&amp;nbsp 오로지 특정 위치에서 사용할 경우라면
&amp;nbsp&amp;nbsp 구현 클래스를 명시적으로 선언하지 않고
&amp;nbsp&amp;nbsp 익명 구현 객체를 생성해서 사용하는 것이 좋음</p>
<blockquote>
</blockquote>
<p><strong>[익명 자식 객체를 생성하는 방법]</strong>
인터페이스 [필드|변수] = new 인터페이스() {
&amp;nbsp&amp;nbsp //인터페이스에 선언된 추상 메소드의 실체 메소드 선언
&amp;nbsp&amp;nbsp //필드
&amp;nbsp&amp;nbsp //메소드
};</p>
<p>: &#39;인터페이스() { ··· }&#39;는 인터페이스를 구현해서
&amp;nbsp&amp;nbsp 중괄호 {}와 같이 클래스를 선언하라는 뜻
: new 연산자는 이렇게 선언된 구현 클래스를
&amp;nbsp&amp;nbsp 객체로 생성함
: 중괄호 {}에는 인터페이스에 선언된 모든 추상 메소드의
&amp;nbsp&amp;nbsp 실체 메소드를 작성(재정의)해야 함
&amp;nbsp&amp;nbsp 그렇지 않으면 컴파일 에러가 발생
: 필드와 메소드를 선언할 수 있지만,
&amp;nbsp&amp;nbsp 실체 메소드에서만 사용이 가능하고
&amp;nbsp&amp;nbsp 외부에서는 사용할 수 없음</p>
<pre><code>- 필드를 선언할 때 초기값으로 익명 구현 객체를 생성해서 대입하는 예
ex)
class A {
    //클래스 A의 필드 선언
    RemoteControl field  = new RemoteControl() {
        //RemoteControl 인터페이스의
          //추상 메소드에 대한 실체 메소드
        @Override
        void turnOn() { }
    };
}

- 메소드 내에서 로컬 변수를 선언할 때
  초기값으로 익명 구현 객체를 생성해서 대입하는 예
ex)
void method() {
    //로컬 변수 선언
    RemoteControl localVar = new RemoteControl() {
        //RemoteControl 인터페이스의
        //추상메소드에 대한 실체 메소드
        @Override
        void turnOn() { }
    }
}

- 메소드의 매개 변수가 인터페이스 타입일 경우
  메소드를 호출하는 코드에서 익명 구현 객체를 생성해서
  매개값으로 대입하는 예
ex)
class A {
    void method1(RemoteControl rc) { }

    void method2() {
        method1(
            new RemoteControl() {
                @Override
                void turnOn() { }
            }
        );
    }
}</code></pre><pre><code class="language-java">// 인터페이스
interface RemoteControl {
    public void turnOn();

    public void turnOff();
}

// 익명 구현 객체 생성
class Anonymous2 {
    // 필드 초기값으로 대입
    RemoteControl field = new RemoteControl() {
        // 필드선언과 초기값 대입
        @Override
        public void turnOn() {
            System.out.println(&quot;TV를 켭니다.&quot;);
        }

        @Override
        public void turnOff() {
            System.out.println(&quot;TV를 끕니다.&quot;);
        }
    };

    void method1() {
        // 로컬 변수값으로 대입
        RemoteControl localVar = new RemoteControl() {
            // 로컬 변수 선언과 초기값 대입
            @Override
            public void turnOn() {
                System.out.println(&quot;Audio를 켭니다.&quot;);
            }

            @Override
            public void turnOff() {
                System.out.println(&quot;Audio를 끕니다.&quot;);
            }
        };
        // 로컬 변수 사용
        localVar.turnOn();
    }

    void method2(RemoteControl rc) {
        rc.turnOn();
    }
}

// 익명 구현 객체 생성
public class AnonymouseExample2 {
    public static void main(String[] args) {
        Anonymous2 anony2 = new Anonymous2();
        // 익명 객체 필드 사용
        anony2.field.turnOn();
        // 익명 객체 로컬 변수 사용
        anony2.method1();
        // 익명 객체 매개값 사용
        anony2.method2(
                new RemoteControl() {
                    @Override
                    public void turnOn() {
                        System.out.println(&quot;SmartTV를 켭니다.&quot;);
                    }

                    @Override
                    public void turnOff() {
                        System.out.println(&quot;SmartTV를 끕니다.&quot;);
                    }
                }
        );
    }
}

💻 출력
TV를 켭니다.
Audio를 켭니다.
SmartTV를 켭니다.</code></pre>
<pre><code>- UI 클래스
: Button 클래스의 내용을 보면 중첩 인터페이스(OnClickListener) 타입으로
  필드(listener)를 선언하고 Setter 메소드(setOnClickListener())로 외부에서
  구현 객체를 받아 필드에 대입함
: 버튼 이벤트가 발생했을 때(touch()메소드가 실행되었을 때)
  인터페이스를 통해 구현 객체의 메소드를 호출(listener.onClick())함

public class Button {
    // 인터페이스 타입 필드
    OnClickListener listener;

    // 매개변수의 다형성
    void setOnClickListener(OnClickListener listener) {
        this.listener = listener;
    }

    //구현 객체의 onClick() 메소드 호출
    void touch() {
        listener.onClick();
    }

    //중첩 인터페이스
    static interface OnClickListener {
        void onClick();
    }
}</code></pre><pre><code class="language-java">/*
 * Window 클래스를 2개의 Button 객체를
 * 가지고 있는 창이라고 가정해보면
 * 
 * 첫 번째 button1의 클릭 이벤트 처리는
 * 필드로 선언한 익명 구현 객체가 담당
 * 
 * 두 번째 button2의 클릭 이번트 처리는
 * setOnClickListener()를 호출할때
 * 매개값으로 준 익명 구현 객체가 담당
 */
//UI 클래스
class Button {
    // 인터페이스 타입 필드
    OnClickListener listener;

    // 매개변수의 다형성
    void setOnClickListener(OnClickListener listener) {
        this.listener = listener;
    }

    //구현 객체의 onClick() 메소드 호출
    void touch() {
        listener.onClick();
    }

    //중첩 인터페이스
    static interface OnClickListener {
        void onClick();
    }
}

//UI 클래스
class Window{
    Button button1 = new Button();
    Button button2 = new Button();

    //필드 초기값으로 대입
    // 필드값으로 익명 객체 대입
    Button.OnClickListener listener = new Button.OnClickListener() {
        @Override
        public void onClick() {
            System.out.println(&quot;전화를 겁니다.&quot;);
        }
    };

    Window() {
        //매개값으로 필드 대입
        button1.setOnClickListener(listener);
        //매개값으로 익명 객체 대입
        button2.setOnClickListener(new Button.OnClickListener() {
            @Override
            public void onClick() {
                System.out.println(&quot;메시지를 보냅니다.&quot;);
            }
        });
    }
}

//실행클래스
public class Main {
    public static void main(String[] args) {
        Window w = new Window();
        // 버튼 클릭
        w.button1.touch();
        w.button2.touch();
    }
}

💻 결과
전화를 겁니다.
메시지를 보냅니다.</code></pre>
<hr>
<h3 id="✔️-익명-객체의-로컬-변수-사용">✔️ 익명 객체의 로컬 변수 사용</h3>
<p>: 메소드의 매개 변수나 로컬 변수를 익명 객체 내부에서 사용할 때 제한이 있음
&amp;nbsp&amp;nbsp 익명 객체는 메소드 실행이 종료되면 없어지는 것이 일반적이지만,
&amp;nbsp&amp;nbsp 메소드가 종료되어도 계속 실행 상태로 존재 할 수 있음</p>
<pre><code>ex)
익명 스레드 객체를 사용할 때
매개 변수나 로컬 변수는 메소드 실행이 끝나면
스택 메모리에서 사라지기 때문에 익명 객체에서 지속적으로 사용할 수 없음</code></pre><p>→ 이 문제의 해결방법은
&amp;nbsp&amp;nbsp 컴파일 시 익명 객체에서 사용하는
&amp;nbsp&amp;nbsp 매개 변수나 로컬 변수의 값을
&amp;nbsp&amp;nbsp 익명 객체 내부에 복사해두고 사용함
&amp;nbsp&amp;nbsp 그리고 매개 변수나 로컬 변수가 수정되어
&amp;nbsp&amp;nbsp 값이 변경되면 익명 객체에 복사해 둔 값과
&amp;nbsp&amp;nbsp 달라지므로 매개 변수나 로컬 변수를
&amp;nbsp&amp;nbsp final로 선언할 것을 요구함</p>
<p>: 자바 7 이전까지는 final 키워드 필수
&amp;nbsp&amp;nbsp 자바 8 이후부터는 생략 가능
&amp;nbsp&amp;nbsp final 선언을 하지 않아도 값이 수정될 수 없도록
&amp;nbsp&amp;nbsp final의 특성을 부여 받았기 때문</p>
<pre><code>``` java
/*
 * 매개 변수와 로컬 변수가 익명 객체 내부에서 사용할 때
 * 매개 변수와 로컬 변수가 final 특성을 갖고 있음을 보여줌
 */

// 인터페이스
interface Calculatable {
    public int sum();
}


// 익명 객체의 로컬 변수 사용
class Anonymous3 {
    private int field;

    public void method(final int arg1, int arg2) {
        final int var1 = 0;
        int var2 = 0;

        field = 10;

        //(x)
        //arg1 = 20;
        //arg2 = 20;

        //(x)
        //var1 = 30;
        //var2 = 30;

        Calculatable calc = new Calculatable() {
            @Override
            public int sum() {
                int result = field + arg1 + arg2 + var1 + var2;
                return result;
            }
        };

        System.out.println(calc.sum());

    }
}

public class AnonymousExample3 {
    public static void main(String[] args) {
        Anonymous3 anony3 = new Anonymous3();
        anony3.method(0, 0);
    }
}

💻 결과
10</code></pre>]]></description>
        </item>
    </channel>
</rss>