<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>u_yonu.log</title>
        <link>https://velog.io/</link>
        <description>비전공자의 개발도전기</description>
        <lastBuildDate>Wed, 04 Mar 2026 08:45:40 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>u_yonu.log</title>
            <url>https://velog.velcdn.com/images/u_yonu/profile/ab517c60-8334-4ef8-b93a-b8d90e302c5a/image.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. u_yonu.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/u_yonu" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[Java] 컬렉션 프레임워크(Collection Framework)]]></title>
            <link>https://velog.io/@u_yonu/Java-%EC%BB%AC%EB%A0%89%EC%85%98-%ED%94%84%EB%A0%88%EC%9E%84%EC%9B%8C%ED%81%ACCollection-Framework</link>
            <guid>https://velog.io/@u_yonu/Java-%EC%BB%AC%EB%A0%89%EC%85%98-%ED%94%84%EB%A0%88%EC%9E%84%EC%9B%8C%ED%81%ACCollection-Framework</guid>
            <pubDate>Wed, 04 Mar 2026 08:45:40 GMT</pubDate>
            <description><![CDATA[<h2 id="컬렉션-프레임워크">컬렉션 프레임워크</h2>
<p>알고리즘 문제를 풀다보면 대부분 처음 고민하게 되는 것은 어떻게 데이터를 받아오고, 정렬하할 것이다.
자바에서 데이터를 어떻게 <strong>저장</strong>하고, 어떻게 <strong>꺼내고</strong>, 어떻게 <strong>정렬</strong>할 것인가&#39;는 거의 항상 <strong>컬렉션 프레임워크</strong>로 귀결된다. </p>
<hr>
<h3 id="자료구조data-structure">자료구조(Data Structure)</h3>
<ul>
<li>데이터를 효율적으로 접근하기 위해 선택되는 <strong>데이터의 조직 및 저장 형식</strong></li>
<li>데이터 값들의 모음, 값들 간의 관계, 그리고 적용 가능한 연산(검색/삽입/삭제 등)의 집합</li>
</ul>
<h4 id="자료구조의-분류">자료구조의 분류</h4>
<ul>
<li><strong>정적 자료구조(Static Data Structure)</strong>: 크기가 고정된 자료 구조<br>예) 배열(Array)</li>
<li><strong>동적 자료구조(Dynamic Data Structure)</strong>: 크기가 변할 수 있는 자료구조<br>예) 리스트(List), 스택(Stack), 큐(Queue)</li>
</ul>
<h4 id="자료구조-선택-기준">자료구조 선택 기준</h4>
<ul>
<li>데이터 접근 속도</li>
<li>메모리 사용 효율성</li>
<li>삽입/삭제의 효율성</li>
<li>순서 유지 여부</li>
<li>중복 데이터 허용 여부</li>
</ul>
<hr>
<h3 id="컬렉션-프레임워크-1">컬렉션 프레임워크</h3>
<ul>
<li><strong>표준화된 데이터 구조</strong>(자료구조)와 이를 처리하기 위한 <strong>클래스 / 인터페이스의 집합</strong></li>
<li>데이터를 동적 크기로 관리하고, 삽입 / 삭제 / 검색 / 정렬 등을 효율적으로 처리할 수 있음</li>
<li><strong>제네릭을 지원</strong>하여 타입 안정성(Type Safety) 보장</li>
<li>표준화된 메서드 제공</li>
</ul>
<p><img src="https://velog.velcdn.com/images/u_yonu/post/4bc2f7c6-b958-4806-a0c9-0d02383afa78/image.png" alt=""></p>
<p>위의 표처럼 다양한 컬렉션 프레임 워크가 있다. 오늘은 그중에서 가장 근간이 되는 
List 계열, Set 계열, Map 계열에 대해서 알아보고자 한다.</p>
<hr>
<h3 id="list-계열">List 계열</h3>
<h4 id="list-계열-컬렉션-특징">List 계열 컬렉션 특징</h4>
<ul>
<li><strong>순서가 있는 데이터 집합</strong></li>
<li><strong>중복 허용</strong></li>
<li>저장된 순서를 유지</li>
<li>배열과 달리 <strong>크기가 동적으로 변함</strong></li>
</ul>
<h4 id="대표-구현-클래스">대표 구현 클래스</h4>
<ul>
<li><code>ArrayList</code></li>
<li><code>LinkedList</code></li>
<li><code>Vector</code></li>
</ul>
<h4 id="주요-메서드">주요 메서드</h4>
<p><strong>1) 추가(Add)</strong></p>
<table>
<thead>
<tr>
<th>반환 타입</th>
<th>메서드</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><code>void</code></td>
<td><code>add(int index, E element)</code></td>
<td>지정한 인덱스에 요소 삽입(뒤 요소는 한 칸씩 밀림)</td>
</tr>
<tr>
<td><code>boolean</code></td>
<td><code>add(E e)</code></td>
<td>리스트 끝에 요소 추가(성공 여부 반환)</td>
</tr>
<tr>
<td><code>boolean</code></td>
<td><code>addAll(int index, Collection&lt;? extends E&gt; c)</code></td>
<td>지정한 인덱스에 컬렉션의 모든 요소를 삽입</td>
</tr>
<tr>
<td><code>boolean</code></td>
<td><code>addAll(Collection&lt;? extends E&gt; c)</code></td>
<td>리스트 끝에 컬렉션의 모든 요소를 추가</td>
</tr>
</tbody></table>
<p><strong>2) 삭제/비우기(Remove/Clear)</strong></p>
<table>
<thead>
<tr>
<th>반환 타입</th>
<th>메서드</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><code>void</code></td>
<td><code>clear()</code></td>
<td>리스트의 모든 요소 삭제(비움)</td>
</tr>
</tbody></table>
<p><strong>3) 포함 여부(Contains)</strong></p>
<table>
<thead>
<tr>
<th>반환 타입</th>
<th>메서드</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><code>boolean</code></td>
<td><code>contains(Object o)</code></td>
<td>특정 요소가 포함되어 있는지 확인</td>
</tr>
<tr>
<td><code>boolean</code></td>
<td><code>containsAll(Collection&lt;?&gt; c)</code></td>
<td>컬렉션 <code>c</code>의 모든 요소가 리스트에 포함되어 있는지 확인</td>
</tr>
</tbody></table>
<p><strong>4) 주요 메서드: 복사(Copy)</strong></p>
<table>
<thead>
<tr>
<th>반환 타입</th>
<th>메서드</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><code>static &lt;E&gt; List&lt;E&gt;</code></td>
<td><code>copyOf(Collection&lt;? extends E&gt; coll)</code></td>
<td>주어진 컬렉션을 복사해 새 리스트를 반환(원본과 별개)</td>
</tr>
</tbody></table>
<p><strong>5) 비교 / 동등성(Equals / Hash)</strong></p>
<table>
<thead>
<tr>
<th>반환 타입</th>
<th>메서드</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><code>boolean</code></td>
<td><code>equals(Object o)</code></td>
<td>리스트 내용이 같은지 비교(순서 포함)</td>
</tr>
<tr>
<td><code>int</code></td>
<td><code>hashCode()</code></td>
<td>리스트의 해시값 반환(동등성 규약과 연계)</td>
</tr>
</tbody></table>
<p><strong>6) 조회(Get)</strong></p>
<table>
<thead>
<tr>
<th>반환 타입</th>
<th>메서드</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><code>E</code></td>
<td><code>get(int index)</code></td>
<td>해당 인덱스의 요소 반환</td>
</tr>
</tbody></table>
<p><strong>7) 검색(Search)</strong></p>
<table>
<thead>
<tr>
<th>반환 타입</th>
<th>메서드</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><code>int</code></td>
<td><code>indexOf(Object o)</code></td>
<td>요소 <code>o</code>의 첫 등장 인덱스 반환(없으면 <code>-1</code>)</td>
</tr>
</tbody></table>
<p><strong>8) 상태 확인</strong></p>
<table>
<thead>
<tr>
<th>반환 타입</th>
<th>메서드</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><code>boolean</code></td>
<td><code>isEmpty()</code></td>
<td>리스트가 비어 있으면 <code>true</code></td>
</tr>
</tbody></table>
<hr>
<h3 id="arraylist">ArrayList</h3>
<ul>
<li><strong>배열 기반</strong> 구현</li>
<li>인덱스를 통한 접근이 빠름(조회 유리)</li>
<li>중간 삽입/삭제 시 <strong>요소 이동 비용</strong> 때문에 성능 저하 가능</li>
<li>데이터 <strong>조회가 많고</strong>, 삽입/삭제가 적을 때</li>
</ul>
<p><img src="https://velog.velcdn.com/images/u_yonu/post/8eec6575-8c18-4264-89e8-a1ed1e3055c9/image.png" alt=""></p>
<h3 id="linkedlist">LinkedList</h3>
<ul>
<li><strong>노드 기반</strong> 구현(각 노드가 이전 / 다음 노드 참조를 가짐)</li>
<li>삽입 / 삭제가 빠른 편(노드 연결만 변경)</li>
<li>인덱스 접근은 상대적으로 불리할 수 있음</li>
<li>데이터 <strong>삽입 / 삭제가 많고</strong>, 조회가 상대적으로 적을 때</li>
</ul>
<p><img src="https://velog.velcdn.com/images/u_yonu/post/4376b913-1fa8-421d-9481-0a9bfda838dc/image.png" alt=""></p>
<hr>
<h3 id="set-계열">Set 계열</h3>
<h4 id="set-계열-컬렉션-특징">Set 계열 컬렉션 특징</h4>
<ul>
<li><strong>중복 허용하지 않음</strong></li>
<li><strong>순서 보장하지 않음</strong>(구현체에 따라 예외 있음)</li>
<li><code>null</code> 허용(보통 1개)</li>
<li>“고유성”이 중요한 데이터에 유용</li>
</ul>
<h4 id="대표-구현-클래스-1">대표 구현 클래스</h4>
<ul>
<li><code>HashSet</code></li>
<li><code>LinkedHashSet</code></li>
<li><code>TreeSet</code></li>
</ul>
<hr>
<h4 id="hashset">HashSet</h4>
<ul>
<li>저장 순서 유지 X</li>
<li>내부적으로 <code>HashMap</code> 기반</li>
<li>추가/삭제/검색이 빠름(해시 기반)</li>
<li><code>null</code> 1개 저장 가능<blockquote>
<p>여기서 쓰이는 <strong>Hash</strong>라는 용어는 <strong>&#39;데이터를 빠르게 저장하고 검색하기 위해서 사용하는 특별한 값 또는 기법&#39;</strong>을 말하는데, 이는 데이터를 <strong>&#39;고유한 숫자 값&#39;</strong>으로 변환하는 과정을 말한다.
=&gt; 여기서 고유한 숫자 = hashCode() 값</p>
</blockquote>
</li>
</ul>
<hr>
<h4 id="linkedhashset">LinkedHashSet</h4>
<ul>
<li>저장 순서 유지 O</li>
<li>내부적으로 <code>LinkedHashMap</code> 기반(해시 + 연결 리스트)</li>
<li>HashSet보다 약간 느릴 수 있음(연결 리스트 관리 비용)</li>
<li><code>null</code> 1개 저장 가능</li>
</ul>
<hr>
<h4 id="treeset">TreeSet</h4>
<ul>
<li>데이터가 <strong>정렬된 상태</strong>로 유지(기본 오름차순)</li>
<li>사용자 정의 정렬이 필요하면 <code>Comparator</code> 사용 가능</li>
<li>내부적으로 <strong>레드-블랙 트리(균형 이진 탐색 트리)</strong> 기반</li>
<li><code>null</code> 저장 불가(정렬/비교 불가능)</li>
</ul>
<hr>
<h4 id="set-주요-메서드">Set 주요 메서드</h4>
<p><strong>1) 추가(Add)</strong></p>
<table>
<thead>
<tr>
<th>반환 타입</th>
<th>메서드</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><code>boolean</code></td>
<td><code>add(E e)</code></td>
<td>요소 추가(중복이면 추가되지 않음, 성공 여부 반환)</td>
</tr>
<tr>
<td><code>boolean</code></td>
<td><code>addAll(Collection&lt;? extends E&gt; c)</code></td>
<td>컬렉션의 모든 요소를 Set에 추가</td>
</tr>
</tbody></table>
<p><strong>2) 삭제 / 비우기(Remove / Clear)</strong></p>
<table>
<thead>
<tr>
<th>반환 타입</th>
<th>메서드</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><code>boolean</code></td>
<td><code>remove(Object o)</code></td>
<td>특정 요소 삭제(삭제 성공 여부 반환)</td>
</tr>
<tr>
<td><code>void</code></td>
<td><code>clear()</code></td>
<td>Set의 모든 요소 삭제</td>
</tr>
</tbody></table>
<p><strong>3) 포함 여부(Contains)</strong></p>
<table>
<thead>
<tr>
<th>반환 타입</th>
<th>메서드</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><code>boolean</code></td>
<td><code>contains(Object o)</code></td>
<td>특정 요소가 포함되어 있는지 확인</td>
</tr>
<tr>
<td><code>boolean</code></td>
<td><code>containsAll(Collection&lt;?&gt; c)</code></td>
<td>컬렉션 <code>c</code>의 모든 요소가 Set에 포함되어 있는지 확인</td>
</tr>
</tbody></table>
<p><strong>4) 복사(Copy)</strong></p>
<table>
<thead>
<tr>
<th>반환 타입</th>
<th>메서드</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><code>static &lt;E&gt; Set&lt;E&gt;</code></td>
<td><code>copyOf(Collection&lt;? extends E&gt; coll)</code></td>
<td>주어진 컬렉션을 복사해 새 Set을 반환(원본과 별개)</td>
</tr>
</tbody></table>
<p><strong>5) 비교 / 동등성(Equals / Hash)</strong></p>
<table>
<thead>
<tr>
<th>반환 타입</th>
<th>메서드</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><code>boolean</code></td>
<td><code>equals(Object o)</code></td>
<td>Set 동등성 비교(순서가 아니라 “구성 요소” 기준)</td>
</tr>
<tr>
<td><code>int</code></td>
<td><code>hashCode()</code></td>
<td>해시값 반환(동등성 규약과 연계)</td>
</tr>
</tbody></table>
<p><strong>6) 상태 확인</strong></p>
<table>
<thead>
<tr>
<th>반환 타입</th>
<th>메서드</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><code>int</code></td>
<td><code>size()</code></td>
<td>Set의 크기(요소 수) 반환</td>
</tr>
<tr>
<td><code>boolean</code></td>
<td><code>isEmpty()</code></td>
<td>Set이 비어 있으면 <code>true</code></td>
</tr>
</tbody></table>
<p><strong>7) 순회(Iteration)</strong></p>
<table>
<thead>
<tr>
<th>반환 타입</th>
<th>메서드</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><code>Iterator&lt;E&gt;</code></td>
<td><code>iterator()</code></td>
<td>Set을 순회할 수 있는 <code>Iterator</code> 반환</td>
</tr>
</tbody></table>
<blockquote>
<p>Iterator<E>는 한마디로 <strong>컬렉션(Set/List 등)</strong>을 <strong>&quot;하나씩 꺼내서 순회할 수 있게 해주는 도구(반복자)&quot;</strong>로 Set은 인덱스가 없어서(get 메서드 같은 게 없음) 내부 요소를 하나씩 보려면 순회 방법이 필요하고, 그 표준 방식이 iterator()이다.</p>
</blockquote>
<pre><code>Set&lt;String&gt; set = new HashSet&lt;&gt;();
set.add(&quot;A&quot;);
set.add(&quot;B&quot;);

Iterator&lt;String&gt; it = set.iterator();

while (it.hasNext()) {
    String v = it.next();
    System.out.println(v);
}</code></pre><blockquote>
<p> for each 구문 또한 iterator 기반의 방법이다.</p>
</blockquote>
<hr>
<h3 id="map-계열">Map 계열</h3>
<h4 id="map-계열-컬렉션-특징">Map 계열 컬렉션 특징</h4>
<ul>
<li><strong>키(Key)와 값(Value)</strong> 의 쌍으로 저장</li>
<li>키는 중복 불가, 값은 중복 가능</li>
<li>키를 통해 빠른 검색 가능</li>
<li><code>null</code> 허용 여부는 구현체에 따라 다름(<code>TreeMap</code>은 null key 불가)</li>
</ul>
<h4 id="대표-구현-클래스-2">대표 구현 클래스</h4>
<ul>
<li><code>HashMap</code></li>
<li><code>LinkedHashMap</code></li>
<li><code>TreeMap</code></li>
</ul>
<hr>
<h4 id="hashmap">HashMap</h4>
<ul>
<li>저장 순서 유지 X</li>
<li>내부적으로 해시 테이블 사용</li>
<li><code>null</code> 키 1개 허용, <code>null</code> 값 여러 개 허용</li>
<li>빠른 검색/삽입/삭제</li>
</ul>
<h4 id="linkedhashmap">LinkedHashMap</h4>
<ul>
<li>저장 순서 유지 O</li>
<li>내부적으로 해시 테이블 + 연결 리스트</li>
<li><code>null</code> 키 1개 허용, <code>null</code> 값 여러 개 허용</li>
<li>HashMap과 유사한 성능이지만 순서 관리 비용이 약간 추가될 수 있음</li>
</ul>
<h4 id="treemap">TreeMap</h4>
<ul>
<li>키 기준으로 정렬된 상태 유지(기본 오름차순)</li>
<li><code>Comparator</code>로 사용자 정의 정렬 가능</li>
<li>내부적으로 레드-블랙 트리 기반</li>
<li><code>null</code> 키 허용하지 않음</li>
</ul>
<hr>
<h4 id="map-주요-메서드">Map 주요 메서드</h4>
<p><strong>1) 추가/수정(Put &amp; Compute)</strong></p>
<table>
<thead>
<tr>
<th>반환 타입</th>
<th>메서드</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><code>V</code></td>
<td><code>put(K key, V value)</code></td>
<td>키-값 쌍 추가(키가 이미 있으면 값이 덮어써짐)</td>
</tr>
<tr>
<td><code>default V</code></td>
<td><code>compute(K key, BiFunction&lt;? super K, ? super V, ? extends V&gt; remappingFunction)</code></td>
<td>키에 대해 새 값을 재계산(없으면 <code>null</code>로 계산될 수 있음)</td>
</tr>
<tr>
<td><code>default V</code></td>
<td><code>computeIfAbsent(K key, Function&lt;? super K, ? extends V&gt; mappingFunction)</code></td>
<td>키가 없을 때만 값 생성 후 저장</td>
</tr>
<tr>
<td><code>default V</code></td>
<td><code>computeIfPresent(K key, BiFunction&lt;? super K, ? super V, ? extends V&gt; remappingFunction)</code></td>
<td>키가 있을 때만 값 재계산 후 저장</td>
</tr>
</tbody></table>
<p><strong>2) 조회(Get)</strong></p>
<table>
<thead>
<tr>
<th>반환 타입</th>
<th>메서드</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><code>V</code></td>
<td><code>get(Object key)</code></td>
<td>키에 해당하는 값을 반환(없으면 <code>null</code>)</td>
</tr>
<tr>
<td><code>default V</code></td>
<td><code>getOrDefault(Object key, V defaultValue)</code></td>
<td>키가 없으면 기본값 반환</td>
</tr>
</tbody></table>
<p><strong>3) 삭제(Remove)</strong></p>
<table>
<thead>
<tr>
<th>반환 타입</th>
<th>메서드</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><code>V</code></td>
<td><code>remove(Object key)</code></td>
<td>키에 해당하는 엔트리 삭제 후 기존 값 반환(없으면 <code>null</code>)</td>
</tr>
</tbody></table>
<p><strong>4) 포함 여부(Contains)</strong></p>
<table>
<thead>
<tr>
<th>반환 타입</th>
<th>메서드</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><code>boolean</code></td>
<td><code>containsKey(Object key)</code></td>
<td>특정 키가 존재하는지 확인</td>
</tr>
<tr>
<td><code>boolean</code></td>
<td><code>containsValue(Object value)</code></td>
<td>특정 값이 존재하는지 확인</td>
</tr>
</tbody></table>
<p><strong>5) 키/값/엔트리 뷰(View)</strong></p>
<table>
<thead>
<tr>
<th>반환 타입</th>
<th>메서드</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><code>Set&lt;K&gt;</code></td>
<td><code>keySet()</code></td>
<td>모든 키를 Set 형태로 반환</td>
</tr>
<tr>
<td><code>Collection&lt;V&gt;</code></td>
<td><code>values()</code></td>
<td>모든 값을 Collection 형태로 반환</td>
</tr>
<tr>
<td><code>Set&lt;Map.Entry&lt;K,V&gt;&gt;</code></td>
<td><code>entrySet()</code></td>
<td>(키,값) 엔트리 집합을 Set 형태로 반환</td>
</tr>
</tbody></table>
<p><strong>6) 복사(Copy)</strong></p>
<table>
<thead>
<tr>
<th>반환 타입</th>
<th>메서드</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><code>static &lt;K,V&gt; Map&lt;K,V&gt;</code></td>
<td><code>copyOf(Map&lt;? extends K, ? extends V&gt; map)</code></td>
<td>주어진 Map을 복사해 새 Map을 반환(원본과 별개)</td>
</tr>
</tbody></table>
<p><strong>7) 상태 확인</strong></p>
<table>
<thead>
<tr>
<th>반환 타입</th>
<th>메서드</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><code>int</code></td>
<td><code>size()</code></td>
<td>저장된 키-값 쌍(엔트리) 개수 반환</td>
</tr>
<tr>
<td><code>boolean</code></td>
<td><code>isEmpty()</code></td>
<td>Map이 비어 있으면 <code>true</code></td>
</tr>
<tr>
<td><code>void</code></td>
<td><code>clear()</code></td>
<td>모든 엔트리 삭제</td>
</tr>
</tbody></table>
<hr>
<p><strong>8) 반복/순회(Iteration)</strong></p>
<table>
<thead>
<tr>
<th>반환 타입</th>
<th>메서드</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><code>default void</code></td>
<td><code>forEach(BiConsumer&lt;? super K, ? super V&gt; action)</code></td>
<td>모든 엔트리에 대해 (key,value)로 순회 수행</td>
</tr>
</tbody></table>
<hr>
<p><strong>9) 동등성(Equals / Hash)</strong></p>
<table>
<thead>
<tr>
<th>반환 타입</th>
<th>메서드</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><code>boolean</code></td>
<td><code>equals(Object o)</code></td>
<td>Map 동등성 비교(엔트리 구성 기준)</td>
</tr>
<tr>
<td><code>int</code></td>
<td><code>hashCode()</code></td>
<td>해시값 반환</td>
</tr>
<tr>
<td>---</td>
<td></td>
<td></td>
</tr>
</tbody></table>
<h3 id="자료구조를-이용한-정렬sort">자료구조를 이용한 정렬(Sort)</h3>
<ul>
<li>요소들을 특정 기준에 맞춰 오름차순 / 내림차순으로 배치하는 것</li>
<li>일반적으로 <strong>순서를 가지는 컬렉션(List)</strong> 이 정렬 대상이 된다.</li>
<li>배열 정렬: <code>Arrays.sort()</code></li>
<li>컬렉션 정렬: <code>Collections.sort()</code></li>
</ul>
<pre><code class="language-java">// 배열 정렬
Arrays.sort(arr);

// 리스트 정렬
Collections.sort(list);</code></pre>
<p>=&gt; 실제 정렬은 모두 오름차순이 된다. 따라서 다른 정렬 기준으로 만들기 위해서 <strong>&#39;정렬기준&#39;</strong>가 필요하다.</p>
<h3 id="정렬기준">정렬기준</h3>
<p>자바에서는 객체 정렬 기준을 정의하는 방법은 두가지로 아래와 같다.</p>
<ul>
<li>Comparable : 객체가 &#39;기본 정렬 기준&#39;을 스스로 가짐</li>
<li>Comparator : 객체 외부에서 &#39;별도의 정렬 기준&#39;을 만듬</li>
</ul>
<h4 id="comparable-인터페이스">Comparable 인터페이스</h4>
<ul>
<li>객체의 기본정렬 기준을 정의</li>
<li>클래스가 직접 <code>implemets Comparable&lt;T&gt;</code>로 구현</li>
<li>compareTo(T o) 메서드를 구현하여 정렬 기준을 정의
예) 이름 순, 나이 순 등<pre><code>public interface Comparable&lt;T&gt; {
  public int compareTo(T o);
}</code></pre></li>
</ul>
<blockquote>
<p><strong>반환값의 의미</strong></p>
</blockquote>
<ul>
<li>0 : 현재 객체와 비교 대상 객체가 같음</li>
<li>양수 : 현재 객체가 비교 대상 객체보다 큼</li>
<li>음수 : 현재 객체가 비교대상 객체보다 작음 </li>
</ul>
<h4 id="구현예시">구현예시</h4>
<pre><code>// 구현예시 
import java.util.Objects;

class Student implements Comparable&lt;Student&gt; {
    private final String name;
    private final int age;

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

    // 기본 정렬 기준: age 오름차순
    @Override
    public int compareTo(Student other) {
        return Integer.compare(this.age, other.age);
    }

    @Override
    public String toString() {
        return name + &quot;(&quot; + age + &quot;)&quot;;
    }
}


import java.util.*;

public class Main {
    public static void main(String[] args) {
        List&lt;Student&gt; students = new ArrayList&lt;&gt;();
        students.add(new Student(&quot;Min&quot;, 23));
        students.add(new Student(&quot;Yonu&quot;, 20));
        students.add(new Student(&quot;Soo&quot;, 21));

        Collections.sort(students); // compareTo 기준으로 정렬
        System.out.println(students);
        // 출력 예: [Yonu(20), Soo(21), Min(23)]
    }
}</code></pre><hr>
<h4 id="comparator-인터페이스">Comparator 인터페이스</h4>
<ul>
<li>별도의 정렬 기준을 정의</li>
<li>정렬 기준이 여러개 필요할 때 유용</li>
<li>클래스 외부에서 정렬 기준을 정의하며, 특정 필드 / 사용자 정의 기준으로 정렬 할 수 있음</li>
<li>compar(T o1, T o2) 메서드를 구현 <pre><code>public interface Comparator&lt;T&gt; {
  int compare(T o1, T o2);
}</code></pre><blockquote>
<p><strong>반환값의 의미</strong></p>
</blockquote>
</li>
<li>0 : 두 객체가 같음</li>
<li>양수 : 첫 번째 객체가 두 번째 객체보다 큼</li>
<li>음수 : 첫 번째 객체가 두 번째 객체보다 작음</li>
</ul>
<h4 id="구현예시-1">구현예시</h4>
<pre><code>// 별도 클래스로 만들기
Collections.sort(names, new StringLengthComparator());
// 익명 내부 클래스로 만들기
Collections.sort(names, new Comparator&lt;String&gt;() {
    @Override
    public int compare(String o1, String o2) {
        return Integer.compare(o1.length(), o2.length());
    }
});
//람다로 만들기
Collections.sort(names, (o1, o2) -&gt; {
    return Integer.compare(o1.length(), o2.length());
});
</code></pre><pre><code>class Student {
    private final String name;
    private final int age;
    private final double gpa;

    public Student(String name, int age, double gpa) {
        this.name = name;
        this.age = age;
        this.gpa = gpa;
    }

    public String getName() { return name; }
    public int getAge() { return age; }
    public double getGpa() { return gpa; }

    @Override
    public String toString() {
        return name + &quot;(age=&quot; + age + &quot;, gpa=&quot; + gpa + &quot;)&quot;;
    }
}
// 별도 클래스로 만들기

import java.util.Comparator;

class AgeAscComparator implements Comparator&lt;Student&gt; {
    @Override
    public int compare(Student o1, Student o2) {
        // o1이 앞이면 음수, o2가 앞이면 양수, 같으면 0
        return Integer.compare(o1.getAge(), o2.getAge());
    }
}

// 익명 클래스
import java.util.*;

Comparator&lt;Student&gt; nameAsc = new Comparator&lt;Student&gt;() {
    @Override
    public int compare(Student o1, Student o2) {
        return o1.getName().compareTo(o2.getName()); // 이름 오름차순
    }
};
//람다 
import java.util.*;

Comparator&lt;Student&gt; ageAsc = (o1, o2) -&gt; Integer.compare(o1.getAge(), o2.getAge());
Comparator&lt;Student&gt; gpaDesc = (o1, o2) -&gt; Double.compare(o2.getGpa(), o1.getGpa());

</code></pre><h4 id="comparable-vs-comparator">Comparable vs Comparator</h4>
<table>
<thead>
<tr>
<th>구분</th>
<th>Comparable</th>
<th>Comparator</th>
</tr>
</thead>
<tbody><tr>
<td>목적</td>
<td>객체의 <strong>기본 정렬 기준(자연 순서)</strong> 을 클래스 내부에 정의</td>
<td>객체 외부에서 <strong>별도의 정렬 기준</strong>을 정의</td>
</tr>
<tr>
<td>구현 위치</td>
<td>정렬 대상 클래스가 <code>implements Comparable&lt;T&gt;</code></td>
<td>별도 클래스/익명 클래스/람다로 <code>Comparator&lt;T&gt;</code> 구현</td>
</tr>
<tr>
<td>핵심 메서드</td>
<td><code>int compareTo(T o)</code></td>
<td><code>int compare(T o1, T o2)</code></td>
</tr>
<tr>
<td>정렬 호출</td>
<td><code>Collections.sort(list)</code> / <code>Arrays.sort(arr)</code></td>
<td><code>Collections.sort(list, comp)</code> / <code>Arrays.sort(arr, comp)</code></td>
</tr>
<tr>
<td>정렬 기준 개수</td>
<td>보통 <strong>1개(대표 기준)</strong></td>
<td><strong>여러 개 가능</strong> (상황별 기준 교체 쉬움)</td>
</tr>
<tr>
<td>클래스 수정 필요</td>
<td><strong>필요함</strong> (클래스에 compareTo 추가)</td>
<td><strong>불필요</strong> (클래스 밖에서 정의)</td>
</tr>
<tr>
<td>재사용성</td>
<td>“기본 기준”은 어디서나 자동 적용되어 편함</td>
<td>기준을 필요한 곳에서만 선택적으로 적용 가능</td>
</tr>
<tr>
<td>유지보수</td>
<td>기준이 바뀌면 클래스 수정/재배포 필요</td>
<td>기준 변경/추가가 쉬움(정렬 코드만 바꾸면 됨)</td>
</tr>
<tr>
<td>장점</td>
<td>- 기본 정렬이 명확해짐<br>- 사용이 간단함(컴퍼레이터 없이 정렬 가능)</td>
<td>- 다양한 정렬 기준을 유연하게 적용<br>- 클래스 변경 없이 정렬 기준 추가 가능<br>- 다중 정렬(<code>thenComparing</code>)에 강함</td>
</tr>
<tr>
<td>단점</td>
<td>- 정렬 기준이 여러 개면 관리가 불편함<br>- 클래스에 정렬 로직이 섞임</td>
<td>- 매번 Comparator를 전달해야 할 수 있음<br>- 기준이 많아지면 Comparator 관리가 필요</td>
</tr>
<tr>
<td>언제 쓰나</td>
<td>“이 클래스의 대표 정렬 기준이 명확”할 때<br>예: 학번, 날짜, id 등</td>
<td>“정렬 기준이 상황에 따라 달라짐/여러 개 필요”할 때<br>예: 이름순/나이순/평점순 등</td>
</tr>
<tr>
<td>---</td>
<td></td>
<td></td>
</tr>
<tr>
<td>조금 복잡했지만 오늘의 개념 끝.</td>
<td></td>
<td></td>
</tr>
</tbody></table>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] 제네릭(Generic)]]></title>
            <link>https://velog.io/@u_yonu/Java-%EC%A0%9C%EB%84%A4%EB%A6%ADGeneric</link>
            <guid>https://velog.io/@u_yonu/Java-%EC%A0%9C%EB%84%A4%EB%A6%ADGeneric</guid>
            <pubDate>Wed, 04 Mar 2026 06:30:32 GMT</pubDate>
            <description><![CDATA[<h3 id="제네릭generic">제네릭(Generic)</h3>
<h4 id="제네릭generic의-정의">제네릭(Generic)의 정의</h4>
<p>다양한 데이터 타입을 처리할 수 있는 클래스, 인터페이스, 메서드를 작성하는 기법이다. 
<img src="https://velog.velcdn.com/images/u_yonu/post/ae2b5733-c938-44f9-bb56-e268e51cf659/image.png" alt=""></p>
<h4 id="제네릭의-장점">제네릭의 장점</h4>
<ol>
<li>컴파일 시점에 타입을 지정할 수 있어 타입 안정성(type safety) 을 제공함</li>
<li>하나의 코드로 여러 타입에 대해 동작하도록 설계할 수 있어 코드 재사용성이 증가</li>
<li>타입이 명확하므로 불필요한 형 변환(casting) 을 줄일 수 있음</li>
</ol>
<h4 id="제네릭-클래스generic-class">제네릭 클래스(Generic Class)</h4>
<p>클래스(또는 인터페이스) 정의에 타입 매개변수를 넣는 방식으로 해당 클래스 <strong>전체 범위</strong>에서 타입을 사용할 수 있다.</p>
<pre><code>java
class Holder&lt;T&gt; {
    private T data;

    public Holder(T data) {
        this.data = data;
    }

    public T get() { return data; }
    public void set(T data) { this.data = data; }
}</code></pre><p><img src="https://velog.velcdn.com/images/u_yonu/post/5866bff6-2d38-420b-a13c-aac95150ac21/image.png" alt=""></p>
<ul>
<li><p><strong>제네릭 클래스의 선언</strong></p>
<ul>
<li>클래스 또는 인터페이스 선언 시 <code>&lt;&gt;</code>에 타입 파라미터를 표시한다.</li>
<li>타입 파라미터는 특별한 의미의 알파벳이라기보다, <strong>임의의 참조형 타입</strong>을 의미한다.</li>
</ul>
<blockquote>
<p>관례적으로 자주 쓰는 이름  </p>
<ul>
<li><code>T</code>: Type  </li>
<li><code>E</code>: Element  </li>
<li><code>K</code>: Key  </li>
<li><code>V</code>: Value  </li>
</ul>
</blockquote>
</li>
<li><p><strong>제네릭 클래스의 객체 생성</strong></p>
<ul>
<li><p>변수 선언 쪽과 생성자 쪽의 타입은 <strong>반드시 일치</strong>해야 한다.</p>
<pre><code class="language-java">Holder&lt;String&gt; h1 = new Holder&lt;String&gt;(&quot;hello&quot;);
System.out.println(h1.get()); // hello</code></pre>
</li>
<li><p>타입이 추론 가능한 경우, 생성자 쪽 타입은 생략할 수 있다. (Java 7+ 다이아몬드 연산자 <code>&lt;&gt;</code>)</p>
<pre><code class="language-java">Holder&lt;Integer&gt; h2 = new Holder&lt;&gt;(100);
System.out.println(h2.get()); // 100</code></pre>
</li>
<li><p>제네릭 타입을 지정하지 않는 raw type으로도 생성할 수 있지만 권장하지 않는다.<br>→ 타입 안정성이 깨지고, 타입 파라미터 <code>T</code>가 사실상 <code>Object</code>처럼 취급된다.</p>
</li>
</ul>
</li>
</ul>
<hr>
<h4 id="제네릭-메서드generic-method">제네릭 메서드(Generic Method)</h4>
<p>제네릭 메서드는 <strong>메서드 내부에서 사용할 타입 파라미터를 메서드가 직접 선언</strong>하는 방식이다.<br>즉, 클래스에 제네릭이 있든 없든 상관없이, <strong>특정 메서드만 제네릭하게</strong> 만들 수 있다.</p>
<ul>
<li>타입 파라미터를 사용하는 메서드</li>
<li>클래스의 타입 파라미터와는 별개로, <strong>메서드 레벨에서 제네릭 타입을 정의</strong>하고 사용할 수 있음</li>
<li>제네릭 메서드를 정의하려면 <strong>반환 타입 앞</strong>에 타입 파라미터를 선언한다.<ul>
<li>형태: <code>public static &lt;T&gt; T methodName(...)</code></li>
</ul>
</li>
<li>호출할 때 타입 파라미터는 보통 <strong>컴파일러가 추론</strong>하므로 생략 가능</li>
<li>필요하면 타입을 <strong>명시적으로 지정</strong>할 수도 있음  <ul>
<li>형태: <code>클래스명.&lt;타입&gt;메서드명(...)</code></li>
<li>예시 <pre><code>String s = Utils.&lt;String&gt;first(&quot;A&quot;, &quot;B&quot;);
Integer n = Utils.&lt;Integer&gt;first(1, 2);</code></pre></li>
</ul>
</li>
</ul>
<hr>
<h4 id="한정된-타입-매개변수bounded-type-parameter">한정된 타입 매개변수(Bounded Type Parameter)</h4>
<p>한정된 타입 매개변수는 제네릭을 정의할 때, <strong>아무 타입이나 다 받는 것이 아니라 특정 범위의 타입만 허용</strong>하고 싶을 때 사용한다.</p>
<ul>
<li>제네릭 클래스 / 메서드를 정의할 때 &quot;특정한 종류의 타입만&quot; 받도록 제한할 수 있다.</li>
<li>구체적인 타입 제한이 필요하면 <code>extends</code> 키워드를 사용한다.  <ul>
<li>여기서 <code>extends</code>는 상속뿐 아니라 <strong>인터페이스 제한</strong>에도 사용된다.</li>
</ul>
</li>
<li>타입 파라미터에 대한 제한은 <strong>상한 경계(extends)</strong> 만 가능하다.  <ul>
<li><code>super</code>(하한 경계)는 <strong>와일드카드에서</strong> 사용한다.
<img src="https://velog.velcdn.com/images/u_yonu/post/cdac25aa-50ae-4d77-a55b-ba56044261fa/image.png" alt=""></li>
</ul>
</li>
</ul>
<hr>
<h4 id="와일드-카드">와일드 카드</h4>
<ul>
<li>제네릭 클래스 인스턴스 변수의 참조 타입을 작성할 때</li>
<li>와일드 카드로서 문자 ?를 사용</li>
<li>불특정 타입을 나타내기 위해 사용하는 특수한 타입 매개변수</li>
<li>제네릭 클래스에 다형성 적용가능</li>
</ul>
<table style="margin-left:auto;margin-right:auto; text-align:center;">
  <thead>
    <tr>
      <th>종류</th>
      <th>표현</th>
      <th>설명</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>제한없는 와일드 카드</td>
      <td><code>GenericType&lt;?&gt;</code></td>
      <td>타입에 제한이 없음</td>
    </tr>
    <tr>
      <td>상한 경계 와일드 카드</td>
      <td><code>GenericType&lt;? extends T&gt;</code></td>
      <td>T와 T를 상속받은 타입만 사용 가능</td>
    </tr>
    <tr>
      <td>하한 경계 와일드 카드</td>
      <td><code>GenericType&lt;? super T&gt;</code></td>
      <td>T와 T의 조상 타입만 사용 가능</td>
    </tr>
  </tbody>
</table>


<p><img src="https://velog.velcdn.com/images/u_yonu/post/c1821d62-f24e-4c2c-b436-94ac659f4f61/image.png" alt=""></p>
<hr>
<p>제네릭 끝.!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Algorithm] 배열 정렬(Array Sorting)]]></title>
            <link>https://velog.io/@u_yonu/Algorithm-%EB%B0%B0%EC%97%B4%EC%9D%98-%EC%A0%95%EB%A0%AC</link>
            <guid>https://velog.io/@u_yonu/Algorithm-%EB%B0%B0%EC%97%B4%EC%9D%98-%EC%A0%95%EB%A0%AC</guid>
            <pubDate>Fri, 27 Feb 2026 06:52:28 GMT</pubDate>
            <description><![CDATA[<h3 id="1차원-배열복습">1차원 배열(복습)</h3>
<p>같은 자료형의 데이터를 연속된 메모리 공간에 저장하는 선형 자료구조</p>
<p>** 배열의 생성(초기화) **
int[] arr = new int[5];</p>
<p>** 선언과 동시에 값 지정 **
int[] array = {1, 2, 3, 4, 5};</p>
<p>** 시간 복잡도 **</p>
<ul>
<li>접근 및 수정 O(1) : 인덱스를 통해 즉시 접근 가능
Ex) arr[2]</li>
<li>검색 O(N) : 원하는 값을 찾기 위해 처음부터 끝까지 확인 가능</li>
<li>삽입/삭제 O(N) : 중간에 데이터를 넣거나 뺄 때 나머지 요소 이동</li>
</ul>
<p>*<em>cf) 배열과 연결 리스트의 차이 *</em>
<img src="https://velog.velcdn.com/images/u_yonu/post/bd4da55f-cda0-4ad7-8c55-7447b2c83644/image.png" alt=""></p>
<hr>
<h3 id="정렬sort">정렬(Sort)</h3>
<ul>
<li>데이터(숫자, 문자, 객체 등)들을 일정한 규칙(오름차순, 내림차순 등)에 따라 순서대로 재배열 하는것을 말함</li>
<li>다양한 알고리즘에서 선행 작업으로 활용되기도 함(데이터 처리 속도 향상)</li>
<li>자바에서는 Arrays 클래스와 Collections 클래스에서 sort()메서드를 지원함</li>
</ul>
<hr>
<h4 id="버블-정렬bubble-sort">버블 정렬(Bubble Sort)</h4>
<ul>
<li>인접한 두 개의 원소를 비교하여 크기가 순서에 맞지 않는다면 서로 교환(Swap)하는 과정을 반복하여 정렬하는 알고리즘</li>
<li>한번의 사이클이 끝날 때 마다 가장 큰(또는 작은) 원소가 끝에 위치하게 되는 모습이 거품이 올라오는 것과 유사하다고 하여 &#39;버블 정렬(Bubble Sort)라고 부름</li>
<li>시간 복잡도 : O(N<sup>2</sup>) 
<img src="https://velog.velcdn.com/images/u_yonu/post/7649b65b-992f-41b6-8aa8-1f1b3a86deb3/image.jpeg" alt=""></li>
</ul>
<h4 id="버블-정렬-과정">버블 정렬 과정</h4>
<ul>
<li>배열의 처음부터 끝까지 인접 원소를 짝지어 비교</li>
<li>비교한 두 원소의 순서가 잘못되어 있자다면 교환(Swap)-&gt; 오름차순, 내림차순</li>
<li>한 사이클이 끝나면 배열의 마지막 인덱스에 가장 큰(작은) 원소가 위치</li>
<li>범위를 줄여 나가며 N-1번 정도 반복 수행하면 정렬 완료Í‹››<p align = center><img src = "https://velog.velcdn.com/images/u_yonu/post/f9ed46fc-e475-4128-ad04-50f2f44ccdb7/image.png" width="50%" height="50%">


</li>
</ul>
<h4 id="구현예시--java">구현예시 : Java</h4>
<pre><code>import java.util.Arrays;

public class BubbleSort {
    public static void main(String[] args) {
        int[] arr = { 1, 16, 2, 20, 97, 99 };

        int N = arr.length; 
        // array의 길이를 저장

        for (int i = N - 1; i &gt; 0; i--) {
            for (int j = 0; j &lt; i; j++) {
                // 오름차순 정렬
                if (arr[j] &gt; arr[j + 1]) {
                    int tmp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = tmp;
                }
            } 
            System.out.println(Arrays.toString(arr));
        } 

    }

}</code></pre><hr>
<h4 id="선택-정렬selection-sort">선택 정렬(Selection Sort)</h4>
<ul>
<li>정렬되어 있지 않은 배열 혹은 리스트에서 가장 작은(또는 가장 큰) 원소를 찾아 맨 앞(또는 맨 뒤)으로 옮기는 과정을 반복하여 전체를 정렬하는 과정</li>
<li>시간 복잡도 : O(N<sup>2</sup>) </li>
</ul>
<h4 id="선택-정렬-과정">선택 정렬 과정</h4>
<ul>
<li>주어진 리스트 중에서 최솟값을 찾는다</li>
<li>맨 앞의 원소와 가장 작은 값을 swap한다</li>
<li>맨 앞의 원소를 제외한 나머지 구간에 반복 수행한다</li>
</ul>
<h4 id="구현예시--java-1">구현예시 : Java</h4>
<pre><code>import java.util.Arrays;

public class SelectionSort {
    public static void main(String[] args) {
        int[] arr = { 1, 16, 2, 20, 97, 99 };

        int N = arr.length;

        for (int i = 0; i &lt; N - 1; i++) {
            int minIdx = i; 
            for (int j = i + 1; j &lt; N; j++) {
                if (arr[minIdx] &gt; arr[j]) {
                    minIdx = j; 
                }
            }
//            if(minIdx == i) continue;
            int tmp = arr[i];
            arr[i] = arr[minIdx];
            arr[minIdx] = tmp;

        } 

        System.out.println(Arrays.toString(arr));
    }

}</code></pre><img src ="https://velog.velcdn.com/images/u_yonu/post/f8e660b3-5470-4f72-b1a4-19fc89ef4222/image.png">

<blockquote>
<p>안정 vs 불안정 정렬 차이 : 중복된 값이 있을 때, 입력된 순서가 정렬 후에도 유지되는 가?
버블 정렬 : 인접한 수만 바꾸고 값이 같으면 바꾸지 않고 지나감
선택 정렬 : 수에 따라 변경이 될 수 있음
ex)  2 (a), 2(b), 1 -&gt; 1,  2 (b), 2 (a) : 맨 앞에 있는 2(A)와 1을 바꾸면서 순서 역전</p>
</blockquote>
<hr>
<h4 id="카운팅-정렬counting-sort">카운팅 정렬(Counting Sort)</h4>
<p>각 항목이 몇 번 등장했는지(빈도)를 세서, 그 정보를 이용해 정렬 결과를 만든다.
→ 비교 기반 정렬이 아니라 카운트 기반 정렬이라 선형 시간에 가깝게 가능</p>
<p><strong>특징</strong>
(1) 안정 정렬(Stable)로 구현 가능: 같은 값의 원래 순서 유지
(2) 정수(또는 정수로 매핑 가능한 값)에 대해서만 적용하기 쉬움
(값 자체를 인덱스로 쓰는 count 배열을 만들기 때문)
(3) 비 비교 정렬</p>
<p>** 조건 / 제약 **</p>
<p>(1) count[value] 형태로 쓰려면 값의 범위(최대값)를 알아야 한다.
(2) 값의 최대가 크면 count 배열이 커져서 공간 사용량이 증가한다.</p>
<p>** 시간 복잡도 **</p>
<p>O(n + k)</p>
<ul>
<li>n : 입력 데이터(배열) 길이</li>
<li><blockquote>
<p>배열을 돌면서 각 숫자가 몇 번 나왔나 세기 : O(n) (1단계)</p>
</blockquote>
</li>
<li><blockquote>
<p>2단계 수행후 원래 배열을 한 번 더 탐색 : O(n) (3단계)</p>
</blockquote>
</li>
<li>k : 값의 범위(최대값 규모)</li>
<li><blockquote>
<p>0부터 k까지 돌면서 누적합 계산 : O(k)(2단계)</p>
</blockquote>
</li>
</ul>
<p>따라서, O(2n+k) = O(n+k)</p>
<h4 id="카운팅-정렬의-과정">카운팅 정렬의 과정</h4>
<p>  (1) 데이터가 들어갈 수 있는 범위 확인
  cf) 데이터 범위가 항상 0부터 시작한다는 보장은 없음</p>
<p>  (2) 0~k (데이터 범위)까지의 배열 생성</p>
<p>  (3) 데이터를 순회하면서 해당 인덱스의 값을 증가시킴</p>
<p>  (4) 카운트 배열의 누적합을 구하여 정렬된 결과를 어느 위치에 배치해야하는 지 알 수 있음</p>
<p>  (5) 원본 배열의 뒤에서부터 순회하며 원소를 배치
  <img src="https://velog.velcdn.com/images/u_yonu/post/8b6de593-6bc1-4755-bcb8-0b3f660d8ccc/image.png" alt=""></p>
<h4 id="구현예시--java-2">구현예시 : Java</h4>
<pre><code>public static int[] countingSort(int[] arr) {
int N = arr.length;

// 1. 가장 큰 값 찾기

int K = -1;
for (int i = 0; i &lt; N; i++) {
if (arr[i] &gt; K) K = arr[i];
}

// 2. Counting 하기
// 등장 횟수를 저장할 count 배열 생성
int[] count = new int[K + 1];
// 각 숫자 등장 횟수 세기
for (int i = 0; i &lt; N; i++) {
count[arr[i]]++;
}

// 3. 누적합 구하기
for (int i = 1; i &lt; K + 1; i++) {
count[i] += count[i - 1]; // count[i] → i 이하의 숫자가 총 몇 개인지
}

// 4. 역방향으로 원본을 순회하면서 정렬 시작
int[] sortedArr = new int[N]; // 원본 배열과 동일한 크기의 배열
for (int i = N - 1; i &gt;= 0; i--) // 뒤에서부터 순회
{
int num = arr[i]; // 현재 정렬 대상 값
int idx = count[num] - 1; // 누적합 정보로 실제 들어갈 인덱스 계산
sortedArr[idx] = num; // 계산된 위치에 값 저장
count[num]--; // 다음 동일 숫자가 앞에 올 수 있도록 위치 한 칸 전진
}
return sortedArr;
}
}                      
</code></pre><hr>
<h3 id="기수-정렬radix-sort">기수 정렬(Radix Sort)</h3>
<p>원소끼리 a &lt; b 비교를 반복하는 대신, 자릿수(digit) 를 기준으로 여러 번 분류/정렬을 반복해 전체를 정렬하는 알고리즘
-&gt; 보통 각 자릿수 정렬 단계에서 카운팅 정렬 같은 안정 정렬을 사용함</p>
<p>** 정렬 방식 (LSD 방식) ** </p>
<p>1의 자리 → 10의 자리 → 100의 자리 → … 순서로 정렬(Least Significant Digit)</p>
<p>** 특징 **</p>
<p>(1) 안정 정렬(Stable) 로 구현 가능(자릿수별 정렬이 안정적이면 전체도 안정적)</p>
<p>(2) 주로 0 이상의 정수 정렬에 많이 사용
(3) 정수뿐 아니라 자릿수 개념으로 표현 가능한 문자열에도 응용 가능</p>
<p>** 시간 복잡도** </p>
<p>O(d × (n + k))</p>
<ul>
<li>n: 데이터 개수(배열 길이)</li>
<li>d: 자릿수 개수</li>
<li>k: 한 자릿수의 값 범위(10진수면 0~9라서 보통 k=10)</li>
</ul>
<p>-&gt; 카운팅 정렬 O(n+k)를 자릿수 d번 반복하는 것과 같음
-&gt; d가 커질수록(자릿수 많을수록) 느려짐</p>
<p>** 제약/주의 **</p>
<p>(1) 자릿수가 늘면 비용 증가
(2) 음수 / 소수는 그대로 적용하기 어렵고, 처리하려면 추가 변환/전처리가 필요함</p>
<h4 id="구현예시--java-3">구현예시 : Java</h4>
<pre><code>
// 기수정렬(LSD방식)
public static void radixSort(int[] arr) {

// 최댓값 찾기(자릿수 계산)
int max = arr[0];
for (int v : arr) {
if (v &gt; max) max = v;
}

// 1의 자리, 10의자리, 100의자리.... 정렬
// 가장 큰수의 자릿수까지만 정렬 ( ex 123 /1000 = 0 되어서 종료)
for (int exp = 1; max / exp &gt; 0; exp *= 10) {
countingSort(arr, exp); } }

public static void countingSort(int[] arr, int exp) {
int n = arr.length;
int[] output = new int[n]; // 자릿수 정렬이 완료된 데이터 임시 보관
int[] count = new int[10]; // 자릿수별로 비교, 올 수 있는 숫자는 0-9

// 1. 개수 세기
for (int i = 0; i &lt; n; i++) {
int digit = (arr[i] / exp) % 10; // 전체값이 아니라 특정 자릿수만 추출
count[digit]++; }

// 2. 누적합
for (int i = 1; i &lt; 10; i++) {
count[i] += count[i - 1]; }

// 3. 역방향으로
for (int i = n - 1; i &gt;= 0; i--) {
int digit = (arr[i] / exp) % 10; //자릿수 추출
output[count[digit] - 1] = arr[i]; //자릿수 기준 위치에 저장
count[digit]--; }

// 4. output arr에 덮기
// 새 배열에 반환하는 카운팅과 달리 다음 자릿수 정렬을 위해 원본 배열 업데이트
for (int i = 0; i &lt; n; i++) {
arr[i] = output[i]; } } }
</code></pre><p>열심히 이 글을 읽으시고, 코딩체력이 높으신 분들은 당연하게 </p>
<blockquote>
<p>Arrays.sort() 쓰면 되는 거 아님? 
이라는 생각을 하셨을 것이다.</p>
</blockquote>
<p>cf) Arrays.sort() 
java.util.Arrays의 sort()는 배열을 정렬하는 표준 메서드</p>
<ul>
<li><p>대표형태</p>
<pre><code>Arrays.sort(int[] a);                 // 기본형(primitive) 배열
Arrays.sort(Integer[] a);             // 객체 배열(Wrapper)
Arrays.sort(T[] a, Comparator&lt;? super T&gt; c);  // 비교기(정렬 기준) 지정
Arrays.sort(a, from, to);             // 부분 정렬</code></pre><p>(1) 기본형 배열 
Ex) int[], double[]</p>
</li>
<li><p>Dual-Pivot Quicksort 계열을 사용</p>
</li>
<li><p>평균적으로 빠르고 상수항이 작음</p>
</li>
<li><p>안정 정렬(stable) X</p>
</li>
<li><p>시간복잡도: 평균 O(n log n)</p>
</li>
</ul>
<pre><code>int[] a = {5, 2, 9, 1};
Arrays.sort(a);</code></pre><p>(2) 객체 배열 </p>
<p>Ex) Integer[], String[] etc</p>
<ul>
<li>TimSort(MergeSort 계열, “runs” 활용) 사용</li>
<li>안정 정렬(stable)
→ 같은 값(비교 결과 0)이면 원래 순서가 유지됨</li>
<li>시간복잡도: O(nlogn)</li>
<li>부분적으로 이미 정렬된 데이터에 강함<pre><code>String[] s = {&quot;b&quot;, &quot;a&quot;, &quot;a&quot;};
Arrays.sort(s); // stable: 같은 &quot;a&quot;의 상대 순서 유지</code></pre></li>
</ul>
<hr>
<p>대부분의 코테/실무 정렬은 Arrays.sort()로 충분..!
샤라웃 투 ㅅㅇ
땡스 투 ㅅㅎ</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Research] 문헌 검색 방법(Literature Search Strategy)]]></title>
            <link>https://velog.io/@u_yonu/ETC-%EB%AC%B8%ED%97%8C-%EA%B2%80%EC%83%89-%EB%B0%A9%EB%B2%95</link>
            <guid>https://velog.io/@u_yonu/ETC-%EB%AC%B8%ED%97%8C-%EA%B2%80%EC%83%89-%EB%B0%A9%EB%B2%95</guid>
            <pubDate>Sat, 14 Feb 2026 11:09:10 GMT</pubDate>
            <description><![CDATA[<p>오늘은 간단하게 &#39;문헌&#39;을 검색하는 방법을 알아보려고 한다.
실제, &#39;문헌&#39; 이라는 것은 사전적으로는 아래와 같다.
<img src="https://velog.velcdn.com/images/u_yonu/post/cb70d7a1-9475-4854-919b-2ebfd617a131/image.png" alt=""></p>
<p>하지만, 오늘날 많은 연구자들에게 &#39;문헌&#39;은 보통 선행연구를 알아 볼 수 있는 &#39;논문&#39;을 많이 말한다.
대학생, 대학원생, 직장인들까지 많은 사람들은 정보라는 것을 찾아보는 삶을 살아가고 있다.
하지만, 요즘은 참 거짓 정보가 넘치고 신뢰성있는 자료를 찾는 과정이 점점 더 어려워지고 있다.
오늘은 &#39;비교적&#39; 신뢰 할 만 (비.교.적. 강조.) 논문을 찾아보고자 한다.</p>
<p>이 글은 “논문을 찾는 방법”을 넘어서, <strong>연구 질문을 검색 가능한 형태로 바꾸고</strong>,  
-&gt; <strong>재현 가능한 검색식</strong>을 만들고, <strong>체계적으로 스크리닝/정리</strong>하는 과정까지 다룬다.<br>-&gt; (전공/분야 상관없이 적용 가능한 프레임워크 + 보건/의생명 쪽 예시 포함)</p>
<hr>
<h3 id="문헌-검색">문헌 검색</h3>
<p>문헌 검색에서 가장 큰 실수는 &#39;일단 검색창에 넣고 많이 읽자&#39;이다. 실제 연구에서는 <strong>검색의 목표</strong>가 명확해야 한다.
쉽게 생각하면 구글, 네이버 창을 열어 그저 &#39;검색&#39;을 하면 되는 것 같지만, 학술적인 검색을 위해서는 핵심질문을 설정하고, 검색전략 수립, 검색원 선정, 검색어의 선택과 조합 등 일련의 과정이 필요하다.</p>
<blockquote>
<ul>
<li>핵심 질문 설정</li>
</ul>
</blockquote>
<ul>
<li>검색 전략 수립</li>
<li>데이터베이스(DB) 선택</li>
<li>검색어/검색식 설계</li>
<li>스크리닝 및 기록(로그)</li>
</ul>
<p>그렇다면, 검색은 어떻게 하면 좋을까? 이또한 <strong>검색의 목표</strong>에 따라 다르다.</p>
<ul>
<li><strong>탐색적 검색</strong>: 주제 감 잡기, 키워드/연구흐름 파악</li>
<li><strong>논문 작성용 검색</strong>: 서론/배경/근거를 탄탄하게 만들기</li>
<li><strong>체계적 문헌고찰(SR/MA)용 검색</strong>: 재현 가능한 검색식 + 누락 최소화</li>
</ul>
<p>같은 &#39;문헌 검색&#39;이라도 목표가 다르면</p>
<ul>
<li>어디서 검색하는지(DB)</li>
<li>얼마나 넓게 찾는지(민감도)</li>
<li>무엇을 남기는지(스크리닝 로그)</li>
</ul>
<p>가 완전히 달라진다.</p>
<blockquote>
<p>검색에서도 <strong>민감도(Sensitivity)</strong>와 <strong>특이도(Specificity)</strong>를 생각해볼수 있다.</p>
<ul>
<li><strong>민감도</strong> : 검색에 의해 적절한 연구/문헌을 찾을 가능성
-&gt; 민감도가 높은 검색전략은 포괄적(comprehensive)인 검색</li>
<li><strong>특이도</strong> : 부적절한 연구/문헌을 배제할 가능성
-&gt; 특이도가 높은 검색전략은 특정 문제에 대한 중요한 연구를 집중해서 포함하는 것을 목적으로 함</li>
</ul>
</blockquote>
<blockquote>
<p>cf) 민감도와 특이도는 상쇄 관계라 목적에 따라 균형이 달라진다(예: SR/MA는 민감도 우선)</p>
</blockquote>
<h4 id="검색-전-확인-사항">검색 전 확인 사항</h4>
<p>당장 무언가를 검색엔진에서 검색하기 이전에 아래에 정리되는 것을 정리하면 효율이 확 올라간다.</p>
<p><strong>1. 핵심 질문(Research Question)</strong></p>
<ul>
<li>내가 진짜 알고 싶은 것은 무엇인가?</li>
</ul>
<p>*<em>2. 범위(Scope) *</em></p>
<ul>
<li>기간 : 예) 2015-2026</li>
<li>대상 : 예) 인간 / 동물 / 세포, 연령대, 지역 등</li>
<li>연구유형 : 예) RCT, cohort, cross-sectional, qualitative 등</li>
<li>언어 : 예) 한국어 / 영어 등</li>
</ul>
<h4 id="검색어-선정">검색어 선정</h4>
<p>검색어는 핵심 질문에 잠재적으로 관련된 문헌을 최대한 포함하기 위해, 보통은 폭넓게(민감도 높게) 설계한다.</p>
<p><del>(사실 이 글의 기반은 나중에 소개할 체계적 문헌고찰 / 메타분석의 기반이 되는 개념들이 많다)</del></p>
<p><strong>(1) 핵심 질문 분해</strong>
핵심질문을 분해하여 개별요소 형태로 정리 각 개별요소에서 주요 개념어를 도출한다.</p>
<ul>
<li>민감도를 높이기 위해 의학주제어, 유의어, 대안어 등을 활용할 수 있음 </li>
<li>포괄적이고 정확한 검색을 위해 논리연산자 혹은 절단 검색 기능을 활용함</li>
</ul>
<p>ex1) PICO (임상/중재)</p>
<ul>
<li><strong>P</strong>opulation (대상)</li>
<li><strong>I</strong>ntervention (중재)</li>
<li><strong>C</strong>omparator (비교)</li>
<li><strong>O</strong>utcome (결과)</li>
</ul>
<p>예) 청소년 비만 예방을 위한 모바일 앱 중재가 BMI를 낮추는가?</p>
<ul>
<li>참고 : 일반적으로 특정 의료 결과로만 분석할 경우를 제외하고 PICO중 결과/성과(O)에 해당하는 검색어는 검색식에 포함하지 않는 것을 권장</li>
</ul>
<p>ex2) PECO (노출/역학)</p>
<ul>
<li><strong>P</strong>opulation</li>
<li><strong>E</strong>xposure (노출)</li>
<li><strong>C</strong>omparator</li>
<li><strong>O</strong>utcome</li>
</ul>
<p>예) “청소년에서 패스트푸드 섭취(노출)가 비만(결과)과 관련 있는가?”</p>
<p>ex3) SPIDER (질적 연구)</p>
<ul>
<li>Sample / Phenomenon of Interest / Design / Evaluation / Research type</li>
</ul>
<p>각각을 질문을 검색식으로 바꾸는 프레임워크라고 한다. 
프레임워크는 &#39;모든 요소를 다 넣는 게 정답이 아니라, <strong>내가 검색에서 반드시 걸어야 하는 핵심 요소만 뽑는 도구</strong>이다.</p>
<p><strong>(2) 키워드의 표현 방식</strong></p>
<p>연구질문 중 청소년 비만에 대해 생각해보자. 검색을 진행한다고했을때, 비단 한가지 방법과 검색어로 적용할 수 있는 것이 아니다. 검색어는 아래와 같이 여러가지 종류로 나눠질 수 있다.</p>
<p>1) <strong>자연어(Free text)</strong><br>일상적으로 우리가 사용하는 자연어를 기반으로 작성할 수 있는 검색어를 말한다. </p>
<p>예) adolescent obesity, teen obesity, youth obesity</p>
<p>2) <strong>통제어(Controlled vocabulary)</strong> </p>
<ul>
<li>PubMed: MeSH  </li>
<li>Embase: Emtree<br>예) obesity[MeSH], adolescent[MeSH]</li>
</ul>
<blockquote>
<p>MeSH : 의학주제어 혹은 의학주제표목(Medical Subjects Headings)</p>
<ul>
<li>미국의학도서관에서 색인을 위해 구축한 계층적인 용어구조</li>
<li>Medline, Cocharne library, PsyclNFO 등 DB에서 제공</li>
</ul>
</blockquote>
<p>3) <strong>유의어 / 대안어</strong></p>
<ul>
<li>약어, 유의어, 미국식 / 영국식 용어 차이 </li>
</ul>
<p>예1) overweight, body mass index, BMI
예2) 암 : cancer, carcinoma, tumor, neoplasm</p>
<ul>
<li>adolescen* (truncation)</li>
</ul>
<p><strong>(3) 검색식 조합</strong></p>
<p><strong>1) 불리언 연산자</strong></p>
<ul>
<li>OR : 주로 비슷한 개념을 포함시킬 떄 사용. 합집합 개념(AUB)
ex) (adolescent OR teen OR youth)</li>
<li>AND : 주로 서로 다른 개념을 합칠 때 사용. 교집합 개념(A∩B) 
ex) (adolescent OR teen OR youth) AND (obesity OR overweight)</li>
<li>NOT : 차집합(A-B) 개념. 필요한 단어가 제거되지 않도록 주의하여 사용
(obesity) NOT (mouse OR mice)</li>
</ul>
<p><strong>2) 절단 검색</strong></p>
<ul>
<li><p>$ 또는 * </p>
<ul>
<li>어미에 붙이는 검색어로 제한 없이 검색됨<ul>
<li>예) Cardio* → Cardiology (심장내과, 진료과), Cardiovascular disease (심혈관 질환, CVD), Cardiomyopathy (심근병증, 세부 질환), Cardiologist (심장전문의, 전문가)</li>
</ul>
</li>
</ul>
</li>
<li><p>#</p>
<ul>
<li>단어 내 혹은 어미에 붙이는 검색어로 정확히 한 문자만 치환하여 검색됨<ul>
<li>예) wom#n -&gt; woman, women</li>
</ul>
</li>
</ul>
</li>
<li><p>?</p>
<ul>
<li>단어 내 혹은 어미에 붙이는 검색어로 한 글자 이하로(0 또는 1) 치환하여 검색됨</li>
<li>예) tum?r : tumor, tumour</li>
</ul>
</li>
</ul>
<p>참고 : 절단 / 와일드카드는 DB마다 문법이 다르므로, 검색 시작 전에 해당 DB의 wildcard 규칙(*, ?, # 등)을 먼저 확인하는 것이 안전하다.</p>
<h4 id="데이터-베이스-선택">데이터 베이스 선택</h4>
<ul>
<li><strong>PubMed/MEDLINE</strong>: 의생명 기본, MeSH 강력, 무료</li>
<li><strong>Embase</strong>: 약물/임상/유럽 커버리지 강함, Emtree 강력(유료)</li>
<li><strong>Scopus</strong>: 광범위(공학/사회과학 포함), 인용분석 편함(유료)</li>
<li><strong>Web of Science</strong>: 인용 네트워크/핵심 저널 중심(유료)</li>
<li><strong>Google Scholar</strong>: 넓게 잡히지만 노이즈 많음, 재현성 약함</li>
<li><strong>Cochrane Library</strong>: SR/RCT 중심</li>
</ul>
<p>현실적으로 보통 모든 데이터 베이스를 보지는 않고, 논문 작성용은 성향이 적절한 1개만 선택하여 주로 보고, 체계적 문헌 고찰 같은 방법론적인 탐색을 할때는 3개 이상을 보게된다.</p>
<h4 id="검색결과-정리">검색결과 정리</h4>
<p>검색이 끝났다면, 이제부터는 ‘읽기’가 아니라 ‘정리’의 단계이다. 이 과정을 체계적으로 하지 않으면, 같은 논문을 여러 번 읽거나, 중요한 논문을 놓치는 일이 발생한다.</p>
<p>보통은 EndNote, Zotero 같은 서지관리 프로그램을 이용해 문헌을 정리한다.
(해당 프로그램 사용법은 차후에 별도로 다루도록 하자.)
정리를 하는 방법은 연구자 마다 다르지만, 간단하게 내가 하는 방식을 소개해보자면 아래와 같다. </p>
<p>** 기본정리 단계**</p>
<blockquote>
<ol>
<li>검색 결과 전체 다운로드
  → 가능하면 RIS / BibTeX 형식으로 저장<ol start="2">
<li>중복 제거(Deduplication)
→ 여러 DB에서 검색했다면 중복 문헌이 반드시 발생
→ 프로그램의 자동 중복 제거 기능 + 수동 확인 병행</li>
<li>폴더 / 컬렉션 분류</li>
</ol>
</li>
</ol>
</blockquote>
<p>** 추가 정리**</p>
<p>체계적 접근을 위해 아래를 기록해두면 좋다.</p>
<blockquote>
</blockquote>
<ol>
<li>검색 DB (예: PubMed, Embase)</li>
<li>검색 날짜</li>
<li>사용한 검색식</li>
<li>검색 결과 건수</li>
<li>포함/제외 기준</li>
</ol>
<p>이 기록은 <strong>재현 가능성(reproducibility)</strong>을 보장하는 핵심 요소이고, 특히 연구적으로 검색을 사용하는 SR/MA를 진행할 경우 필수적이다.</p>
<hr>
<p>오늘은 연구자들이 문헌을 검색하는 전략에 대해서 다뤄 보았다. 실질적으로 학부연구생과 석사과정 총 4년의 기간에서 크게 느꼈던 어려움 중에 하나는 바로 &#39;논문&#39;읽기였다. 
결국 연구라는 것은 &#39;거인의 어깨(Standing on the shoulders of giants)&#39;위에 올라타서 지식의 지평을 넓히는 과정이다.
그러한 연구의 시작인 논문 읽기를 이 글을 통해 조금은 친숙해지셨으면 한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] 인터페이스(Interface)]]></title>
            <link>https://velog.io/@u_yonu/Java-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4Interface</link>
            <guid>https://velog.io/@u_yonu/Java-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4Interface</guid>
            <pubDate>Fri, 13 Feb 2026 07:09:59 GMT</pubDate>
            <description><![CDATA[<h3 id="인터페이스interface">인터페이스(Interface)</h3>
<h4 id="인터페이스의-개념">인터페이스의 개념</h4>
<p> 인터페이스(Interface)는 원래 다양한 분야에서 쓰이는 용어로, 두 개체가 상호작용 하는 방식을 정의하는 경계를 의미한다.
 예시) 개체 : 시스템/장치/프로그램 등
 즉, 서로 다른 두 대상이 같이 동작하기 위해 필요한 언어와 규칙(표준)을 정해주는 역할이다.
 이 규칙을 통해 내부가 복잡하더라도 사용자는 단순한 방식으로 기능을 활용가능하고, 다른 구성요소들도 동일한 규칙을 따라 일관되게 확장될 수 있다.</p>
<p>*<em>예시1) *</em>
두 개체: 노트북(시스템) ↔ USB 메모리/키보드/마우스(장치)
인터페이스(경계): USB 규격(포트 모양, 전압/신호, 통신 방식)</p>
<p>*<em>예시2) *</em>
두 개체: 쇼핑몰 서버(프로그램) ↔ 결제대행사 API(다른 프로그램)
인터페이스(경계): “결제 요청/응답” API 규격(필드명, 요청 방식, 응답 코드)</p>
<p><img src="https://velog.velcdn.com/images/u_yonu/post/da4eb807-3e92-4693-8ea0-485337aaae84/image.png" alt=""></p>
<h4 id="자바에서의-인터페이스">자바에서의 인터페이스</h4>
<p>자바에서의 인터페이스는 이러한 개념을 코드로 옮긴 것으로, 한마디로 완전히 추상화된 설계도(규격)이다.</p>
<ul>
<li><p>클래스와 문법적으로 비슷하지만 class 대신 interface 키워드를 사용</p>
</li>
<li><p>기본적으로 인터페이스의 메서드는 추상 메서드로 취급
(Java 8부터 default 메서드와 static 메서드가 추가되어 예외가 생김)</p>
</li>
<li><p>인터페이스에 선언된 메서드는 기본적으로 public abstract 이며 생략 가능</p>
</li>
<li><p>인터페이스에 선언된 변수는 자동으로 public static final(상수)로 간주되며 생략 가능</p>
</li>
</ul>
<h4 id="인터페이스의-구현">인터페이스의 구현</h4>
<ul>
<li>인터페이스는 인스턴스를 직접 생성할 수 없음</li>
<li>따라서 인터페이스를 사용하려면, 클래스가 implements 키워드로 구현(implements) 해야 함</li>
</ul>
<p>예시 코드) </p>
<pre><code>interface Basic {}
class Advanced extends Basic{}
=&gt; 불가능
class Advanced implements Basic{}
=&gt; 가능</code></pre><ul>
<li><p>하나의 클래스는 여러 개의 인터페이스를 다중 구현할 수 있음</p>
</li>
<li><p>구현 클래스는 인터페이스에 선언된 모든 추상 메서드를 반드시 구현(override) 해야 객체를 생성할 수 있음</p>
</li>
<li><p>만약 일부만 구현한다면, 그 클래스는 추상 클래스(abstract class) 로 선언되어야함 
<img src="https://velog.velcdn.com/images/u_yonu/post/9a18296c-ab9d-4be8-81b7-3988d0c4bfd3/image.png" alt=""></p>
</li>
</ul>
<h4 id="인터페이스의-상속">인터페이스의 상속</h4>
<ul>
<li><p>인터페이스는 extends 키워드를 사용해 다른 인터페이스를 상속</p>
</li>
<li><p>클래스와 달리 인터페이스는 다중 상속이 가능
(일반적으로 구현부 없이 규격(메서드 선언)만 정의하므로 충돌 위험이 상대적으로 적기 때문)</p>
</li>
</ul>
<h4 id="default-메서드-java-8">default 메서드 (Java 8+)</h4>
<ul>
<li><p>인터페이스에도 구현부가 있는 메서드를 정의할 수 있음
→ 선언 시 메서드 앞에 default 키워드를 반드시 붙임</p>
</li>
<li><p>접근 제한자는 public만 가능하며, public은 생략 가능</p>
</li>
<li><p>구현 클래스는 필요하면 default 메서드를 재정의(override) 할 수 있음</p>
</li>
<li><p>기존 인터페이스에 메서드를 추가해야 할 때, 모든 구현 클래스가 한꺼번에 깨지는 문제를 줄이기 위해 사용
→ 기본 구현을 인터페이스에 제공하므로, 구현체가 반드시 구현할 필요는 없음</p>
</li>
</ul>
<p>cf) default method 충돌 해결</p>
<ul>
<li>여러 인터페이스의 디폴트 메서드 간의 충돌
  → 구현 클래스에서 오버라이딩</li>
<li>디폴트 메서드와 조상 클래스의 메서드 간의 충돌
  → 자동으로 조상 클래스 상속</li>
</ul>
<h4 id="정적static-메서드-java-8">정적(static) 메서드 (Java 8+)</h4>
<ul>
<li><p>인터페이스에도 static 메서드를 선언할 수 있으며, 사용 방식은 클래스의 static 메서드와 동일</p>
</li>
<li><p>호출은 인터페이스명.메서드() 형태로 함 (구현 클래스의 객체로 호출하지 않음)</p>
</li>
<li><p>해당 인터페이스와 관련된 유틸리티/헬퍼 기능을 제공할 때 유용</p>
</li>
<li><p>static 메서드는 구현 클래스에 상속되지 않으며, 구현 클래스에서 재정의(override) 할 수도 없음</p>
</li>
</ul>
<h4 id="private-메서드java-9">private 메서드(Java 9+)</h4>
<ul>
<li>인터페이스 내부에서만 사용되는 헬퍼 메서드</li>
<li>디폴트 메서드, 정적 메서드에서 반복되는 로직 분리 후 작성</li>
<li>외부에서 접근하지 못하도록 숨김</li>
<li>재사용성 증가</li>
<li>static 키워드를 사용할 수 있음
<img src="https://velog.velcdn.com/images/u_yonu/post/362e1eb6-70c8-434f-b2c8-3e0e174a8258/image.png" alt=""></li>
</ul>
<h4 id="인터페이스와-다형성">인터페이스와 다형성</h4>
<ul>
<li>인터페이스를 구현한 클래스로 만든 객체는 해당 인터페이스 타입으로 참조할 수 있음</li>
<li>동적 바인딩 : 런타임 시점에서는 실제 객체의 메서드가 호출</li>
</ul>
<h4 id="인터페이스의-필요성">인터페이스의 필요성</h4>
<table>
<thead>
<tr>
<th>인터페이스 특징</th>
<th>내용</th>
</tr>
</thead>
<tbody><tr>
<td>표준화 처리 가능</td>
<td>여러 클래스들이 동일한 인터페이스를 구현하여 일관된 방식으로 동작 처리</td>
</tr>
<tr>
<td>개발 기간 단축 가능</td>
<td>시스템 구조를 먼저 설계하고, 각 부분을 독립적으로 개발하여 개발 기간 단축</td>
</tr>
<tr>
<td>서로 관계가 없는 클래스들 간의 관계 형성</td>
<td>관련이 없는 클래스들이 동일한 인터페이스를 구현하여 공통된 동작 공유</td>
</tr>
<tr>
<td>간접적인 클래스 사용으로 모듈 교체 용이</td>
<td>구체적인 클래스에 의존하지 않고 인터페이스를 통해 클래스 사용, 모듈 교체 용이</td>
</tr>
<tr>
<td>독립적 프로그래밍 가능</td>
<td>각 클래스가 독립적으로 개발 및 테스트 가능, 코드 재사용성과 유지보수성 향상</td>
</tr>
<tr>
<td>다형성 지원</td>
<td>같은 인터페이스를 구현하는 객체들을 일관되게 처리하여 코드 유연성과 확장성 증가</td>
</tr>
<tr>
<td>설계의 유연성 제공</td>
<td>클래스 간의 강한 결합을 피하여 설계의 유연성 증가, 시스템 변경 및 확장 시 영향 최소화</td>
</tr>
</tbody></table>
<h4 id="클래스-vs-인터페이스">클래스 vs 인터페이스</h4>
<table>
<thead>
<tr>
<th>구분</th>
<th>클래스</th>
<th>인터페이스</th>
</tr>
</thead>
<tbody><tr>
<td>특징</td>
<td><code>class</code> 키워드를 사용하여 정의<br>필드와 메서드, 생성자로 이루어짐</td>
<td><code>interface</code> 키워드를 사용하여 정의<br><code>static</code> 상수와 추상메서드(메서드 선언부)로 이루어짐<br><code>public static final</code> 생략 가능<br><code>public abstract</code> 생략 가능</td>
</tr>
<tr>
<td>관계</td>
<td>인터페이스를 구현함</td>
<td>클래스에 의해 구현됨</td>
</tr>
<tr>
<td>멤버 변수</td>
<td>선언 가능</td>
<td>상수만 가능</td>
</tr>
<tr>
<td>다중 상속</td>
<td>클래스는 하나의 클래스만 상속 가능</td>
<td>인터페이스는 여러 개의 인터페이스 상속 가능<br>(구현부가 없으므로 헷갈리지 않음)</td>
</tr>
<tr>
<td>다중 구현</td>
<td>클래스는 여러 개의 인터페이스를 다중으로 구현(<code>implements</code>) 가능</td>
<td></td>
</tr>
<tr>
<td>인스턴스</td>
<td>생성 가능</td>
<td>생성 불가</td>
</tr>
<tr>
<td>타입</td>
<td>타입으로 사용 가능</td>
<td>타입으로 사용 가능</td>
</tr>
</tbody></table>
<h4 id="추상클래스-vs-인터페이스">추상클래스 vs 인터페이스</h4>
<table>
<thead>
<tr>
<th>구분</th>
<th>추상 클래스</th>
<th>인터페이스</th>
</tr>
</thead>
<tbody><tr>
<td>객체생성</td>
<td>불가</td>
<td>불가</td>
</tr>
<tr>
<td>일반 메소드</td>
<td>가능</td>
<td>불가</td>
</tr>
<tr>
<td>일반 필드</td>
<td>가능</td>
<td>불가(<code>static</code> 상수만 가능)</td>
</tr>
<tr>
<td>메서드</td>
<td><code>abstract</code>를 붙여야만 추상 메서드</td>
<td>모든 메서드는 추상 메서드</td>
</tr>
<tr>
<td>사용</td>
<td>- 추상적인 클래스의 성격을 가질 때(일부 메서드만 미완성 설계도)<br>- 서로 유사한 클래스 사이에 코드를 공유하고 싶을 때</td>
<td>- 서로 관련 없는 클래스 사이에 공통으로 적용되는 인터페이스를 구현하게 하기 원할 때 (ex) <code>Comparable</code>, <code>Serializable</code><br>- 객체(클래스)의 어떤 기능을 구현하고 있다는 “약속”의 성격이 있을 때</td>
</tr>
<tr>
<td>공통점</td>
<td>- 특정 기능의 구현을 강제하고 싶을 때<br>- 다형성 가능<br>- 보다 추상화된 설계도에 의존하는 코드를 작성하고 싶을 때<br>- 타입으로 사용 가능</td>
<td>- 특정 기능의 구현을 강제하고 싶을 때<br>- 다형성 가능<br>- 보다 추상화된 설계도에 의존하는 코드를 작성하고 싶을 때<br>- 타입으로 사용 가능</td>
</tr>
</tbody></table>
<hr>
<p>슬슬 복잡해지는 Java의 구조
복잡과 익숙해짐의 사이</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] 추상 클래스(Abstract Class)]]></title>
            <link>https://velog.io/@u_yonu/Java-%EC%B6%94%EC%83%81-%ED%81%B4%EB%9E%98%EC%8A%A4Abstract-Class</link>
            <guid>https://velog.io/@u_yonu/Java-%EC%B6%94%EC%83%81-%ED%81%B4%EB%9E%98%EC%8A%A4Abstract-Class</guid>
            <pubDate>Fri, 13 Feb 2026 07:06:24 GMT</pubDate>
            <description><![CDATA[<h4 id="추상-클래스-정의">추상 클래스 정의</h4>
<p>추상클래스에 대해서 생각해보자. 예를 들어 백엔드 개발자, 프론트엔드 개발자는 모두 develop()이라는 동작이 필요하다. 이 공통 동작을 조상 클래스 Developer에 선언하고, 각 자손 클래스가 자기 방식대로 override 하도록 만들고 싶다.</p>
<p>그런데, 여기서 문제가 생긴다.</p>
<ul>
<li><p>Developer 자체는 실제로 “개발”을 수행하는 구체 객체로 쓰이지 않는다.
(실제로는 백엔드/프론트엔드처럼 구체적인 개발자가 일을 한다.)</p>
</li>
<li><p>develop()은 자식 클래스에서 반드시 재정의해서 사용될 메서드라, 조상 Developer에서 구현을 만들어도 의미가 없다.</p>
</li>
<li><p>따라서 Developer에서는 메서드의 선언부만 남기고 구현부를 비워두는 방식이 더 적절하다</p>
</li>
<li><p>추상 메서드(abstract method) : 구현부가 없는 메서드</p>
<ul>
<li>구현부가 없으므로 ;로 끝남</li>
<li>추상 메서드에는 abstract 키워드를 붙임</li>
</ul>
</li>
<li><p>추상 클래스(abstract class) : 추상 메서드를 가진 클래스</p>
<ul>
<li>추상 메서드를 가진 클래스는 객체 생성이 불가능하다는 의미로 클래스에도 abstract를 붙임</li>
</ul>
</li>
</ul>
<p>예시)</p>
<pre><code>abstract class Developer {
    protected String name;
    protected int years;

    public Developer(String name, int years) {
        this.name = name;
        this.years = years;
    }

    // 공통 동작(재사용 가능)
    public void attendStandup() {
        System.out.println(name + &quot; : 데일리 스탠드업 참여&quot;);
    }

    public void reviewCode() {
        System.out.println(name + &quot; : 코드 리뷰 진행&quot;);
    }

    // 자식 클래스가 반드시 구현해야 하는 핵심 동작
    public abstract void develop();
}

class BackendDeveloper extends Developer {
    public BackendDeveloper(String name, int years) {
        super(name, years);
    }

    @Override
    public void develop() {
        System.out.println(name + &quot; : API 개발 / DB 설계&quot;);
    }
}

class FrontendDeveloper extends Developer {
    public FrontendDeveloper(String name, int years) {
        super(name, years);
    }

    @Override
    public void develop() {
        System.out.println(name + &quot; : UI 구현 / 상태 관리&quot;);
    }
}
</code></pre><h4 id="추상-클래스-특징">추상 클래스 특징</h4>
<p>abstract class는 상속 전용 클래스로 사용된다. 따라서 추상 메서드(구현부가 없는 메스드)가 존재할 수 있으므로, 객체 생성이 불가능하다.
대신, 상위 클래스 타입으로 자식 객체를 참조 가능 </p>
<pre><code>Developer dev = new BackendDeveloper(&quot;Yonu&quot;, 2); // O
dev.develop(); // BackendDeveloper의 develop() 실행
</code></pre><p>*** 자식 클래스가 상속받은 추상 메서드를 재정의 하지 않으면 그 자식 클래스도 추상 클래스가 되어야함 </p>
<pre><code>abstract class LazyDeveloper extends Developer {
    public LazyDeveloper(String name, int years) {
        super(name, years);
    }
    // develop()을 구현하지 않았으므로 추상 클래스여야 함
}

</code></pre><h4 id="추상-클래스-사용-목적">추상 클래스 사용 목적</h4>
<p>(1) 공통 설계 강제</p>
<p>하위 클래스가 반드시 구현해야 하는 메서드를 추상 메서드로 제공하여 구현을 강제한다.</p>
<p>(2) 코드 재사용성 향상</p>
<p>공통 필드/공통 메서드를 상위 클래스에 두고 하위 클래스가 재사용할 수 있다.</p>
<p>(3) 일관성 유지</p>
<p>같은 이름/형태의 메서드를 반드시 갖도록 하여, 하위 클래스들이 동일한 규격으로 동작하게 만든다.</p>
<p>(4) 다형성 지원</p>
<p>상위 타입으로 묶어 처리할 수 있어 유연한 설계가 가능하다.</p>
<h4 id="클래스-vs-추상-클래스">클래스 vs 추상 클래스</h4>
<table>
<thead>
<tr>
<th>구분</th>
<th>클래스</th>
<th>추상 클래스</th>
</tr>
</thead>
<tbody><tr>
<td>정의</td>
<td>구체적인 객체(인스턴스)를 생성할 수 있는 클래스</td>
<td>추상 메서드를 포함할 수 있는 클래스<br>객체(인스턴스) 생성이 불가능한 클래스<br>추상적 개념의 구체적인 객체 생성이 논리적으로 맞지 않는 클래스, 객체 생성이 필요 없는 클래스</td>
</tr>
<tr>
<td>객체 생성</td>
<td>가능</td>
<td>불가</td>
</tr>
<tr>
<td>추상 메서드</td>
<td>포함 불가</td>
<td>추상 메서드를 포함할 수 있음<br>(추상 메서드 없어도 추상 클래스 생성 가능 - 객체 생성을 못하도록 강제)</td>
</tr>
<tr>
<td>상속</td>
<td>다른 클래스에 의해 상속될 수 있음</td>
<td>다른 클래스에 의해 상속되면 추상 메서드가 구현되어야만 객체 생성 가능(세부 구현 강제)<br>만약 하위 클래스가 추상 메서드를 모두 구현하지 않으면 하위 클래스도 추상 클래스</td>
</tr>
<tr>
<td>키워드</td>
<td><code>class</code> 키워드 사용</td>
<td><code>abstract class</code> 키워드 사용</td>
</tr>
<tr>
<td>목적</td>
<td>완전한 클래스를 정의하여, 해당 클래스로 객체를 생성하기 위함</td>
<td>객체 생성 방지, 공통된 기본 기능을 정의(코드 중복 제거), 하위 클래스에서 세부 구현을 강제</td>
</tr>
<tr>
<td>타입</td>
<td>타입으로 사용 가능</td>
<td>타입으로 사용 가능</td>
</tr>
</tbody></table>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] 다형성(Polymorphism)]]></title>
            <link>https://velog.io/@u_yonu/Java-%EB%8B%A4%ED%98%95%EC%84%B1Polymorphism</link>
            <guid>https://velog.io/@u_yonu/Java-%EB%8B%A4%ED%98%95%EC%84%B1Polymorphism</guid>
            <pubDate>Fri, 13 Feb 2026 06:39:32 GMT</pubDate>
            <description><![CDATA[<h3 id="다형성polymorphism">다형성(Polymorphism)</h3>
<ul>
<li><p>하나의 객체를 여러 타입의 참조 변수로 다룰 수 있는 성질</p>
</li>
<li><p>즉, 서로 다른 여러 객체를 공통된 타입(상위 클래스/인터페이스) 으로 묶어 동일한 방식으로 처리할 수 있음</p>
</li>
<li><p>상속 관계에서는 부모(조상) 타입 참조 변수로 자식(자손) 객체를 참조할 수 있음</p>
</li>
<li><p>참조 타입이 바뀌어도 실제 객체는 그대로이며, 실행되는 동작(메서드)은 실제 객체 기준으로 결정(동적 바인딩)</p>
<blockquote>
<p>참조 타입 = “무엇으로 보느냐”
실제 객체 = “진짜 누구냐”
실행 결과는 진짜 누구냐(실제 객체) 를 따른다.</p>
</blockquote>
</li>
</ul>
<p>예시)</p>
<pre><code>Animal a = new Dog();   // Dog 객체를 Animal 타입으로 참조
a.sound();              // 호출은 Dog의 sound()가 실행됨
</code></pre><h4 id="다형성의-장점">다형성의 장점</h4>
<ul>
<li><p><strong>유연성</strong> 
상위 클래스 또는 인터페이스 타입 하나로 다양한 구현 객체를 처리할 수 있어, 객체를 쉽게 교체할 수 있다.</p>
</li>
<li><p>*<em>재사용성 *</em>
공통 로직은 상위 클래스(또는 공통 인터페이스 기반의 공통 처리 코드)에 모으고, 각 클래스는 필요한 부분만 구현해 중복을 줄일 수 있다.</p>
</li>
<li><p><strong>확장성</strong>
새로운 클래스(새 구현체)를 추가해도, 기존 코드는 상위 타입(인터페이스)에만 의존하므로 클라이언트 코드 변경 없이 확장이 가능하다.</p>
</li>
<li><p><strong>유지보수성</strong> 
변경이 생겼을 때 영향 범위를 줄일 수 있다.
구현이 바뀌어도 인터페이스(규격)는 유지하면 되고, 필요하면 구현체만 수정/교체하면 되므로 수정 범위가 작아진다.</p>
</li>
</ul>
<h4 id="다형성의-특징">다형성의 특징</h4>
<ul>
<li>상속 관계에 있을 때 조상 클래스 타입으로 자손 클래스 객체 참조 가능</li>
</ul>
<table>
<thead>
<tr>
<th>참조 타입 변수</th>
<th>인스턴스 생성</th>
<th>O / X</th>
<th>이유</th>
</tr>
</thead>
<tbody><tr>
<td><code>Payment p</code></td>
<td><code>new CardPay()</code></td>
<td>O</td>
<td><code>CardPay</code>는 <code>Payment</code>를 구현 → 상위 타입으로 참조 가능(업캐스팅)</td>
</tr>
<tr>
<td><code>Payment p</code></td>
<td><code>new KakaoPay()</code></td>
<td>O</td>
<td><code>KakaoPay</code>는 <code>Payment</code>를 구현 → 상위 타입으로 참조 가능(업캐스팅)</td>
</tr>
<tr>
<td><code>CardPay c</code></td>
<td><code>new CardPay()</code></td>
<td>O</td>
<td>같은 타입 객체 생성</td>
</tr>
<tr>
<td><code>CardPay c</code></td>
<td><code>new KakaoPay()</code></td>
<td>X</td>
<td>서로 다른 구현체(형제 관계) → 상속/구현 관계가 없어 참조 불가</td>
</tr>
<tr>
<td><code>Object o</code></td>
<td><code>new CardPay()</code></td>
<td>O</td>
<td>모든 클래스는 <code>Object</code>를 상속 → <code>Object</code>로 참조 가능</td>
</tr>
</tbody></table>
<h4 id="jvm-메모리힙-영역">JVM 메모리(힙 영역)</h4>
<p>실제 인터페이스 기반으로 객체를 생성할 때, JVM 메모리(힙 영역)에서 실제로 일아나는 일은 다음과 같다.</p>
<p>1) new KakaoPay()는 힙에 객체 1개를 만듬</p>
<pre><code>new KakaoPay()</code></pre><p>실행되면 Heap에 KakaoPay 인스턴스(객체) 1개가 생성된다.
이 표현식의 결과는 “객체 자체”가 아니라, 힙에 있는 객체를 가리키는 참조값(주소) 이다.
즉, 힙에는 KakaoPay 객체가 생기고, 그 주소를 다른 변수가 들고 있게 된다.</p>
<p>2) 아래 세 줄은 힙 객체 3개를 만듬 </p>
<pre><code>object obj = new KakaoPay() ;
Payment p = new KakaoPay() ;
Kakaopay kp = new KakaoPay() ;</code></pre><ul>
<li>위 코드는 new가 3번이므로, 힙에 KakaoPay 객체가 3개 생김</li>
<li>각각의 참조 변수(obj, p, kp)는 서로 다른 객체의 주소를 들고 있음</li>
</ul>
<p>3) 같은 힙 객체 1개를 여러 타입으로 참조하려면 아래와 같음</p>
<pre><code>KakaoPay real = new KakaoPay(); // Heap: 객체 1개

Object  obj = real;            // Stack: obj는 그 주소를 들고 있음
Payment p   = real;            // Stack: p도 같은 주소
KakaoPay kp = real;            // Stack: kp도 같은 주소</code></pre><ul>
<li>Heap에는 객체 1개</li>
<li>Stack에는 참조 변수 3개가 생기고,</li>
<li>세 변수는 전부 같은 주소(같은 객체) 를 가리킴</li>
</ul>
<p>4) 참조 타입이 다르면 &#39;보이는 범위&#39;가 달라짐
(1) Object obj</p>
<pre><code>obj.toString(); // O (Object에 있는 메서드)
</code></pre><ul>
<li>Object 타입이라 Object가 가진 기능만 보임</li>
</ul>
<p>(2) Payment p</p>
<pre><code>p.pay(1000);   // O (Payment 규격에 있는 메서드)
</code></pre><ul>
<li>Payment 타입이라 인터페이스에 선언된 메서드만 보임</li>
</ul>
<p>(3) KakaoPay kp</p>
<pre><code>kp.pay(1000);      // O
kp.kakaoOnly();    // O (KakaoPay 전용 메서드가 있다면)</code></pre><ul>
<li>구체 타입이라 KakaoPay 전용 기능까지 보임</li>
</ul>
<h4 id="참조변수의-형-변환">참조변수의 형 변환</h4>
<p>예시) 
KakaoPay implements Payment
CardPay implements Payment
그리고 모든 클래스는 Object를 상속</p>
<p>Object
↳ KakaoPay (그리고 Payment를 구현)
↳ CardPay (그리고 Payment를 구현)</p>
<ul>
<li>인터페이스는 상속이 아니라 구현이지만, 캐스팅 방향(위로/아래로) 개념은 똑같이 적용</li>
</ul>
<p>(1) 업캐스팅 : 자손 -&gt; 조상</p>
<ul>
<li>묵시적 형 변환 가능 </li>
<li>안전함 (무조건 성립)<pre><code>KakaoPay kp = new KakaoPay();
Payment p = kp;        // 업캐스팅 (생략 가능)
Object obj = kp;       // 업캐스팅 (생략 가능)
</code></pre></li>
</ul>
<p>p.pay(10000);      // O (Payment에 있음)
p.kakaoOnly();     // X (Payment에는 없음)</p>
<pre><code>(2) 다운캐스팅 : 조상 -&gt; 자손

* 명시적 형 변환 필요: (KakaoPay) p

* 항상 가능한 게 아님 (진짜 객체가 KakaoPay일 때만 가능)

잘못된 예시 1)</code></pre><p>Payment p = new CardPay();   // 실제 객체는 CardPay
KakaoPay kp = (KakaoPay) p;  // X (런타임 ClassCastException)</p>
<pre><code>p의 “타입”은 Payment지만 p가 가리키는 “실제 객체”가 CardPay라서 KakaoPay로 못바꿈


#### instanceof 연산자

instanceof는 &#39;참조 변수가 가리키는 실제 객체가 어떤 타입인지&#39; 확인할 때 쓴다.
-&gt; 결과를 boolean으로 반환
-&gt; true가 반환이 되면 해당 타입으로 형 변환 가능
</code></pre><p>Payment p = new KakaoPay();</p>
<p>p instanceof Payment   // true
p instanceof KakaoPay  // true
p instanceof CardPay   // false
p instanceof Object    // true</p>
<pre><code>사용 이유 : 다운캐스팅은 위험할 수 있어서
</code></pre><p>Payment p = new CardPay();</p>
<p>// 아래는 위험: 실제 객체가 CardPay인데 KakaoPay로 바꾸려 하면 런타임 에러
KakaoPay kp = (KakaoPay) p; // ClassCastException</p>
<pre><code>사용 예시</code></pre><p>Payment p = new KakaoPay();</p>
<p>if (p instanceof KakaoPay) {
    KakaoPay kp = (KakaoPay) p;
    kp.kakaoOnly();   // KakaoPay 전용 기능 사용
}</p>
<pre><code>cf) Java 16+ 패턴 매칭

* instanceof KakaoPay가 true면, kp 변수가 자동으로 KakaoPay 타입으로 선언된 것처럼 사용 가능
</code></pre><p>Payment p = new KakaoPay();</p>
<p>if (p instanceof KakaoPay kp) {
    kp.kakaoOnly();
}</p>
<p>```</p>
<h4 id="참조-변수와-인스턴스-멤버의-관계">참조 변수와 인스턴스 멤버의 관계</h4>
<ul>
<li>상속관계에서 멤버변수가 중복이 되면 참조 변수 타입에 따라 연결이 달라짐</li>
<li>메서드가 중복될 때(오버라이딩), 참조 변수의 타입에 상관없이 항상 실제 인스턴스의 자식 클래스 메서드가 호출 -&gt; 동적 바인딩</li>
<li>static 메서드는 참조변수 타입의 영향을 받기 때문에 이를 방지하고자 클래스 이름으로 메서드 호출(권장)</li>
</ul>
<hr>
<p>객체 지향 프로그래밍에서 특성 중 하나인 &#39;다형성&#39;에 대한 설명</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[APS] SWEA 1984 : 중간 평균값 구하기]]></title>
            <link>https://velog.io/@u_yonu/APS-SWEA-1984-%EC%A4%91%EA%B0%84-%ED%8F%89%EA%B7%A0%EA%B0%92-%EA%B5%AC%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@u_yonu/APS-SWEA-1984-%EC%A4%91%EA%B0%84-%ED%8F%89%EA%B7%A0%EA%B0%92-%EA%B5%AC%ED%95%98%EA%B8%B0</guid>
            <pubDate>Thu, 12 Feb 2026 07:10:07 GMT</pubDate>
            <description><![CDATA[<h3 id="개요">개요</h3>
<p>SWEA 1984 : 중간 평균값 구하기
<a href="https://swexpertacademy.com/main/talk/solvingClub/problemView.do?solveclubId=AZwN4TXKkEzHBIT3&amp;contestProbId=AV5Pw_-KAdcDFAUq&amp;probBoxId=AZwbqzR60ljHBIPa&amp;type=PROBLEM&amp;problemBoxTitle=day_0202_Array1&amp;problemBoxCnt=3">SWEA 1984 : 중간 평균값 구하기</a></p>
<h3 id="문제-분석">[문제 분석]</h3>
<p>10개의 수를 입력 받아, 최대 수와 최소 수를 제외한 나머지의 평균값을 출력하는 프로그램을 작성하라.</p>
<p>(소수점 첫째 자리에서 반올림한 정수를 출력한다.)</p>
<h3 id="제약-사항">[제약 사항]</h3>
<p>각 수는 0 이상 10000 이하의 정수이다.</p>
<h4 id="입력">[입력]</h4>
<p>가장 첫 줄에는 테스트 케이스의 개수 T가 주어지고, 그 아래로 각 테스트 케이스가 주어진다.
각 테스트 케이스의 첫 번째 줄에는 10개의 수가 주어진다.</p>
<h4 id="출력">[출력]</h4>
<p>출력의 각 줄은 &#39;#t&#39;로 시작하고, 공백을 한 칸 둔 다음 정답을 출력한다.
(t는 테스트 케이스의 번호를 의미하며 1부터 시작한다.)</p>
<h4 id="풀이-전략">[풀이 전략]</h4>
<p>처음 생각했을 때, 생각했던 로직은 다음과 같다
(1) 정수를 배열로 받는다.
(2) 조건문을 이용해서
(3) 맥스값 프린트 </p>
<h4 id="구현코드">[구현코드]</h4>
<pre><code>import java.util.Scanner;

public class Solution {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        int T = sc.nextInt();  // 테스트 케이스 수

        for (int t = 1; t &lt;= T; t++) {
            int max = 0;

            for (int i = 0; i &lt; 10; i++) {
                int num = sc.nextInt();
                if (num &gt; max) {
                    max = num;
                }
            }

            System.out.println(&quot;#&quot; + t + &quot; &quot; + max);
        }

        sc.close();
    }
}</code></pre><h4 id="개선사항">[개선사항]</h4>
<ol>
<li><p>max 함수 활용 
if (num &gt; max) {</p>
<pre><code>             max = num;
         }</code></pre><p>이 과정을 기반으로 Math 함수인 max를 이용해서 작성할 수 있다.</p>
</li>
<li><p>개선 코드 </p>
<pre><code>package test;
</code></pre></li>
</ol>
<p>import java.util.Scanner;</p>
<p>public class Solution {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);</p>
<pre><code>    int T = sc.nextInt();  // 테스트 케이스 수

    for (int t = 1; t &lt;= T; t++) {
        int max = 0;

        for (int i = 0; i &lt; 10; i++) {
            int num = sc.nextInt();
            max = Math.max(max, num);

        }

        System.out.println(&quot;#&quot; + t + &quot; &quot; + max);
    }

    sc.close();
}</code></pre><p>}</p>
<pre><code>



---
※ SW Expert 아카데미의 문제를 무단 복제하는 것을 금지합니다.
해당 문제는 개인 학습을 위한 비상업적 용도로 사용한 글입니다.</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[APS] 백준 13458 : 시험 감독]]></title>
            <link>https://velog.io/@u_yonu/APS-%EB%B0%B1%EC%A4%80-13458-%EC%8B%9C%ED%97%98-%EA%B0%90%EB%8F%85</link>
            <guid>https://velog.io/@u_yonu/APS-%EB%B0%B1%EC%A4%80-13458-%EC%8B%9C%ED%97%98-%EA%B0%90%EB%8F%85</guid>
            <pubDate>Thu, 12 Feb 2026 06:16:08 GMT</pubDate>
            <description><![CDATA[<h3 id="개요">개요</h3>
<p>문제 : 백준 13458 : 시험 감독
<a href="https://www.acmicpc.net/problem/13458">백준 13458 : 시험 감독</a></p>
<h3 id="문제-분석">[문제 분석]</h3>
<p>총 N개의 시험장이 있고, 각각의 시험장마다 응시자들이 있다. i번 시험장에 있는 응시자의 수는 Ai명이다.</p>
<p>감독관은 총감독관과 부감독관으로 두 종류가 있다. 총감독관은 한 시험장에서 감시할 수 있는 응시자의 수가 B명이고, 부감독관은 한 시험장에서 감시할 수 있는 응시자의 수가 C명이다.</p>
<p>각각의 시험장에 총감독관은 오직 1명만 있어야 하고, 부감독관은 여러 명 있어도 된다.</p>
<p>각 시험장마다 응시생들을 모두 감시해야 한다. 이때, 필요한 감독관 수의 최솟값을 구하는 프로그램을 작성하시오.</p>
<h4 id="입력">[입력]</h4>
<p>첫째 줄에 시험장의 개수 N(1 ≤ N ≤ 1,000,000)이 주어진다.</p>
<p>둘째 줄에는 각 시험장에 있는 응시자의 수 Ai (1 ≤ Ai ≤ 1,000,000)가 주어진다.</p>
<p>셋째 줄에는 B와 C가 주어진다. (1 ≤ B, C ≤ 1,000,000)</p>
<h4 id="출력">[출력]</h4>
<p>각 시험장마다 응시생을 모두 감독하기 위해 필요한 감독관의 최소 수를 출력한다.</p>
<h4 id="풀이-전략">[풀이 전략]</h4>
<p>풀이 전에 문제를 정리를 해보자.</p>
<ol>
<li>N개 시험장에 A[i]에 해당하는 사람들이 있으니까 그렇게 수열을 만들어줘서 받자</li>
<li>총시험관은 꼭 한명씩 있어야하고 따라서 A[i] -B 만큼을 부시험관들로 해결해야한다. 
(A[i]-B)/C를 구하고 
(A[i]-B)%C 남는 사람들은 +1을 해서 부 시험관 수를 구해야한다.</li>
</ol>
<h4 id="구현코드">[구현코드]</h4>
<pre><code>package test;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    int N = sc.nextInt();
    int[] student = new int[N];
    for(int i = 0; i&lt;N ; i++) student[i] = sc.nextInt();
    int B = sc.nextInt();
    int C = sc.nextInt();
    long sum = 0;
    for(int i = 0; i&lt;N ; i++) {
        sum++;
        if(student[i] &gt; B) {
        int remain = student[i]-B;
        sum += remain/C;
        if (remain%C &gt;0)
            sum++;
        }



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









</code></pre><hr>
<p>오늘은 1+1 야미 끝 </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[APS] 백준 10815 : 숫자 카드]]></title>
            <link>https://velog.io/@u_yonu/APS-%EB%B0%B1%EC%A4%80-10815-%EC%88%AB%EC%9E%90-%EC%B9%B4%EB%93%9C</link>
            <guid>https://velog.io/@u_yonu/APS-%EB%B0%B1%EC%A4%80-10815-%EC%88%AB%EC%9E%90-%EC%B9%B4%EB%93%9C</guid>
            <pubDate>Thu, 12 Feb 2026 04:21:54 GMT</pubDate>
            <description><![CDATA[<h3 id="개요">개요</h3>
<p>문제 : 백준 10815 : 숫자 카드
<a href="https://www.acmicpc.net/problem/10815">백준 10815 : 숫자 카드</a></p>
<h3 id="문제-분석">[문제 분석]</h3>
<p>숫자 카드는 정수 하나가 적혀져 있는 카드이다. 상근이는 숫자 카드 N개를 가지고 있다. 정수 M개가 주어졌을 때, 이 수가 적혀있는 숫자 카드를 상근이가 가지고 있는지 아닌지를 구하는 프로그램을 작성하시오.</p>
<h4 id="입력">[입력]</h4>
<p>첫째 줄에 상근이가 가지고 있는 숫자 카드의 개수 N(1 ≤ N ≤ 500,000)이 주어진다. 둘째 줄에는 숫자 카드에 적혀있는 정수가 주어진다. 숫자 카드에 적혀있는 수는 -10,000,000보다 크거나 같고, 10,000,000보다 작거나 같다. 두 숫자 카드에 같은 수가 적혀있는 경우는 없다.</p>
<p>셋째 줄에는 M(1 ≤ M ≤ 500,000)이 주어진다. 넷째 줄에는 상근이가 가지고 있는 숫자 카드인지 아닌지를 구해야 할 M개의 정수가 주어지며, 이 수는 공백으로 구분되어져 있다. 이 수도 -10,000,000보다 크거나 같고, 10,000,000보다 작거나 같다</p>
<h4 id="출력">[출력]</h4>
<p>첫째 줄에 입력으로 주어진 M개의 수에 대해서, 각 수가 적힌 숫자 카드를 상근이가 가지고 있으면 1을, 아니면 0을 공백으로 구분해 출력한다.</p>
<h4 id="풀이-전략">[풀이 전략]</h4>
<p>풀이 전에 문제를 정리를 해보자.</p>
<ol>
<li>첫번째 접근 : Brute force</li>
</ol>
<ul>
<li>쉽게 생각할 수 있는 N에 대한 M의 1대1 전체 탐색(Brute force) </li>
<li><blockquote>
<p>문제점 시간 복잡도가 N*M이라 구현 시 시간제한에 걸림</p>
</blockquote>
</li>
</ul>
<ol start="2">
<li>두번째 접근 : 이진 탐색</li>
</ol>
<ul>
<li>시간 복잡도를 낮추기 위해 이진 탐색을 적용해서 풀이 할 수 있다.(nlogn)</li>
</ul>
<h4 id="구현코드">[구현코드]</h4>
<pre><code>package test;

import java.util.Arrays;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    int N = sc.nextInt();
    int[] Narr = new int[N];
    for(int i = 0; i&lt;N; i++) 
        Narr[i] =  sc.nextInt();
    int M = sc.nextInt();
    int[] Marr = new int[M];
    int[] test = new int[M];
    Arrays.sort(Narr);

    for (int j = 0 ; j &lt; M ; j ++) {
        int L = 0;
        int R = Narr.length-1;  
        Marr[j] = sc.nextInt(); 
        while (L &lt;= R ) {
        int mid = (L+R)/2;
        if(Narr[mid] == Marr[j]) {
            test[j] = 1;
            break;}
        else if(Narr[mid] &gt; Marr[j]) 
             R = mid - 1;
        else {
            L = mid + 1;
        }


        }

    }

    for (int result : test)
    System.out.print(result+&quot; &quot;);
}

}
</code></pre><h4 id="개선사항">[개선사항]</h4>
<ol>
<li><p>Set을 이용한 방법 
Set을 이용해서 검색할 때 배열을 확인하지 않기 때문에 가장 적절한 방법이라고 생각이 든다.
(시간 복잡도 : O(1))</p>
</li>
<li><p>구현 코드</p>
<pre><code>import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;
</code></pre></li>
</ol>
<p>public class Main {
    public static void main(String[] args) {
        Scanner sc = new         Scanner(System.in);</p>
<pre><code>    // 1. N 입력
    int N = sc.nextInt();

    Set&lt;Integer&gt; nSet = new HashSet&lt;&gt;();

    for(int i = 0; i &lt; N; i++) {
        nSet.add(sc.nextInt());
    }

    int M = sc.nextInt();
    StringBuilder sb = new     StringBuilder();

    for(int i = 0; i &lt; M; i++) {
        int target = sc.nextInt();

        if (nSet.contains(target)) {
            sb.append(&quot;1 &quot;);
        } else {
            sb.append(&quot;0 &quot;);
        }
    }

    System.out.println(sb.toString());
}</code></pre><p>}</p>
<pre><code>




--- 
오늘은 맛있었던 런치야미 끝 


</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[APS] 백준 9076 : 점수 집계]]></title>
            <link>https://velog.io/@u_yonu/APS-%EB%B0%B1%EC%A4%80-9076-%EC%A0%90%EC%88%98-%EC%A7%91%EA%B3%84</link>
            <guid>https://velog.io/@u_yonu/APS-%EB%B0%B1%EC%A4%80-9076-%EC%A0%90%EC%88%98-%EC%A7%91%EA%B3%84</guid>
            <pubDate>Wed, 11 Feb 2026 08:27:46 GMT</pubDate>
            <description><![CDATA[<h3 id="개요">개요</h3>
<p>문제 : 백준 1015. 수열 정렬
<a href="https://www.acmicpc.net/problem/9076">백준 9076 : 점수 집계</a></p>
<h3 id="문제-분석">[문제 분석]</h3>
<p>한국 체조협회에서는 심판의 오심을 막기 위하여 점수 집계 시스템을 고치기로 하였다. 이전에는 5명의 심판이 1점부터 10점까지 정수의 점수를 주면 최고점과 최저점을 하나씩 제외한 점수의 합을 총점으로 하였다. 이를 보완하기 위해서 최고점과 최저점을 뺀 나머지 3명 점수의 최고점과 최저점의 차이가 4점 이상 나게 되면 점수 조정을 거쳐서 다시 점수를 매기려고 한다. 점수를 집계하여 총점을 계산하거나, 점수 조정을 거쳐서 다시 점수를 매기려고 하는 경우에는 총점 대신 KIN(Keep In Negotiation)을 출력하는 프로그램을 작성하시오.</p>
<h4 id="입력">[입력]</h4>
<p>입력의 첫 줄에는 테스트 케이스의 개수 T(1 ≤ T ≤ 10)가 주어진다. 각 테스트 케이스는 한 줄에 다섯 심판이 준 점수 다섯 개의 정수 Ni(1 ≤ Ni ≤ 10, i = 1, 2, ..., 5)가 하나의 공백을 사이에 두고 주어진다.</p>
<h4 id="출력">[출력]</h4>
<p>각 테스트 케이스에 대해서 총점을 한 줄씩 출력한다. 만일 점수 조정을 거쳐서 다시 점수를 매기려고 하는 경우에는 총점 대신 KIN을 출력한다.</p>
<h4 id="풀이-전략">[풀이 전략]</h4>
<p>풀이 전에 문제를 정리를 해보자.</p>
<ol>
<li>테스트 케이스 별로 크기 5인 수열을 만들엇 ㅓ받는다.</li>
<li>수열을 정렬한다.</li>
<li>인덱스 0, 4를 제외 하고 sum을 만든다.</li>
<li>인덱스 1, 3의 차이의 절대값에 4를 기준으로 조건문을 줘서 KIN처리를 해준다.</li>
</ol>
<h4 id="구현코드">[구현코드]</h4>
<pre><code>package test;

import java.util.Arrays;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    int T = sc.nextInt();
    int[] arr = new int[5];

    for (int test_case = 0; test_case&lt;T; test_case++) {
    for(int i = 0; i&lt;5 ; i++) arr[i]=sc.nextInt(); // testcase별 점수 5개 받기
    Arrays.sort(arr); // 정렬
    int sum = arr[1]+arr[2]+arr[3];
    if (Math.abs(arr[1]-arr[3])&gt;=4) // 차이가 4점이상 나면 점수조정
        System.out.println(&quot;KIN&quot;);
    else { 
        System.out.println(sum);

    }

    }// testcase for문 

    }
}
</code></pre><h4 id="개선사항">[개선사항]</h4>
<ol>
<li>BufferedReader를 이용한 속도 향상</li>
<li>구현 코드<pre><code>import java.io.*;
import java.util.*;
</code></pre></li>
</ol>
<p>public class Main {
    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringBuilder sb = new StringBuilder();</p>
<pre><code>    int T = Integer.parseInt(br.readLine().trim());
    for (int tc = 0; tc &lt; T; tc++) {
        StringTokenizer st = new StringTokenizer(br.readLine());
        int[] a = new int[5];
        for (int i = 0; i &lt; 5; i++) a[i] = Integer.parseInt(st.nextToken());

        Arrays.sort(a);

        if (a[3] - a[1] &gt;= 4) sb.append(&quot;KIN\n&quot;);
        else sb.append(a[1] + a[2] + a[3]).append(&#39;\n&#39;);
    }

    System.out.print(sb.toString());
}</code></pre><p>}</p>
<pre><code>




--- 
오늘은 달콤했던 런치야미 끝 


</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[APS] 백준 1015 : 수열 정렬]]></title>
            <link>https://velog.io/@u_yonu/APS-%EB%B0%B1%EC%A4%80-1015-%EC%88%98%EC%97%B4-%EC%A0%95%EB%A0%AC</link>
            <guid>https://velog.io/@u_yonu/APS-%EB%B0%B1%EC%A4%80-1015-%EC%88%98%EC%97%B4-%EC%A0%95%EB%A0%AC</guid>
            <pubDate>Tue, 10 Feb 2026 08:21:59 GMT</pubDate>
            <description><![CDATA[<h3 id="개요">개요</h3>
<p>문제 : 백준 1015. 수열 정렬
<a href="https://www.acmicpc.net/problem/1015">백준 1015 : 수열 정렬</a></p>
<h3 id="문제-분석">[문제 분석]</h3>
<p>P[0], P[1], ...., P[N-1]은 0부터 N-1까지(포함)의 수를 한 번씩 포함하고 있는 수열이다. 수열 P를 길이가 N인 배열 A에 적용하면 길이가 N인 배열 B가 된다. 적용하는 방법은 B[P[i]] = A[i]이다.</p>
<p>배열 A가 주어졌을 때, 수열 P를 적용한 결과가 비내림차순이 되는 수열을 찾는 프로그램을 작성하시오. 비내림차순이란, 각각의 원소가 바로 앞에 있는 원소보다 크거나 같을 경우를 말한다. 만약 그러한 수열이 여러개라면 사전순으로 앞서는 것을 출력한다.</p>
<h4 id="입력">[입력]</h4>
<p>첫째 줄에 배열 A의 크기 N이 주어진다. 둘째 줄에는 배열 A의 원소가 0번부터 차례대로 주어진다. N은 50보다 작거나 같은 자연수이고, 배열의 원소는 1,000보다 작거나 같은 자연수이다.</p>
<h4 id="출력">[출력]</h4>
<p>첫째 줄에 비내림차순으로 만드는 수열 P를 출력한다.</p>
<h4 id="풀이-전략">[풀이 전략]</h4>
<p>일단, 문제를 읽었을 때, 이해가 잘 안간다. 
내 한국어 능력이 문제인지, 문제가 이상한 건지 모르겠다.
풀이 전에 문제를 정리를 해보자.</p>
<ol>
<li>A라는 수열이 있고</li>
<li>그에 대한 B라는 비내림차순(단조증가)로 정렬된 수열이 있다.</li>
<li>P는 B에 적용했을때, A가 되는 Index의 수열이다.
즉, B[P[i]] = A[i]
여기서 P[i] 는 두값이 같아지는 Index 이다 .</li>
</ol>
<p>예시) 
N = 3 , A = [2, 3, 1]인 경우
B = [1, 2, 3] 일것이다.
B[P[i]] = A[i] 이여야한다 .
A[0]=2
B[P[0]]= 2
=&gt; P[0] = 1 
이런 식으로 유추된다. </p>
<p>따라서, 해당 예시에서 P[i] = [1, 2, 0] 으로 구할 수 있다.</p>
<p>처음 생각했을 때, 생각했던 로직은 다음과 같다
(1) A, B, P 수열을 생성하고 A의 수열을 입력받는다.
(2) B는 A에서 깊은 복사를 받은 후 정렬을 해준다.
(3) 조건문과 반복문을 통해 P[i]의 값을 추정하여 수열을 만든다.</p>
<h4 id="구현코드">[구현코드]</h4>
<pre><code>import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    int N = sc.nextInt();   
    int[] A = new int[N];

    int[] P = new int[N];
    for (int i = 0 ; i&lt;N ; i++) {
        A[i] = sc.nextInt();
    }

    int[] B = A.clone();

    for (int i = 0 ; i&lt; N-1; i++) 
        for (int j = 0 ; j&lt; N-1; j++) {
            if(B[j] &gt; B[j+1]) {
                int tmp = B[j];
                B[j] = B[j+1];
                B[j+1] =tmp;
            }
    }
    for (int i =0 ; i&lt;N ; i++) 
    for (int j = 0 ; j&lt; N; j++) {
         if (A[i]== B[j]) {
             P[i] = j;
             B[j] = -1;
             break;
         }


     }

    for (int i = 0 ; i&lt;N ; i++)
        System.out.print(P[i]+&quot; &quot;);
    }
}
</code></pre><h4 id="다른풀이">[다른풀이]</h4>
<ol>
<li><p>Arrays.sort() 사용 
원래 본래 풀이에서는 실제 그냥 버블 정렬을 통해서 정렬을 했다. 하지만, Arrays.sort()라는 Java에서 배열을 정렬할 때 사용하는 표준 메서드가 있다.
cf) .clone() : 그냥 &#39;=&#39;할당을 하게되면 얕은복사가 되서 해당 문제풀이에서 이슈가 발생한다. 따라서 깊은 복사를 통해서 만들어야지 적절한 문제해결이 가능하다.</p>
</li>
<li><p>풀이적용</p>
</li>
</ol>
<pre><code>import java.util.Arrays;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    int N = sc.nextInt();   
    int[] A = new int[N];

    int[] P = new int[N];
    for (int i = 0 ; i&lt;N ; i++) {
        A[i] = sc.nextInt();
    }

    int[] B = A.clone();
    Arrays.sort(B);

    for (int i =0 ; i&lt;N ; i++) 
    for (int j = 0 ; j&lt; N; j++) {
         if (A[i]== B[j]) {
             P[i] = j;
             B[j] = -1;
             break;
         }


     }

    for (int i = 0 ; i&lt;N ; i++)
        System.out.print(P[i]+&quot; &quot;);
    }
}













</code></pre><hr>
<p>오늘은 머리가 아팠던 런치야미 끝</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[APS] 백준 1181 : 단어 정렬]]></title>
            <link>https://velog.io/@u_yonu/APS-%EB%B0%B1%EC%A4%80-1181-%EB%8B%A8%EC%96%B4-%EC%A0%95%EB%A0%AC</link>
            <guid>https://velog.io/@u_yonu/APS-%EB%B0%B1%EC%A4%80-1181-%EB%8B%A8%EC%96%B4-%EC%A0%95%EB%A0%AC</guid>
            <pubDate>Tue, 10 Feb 2026 04:17:09 GMT</pubDate>
            <description><![CDATA[<h3 id="개요">개요</h3>
<p>문제 : 백준 1181. 단어 정렬
<a href="https://www.acmicpc.net/problem/1181">백준 1181 : 단어 정렬</a></p>
<h3 id="문제-분석">[문제 분석]</h3>
<p>알파벳 소문자로 이루어진 N개의 단어가 들어오면 아래와 같은 조건에 따라 정렬하는 프로그램을 작성하시오.</p>
<p>길이가 짧은 것부터
길이가 같으면 사전 순으로
단, 중복된 단어는 하나만 남기고 제거해야 한다.</p>
<h4 id="입력">[입력]</h4>
<p>첫째 줄에 단어의 개수 N이 주어진다. (1 ≤ N ≤ 20,000) 둘째 줄부터 N개의 줄에 걸쳐 알파벳 소문자로 이루어진 단어가 한 줄에 하나씩 주어진다. 주어지는 문자열의 길이는 50을 넘지 않는다.</p>
<h4 id="출력">[출력]</h4>
<p>조건에 따라 정렬하여 단어들을 출력한다.</p>
<h4 id="풀이-전략">[풀이 전략]</h4>
<p>처음 생각했을 때, 생각했던 로직은 다음과 같다
(1) 중복된 단어를 없애기 위해 set을 이용한다.
(2) sort를 이용해서 오름차순 정렬을 하면서
(3) compare to를 이용해서 length에 따른 비교 구현</p>
<h4 id="구현코드">[구현코드]</h4>
<pre><code>
import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        int N = sc.nextInt();

        Set&lt;String&gt; set = new HashSet&lt;&gt;();
        for (int i = 0; i &lt; N; i++) {
            set.add(sc.next());
        }

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

        Collections.sort(list, new Comparator&lt;String&gt;() {
            @Override
            public int compare(String a, String b) {
                // 1. 길이 짧은 순
                if (a.length() != b.length()) {
                    return a.length() - b.length();
                }
                // 2. 사전 순
                return a.compareTo(b);
            }
        });

        // 출력
        for (String s : list) {
            System.out.println(s);
        }
    }
}</code></pre><hr>
<p>오늘은 체했던 모닝야미 끝</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Database] 데이터베이스 정의와 특징 (Database Basics)]]></title>
            <link>https://velog.io/@u_yonu/Database-%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4-%EC%A0%95%EC%9D%98%EC%99%80-%ED%8A%B9%EC%A7%95</link>
            <guid>https://velog.io/@u_yonu/Database-%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4-%EC%A0%95%EC%9D%98%EC%99%80-%ED%8A%B9%EC%A7%95</guid>
            <pubDate>Fri, 06 Feb 2026 07:07:16 GMT</pubDate>
            <description><![CDATA[<h3 id="데이터-베이스의-정의--특징">데이터 베이스의 정의 / 특징</h3>
<p>  데이터 베이스는 옛날에 미군에서 컴퓨터 도서관을 만들면서 데이터 기지라는 뜻으로 처음 사용했고 지금까지 용어가 내려오고 있는 단어이다. 오늘은 멀고도 가까운 데이터 베이스에 대해 알아보고자 한다.</p>
<h4 id="데이터-베이스의-정의">데이터 베이스의 정의</h4>
<p>데이터 베이스, DB를 생각하면 생각나는 것이 아주 많다. &#39;데이터의 저장소&#39;가 생각날 수도 있을 거 같고, &#39;데이터 웨어하우스&#39;나 &#39;데이터 마트&#39;같은게 익숙하거나 완전 처음 들어볼 수 도 있다. </p>
<p>근데, 이걸 글로 나타낸 것을 보면 </p>
<blockquote>
<ul>
<li>동시에 복수의 적용 업무를 지원할 수 있도록 복수 이용자의 요구에 대응해서 데이터를 받아들이고 저장,
공급하기 위하여 일정한 구조에 따라서 편성된 데이터의 집합 또는 관련된 레코드의 집합</li>
</ul>
</blockquote>
<p>아주 어렵다. </p>
<p><img src="https://velog.velcdn.com/images/u_yonu/post/c6904f8f-8fdb-4d17-b31a-6a194a07cf2a/image.png" alt=""></p>
<p>그렇기에 우리는 조금 나눠서 생각해보자!
도대체 왜? 데이터 베이스라는 것을 쓰는걸까? </p>
<p>아까 정의에서 나타난 개념 중 가장 중요한 것은 두가지로
<strong>&#39;공용(Shared)&#39;</strong>와 <strong>&#39;통합(Integrated)</strong>
이다.</p>
<p>데이터는 단순히 데이터가 모래처럼 쌓여있는것을 말하지 않는다.
<img src="https://velog.velcdn.com/images/u_yonu/post/d7f6c7b4-a377-495c-93f7-e50119ae37ad/image.png" alt=""></p>
<p>쉽게 예시를 들면, 각자 PC에 흔어져 있는 엑셀파일이 아니라 조직 자체가 실시간으로 공유하여 중복 없이 관리하는 데이터의 총체라고 할 수 있다.</p>
<p>A업무 - 유(기획)
B업무 - 문(디자인)
C업무 - 박(인사)</p>
<p>를 각각 특정 제품 데이터를 사용한다고 했을때, 이를 각각 다 다른 데이터 형식, 디자인으로 가지고 있을 수 있다. 그렇다면 불필요한 중복이 생기게 되고 무결성이 깨지게 된다. 따라서 이를 줄이기 위해 실질적으로 &#39;데이터 베이스&#39;를 만들어 &#39;통합&#39;적으로 &#39;공유&#39;하는 것이다.
<a href="blob:https://velog.io/78e68cf4-e9fc-4033-8c8d-814e639c753b">업로드중..</a></p>
<h4 id="데이터-베이스의-특성">데이터 베이스의 특성</h4>
<p>데이터 베이스의 특성은 정형화해서 말하기 어려운 부분이 물론 있지만 보통 총 4가지로 말한다.</p>
<ul>
<li>통합된 데이터(Integrated Data) : 동일한 내용의 데이터가 중복되어 있지 않다는 것을 의미</li>
<li><ul>
<li>데이터 중복은 관리상의 복잡한 부작용을 초래함</li>
</ul>
</li>
<li>저장된 데이터(Stored Data) : 컴퓨터가 접근 가능한 저장매체에 저장되는 것을 의미</li>
<li><ul>
<li>저장매체 : 자기 디스크나 자기테이프 등 </li>
</ul>
</li>
<li>공용 데이터(Shared Data) : 여러 사용자가 서로 다른 목적으로 데이터를 공동으로 이용한다는 것을 의미</li>
<li><ul>
<li>대용량화되고 구조가 복잡한 것이 많다.</li>
</ul>
</li>
<li>변화하는 데이터(Changeable Data) : 데이터베이스에 &#39;지금&#39; 저장된 내용은 현 시점에서의 상태를 나타냄</li>
<li><blockquote>
<p>새로운 데이터의 추가, 기존 데이터의 삭제, 갱신으로 항상 변화하면서도 항상 현재의 정확한 데이터를 유지한다는 뜻</p>
</blockquote>
</li>
</ul>
<h4 id="다양한-측면에서의-특징">다양한 측면에서의 특징</h4>
<p>앞서 알아본 일반적 특성 이외에도 다양한 방면에서 특징을 가지고 있다.</p>
<ul>
<li>정보의 축적 및 전달 측면<ul>
<li>기계 가독성 : 대량의 정보를 정보처리기기가 읽고 쓸 수 있음</li>
<li>검색 가능성 : 필요한 정보를 검색할 수 있음</li>
<li>원격 조작성 : 정보통신망을 이용하여 원거리에서도 온라인으로 이용할 수 있음</li>
</ul>
</li>
</ul>
<ul>
<li><p>정보이용 측면 : 이용자의 정보 요구에 따라 다양한 정보를 신속하게 획득하고 원하는 정보를
경제적으로 찾아 낼 수 있음</p>
</li>
<li><p>정보관리 측면 : 방대한 양의 정보를 체계적으로 축적하고 새로운 내용 추가나 갱신이 용이함</p>
</li>
<li><p>정보기술발전 측면 : 데이터베이스는 정보처리, 검색, 관리 소프트웨어 등 네트워크 발전기술을 견인할
수 있음</p>
</li>
<li><p>경제, 산업적 측면 : 데이터베이스는 인프라로서 특성을 가지고 있어 경제, 산업, 사회 활동의 효율성을
제고하고 국민의 편의를 증진하는 수단으로 의미를 가짐</p>
</li>
</ul>
<hr>
<p>오늘은 Data를 처리하는 가장 근본적인 기술 중 하나인 DB의 정의와 특징에 대해 배웠다.
많이들 ADsP나 ADP를 준비할텐데 비단, 시험 공부로 끝나지 않고 근본 원리에 대해 배우는 시간이 되셨으면 좋겠다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[DataScience] 데이터와 정보(Data & Information)]]></title>
            <link>https://velog.io/@u_yonu/DataScience-%EB%8D%B0%EC%9D%B4%ED%84%B0%EC%99%80-%EC%A0%95%EB%B3%B4</link>
            <guid>https://velog.io/@u_yonu/DataScience-%EB%8D%B0%EC%9D%B4%ED%84%B0%EC%99%80-%EC%A0%95%EB%B3%B4</guid>
            <pubDate>Fri, 06 Feb 2026 05:58:48 GMT</pubDate>
            <description><![CDATA[<p>요즘 데이터 사이언티스트에 대한 수요가 높다는 이야기를 종종 듣는다. 실제 보건 통계를 전공하면서 데이터와 통계에 대해 익숙해졌다. 
오늘부터는 데이터 사이언스에 관한 내용을 정리하면서 이론적으로 필요한 내용들을 정리하고자 한다.</p>
<hr>
<h3 id="들어가는-질문---데이터란">들어가는 질문 - 데이터란?</h3>
<p>21세기 지금 이 글을 적고있는 2026년 2월 대한민국에 사람들은 &#39;데이터&#39;라는 언어에 이미 많이 익숙하다. 실제 우리가 휴대폰 요금제를 구할 때도 &#39;데이터&#39;라는 용어를 사용한다. 
데이터는 라틴어인 Dare(주다)의 과거 분사형으로 &#39;주어진 것&#39;이라는 의미로 사용되었었는데, 현재는 추론과 추정의 근거를 이루는 사실 이라는 표현으로 많이 사용한다. 이는 데이터라는 것은 단순한 객체로서의 가치뿐 아니라 상호관계 속에서 가치를 가지기 때문이다.</p>
<h3 id="데이터--정보">데이터 &amp; 정보</h3>
<h4 id="데이터의-유형">데이터의 유형</h4>
<p>  &#39;데이터&#39;의 특성을 나타내는 것 중에 가장 먼저 쓰는 용어는 &#39;정성적&#39;, &#39;정량적&#39; 특성이라는 표현이다. </p>
<p>  정성적은 물질의 성분이나 성질, 쉽게 말해 수치화 되어 있지 않은 특성을 말한다.
<img src="https://velog.velcdn.com/images/u_yonu/post/dcf51575-3d7e-4c9e-8946-4c4daae0d9b2/image.png" alt=""></p>
<p>정량적은 양을 나타내거나 수치, 도형, 기호 등으로 나타내는 특성을 말한다.
<img src="https://velog.velcdn.com/images/u_yonu/post/18a1dcd8-5735-4cb3-a4bb-ca384431839c/image.png" alt=""></p>
<p>이것을 확장해서 데이터를 비교하게 되면 아래와 같다.</p>
<ul>
<li><p>정성적 데이터(Qualitative Data) : 저장이나 검색 등에 많은 비용이 소모되는 언어, 문자 등의 형태의 데이터
ex) 질환 사진, 블로그 글 등</p>
</li>
<li><p>정량적 데이터(Quantitative Data) : 정형화된 데이터들이며 실제 수치, 도형 기호 등으로 형태가 있으며 저장 검색 등 이 쉬움
ex) 나이, 키, 몸무게 등</p>
</li>
</ul>
<hr>
<h4 id="데이터의-역할--지식경영의-핵심-이슈">데이터의 역할 : 지식경영의 핵심 이슈</h4>
<p>아주 갑자기 데이터를 설명하다가 &#39;지식경영&#39;이라는 말이 나왔다. 나도 모르게 당황스러운 흐름이다.. 유명한 데이터 관련 시험에서 이런 흐름으로 내용이 이루어져있는데, </p>
<p>왜일까? </p>
<p>사실 데이터 그 자체는 어떠한 의미를 가지지 않는다. 우리는 그 데이터를 통해서 올바른 의사결정을 내리고 미래를 예측하고자 하는 것이 목적이다.</p>
<h4 id="암묵지tacit-knowledge--형식지explicit">암묵지(Tacit Knowledge) &amp; 형식지(Explicit)</h4>
<ul>
<li>암묵지 : 학습과 경험을 통해 개인에게 체화되어 있지만 겉으로 드러나지 않는 지식 -&gt; 사회적으로 중요하지만 공유되기 어려움
  ex) 글씨 이쁘게 쓰는 법, 과자봉지 빨리뜯는 법 등</li>
<li>형식지 : 문서나 메뉴얼 같이 형상화되어있는 지식</li>
<li><blockquote>
<p>전달과 공유가 용이함
ex) 책, 유튜브영상 등</p>
</blockquote>
</li>
</ul>
<p>cf)
암묵지 &amp; 형식지의 4단계 지식 전환 모드
: SECI 모델(Socialization-Externalization-Combination-Internalization Model)</p>
<ul>
<li><p>1단계 : 공통화
암묵지의 지식 노하우를 다른 사람에게 알려주는 것</p>
</li>
<li><p>2단계 : 표출화
암묵적 지식 노하우를 책, 교본 등 형식지로 만드는 것</p>
</li>
<li><p>3단계 : 연결화
책이나 교본(형식지)에 자신이 알고 있는 새로운 지식(형식지)를 추가하는 것</p>
</li>
<li><p>4단계 : 내면화
만들어진 책이나 교본(형식지)를 보고 다른 직원들이 노하우(암묵적 지식)를 습득하는 것
<img src="https://velog.velcdn.com/images/u_yonu/post/678b59c1-ab04-4629-9edb-8cf33ec4d071/image.png" alt=""></p>
<hr>
</li>
</ul>
<h4 id="데이터와-정보의-관계dikw-피라미드">데이터와 정보의 관계(DIKW 피라미드)</h4>
<p>여러 시험에서 잘 다뤄지는 내용으로 실제 데이터에서부터 지혜를 얻는 과정을 계층구조로 표현한 것이다.
<img src="https://velog.velcdn.com/images/u_yonu/post/0f6c59cf-a758-4e25-9c1f-eddb5171af50/image.jpg" alt=""></p>
<p>순서대로 생각해보면 아래와 같다.</p>
<ul>
<li><p>데이터(Data) : 존재형식이나 다 데이터와의 상관관계등이 없는 가공하기 전의 수치나 기호</p>
</li>
<li><p>정보(Information) : 데이터의 가공, 처리와 데이터간 연관관계 속에서 의미가 도출된 것</p>
</li>
<li><p>지식(Knowledge) : 데이터의 연결된 패턴을 이해하여 이를 토대로 예측한 결과물</p>
</li>
<li><p>지혜(Wisdom) : 근본 원리에 대한 깊은 이해를 바탕으로 도출되는 아이디어(추론)</p>
</li>
</ul>
<p>실제 우리가 햄버거 집을 가보자고 하자. 내가 지금있는 역삼역 근처에는 햄버거집이 KFC와 노브랜드 버거가 있다.(아래의 예시는 가정이다.)</p>
<p>KFC 치킨버거 : 6000원
노브랜드 치킨버거 : 6500원 이라고 했을때</p>
<p>데이터 : KFC 6000원, 노브랜드 6500원
정보 : KFC가 500원 더 싸다
지식 : 가난한 나는 더 싼 KFC에서 햄버거를 먹어야 겠당!
지혜 : 다른 것도 KFC가 더 싸겠군!</p>
<p>이 과정이라고 생각하면 된다.</p>
<hr>
<p>오늘 내용 중에서 중요한 것은 
다름이 아니라 
&#39;데이터&#39;는 결국 &#39;추론&#39;을 하기위해 수집된는 것이다!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[APS] 백준 10798 : 세로읽기]]></title>
            <link>https://velog.io/@u_yonu/APS-%EB%B0%B1%EC%A4%80-10798-%EC%84%B8%EB%A1%9C%EC%9D%BD%EA%B8%B0</link>
            <guid>https://velog.io/@u_yonu/APS-%EB%B0%B1%EC%A4%80-10798-%EC%84%B8%EB%A1%9C%EC%9D%BD%EA%B8%B0</guid>
            <pubDate>Fri, 06 Feb 2026 01:51:53 GMT</pubDate>
            <description><![CDATA[<h3 id="개요">개요</h3>
<p>문제 : 백준 10798. 세로읽기
<a href="https://www.acmicpc.net/problem/10798">백준 10798 : 세로읽기</a></p>
<h3 id="문제-분석">[문제 분석]</h3>
<p>아직 글을 모르는 영석이가 벽에 걸린 칠판에 자석이 붙어있는 글자들을 붙이는 장난감을 가지고 놀고 있다. </p>
<p>이 장난감에 있는 글자들은 영어 대문자 ‘A’부터 ‘Z’, 영어 소문자 ‘a’부터 ‘z’, 숫자 ‘0’부터 ‘9’이다. 영석이는 칠판에 글자들을 수평으로 일렬로 붙여서 단어를 만든다. 다시 그 아래쪽에 글자들을 붙여서 또 다른 단어를 만든다. 이런 식으로 다섯 개의 단어를 만든다. 아래 그림 1은 영석이가 칠판에 붙여 만든 단어들의 예이다. 
<img src="https://velog.velcdn.com/images/u_yonu/post/6149dc19-141d-4685-abf8-071ab7b4947b/image.png" alt="">
&lt;그림 1&gt;</p>
<p>한 줄의 단어는 글자들을 빈칸 없이 연속으로 나열해서 최대 15개의 글자들로 이루어진다. 또한 만들어진 다섯 개의 단어들의 글자 개수는 서로 다를 수 있다. </p>
<p>심심해진 영석이는 칠판에 만들어진 다섯 개의 단어를 세로로 읽으려 한다. 세로로 읽을 때, 각 단어의 첫 번째 글자들을 위에서 아래로 세로로 읽는다. 다음에 두 번째 글자들을 세로로 읽는다. 이런 식으로 왼쪽에서 오른쪽으로 한 자리씩 이동 하면서 동일한 자리의 글자들을 세로로 읽어 나간다. 위의 그림 1의 다섯 번째 자리를 보면 두 번째 줄의 다섯 번째 자리의 글자는 없다. 이런 경우처럼 세로로 읽을 때 해당 자리의 글자가 없으면, 읽지 않고 그 다음 글자를 계속 읽는다. 그림 1의 다섯 번째 자리를 세로로 읽으면 D1gk로 읽는다. </p>
<p>그림 1에서 영석이가 세로로 읽은 순서대로 글자들을 공백 없이 출력하면 다음과 같다:</p>
<p>Aa0aPAf985Bz1EhCz2W3D1gkD6x</p>
<p>칠판에 붙여진 단어들이 주어질 때, 영석이가 세로로 읽은 순서대로 글자들을 출력하는 프로그램을 작성하시오.</p>
<h4 id="입력">[입력]</h4>
<p>총 다섯줄의 입력이 주어진다. 각 줄에는 최소 1개, 최대 15개의 글자들이 빈칸 없이 연속으로 주어진다. 주어지는 글자는 영어 대문자 ‘A’부터 ‘Z’, 영어 소문자 ‘a’부터 ‘z’, 숫자 ‘0’부터 ‘9’ 중 하나이다. 각 줄의 시작과 마지막에 빈칸은 없다.</p>
<h4 id="출력">[출력]</h4>
<p>영석이가 세로로 읽은 순서대로 글자들을 출력한다. 이때, 글자들을 공백 없이 연속해서 출력한다. </p>
<h4 id="풀이-전략">[풀이 전략]</h4>
<p>처음 생각했을 때, 생각했던 로직은 다음과 같다
(1) 1차원 배열을 통해서 입력받은 문자열을 저장함 
** 이때 strArr의 length를 이용하서 max 값을 얻어 실제 arr 열의 길이를 구함 
(2) 2차원 배열을 통해 char를 다 저장해줌 이때, 기본값은 null임
(3) 반복문을 두번 돌려서 세로로 한글자씩 받아오는데, 이때 세로줄에 null이 있으면 통과하는 코드 추가 </p>
<h4 id="구현코드">[구현코드]</h4>
<pre><code>import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String[] strArr = new String[5];
        int max = 0;
        for (int i = 0 ; i&lt; 5 ; i++) {
            strArr[i] = sc.next();
            if (strArr[i].length() &gt; max) max = strArr[i].length();
            } 
        char[][] arr = new char[5][max];
        for (int i =0 ; i&lt;5 ; i++) for(int j = 0; j&lt;strArr[i].length() ; j++) arr[i][j] = strArr[i].charAt(j);

        for(int i= 0 ; i&lt;max ; i++)
            for(int j= 0 ; j&lt;5 ; j++) {
                if (arr[j][i] == &#39;\u0000&#39;)
                    continue; 
                System.out.print(arr[j][i]);}

    }
}</code></pre><h4 id="다른풀이">[다른풀이]</h4>
<ol>
<li>문제 접근 방식
strArr와 size를 기반으로 길이 기반 풀이 길이를 같이 저장해서 길이로 조건을 줘서 print를 다르게 줌</li>
</ol>
<ol start="2">
<li>풀이적용</li>
</ol>
<pre><code>import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        // 선언
        Scanner sc = new Scanner(System.in);
        String[] strArr = new String[5];
        int[] size = new int[5]; // 5줄의 길이를 저장
        // 할당
        for (int i = 0 ; i&lt; 5 ; i++) {
            strArr[i] = sc.next();
            size[i] = strArr[i].length();
            }
        // 길이가 된다면 출력
        for(int i= 0 ; i&lt;15 ; i++) {
            for(int j= 0 ; j&lt;5 ; j++) {
                if (size[j]&gt;i)
                    System.out.print(strArr[j].charAt(i));
            }
        }
    }
}</code></pre><hr>
<p>오늘은 맛있는 새벽야미 끝</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] Object 클래스(Object Class)]]></title>
            <link>https://velog.io/@u_yonu/Java-Object-%ED%81%B4%EB%9E%98%EC%8A%A4Object-Class</link>
            <guid>https://velog.io/@u_yonu/Java-Object-%ED%81%B4%EB%9E%98%EC%8A%A4Object-Class</guid>
            <pubDate>Thu, 05 Feb 2026 07:53:01 GMT</pubDate>
            <description><![CDATA[<h3 id="object-클래스">Object 클래스</h3>
<ul>
<li>자바의 가장 최상위 클래스로 모든 클래스의 조상</li>
<li>모든 클래스는 직접적으로나 간접적으로 Object를 상속 받음</li>
<li>Object의 멤버는 모든 클래스의 멤버</li>
</ul>
<h4 id="tostring-메서드">toString() 메서드</h4>
<ul>
<li>객체를 문자열로 변경하는 메서드를 말함</li>
</ul>
<p>상세코드 </p>
<pre><code>public String toString(){
    return getClass().getName() + &quot;@&quot; + Integer.toHexString(hashCode());

}</code></pre><pre><code>- getClass()

    * 현재 객체의 실제 클래스 정보를 반환
    * 다형성 상황에서도 정확한 클래스가 나옴

- getName()

    * 클래스의 전체 경로 포함 이름 반환

        예: com.example.Student

- &quot;@&quot; : 구분자
- hashCode()
  * 객체의 고유한 정수값(int)
  * 기본 구현에서는 보통 객체의 메모리 주소 기반

 - Integer.toHexString(hashCode())
  * 메모리 주소 표현 방식이랑 친숙
  * 길이가 짧고 개발자들이 보기 편함</code></pre><p>위의 코드의 결과는 </p>
<p>com.example.Student@3f99bd52
이런 식으로 나오게 된다.</p>
<p>이건 쉽게 말해서, &quot; 나는 com.example.Student 클래스에서 만들어진 객체이고, 이 해시값을 가진 인스턴스야&quot; 라는 뜻을 가진다.</p>
<p>여기서 나타나는 이 문장이 실제 중요한 의미를 가지기는 어렵다. 
따라서 우리는 이걸 Overriding을 해서 우리가 넣고 싶은 의미를 알 수 있게 만든다.</p>
<pre><code>@Override
public String toString() {
    return &quot;Student{name=&#39;&quot; + name + &quot;&#39;, age=&quot; + age + &quot;}&quot;;
}
</code></pre><h4 id="equals-메서드">equals() 메서드</h4>
<ul>
<li>두 객체가 동일한지 비교하는 메서드<pre><code>public boolean equals(Object obj){
  return (this == obj);
}</code></pre>기본 equals() 메서드는 두 객체의 참조값(메모리 주소) 이 동일한지를 비교하므로,
동작 자체는 == 연산자와 동일하다.</li>
</ul>
<p>하지만 String과 같은 일부 클래스는 equals() 메서드를 오버라이딩하여 객체의 값(value) 을 비교하도록 구현되어 있다.
이 때문에 같은 문자열 값을 가지는 서로 다른 객체라도 equals()는 true를 반환할 수 있다.</p>
<p>따라서 일반적으로 다음과 같이 이해할 수 있다.</p>
<p>== → 같은 객체인가? (주소 비교)</p>
<p>equals() → 논리적으로 같은 값인가? (내용 비교)</p>
<p>단, 사용자 정의 클래스에서는 equals()를 오버라이딩하지 않으면
equals() 역시 주소 비교를 수행한다.</p>
<h4 id="hashcode-메서드">hashCode() 메서드</h4>
<ul>
<li>HashSet, HashMap 등에서 객체의 동일성을 확인하기 위해 사용 </li>
<li>equals  메서드를 재정의 할 때는 반드스 hashCode()</li>
</ul>
<p>cf) hashcode : 객체를 식별하는 정수형 값
    - 객체를 빠르게 검색하거나 비교할 때 사용
    - 기본적으로 메모리 주소 기반으로 생성하지만 재정의 가능</p>
<h4 id="getclass-메서드">getClass() 메서드</h4>
<p>: 객체의 런타임 클래스 정보를 반환</p>
<pre><code>public class Main{
public static void main(String[] args){
    String str = &quot;Hello&quot;;
    System.out.println(str.getClass()); // class java.lang.String 
}
}</code></pre><h4 id="기타-메서드">기타 메서드</h4>
<ul>
<li>clone()</li>
<li>finalize()</li>
<li>wait() / notify()
등등</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[APS] 백준 10990 : 별 찍기 - 15]]></title>
            <link>https://velog.io/@u_yonu/APS-%EB%B0%B1%EC%A4%80-10990-%EB%B3%84-%EC%B0%8D%EA%B8%B0-15</link>
            <guid>https://velog.io/@u_yonu/APS-%EB%B0%B1%EC%A4%80-10990-%EB%B3%84-%EC%B0%8D%EA%B8%B0-15</guid>
            <pubDate>Thu, 05 Feb 2026 04:51:35 GMT</pubDate>
            <description><![CDATA[<h3 id="개요">개요</h3>
<p>문제 : 백준 10990. 별 찍기 - 15
<a href="https://www.acmicpc.net/problem/10990">백준 10990 별 찍기 - 15</a></p>
<h3 id="문제-분석">[문제 분석]</h3>
<p>예제를 보고 규칙을 유추한 뒤에 별을 찍어 보세요.
<img src="https://velog.velcdn.com/images/u_yonu/post/943275f5-49b3-423f-ae81-c5cba8ea7996/image.png" alt=""></p>
<h4 id="입력">[입력]</h4>
<p>첫째 줄에 N(1 ≤ N ≤ 100)이 주어진다.</p>
<h4 id="출력">[출력]</h4>
<p>첫째 줄부터 N번째 줄까지 차례대로 별을 출력한다.</p>
<h4 id="풀이-전략">[풀이 전략]</h4>
<p>처음 생각했을 때, 생각했던 로직은 다음과 같다
(1) 빈칸 / * / 빈칸 / * 구조로 구현
(2) 조건문 : 처음에만 실제 별이 하나가 나타나야함
(3) 첫 번째 빈칸 N-1~0개으로 줌
(3) 가운데 빈칸 0, 1, 3, 5으로 증가함</p>
<h4 id="구현코드">[구현코드]</h4>
<pre><code>import java.util.Scanner;

public class Main {
public static void main(String[] args) {


Scanner sc = new Scanner(System.in);
int N = sc.nextInt(); 
for(int i = 0 ; i &lt; N ; i++) {
    for(int j = 1 ; j &lt; N-i  ; j++) { 
        System.out.print(&quot; &quot;);
        }
    if (i!=0)
        System.out.print(&quot;*&quot;);
    for(int j = N -2*i+1 ; j &lt; N ; j ++) { 
        System.out.print(&quot; &quot;);
        }

    System.out.print(&quot;*&quot;);

    System.out.println();

}
}
}</code></pre><h4 id="개선사항">[개선사항]</h4>
<ol>
<li><p>절대값을 사용
Math.abs() 메서드는 입력된 숫자의 절댓값(Absolute Value)을 반환하는 Java의 표준 수학 함수이다. 단순히, 부호를 없애는 함수를 넘어 실제 기준점으로부터의 거리(Distance)를 계산하여 대칭으로 만들어내는 핵심 역할 수행</p>
</li>
<li><p>문제 접근 방식
핵심 : 좌표 기반 접근
=&gt; 별이 찍히는 위치를 중심축으로부터의 거리로 해석
중심축 : j = N인 지점을 중심축으로 봄
거리계산 :  |N - j| 중심축(N)과 현재 가로위치(j) 사이의 거리
별의 위치 : 위에서 아래로 내려올수록(i가 증가할수록), 별은 중심축에서 i만큼 떨어진 양쪽 대칭 지점에 찍힘</p>
</li>
</ol>
<ol start="2">
<li>풀이적용</li>
</ol>
<pre><code>import java.util.Scanner;
public class Main{
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int N = sc.nextInt();
        // 세로(N)
        for (int i=0; i&lt;N;i++) {
            // 가로 (N+세로 길이)
            for (int j=1; j&lt;=N+i;j++) {
                // i == |N - j| 라면 * 찍기
                if (i==Math.abs(N-j))
                    System.out.print(&quot;*&quot;);
                // 아닌 경우 공백
                else
                    System.out.print(&quot; &quot;);
            }
            System.out.println();
        }
    }
}</code></pre><hr>
<p>오늘은 맛있는 런치야미 끝</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[APS] 백준 2752 : 세 수 정렬]]></title>
            <link>https://velog.io/@u_yonu/APS-%EB%B0%B1%EC%A4%80-2752.-%EC%84%B8%EC%88%98%EC%A0%95%EB%A0%AC</link>
            <guid>https://velog.io/@u_yonu/APS-%EB%B0%B1%EC%A4%80-2752.-%EC%84%B8%EC%88%98%EC%A0%95%EB%A0%AC</guid>
            <pubDate>Wed, 04 Feb 2026 01:08:49 GMT</pubDate>
            <description><![CDATA[<h3 id="개요">개요</h3>
<p>문제 : 백준 2752. 세수정렬
<a href="https://www.acmicpc.net/problem/2752">백준 2752. 세수정렬</a></p>
<h3 id="문제-분석">[문제 분석]</h3>
<p>동규는 세수를 하다가 정렬이 하고 싶어졌다.</p>
<p>정수 세 개를 생각한 뒤에, 이를 오름차순으로 정렬하고 싶어졌다.</p>
<p>정수 세 개가 주어졌을 때, 가장 작은 수, 그 다음 수, 가장 큰 수를 출력하는 프로그램을 작성하시오.</p>
<h4 id="입력">[입력]</h4>
<p>정수 세 개가 주어진다. 이 수는 1보다 크거나 같고, 1,000,000보다 작거나 같다. 이 수는 모두 다르다.</p>
<h4 id="출력">[출력]</h4>
<p>제일 작은 수, 그 다음 수, 제일 큰 수를 차례대로 출력한다.</p>
<h4 id="풀이-전략">[풀이 전략]</h4>
<p>처음 생각했을 때, 생각했던 로직은 다음과 같다
(1) 정수 3개를 배열로 받는다.
(2) 배열을 반복문을 통해 비교한다.
(3) 조건문을 통해서 실질적으로 순서 할당</p>
<h4 id="구현코드">[구현코드]</h4>
<pre><code>
import java.util.Scanner;

public class Main {
public static void main(String[] args) {
    int[] arr= new int[3];
    Scanner sc = new Scanner(System.in);
    arr[0] = sc.nextInt();
    arr[1] = sc.nextInt();
    arr[2] = sc.nextInt();
    for (int i=0; i&lt;3; i++)
        for(int j=0; j&lt;2 ; j++)
            if(arr[j] &gt; arr[j+1]) {
                int temp = 0; 
                temp = arr[j];
                arr[j] = arr[j+1];
                arr[j+1] = temp; 
                }

    System.out.print(arr[0]+&quot; &quot;);
    System.out.print(arr[1]+&quot; &quot;);
    System.out.print(arr[2]+&quot; &quot;);

}

}</code></pre><h4 id="개선사항">[개선사항]</h4>
<ol>
<li>Arrays.sort 함수 사용<pre><code>for (int i=0; i&lt;3; i++)
     for(int j=0; j&lt;2 ; j++)
         if(arr[j] &gt; arr[j+1]) {
             int temp = 0; 
             temp = arr[j];
             arr[j] = arr[j+1];
             arr[j+1] = temp; 
             }</code></pre>위에 구현한 코드는 이렇게 아래와 같이 작성할 수 있음</li>
</ol>
<pre><code>Arrays.sort(arr);</code></pre><ol start="2">
<li>최적화</li>
</ol>
<pre><code>import java.util.Arrays;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {

        Scanner sc = new Scanner(System.in);

        /* 풀이 접근 방법
        배열을 만든 후 해당 배열 안에 입력값들을 받은 후
        Arrays.sort()를 이용해서 오름차순으로 정렬 뒤 차례대로 출력
         */

        //입력 받은 값 만큼의 배열을 만든 후 배열 크기 설정 
        int[] arr = new int[3];

        //반복문을 통해 arr의 크기 만큼 입력값 받기
        //보통 배열을 이용할 때 초기식의 초기값은 0으로 시작하는 게 좋음
        for(int i = 0; i&lt;arr.length; i++) {

            //arr.length의 크기는 3번이니 총 3번의 값을 받음
            arr[i] = sc.nextInt();
        }

        //arr을 오름차순으로 배열
        Arrays.sort(arr);

        //차례대로 출력
        for(int i : arr) {
            System.out.printf(&quot;%d &quot;, i);
        }

    }
} </code></pre><hr>
<p>오늘도 맛있는 모닝야미  끝</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[ETC] Windows 환경에서 Java 설치하기(Java Installation on Windows)]]></title>
            <link>https://velog.io/@u_yonu/Window%EC%97%90%EC%84%9C-Java-%EC%84%A4%EC%B9%98%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@u_yonu/Window%EC%97%90%EC%84%9C-Java-%EC%84%A4%EC%B9%98%ED%95%98%EA%B8%B0</guid>
            <pubDate>Tue, 03 Feb 2026 17:06:51 GMT</pubDate>
            <description><![CDATA[<h3 id="들어가며">들어가며</h3>
<p> 사실 이 글을 적게된 아주 큰 이유는 내가 &#39;진짜 비전공자&#39;이기 때문이 크다.. 비전공자에게 프로그래밍의 시작에서 가장 어려운 지점은 바로 &#39;프로그램&#39;을 설치하는게 복잡하다는 점이다.
 이 글이 누군가에게 읽히게 될지는 잘모르겠지만 실제 비전공자분들이 &#39;자바&#39;라는 프로그램 언어를 시작하는데 도움이 되길 바란다.</p>
<h3 id="jdkjava-development-kit">JDK(Java Development Kit)</h3>
<p> JDK(Java Development Kit)란 자바(Java) 언어로 프로그램을 개발하기 위해 필요한 모든 도구와 라이브러리(컴파일러, 디버거 등)를 모아놓은 소프트웨어 개발 키트를 말한다. 프로그래밍을 배우기 시작하는 여러분에게는 기본적으로 이 개발 키트를 다운로드 하는 것으로 드디어 자바라는 무거운 문을 열게된다.</p>
<h3 id="window에-jdk-설치하기">Window에 JDK 설치하기</h3>
<p>자바를 다운로드 하는 방법은 다양하지만, 오늘 우리는 scoop 이용하는 방법에 대해 알아보고자한다. 여기서 scoop이란 아래와 같다.</p>
<blockquote>
<p>앱과 해당 종속성을 다운로드하고 설치하는 데 사용되는 Microsoft Windows용 명령줄 패키지 관리자으로 Scoop은 웹 개발 도구 및 기타 소프트웨어 개발 도구를 설치하는 데 자주 사용&#39;되는 도구를 말함</p>
</blockquote>
<p>아주 어렵게 말했지만, 쉽게 말하자면 터미널에서 명령어 한 줄로 프로그램 깔고, 업데이트하고, 정리해주는 아주 고마운 프로그램이다.</p>
<h4 id="scoop-설치">Scoop 설치</h4>
<p>Scoop의 대문은 아래와 같다.
<img src="https://velog.velcdn.com/images/u_yonu/post/469dcba9-5218-48fc-a19c-0caac1cd77c5/image.png" alt=""></p>
<p><a href="https://scoop.sh/">Scoop 다운로드 사이트</a></p>
<p>Scoop에 들어갔다면, Window PowerShell을 열어준다.
<img src="https://velog.velcdn.com/images/u_yonu/post/b46311ea-623b-42ae-905f-17ef6d15f40a/image.png" alt=""></p>
<p>해당 화면에서 아래와 같은 순서로 진행하게 되면 Scoop을 설치할 수 있다.
(1) c:\ 이동<br><img src="https://velog.velcdn.com/images/u_yonu/post/b67b92f3-66cd-40a0-87b8-4710cc966712/image.png" alt="">
&quot; Open a PowerShell terminal (version 5.1 or later) and from the PS C:&gt; prompt, run: &quot; 
=&gt; Scoop의 Quickstart에도 설명이 나와있다.</p>
<p>(2) Scoop 설치 스크립트 실행</p>
<pre><code>Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
</code></pre><p>의미 : PowerShell 실행 정책 설정 명령어
=&gt; 외부에서 내려받은 스크립트를 실행 가능하게 만드는 사전 설정</p>
<pre><code>Invoke-RestMethod -Uri https://get.scoop.sh | Invoke-Expression
</code></pre><p>의미 : Scoop 설치 스크립트를 다운로드해서 즉시 실행하는 명령어</p>
<p> <img src="https://velog.velcdn.com/images/u_yonu/post/42596799-55b3-4b3f-87df-e699cf0e9a7e/image.png" alt=""></p>
<p> (3) Scoop 설치완료
 <img src="https://velog.velcdn.com/images/u_yonu/post/345e3c47-9981-44b5-af3f-8953bb86af66/image.png" alt=""></p>
<h4 id="java-버킷-추가">java 버킷 추가</h4>
<p>다음으로는 Scoop을 이용하여 자바 버킷을 추가하자
=&gt; 이게 도대체 무슨 말일까?
버킷 = 설치 가능한 프로그램 목록 + 설치 방법이 적힌 저장소
따라서, 자바 버킷을 Scoop에서 추가한다는 말은 &quot;자바 설치 메뉴판을 Scoop에 추가&quot;한다는 뜻이다.</p>
<pre><code>scoop bucket add java</code></pre><p><img src="https://velog.velcdn.com/images/u_yonu/post/f532fc65-7652-4b17-b0d8-4013add37e5a/image.png" alt=""></p>
<h4 id="java-버킷-검색">java 버킷 검색</h4>
<p>JDK를 검색해서 리스트를 확인해보자</p>
<pre><code>scoop search jdk</code></pre><p><img src="https://velog.velcdn.com/images/u_yonu/post/28ab698f-90fb-4a03-9962-27831d446970/image.png" alt=""></p>
<h4 id="jdk-설치">jdk 설치</h4>
<pre><code>scoop install &quot;Name&quot;
scoop install zulu11-jdk</code></pre><p><img src="https://velog.velcdn.com/images/u_yonu/post/f7af5b35-117c-437d-912f-73477e80b5c6/image.png" alt=""></p>
<h4 id="jdk-설치확인">jdk 설치확인</h4>
<pre><code>java --version</code></pre><p><img src="https://velog.velcdn.com/images/u_yonu/post/49ca25cb-ae61-47c5-b0ae-856285027699/image.png" alt="">
이렇게 내가 원하는 버전의 jdk가 잘 설치가 되었음을 알 수 있다.</p>
<p>cf) Eclipse 다운로드</p>
<p>코드 작성을 편리하게 하게 하기위해서는 IDE를 깔아서 사용하는게 좋은데, 물론 IntelliJ 같은 좋은 프로그램도 있지만, 사실 처음 개발을 배우는 단계에서는 Eclipse가 사용하기 좋다.</p>
<p>Eclipse = 자바 개발용 통합 개발 환경(IDE)</p>
<p>아래 링크에서 다운로드 받을 수 있다.
<a href="https://www.eclipse.org/downloads/">이클립스 파운데이션</a></p>
<p><img src="https://velog.velcdn.com/images/u_yonu/post/5297b3b5-b66f-48be-9115-ad28371bcdb8/image.png" alt=""></p>
<p>다운로드를 받은 후에 installer를 키게 되면 
<img src="https://velog.velcdn.com/images/u_yonu/post/794bdbbe-d69e-4d16-a46b-93d127759fe3/image.png" alt=""></p>
<p>이 화면이 나타나게 되는데 여기서 Eclipse IDE for Java Developers 옵션으로 설치하면 된다.
설치 후 실행하면
<img src="https://velog.velcdn.com/images/u_yonu/post/b6d012fd-1e92-4782-a1bf-932dc762d0b7/image.png" alt=""></p>
<p>워크스페이스를 설정할 수 있고, 이후로는 실제 사용하면 된다.</p>
<hr>
<p>이 글은 26. 02. 04.에 백준을 풀려고 집 데스크탑을 열었는데, 이클립스가 안깔려있어서 귀찮아하며 이럴거면 벨로그에 글이라도 쓰자는 마인드로 적게 되었던 글입니다.</p>
]]></description>
        </item>
    </channel>
</rss>