<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>theo-no.log</title>
        <link>https://velog.io/</link>
        <description>dkssud!</description>
        <lastBuildDate>Sun, 27 Aug 2023 15:21:23 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>theo-no.log</title>
            <url>https://velog.velcdn.com/images/theo-no/profile/ab8c93fc-78bb-48cc-959d-44bbd64986d6/image.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. theo-no.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/theo-no" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[Network - OSI 7계층(1.Physical layer)]]></title>
            <link>https://velog.io/@theo-no/Network-OSI-7%EA%B3%84%EC%B8%B51.Physical-layer</link>
            <guid>https://velog.io/@theo-no/Network-OSI-7%EA%B3%84%EC%B8%B51.Physical-layer</guid>
            <pubDate>Sun, 27 Aug 2023 15:21:23 GMT</pubDate>
            <description><![CDATA[<h2 id="물리-계층physical-layer">물리 계층(Physical layer)</h2>
<br>

<ul>
<li><p><strong>전기적 신호가 나가는 물리적인</strong> 장비</p>
<ul>
<li>네트워크 통신은 복잡한 정보를 주고 받지만 <strong>실제로는 <code>0</code>과 <code>1</code>만 사용되며, 이것을 &#39;잘&#39; 주고받을 수 있으면 된다.</strong> <code>0</code>과 <code>1</code>은 흔히 <strong>비트(bit)</strong> 라고 불린다.</li>
</ul>
</li>
<li><p>이 계층에서는 단지 데이터를 전달할뿐 아래와 같은 요소들은 신경쓰지 않는다.</p>
<ul>
<li><p>데이터가 무엇인지</p>
</li>
<li><p>어떤 에러가 있는지</p>
</li>
<li><p>어떻게 전송하는 것이 효과적인지</p>
</li>
</ul>
</li>
<li><p><strong>단지 데이터를 전기적인 신호로 변환해서 주고받는 기능</strong>만 있을 뿐이다.</p>
<ul>
<li><p>디지털 신호(0과 1)을 아날로그 신호로, 아날로그 신호를 디지털 신호로 변경</p>
<ul>
<li>랜 카드가 데이터를 0과 1로 바꿔준다.</li>
</ul>
</li>
</ul>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/theo-no/post/0e5d3f2d-ecb7-4f7f-bd93-bab9a43570c7/image.png" alt=""></p>
<pre><code>                             [출처 : https://jhnyang.tistory.com]</code></pre><h3 id="전송-단위">전송 단위</h3>
<ul>
<li>비트</li>
</ul>
<h3 id="전송-매체">전송 매체</h3>
<ul>
<li><p>유선</p>
<ul>
<li><p>트위스트 페어 케이블</p>
<ul>
<li><p>한 쌍의 케이블이 꼬여있는 케이블, 일반적으로 랜 선</p>
</li>
<li><p>UTP 케이블과 STP 케이블이 있다.</p>
</li>
</ul>
</li>
<li><p>광 케이블</p>
</li>
</ul>
</li>
<li><p>무선</p>
<ul>
<li><p>라디오파</p>
</li>
<li><p>마이크로파</p>
</li>
<li><p>적외선</p>
</li>
</ul>
</li>
<li><p>리피터</p>
<ul>
<li><p>전송과정 중에 신호가 약해진 신호를 다시 정상화하는 장비이다.</p>
</li>
<li><p>다른 장비들에서 리피터의 역할을 하기 때문에 이제는 따로 사용되지 않는다.</p>
</li>
</ul>
</li>
<li><p>허브</p>
<ul>
<li><p>여러 개의 포트를 가지고 있어, 여러 대의 컴퓨터끼리 송수신할 수 있도록 해주는 장비이다.</p>
</li>
<li><p>허브는 리피터의 역할도 한다.</p>
</li>
<li><p>허브는 들어오는 데이터를 연결되어 있는 모든 컴퓨터로 전송한다는 문제점이 있다.</p>
</li>
<li><p>이러한 문제점 때문에 허브는 현재 사용되고 있지 않다.</p>
</li>
<li><p>허브를 대체한 네트워크 장비는 MAC 주소를 통해 특정한 컴퓨터에 데이터를 전송할 수 있는 <strong>스위치</strong>이다.</p>
</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[프로그래밍 패러다임 - 선언형 프로그래밍과 함수형 프로그래밍]]></title>
            <link>https://velog.io/@theo-no/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-%ED%8C%A8%EB%9F%AC%EB%8B%A4%EC%9E%84-%EC%84%A0%EC%96%B8%ED%98%95-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D%EA%B3%BC-%ED%95%A8%EC%88%98%ED%98%95-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D</link>
            <guid>https://velog.io/@theo-no/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-%ED%8C%A8%EB%9F%AC%EB%8B%A4%EC%9E%84-%EC%84%A0%EC%96%B8%ED%98%95-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D%EA%B3%BC-%ED%95%A8%EC%88%98%ED%98%95-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D</guid>
            <pubDate>Mon, 21 Aug 2023 13:17:36 GMT</pubDate>
            <description><![CDATA[<h2 id="선언형-프로그래밍">선언형 프로그래밍</h2>
<br>

<h3 id="선언형-프로그래밍이란">선언형 프로그래밍이란</h3>
<br>

<p>선언형 프로그래밍은 어떤 방법(How)으로 동작하는지 나타내기 보다 <strong>무엇(What)을 하는지</strong>를 중점으로 하는 방법이다.</p>
<pre><code class="language-jsx">//코드1(명령형)
function addOne (arr) {
    let results = [];
    for(let i=0; i&lt;arr.length; i+=1){
        results.push(arr[i]+1);
    }
    return results;
}</code></pre>
<p>먼저 코드 1을 보면,</p>
<p>addOne이라는 함수는 arr 배열을 파라미터로 받고 나서 result라는 새로운 배열을 선언한 뒤, 배열 arr의 원소들에 1을 더 해서 result 배열에 push한 다음 그 값을 리턴하는 함수이다.</p>
<p>이렇게 어떻게(How) 동작하는지 확실하게 알 수 있다. 근데 그러면 당연히 이렇게 하지 선언형은 어떤 걸 말하는거지? 궁금점이 생길 것이다.</p>
<pre><code class="language-jsx">//코드2(선언형)
function addOne (arr) {
    return arr.map((i) =&gt; i+1);
}</code></pre>
<p>코드 2를 보면,</p>
<p>단순히 javaScript의 내장형 함수로 바꿔 쓴게 선언형 프로그래밍이라고 생각이 들 수 있다.</p>
<p>하지만 여기서 중요한 건 내장형 함수로 바꾸면서 추사화가 되었다는 것이다.</p>
<p>즉, 선언형 프로그래밍에서 가장 중요한 점은 명령형 프로그래밍의 <strong>추상화</strong>라는 것이다.</p>
<p>위 코드를 보면 <strong>결국 어떤(What) 일이 일어나는지</strong>를 보여주지 어떻게(How) 원하는 결과를 만들어내느지는 중요하지 않다.
<br></p>
<h3 id="선언형-프로그래밍의-분류">선언형 프로그래밍의 분류</h3>
<br>

<p><strong>함수형 언어</strong></p>
<ul>
<li><p>수학적 함수를 조합하여 문제를 해결하는 언어</p>
<ul>
<li>알려진 값을 함수에 적용하는 것을 기반으로 한다.</li>
</ul>
</li>
<li><p>side effect가 발생하지 않도록 함수를 짜야 한다.</p>
<ul>
<li>side effect : 함수의 실행 결과가 함수 밖의 상항에 영향을 끼치거나, 함수 밖의 상황이 함수의 실행결과에 영향을 미치는 것</li>
<li>side effect가 없으려면 입력받은 파라미터 외의 전역변수 등을 참조하지 않아야 하며 수정해서도 안된다. 또, return 값이 있어야 하며 함수를 이용하는 이유는 오직 이 return 값을 받기 위해서이다.</li>
</ul>
</li>
<li><p>재귀 호출이 자주 이용된다.</p>
</li>
<li><p>병렬 처리에 유리하다.</p>
</li>
<li><p>종류 : LISP</p>
  <br>


</li>
</ul>
<p><strong>논리형 언어</strong></p>
<ul>
<li><p>기호 논리학에 기반을 둔 언어로, 논리 문장을 이용하여 프로그램을 표현하고 계산한다.</p>
</li>
<li><p>반복문이나 선택문을 사용하지 않는다.</p>
</li>
<li><p>비절차적 언어이다.</p>
</li>
<li><p>종류 : PROLOG
<br><br></p>
</li>
</ul>
<h3 id="선언형-프로그래밍-종류">선언형 프로그래밍 종류</h3>
<br>
HTML

<ul>
<li><p>웹 브라우저의 표준 문서인 하이퍼텍스트 문서를 만들기 위해 사용하는 언어</p>
</li>
<li><p>특별한 데이터 타입이 없고 변수 사용이 없다.</p>
</li>
<li><p>호환성이 좋고 사용이 편리하다.</p>
</li>
</ul>
<p>LIS</p>
<ul>
<li>함수형 프로그래밍 언어, 수학 표기법을 나타내기 위한 목적</li>
<li>특이하게 전위 표기법을 사용</li>
<li>인공지능 분야에 사용되는 언어</li>
</ul>
<p>PROLOG</p>
<ul>
<li>대표적인 논리형 언어로, Object(객체)간의 Relation을 표기하는 데 집중하는 언어</li>
<li>인공지능 분야에서 논리적인 추론이라 리스트 처리에 사용된다.</li>
</ul>
<p>XML</p>
<ul>
<li>기존 HTML의 단점을 보완하여 웹에서 구조화된 다양한 문서들을 상호 교환할 수 있도록 설계된 언어</li>
<li>HTML에 사용자가 새로운 태그를 정의할 수 있고, 이를 표현하는 방식이 독립적이다.</li>
</ul>
<p>HASKELL</p>
<ul>
<li>함수형 프로그래밍 언어의 한 종류로, 코드가 간결하고 에러가 날 확률이 낮다.</li>
</ul>
<p>SQL </p>
<ul>
<li>관계형 데이터베이스 관리 시스템의 데이터를 관리하기 위해 설계된 특수 목적의 프로그래밍 언어<br>
### 선언형 프로그래밍의 장점

</li>
</ul>
<p>가독성과 재사용성이 좋고, 작동 순서를 구체적으로 작성하지 않아서 오류가 적다.</p>
<p>프로그램 동작을 변경하지 않고도 관련 값을 대체할 수 있다.</p>
<p>해당 언어에서 문제가 발생해도 다른 것에 영향을 주지 않는다.(참조 투명성)
<br><br></p>
<h2 id="함수형-프로그래밍">함수형 프로그래밍</h2>
<br>

<h3 id="함수형-프로그래밍이란">함수형 프로그래밍이란</h3>
<br>

<p>함수형 프로그래밍은 선언형 프로그래밍의 일종으로 프로그램이 상태의 변화 없이 <strong>데이터 처리를 수학적 함수 계산으로 취급하고자 하는 패러다임</strong>이다.</p>
<p>순수 함수의 조합으로 프로그래밍하며 최종 Output이 발생할 수 있도록 순수 함수들을 엮어서 호출한다. 문이 아닌 식이나 선언으로 수행되는 선언형 프로그래밍 패러다임을 따르고 있다.
<br></p>
<h3 id="함수형-프로그래밍의-특징">함수형 프로그래밍의 특징</h3>
<br>

<p><strong>순수 함수</strong></p>
<ul>
<li><p>동일한 입력에는 항상 같은 값을 반환한다.</p>
</li>
<li><p>함수의 출력(return)은 오로지 그 함수에 입력된 값(input)에만 의존한다.</p>
</li>
<li><p>함수의 실행은 프로그램의 실행에 영향을 미치지 않아야 한다.Self-contained되어야 한다. 즉, side effect가 없다.Side effect가 없다는 의미는 오로지 출력(return) 만 수행한다는 의미이다.</p>
<br>

</li>
</ul>
<p><strong>불변성</strong></p>
<ul>
<li><p>Input의 Immutability을 유지해야 순수함수의 순수성 유지가 의미가 있다.</p>
</li>
<li><p>구조체를 Input에 넣었을 때와 클래스를 Input에 넣었을 때 불변성을 유지시키는 구조가 다르다. 구조체는 deep copy이기 때문에 함수 내에서 변경이 불가능하기 때문에 Input의 불변성을 고민하지 않아도 된다. 하지만 클래스는 swallow copy이기 때문에 함수 내에서 속성 변경이 가능하다. 이는 함수가 상태를 변경할 수 있는 여지를 주게 되므로 주의해야 한다.</p>
<br>

</li>
</ul>
<p><strong>참조의 투명성</strong></p>
<ul>
<li><p>함수의 순수성, 전달인자의 불변성을 유지하면 다음과 같은 참조의 투명성을 기대할 수 있다.</p>
<ul>
<li><strong>자기 충족적이다(self-contained)</strong>. 함수 외부에 의존하는 코드가 없고, 함수 사용자 입장에서는 유효한 매개변수만 전달하면 된다.<br></li>
<li><strong>결정론적이다 (deterministic)</strong>. 동일한 매개변수에 대해서는 항상 동일한 결과가 나온다.<br></li>
<li><strong>예외 (Exception) 를 던지지 않는다.</strong> out of memory error 혹은 stack overflow error 는 발생할 수 있지만, 이러한 에러들은 버그로 취급되며, 함수의 사용자가 다룰 수 있는 것은 아니다.<br></li>
<li><strong>다른 코드가 예기치 않게 실패하는 조건을 만들지 않는다.</strong> 예를 들어, 참조 투명성을 가진 함수는 매개 변수의 값을 변경하거나 함수 외부의 데이터를 변경하지 않는다.<br></li>
<li><strong>데이터베이스, 파일 시스템, 네트워크 등의 외부 기기로 인해 동작이 멈추지 (hang) 않는다.</strong><br>

</li>
</ul>
</li>
</ul>
<p><strong>Avoid</strong></p>
<ul>
<li><p>함수형 프로그래밍에서 가장 피해야 하는 지점이다.</p>
<ul>
<li>공유상태 피하기 (Avoid shared state)<br></li>
<li>상태변화 피하기 (Avoid mutating state)<br></li>
<li>부작용 피하기 (Avoid side effects)
<br><br></li>
</ul>
</li>
</ul>
<h3 id="함수형-프로그래밍의-활용">함수형 프로그래밍의 활용</h3>
<br>

<p><strong>함수의 합성</strong></p>
<ul>
<li><p>원하는 Output을 위해 둘 이상의 재사용 가능한 순수 함수를 조합하는 과정을 말한다.</p>
</li>
<li><p>함수형 프로그램은 여러 작은 순수 함수들로 이루어져있기 때문에 이 함수들을 연쇄적으로 또는 병렬로 호출해서 더 큰 함수를 만드는 과정으로 전체 프로그램을 구축한다. 그리고 이 과정에서 함수를 엮기 때문에 고차원함수(Higher-Order Functions)를 활용해야 한다.</p>
<ul>
<li>고차원 함수는 함수를 인자로 받고 또 결과로 반환하는 함수를 이야기한다.</li>
</ul>
</li>
<li><p>이 때문에 함수형 프로그래밍에서 함수는 <strong>일급객체</strong>여야 한다.</p>
<ul>
<li><p>일급객체</p>
<ul>
<li><p>전달인자(argument)로 전달할 수 있다.</p>
</li>
<li><p>동적 프로퍼티 할당이 가능하다. 컴파일 단계가 아니라 런타임시에도 할당이 가능하다는 뜻이다.</p>
</li>
<li><p>변수나 데이터 구조(자료구조) 안에 담을 수 있다</p>
</li>
<li><p>반환 값으로 사용할 수 있다.</p>
</li>
<li><p>할당할 때 사용된 이름과 관계없이 고유한 객체로 구별할 수 있다.</p>
</li>
</ul>
</li>
</ul>
</li>
<li><p>swift에서는 filter, map, flatMap, reduce 등의 기능을 사용할 수 있다.</p>
<br>

</li>
</ul>
<p><strong>Function Decoration</strong></p>
<ul>
<li>순수함수를 재사용하다보면, 이미 만들어진 순수함수를 그대로 적용하기보다 일부 개선하거나, 조금 다른 방향으로 수정해야 하는 상황이 발생할 수 있다. 이 때 function decoration을 적용한다.<br>

</li>
</ul>
<p><strong>Partial Application &amp; Curring</strong></p>
<ul>
<li><p>순수 함수를 조합하다보면, 인자의 수가 서로 맞지 않는 순수함수를 엮어야 하는 상황이 있을 수 있다.</p>
<p>  이 상황을 Arity(the number of arguments taken by a function) Mismatch라 한다.</p>
</li>
<li><p>Arity Mismatch는 왜 일어날까?</p>
<p>  순수함수 중에는 2개 이상의 인자를 필요로 하는 함수가 있을 수 있음</p>
<p>  이 순수함수는 2개 이상의 순수함수에서 실행된 출력값을 받아와야 함</p>
<p>  하지만 함수는 무조건 1개의 return 값만 나옴</p>
<p>  이렇게 인자의 수가 서로 맞지 않는 상황을 Arity Mismatch라 한다.</p>
</li>
<li><p>Partial Application &amp; Curring으로 Arity Mismatch을 해결</p>
<p>  Partial Application : 인자를 부분적으로 먼저 엮어준다.</p>
<p>  Curring : 인자를 하나씩만 받는 함수의 체인으로 만드는 방법이다.</p>
</li>
</ul>
<pre><code class="language-swift">// Partial Application
func add(_ a: Int, _ b: Int) -&gt; (Int) -&gt; Int {
    return { c in
        return a + b + c
    }
}
var addTenFive = add(10, 5)//10과 5를 미리 합쳐준다!
print(addTenFive(5)) // 미리 10과 5가 합쳐줬기 때문에 20이 나온다.

//Curring
func before(_ a: String) -&gt; ((String)-&gt;String) {
  return { b in
      return a + b;
  }
}
var word = before(&quot;이렇게&quot;);
var finalWord = word(&quot;붙어요!&quot;);
print(finalWord); //이렇게붙어요!</code></pre>
<br>

<h3 id="함수형-프로그래밍의-장점">함수형 프로그래밍의 장점</h3>
<ol>
<li>여러 가지 연산 처리 작업이 동시에 일어나는 프로그램을 만들기 쉽다.</li>
<li>멀티 코어 혹은 여러 개 연산 프로세서를 사용하는 시스템에서 효율적인 프로그램을 만들기 쉽다.</li>
<li>상태변화에 따른 부작용에서 자유로워지기 때문에 순수하게 기능 구현에 초점을 맞추어 설계할 수 있다.<br>

</li>
</ol>
<h3 id="함수형-프로그래밍의-단점">함수형 프로그래밍의 단점</h3>
<ol>
<li>순수함수를 구현하기 위해 코드의 가독성이 좋지 않을 수 있다.</li>
<li>재귀적 코드 스타일은 무한루프에 빠질 수 있다.</li>
<li>순수함수를 쓰는건 쉬울 수 있지만, 그것들을 조합하는 것은 쉽지 않다.</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[Desgin Pattern - Iterator(이터레이터) 패턴]]></title>
            <link>https://velog.io/@theo-no/Desgin-Pattern-Iterator%EC%9D%B4%ED%84%B0%EB%A0%88%EC%9D%B4%ED%84%B0-%ED%8C%A8%ED%84%B4</link>
            <guid>https://velog.io/@theo-no/Desgin-Pattern-Iterator%EC%9D%B4%ED%84%B0%EB%A0%88%EC%9D%B4%ED%84%B0-%ED%8C%A8%ED%84%B4</guid>
            <pubDate>Thu, 17 Aug 2023 13:34:30 GMT</pubDate>
            <description><![CDATA[<h1 id="iterator-패턴">Iterator 패턴</h1>
<p>반복자(Iterator) 패턴은 일련의 데이터 집합에 대하여 <strong>순차적인 접근(순회)을 지원</strong>하는 패턴이다.</p>
<p>데이터 집합이란 객체들을 그룹으로 묶어 자료의 구조를 취하는 컬렉션을 말한다. 대표적인 컬렉션으로 한번쯤은 들어본 리스트나 트리, 그래프, 테이블 ..등이 있다.</p>
<pre><code>                           [요소를 다양한 방법으로 저장하는 컬렉션]</code></pre><p><img src="https://velog.velcdn.com/images/theo-no/post/50c30926-3242-4513-a14c-58c9f07144c9/image.png" alt=""></p>
<pre><code>                            [출처 : https://inpa.tistory.com/]</code></pre><p>보통 배열이나 리스트 같은 경우 순서가 연속적인 데이터 집합이기 때문에 간단한 for문을 통해 순회할수 있다. 그러나 해시, 트리와 같은 컬렉션은 데이터 저장 순서가 정해지지 않고 적재되기 때문에, 각 요소들을 어떤 기준으로 접근해야 할지 애매해진다.</p>
<p>예를들어 아래와 같이 트리 구조가 있다면 어떤 상황에선 깊이(세로)를 우선으로 순회 해야 할 수도 있고, 너비(가로)를 우선으로 순회할수도 있기 때문이다.</p>
<pre><code>                           [어떤 기준으로 순회할지 컬렉션마다 다를수 있다]</code></pre><p><img src="https://velog.velcdn.com/images/theo-no/post/814179c6-e041-425f-a000-878806e9f270/image.png" alt=""></p>
<pre><code>                               [출처 : https://inpa.tistory.com/]</code></pre><p>이처럼 복잡하게 얽혀있는 자료 컬렉션들을 순회하는 알고리즘 전략을 정의하는 것을 이터레이터 패턴이라고 한다.</p>
<p>컬렉션 객체 안에 들어있는 모든 원소들에 대한 접근 방식이 공통화 되어 있다면 어떤 종류의 컬렉션에서도 이터레이터만 뽑아내면 여러 전략으로 순회가 가능해 보다 다형적인 코드를 설계할 수 있게 된다.</p>
<p><img src="https://velog.velcdn.com/images/theo-no/post/eef7bd11-4c6d-42d7-b033-ec4ea92b8e9c/image.png" alt=""></p>
<pre><code>                             [출처 : https://inpa.tistory.com/]</code></pre><aside>
💡 자바의 컬렉션 프레임워크(JCF)에서 각종 컬렉션을 무리없이 순회할수 있는 것도 내부에 미리 이터레이터 패턴이 적용되어 있기 때문이다.

</aside>
<br><br>

<h2 id="iterator-패턴-구조">Iterator 패턴 구조</h2>
<p><img src="https://velog.velcdn.com/images/theo-no/post/20ee9db7-f4e3-443a-933d-80dc1f3e2d3d/image.png" alt=""></p>
<pre><code>                             [출처 : https://inpa.tistory.com/]</code></pre><ul>
<li>Aggregate (인터페이스)<ul>
<li>ConcreateIterator 객체를 반환하는 인터페이스를 제공한다.</li>
<li>iterator() : ConcreateIterator 객체를 만드는 팩토리 메서드</li>
</ul>
</li>
<li>ConcreateAggregate (클래스)<ul>
<li>여러 요소들이 이루어져 있는 데이터 집합체</li>
</ul>
</li>
<li>Iterator (인터페이스)<ul>
<li>집합체 내의 요소들을 순서대로 검색하기 위한 인터페이스를 제공한다.</li>
<li>hasNext() : 순회할 다음 요소가 있는지 확인 (true / false)</li>
<li>next() : 요소를 반환하고 다음 요소를 반환할 준비를 하기 위해 커서를 이동시킴</li>
</ul>
</li>
<li>ConcreateIterator (클래스)<ul>
<li>반복자 객체</li>
<li>ConcreateAggregate가 구현한 메서드로부터 생성되며, ConcreateAggregate 의 컬렉션을 참조하여 순회한다.</li>
<li>어떤 전략으로 순회할지에 대한 로직을 구체화 한다.
<Br><br></li>
</ul>
</li>
</ul>
<h2 id="iterator-패턴-흐름">Iterator 패턴 흐름</h2>
<h3 id="클래스-구성">클래스 구성</h3>
<pre><code class="language-java">// 집합체 객체 (컬렉션)
interface Aggregate {
    Iterator iterator();
}
class ConcreteAggregate implements Aggregate {
    Object[] arr; // 데이터 집합 (컬렉션)
    int index = 0;

    public ConcreteAggregate(int size) {
        this.arr = new Object[size];
    }

    public void add(Object o) {
        if(index &lt; arr.length) {
            arr[index] = o;
            index++;
        }
    }

    // 내부 컬렉션을 인자로 넣어 이터레이터 구현체를 클라이언트에 반환
    @Override
    public Iterator iterator() {
        return new ConcreteIterator(arr);
    }
}
// 반복체 객체
interface Iterator {
    boolean hasNext();
    Object next();
}
class ConcreteIterator implements Iterator {
    Object[] arr;
    private int nextIndex = 0; // 커서 (for문의 i 변수 역할)

    // 생성자로 순회할 컬렉션을 받아 필드에 참조 시킴
    public ConcreteIterator(Object[] arr) {
        this.arr = arr;
    }

    // 순회할 다음 요소가 있는지 true / false
    @Override
    public boolean hasNext() {
        return nextIndex &lt; arr.length;
    }

    // 다음 요소를 반환하고 커서를 증가시켜 다음 요소를 바라보도록 한다.
    @Override
    public Object next() {
        return arr[nextIndex++];
    }
}</code></pre>
<h3 id="클래스-흐름">클래스 흐름</h3>
<pre><code class="language-java">public static void main(String[] args) {
    // 1. 집합체 생성
    ConcreteAggregate aggregate = new ConcreteAggregate(5);
    aggregate.add(1);
    aggregate.add(2);
    aggregate.add(3);
    aggregate.add(4);
    aggregate.add(5);

    // 2. 집합체에서 이터레이터 객체 반환
    Iterator iter = aggregate.iterator();

    // 3. 이터레이터 내부 커서를 통해 순회
    while(iter.hasNext()) {
        System.out.printf(&quot;%s → &quot;, iter.next());
    }
}
/*출력결과
1 -&gt; 2 -&gt; 3 -&gt; 4 -&gt; 5 -&gt;
*/</code></pre>
  <br>

<h2 id="예시">예시</h2>
<h3 id="이터레이터로-순회-전략을-나누기"><strong>이터레이터로 순회 전략을 나누기</strong></h3>
<p>클라이언트 요구사항은 다음과 같다. 게시판에 글을 올릴건데, 게시글을 최근글, 작성순으로 정렬해서 나열 할 수 있게 해달라고 한다. 즉, 두가지 정렬 전략을 구현해야 되는 것이다.</p>
<h3 id="클린하지-않은-문제의-코드-❌"><strong>클린하지 않은 문제의 코드 ❌</strong></h3>
<p>다음은 게시글(Post)과 게시판(Borad)를 표현한 인스턴스이다.</p>
<p>게시글에는 게시글 제목 title과 게시글 발행 날짜 필드가 있다. (코드 간략화를 위해 게시글 내용은 생략하였다)</p>
<pre><code class="language-java">// 게시글
class Post {
    String title; // 게시글 제목
    LocalDate date; // 게시글 발행일

    public Post(String title, LocalDate date) {
        this.title = title;
        this.date = date;
    }
}
// 게시판
class Board {
    // 게시글을 리스트 집합 객체로 저장 관리
    List&lt;Post&gt; posts = new ArrayList&lt;&gt;();

    public void addPost(String title, LocalDate date) {
        this.posts.add(new Post(title, date));
    }

    public List&lt;Post&gt; getPosts() {
        return posts;
    }
}
public static void main(String[] args) {
    // 1. 게시판 생성
    Board board = new Board();

    // 2. 게시판에 게시글을 포스팅
    board.addPost(&quot;디자인 패턴 강의 리뷰&quot;, LocalDate.of(2020, 8, 30));
    board.addPost(&quot;게임 하실분&quot;, LocalDate.of(2020, 2, 6));
    board.addPost(&quot;이거 어떻게 하나요?&quot;, LocalDate.of(2020, 6, 1));
    board.addPost(&quot;이거 어떻게 하나요?&quot;, LocalDate.of(2021, 12, 22));

    List&lt;Post&gt; posts = board.getPosts();

    // 3. 게시글 발행 순서대로 조회하기
    for (int i = 0; i &lt; posts.size(); i++) {
        Post post = posts.get(i);
        System.out.println(post.title + &quot; / &quot; + post.date);
    }

    // 4. 게시글 날짜별로 조회하기
    Collections.sort(posts, (p1, p2) -&gt; p1.date.compareTo(p2.date)); // 집합체를 날짜별로 정렬
    for (int i = 0; i &lt; posts.size(); i++) {
        Post post = posts.get(i);
        System.out.println(post.title + &quot; / &quot; + post.date);
    }
}
/*출력결과
디자인 패턴 강의 리뷰 / 2020-08-30
게임 하실분 / 2020-02-06
이거 어떻게 하나요? / 2020-06-01
이거 어떻게 하나요? / 2021-12-22

게임 하실분 / 2020-02-06
이거 어떻게 하나요? / 2020-06-01
디자인 패턴 강의 리뷰 / 2020-08-30
이거 어떻게 하나요? / 2021-12-22
*/</code></pre>
<p>일반적으로 for문을 돌려 집합체의 요소들을 순회하였다. 그러나 이러한 구성 방식은 Board에 들어간 Post를 순회할 때, Board가 어떠한 구조로 이루어져 있는지를 클라이언트에 노출된다. 따라서 이를 보다 객체 지향적으로 구성하기 위해 이터레이터 패턴을 적용해보자.</p>
<h3 id="이터레이터-패턴을-적용한-코드-✔️"><strong>이터레이터 패턴을 적용한 코드 ✔️</strong></h3>
<p>위에서 이터레이터 인터페이스를 직접 만들어 썼지만, 자바에선 이미 이터레이터 인터페이스를 지원한다. 자바의 내부 이터레이터를 재활용해서 <strong>메서드 위임</strong>을 통해 코드를 간단하게 구현할 수도 있다.</p>
<p>순회 전략으로는 리스트 저장 순서대로 조회와 날짜 순서대로 조회 두가지가 존재한다. 따라서 이에 대한 이터레이터 클래스 역시 두가지 생성해주면 된다.</p>
<ul>
<li>ListPostIterator : 저장 순서 이터레이터</li>
<li>DatePostIterator : 날짜 순서 이터레이터</li>
</ul>
<p>그리고 ListPostIterator 와 DatePostIterator 객체를 반환하는 팩토리 메서드를 Board 클래스에 추가만 해주면 완성 된다.</p>
<p><img src="https://velog.velcdn.com/images/theo-no/post/e6366a42-a2a5-437b-a08f-190f8b1958b1/image.png" alt=""></p>
<pre><code class="language-java">// 저장 순서 이터레이터
class ListPostIterator implements Iterator&lt;Post&gt; {
    private Iterator&lt;Post&gt; itr;

    public ListPostIterator(List&lt;Post&gt; posts) {
        this.itr = posts.iterator();
    }

    @Override
    public boolean hasNext() {
        return this.itr.hasNext(); // 자바 내부 이터레이터에 위임해 버림
    }

    @Override
    public Post next() {
        return this.itr.next(); // 자바 내부 이터레이터에 위임해 버림
    }
}
// 날짜 순서 이터레이터
class DatePostIterator implements Iterator&lt;Post&gt; {
    private Iterator&lt;Post&gt; itr;

    public DatePostIterator(List&lt;Post&gt; posts) {
        // 최신 글 목록이 먼저 오도록 정렬
        Collections.sort(posts, (p1, p2) -&gt; p1.date.compareTo(p2.date));
        this.itr = posts.iterator();
    }

    @Override
    public boolean hasNext() {
        return this.itr.hasNext(); // 자바 내부 이터레이터에 위임해 버림
    }

    @Override
    public Post next() {
        return this.itr.next(); // 자바 내부 이터레이터에 위임해 버림
    }
}
// 게시판
class Board {
    // 게시글을 리스트 집합 객체로 저장 관리
    List&lt;Post&gt; posts = new ArrayList&lt;&gt;();

    public void addPost(String title, LocalDate date) {
        this.posts.add(new Post(title, date));
    }

    public List&lt;Post&gt; getPosts() {
        return posts;
    }

    // ListPostIterator 이터레이터 객체 반환
    public Iterator&lt;Post&gt; getListPostIterator() {
        return new ListPostIterator(posts);
    }

    // DatePostIterator 이터레이터 객체 반환
    public Iterator&lt;Post&gt; getDatePostIterator() {
        return new DatePostIterator(posts);
    }
}
public static void main(String[] args) {
    // 1. 게시판 생성
    Board board = new Board();

    // 2. 게시판에 게시글을 포스팅
    board.addPost(&quot;디자인 패턴 강의 리뷰&quot;, LocalDate.of(2020, 8, 30));
    board.addPost(&quot;게임 하실분&quot;, LocalDate.of(2020, 2, 6));
    board.addPost(&quot;이거 어떻게 하나요?&quot;, LocalDate.of(2020, 6, 1));
    board.addPost(&quot;이거 어떻게 하나요?&quot;, LocalDate.of(2021, 12, 22));

    // 게시글 발행 순서대로 조회하기
    print(board.getListPostIterator());

    // 게시글 날짜별로 조회하기
    print(board.getDatePostIterator());
}

public static void print(Iterator&lt;Post&gt; iterator) {
    Iterator&lt;Post&gt; itr = iterator;
    while(itr.hasNext()) {
        Post post = itr.next();
        System.out.println(post.title + &quot; / &quot; + post.date);
    }
}
/*출력결과
디자인 패턴 강의 리뷰 / 2020-08-30
게임 하실분 / 2020-02-06
이거 어떻게 하나요? / 2020-06-01
이거 어떻게 하나요? / 2021-12-22

게임 하실분 / 2020-02-06
이거 어떻게 하나요? / 2020-06-01
디자인 패턴 강의 리뷰 / 2020-08-30
이거 어떻게 하나요? / 2021-12-22
*/</code></pre>
<p>이제 클라이언트는 게시글을 순회할 때 Board 내부가 어떤 집합체로 구현(Array, List, Tree, Queue ..등) 되어 있는지 알 수 없게 감추고 전혀 신경 쓸 필요가 없게 되었다. 그리고 순회 전략을 각 객체로 나눔으로써 때에 따라 적절한 이터레이터 객체만 받으면 똑같은 이터레이터 순회 코드로 다양한 순회 전략을 구사할 수 있게 되었다.</p>
<h3 id="집합체-구현에-상관-없이-순회를-표현-✔️"><strong>집합체 구현에 상관 없이 순회를 표현 ✔️</strong></h3>
<p>Iterator를 사용하는 또다른 이유는 이터레이터를 사용함으로써 집합체 구현과 분리할 수 있기 때문이다.</p>
<pre><code class="language-java">Iterator&lt;Post&gt; itr = iterator;
while(itr.hasNext()) {
    Post post = itr.next();
    System.out.println(post.title + &quot; / &quot; + post.date);
}</code></pre>
<p>이터레이터 객체를 반환하면 컬렉션을 순회할때 <del>hasNext()</del> 와 <del>next()</del> 라는 Iterator의 메소드만을 이용하기 때문에, 집합체인 Board의 내부 구성을 감출수 있게 된다. 즉, 위의 while문은 Board의 구현에 의존하지 않는 것이다.</p>
<p>이 말은 만일 추후에 Board의 집합체를 수정하더라도 Board 클래스가 올바른 Iterator만을 반환해 준다면 클라이언트의 코드(위의 while 루프)는 변경하지 않아도 되게 된다.
  <br><Br></p>
<h2 id="iterator-패턴-특징">Iterator 패턴 특징</h2>
<h3 id="iterator-패턴-사용-시기">Iterator 패턴 사용 시기</h3>
<ul>
<li>컬렉션에 상관없이 객체 접근 순회 방식을 통일하고자 할 때</li>
<li>컬렉션을 순회하는 다양한 방법을 지원하고 싶을 때</li>
<li>컬렉션의 복잡한 내부 구조를 클라이언트로 부터 숨기고 싶은 경우 (편의 + 보안)</li>
<li>데이터 저장 컬렉션 종류가 변경 가능성이 있을 때<ul>
<li>클라이언트가 집합 객체 내부 표현 방식을 알고 있다면, 표현 방식이 달라지면 클라이언트 코드도 변경되어야 하는 문제가 생긴다.</li>
</ul>
</li>
</ul>
<h3 id="iterator-패턴-장점">Iterator 패턴 장점</h3>
<ul>
<li>일관된 이터레이터 인터페이스를 사용해 여러 형태의 컬렉션에 대해 동일한 순회 방법을 제공한다.</li>
<li>컬렉션의 내부 구조 및 순회 방식을 알지 않아도 된다.<ul>
<li>이터레이터 패턴은 별도의 이터레이터 객체를 반환 받아 이를 이용해 순회하기 때문에, 집합체의 내부 구조를 노출하지 않고 순회 할 수 있다.</li>
</ul>
</li>
<li>집합체의 구현과 접근하는 처리 부분을 반복자 객체로 분리해 결합도Visit Website를 줄 일 수 있다.<ul>
<li>Client에서 iterator로 접근하기 때문에 ConcreteAggregate 내에 수정 사항이 생겨도 iterator에 문제가 없다면 문제가 발생하지 않는다.</li>
</ul>
</li>
<li>순회 알고리즘을 별도의 반복자 객체에 추출하여 각 클래스의 책임을 분리하여 단일 책임 원칙(SRP)Visit Website를 준수한다.</li>
<li>데이터 저장 컬렉션 종류가 변경되어도 클라이언트 구현 코드는 손상되지 않아 수정에는 닫혀 있어 개방 폐쇄 원칙(OCP)Visit Website를 준수한다.</li>
</ul>
<h3 id="iterator-패턴-단점">Iterator 패턴 단점</h3>
<ul>
<li>클래스가 늘어나고 복잡도가 증가한다.<ul>
<li>만일 앱이 간단한 컬렉션에서만 작동하는 경우 패턴을 적용하는 것은 복잡도만 증가할 수 있다.</li>
<li>이터레이터 객체를 만드는 것이 유용한 상황인지 판단할 필요가 있다.</li>
</ul>
</li>
<li>구현 방법에 따라 캡슐화를 위배할 수 있다.
<br><br></li>
</ul>
<h2 id="실무에서의-iterator-패턴">실무에서의 Iterator 패턴</h2>
<h3 id="java---javautilenumeration">Java - java.util.Enumeration</h3>
<ul>
<li>Iterator가 만들어지기 전 java 1.0부터 있었던 API</li>
<li>과거의 클래스로서, 현재는 안쓰고 Iterator로 기능이 대체 되었다.</li>
<li>java 9 에서는 Enumeration Iterator로 변환해주는 코드가 추가되었다. <del>asIterator()</del></li>
</ul>
<table>
<thead>
<tr>
<th>Iterator</th>
<th>Enumeration</th>
</tr>
</thead>
<tbody><tr>
<td>요소를 반복하는 데 사용되는 일반 커서이며 모든 컬렉션 클래스에 적용할 수 있다.</td>
<td>Vector와 같은 레거시 클래스에만 적용할 수 있으므로 일반 커서가 아니다. 컬렉션 클래스에 대한 읽기 권한만 있다.</td>
</tr>
<tr>
<td>반복 메서드 : hasNext(), next()</td>
<td>반복 메서드 : hasMoreElements(), nextElement()</td>
</tr>
<tr>
<td>반복자를 사용하여 컬렉션의 요소를 제거할 수 있다.</td>
<td>읽기 권한만 있기 때문에 열거를 사용하여 컬렉션의 요소를 제거할 수 없다.</td>
</tr>
</tbody></table>
<pre><code class="language-java">public static void main(String[] args) {
    Vector&lt;Integer&gt; rollno = new Vector&lt;&gt;();
    rollno.add(1);
    rollno.add(2);
    rollno.add(3);
    rollno.add(4);
    rollno.add(5);

    Enumeration&lt;Integer&gt; classNine = rollno.elements();

    // hasMoreElements(), nextElement() 로 순회
    while (classNine.hasMoreElements()) {
        System.out.println(classNine.nextElement());
    }
}</code></pre>
<h3 id="java---javautiliterator">Java - java.util.Iterator</h3>
<ul>
<li>hasNext() : 순회할 요소가 있는지 확인</li>
<li>next() : 현재 커서의 요소를 출력하고 다음으로 커서를 이동</li>
<li>remove() : Iterator에서 next()로 받았던 해당 엘리먼트를 삭제.<ul>
<li>모든 이터레이터에서 다 지원하는 것은 아니다. UnsupportedOperationException()을 던지는 경우가 많다.</li>
<li>보통 이 기능은 동시에 다발적으로 같은 명령을 수행해도 안전한 컬렉션에서 제공한다.</li>
</ul>
</li>
<li>forEachRemaining() : 함수형 인터페이스를 통해 순회 코드를 심플화 해준다.</li>
</ul>
<pre><code class="language-java">public static void main(String[] args) {
    Set&lt;Integer&gt; aggregate = new TreeSet&lt;&gt;(List.of(1,2,3,4,5));

    // hasNext(), next(), remove()
    Iterator&lt;Integer&gt; itr = aggregate.iterator();
    while(itr.hasNext()) {
        System.out.printf(&quot;%d 삭제&quot;, itr.next());
        itr.remove();
    }

    System.out.println(aggregate); // []
}</code></pre>
<pre><code class="language-java">public static void main(String[] args) {
    Set&lt;Integer&gt; aggregate = new TreeSet&lt;&gt;(List.of(1,2,3,4,5));

    // 이터레이터의 while 문 코드를 for문으로 축약할 수 도 있다.
    for (Iterator&lt;Integer&gt; i = aggregate.iterator(); i.hasNext();) {
        System.out.println(i.next());
    }

    // forEachRemaining()
    aggregate.iterator().forEachRemaining(System.out::println);
}</code></pre>
<h3 id="java---java-staxstreaming-api-for-xml">Java - Java StAX(Streaming API for XML)</h3>
<ul>
<li>XML 파일 포맷을 읽거나 만들때 사용하는 자바 라이브러리</li>
<li>콘솔 기반의 API, 이터레이터 기반의 API를 제공한다.<ul>
<li>이터레이터 기반의 API<ul>
<li>xml의 Element마다 이벤트가 지나가면서 캡쳐하며 그 영역을 표현하는 XMLEvent라는 인스턴스가 새로 만들고 이를 이용하는 방식이다. (XmlEventReader, XmlEventWriter)</li>
</ul>
</li>
<li>콘솔 기반의 API<ul>
<li>하나의 인스턴스가 Element를 지나가면서 직접 안의 내용들을 변경하는 방식이다. 그래서 메모리는 이터레이터 기반보다 효율적이지만 재사용, 변경 측면에서는 좋지 않아 이터레이터 기반의 API를 사용하는 것이 권장된다.</li>
</ul>
</li>
</ul>
</li>
<li>비슷한 SAX(Simple API for XML)도 있지만, SAX는 XML을 읽기만 가능하다.</li>
</ul>
<pre><code class="language-xml">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;books&gt;
    &lt;book title=&quot;오징어 게임&quot;/&gt;
    &lt;book title=&quot;숨바꼭질&quot;/&gt;
    &lt;book title=&quot;우리집에 왜 왔니&quot;/&gt;
&lt;/books&gt;</code></pre>
<pre><code class="language-java">public static void main(String[] args) throws FileNotFoundException, XMLStreamException {

    // 1. XMLEventReader 객체를 만드는 팩토리 객체를 얻는다.
    XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();

    // 2. XMLEventReader 객체를 만든다.
    XMLEventReader reader = xmlInputFactory.createXMLEventReader(new FileInputStream(&quot;book.xml&quot;));

    // 3. 이터레이터 순회한다.
    while(reader.hasNext()) {
        // &lt;books&gt; 엘리먼트를 캡쳐하여 그 영역을 표현하는 XMLEvent 인스턴스를 생성
        XMLEvent nextEvent = reader.nextEvent();

        // 엘리먼트에 자식 엘리먼트가 있을 경우
        if(nextEvent.isStartElement()) {
            StartElement startElement = nextEvent.asStartElement(); // &lt;book&gt;
            QName name = startElement.getName();
            if(name.getLocalPart().equals(&quot;book&quot;)) {
                // 엘리먼트의 속성을 얻는다. &lt;book title=&quot;&quot;/&gt;
                Attribute title = startElement.getAttributeByName(new QName(&quot;title&quot;));
                System.out.println(title.getValue());
            }
        }
    }
}
/*출력결과
오징어 게임
숨바꼭질
우리집에 왜 왔니
*/</code></pre>
<h3 id="spring-framework----compositeiterator">Spring Framework  - CompositeIterator</h3>
<ul>
<li>기존의 Interator에 add 기능만 하나 추가한 것</li>
<li>add() : 여러 Iterator들을 조합(Composite)해서 사용할 수 있다.</li>
</ul>
<pre><code class="language-java">public class IteratorInSpring {

    public static void main(String[] args) {
        CompositeIterator iterator;
    }
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[Desgin Pattern - Proxy(프록시) 패턴]]></title>
            <link>https://velog.io/@theo-no/Desgin-Pattern-Proxy%ED%94%84%EB%A1%9D%EC%8B%9C-%ED%8C%A8%ED%84%B4</link>
            <guid>https://velog.io/@theo-no/Desgin-Pattern-Proxy%ED%94%84%EB%A1%9D%EC%8B%9C-%ED%8C%A8%ED%84%B4</guid>
            <pubDate>Tue, 15 Aug 2023 14:00:02 GMT</pubDate>
            <description><![CDATA[<h1 id="proxy-pattern">Proxy Pattern</h1>
<p>프록시 패턴(Proxy Pattern)은 대상 원본 객체를 대리하여 대신 처리하게 함으로써 로직의 흐름을 제어하는 행동 패턴이다.</p>
<p>프록시(Proxy)의 사전적인 의미는 &#39;대리인&#39;이라는 뜻이다. 즉, 누군가에게 어떤 일을 대신 시키는 것을 의미하는데, 이를 객체 지향 프로그래밍에 접목해보면 <strong>클라이언트가 대상 객체를 직접 쓰는게 아니라 중간에 프록시(대리인)을 거쳐서 쓰는 코드 패턴</strong>이라고 보면 된다. </p>
<p>따라서 <strong>대상 객체(Subject)</strong>의 메소드를 직접 실행하는 것이 아닌, 대상 객체에 접근하기 전에 <strong>프록시(Proxy) 객체</strong>의 메서드를 접근한 후 추가적인 로직을 처리한뒤 접근하게 된다.</p>
<p><strong>이때 프로시는 흐름제어만 할 뿐 결과값을 조작하거나 변경시키면 안된다!</strong></p>
<p><img src="https://velog.velcdn.com/images/theo-no/post/fcde598a-d63a-447e-9fb7-a1a031404bd8/image.png" alt=""></p>
<pre><code>                               [출처 : https://inpa.tistory.com/]</code></pre><p>그냥 객체를 이용하면 되는데 이렇게 번거롭게 중계 대리자를 통해 이용하는 방식을 취하지?</p>
<p>그 이유는 대상 클래스가 민감한 정보를 가지고 있거나 인스턴스화 하기에 무겁거나 추가 기능을 가미하고 싶은데, 원본 객체를 수정할수 없는 상황일 때를 극복하기 위해서 이다. </p>
<p>이로 인해 다음과 같은 효과를 누릴수 있다고 보면 된다.</p>
<ul>
<li>보안(Sequrity)<ul>
<li>프록시는 클라이언트가 작업을 수행할 수 있는 권한이 있는지 확인하고 검사 결과가 긍정적인 경우에만 요청을 대상으로 전달한다.</li>
</ul>
</li>
<li>캐싱(Caching)<ul>
<li>프록시가 내부 캐시를 유지하여 데이터가 캐시에 아직 존재하지 않는 경우에만 대상에서 작업이 실행되도록 한다.</li>
</ul>
</li>
<li>데이터 유효성 검사(Data validation)<ul>
<li>프록시가 입력을 대상으로 전달하기 전에 유효성을 검사한다.</li>
</ul>
</li>
<li>지연 초기화(Lazy initialization)<ul>
<li>대상의 생성 비용이 비싸다면 프록시는 그것을 필요로 할때까지 연기할 수 있다.</li>
</ul>
</li>
<li>로깅(Logging)<ul>
<li>프록시는 메소드 호출과 상대 매개 변수를 인터셉트하고 이를 기록한다.</li>
</ul>
</li>
<li>원격 객체(Remote objects)<ul>
<li>프록시는 원격 위치에 있는 객체를 가져와서 로컬처럼 보이게 할 수 있다.
<br><br></li>
</ul>
</li>
</ul>
<h2 id="proxy-패턴의-구조">Proxy 패턴의 구조</h2>
<p><img src="https://velog.velcdn.com/images/theo-no/post/b5524a74-bd0c-42de-849b-48a9930d5838/image.png" alt=""></p>
<pre><code>                           [출처 : https://inpa.tistory.com/]</code></pre><ul>
<li><strong>Subject</strong> : Proxy와 RealSubject를 하나로 묶는 인터페이스 (다형성)<ul>
<li>대상 객체와 프록시 역할을 동일하게 하는 추상 메소드(operation( )) 를 정의한다.</li>
<li>인터페이스가 있기 때문에 클라이언트는 Proxy 역할과 RealSubject 역할의 차이를 의식할 필요가 없다.</li>
</ul>
</li>
<li><strong>RealSubject</strong> : 원본 대상 객체</li>
<li><strong>Proxy</strong> : 대상 객체(RealSubject)를 중계할 대리자 역할<ul>
<li>프록시는 대상 객체를 합성(composition)한다.</li>
<li>프록시는 대상 객체와 같은 이름의 메서드를 호출하며, 별도의 로직을 수행 할수 있다 (인터페이스 구현 메소드)</li>
<li>프록시는 흐름제어만 할 뿐 결과값을 조작하거나 변경시키면 안 된다.</li>
</ul>
</li>
<li><strong>Client</strong> : Subject 인터페이스를 이용하여 프록시 객체를 생성해 이용.<ul>
<li>클라이언트는 프록시를 중간에 두고 프록시를 통해서 RealSubject와 데이터를 주고 받는다.
<br><br><br></li>
</ul>
</li>
</ul>
<h2 id="proxy-패턴의-종류">Proxy 패턴의 종류</h2>
<br>

<h3 id="기본형-프록시normal-proxy">기본형 프록시(Normal Proxy)</h3>
<pre><code class="language-java">interface ISubject {
    void action();
}
class RealSubject implements ISubject {
    public void action() {
        System.out.println(&quot;원본 객체 액션 !!&quot;);
    }
}
class Proxy implements ISubject {
    private RealSubject subject; // 대상 객체를 composition

    Proxy(RealSubject subject) {
        this.subject = subject;
    }

    public void action() {
        subject.action(); // 위임
        /* do something */
        System.out.println(&quot;프록시 객체 액션 !!&quot;);
    }
}
class Client {
    public static void main(String[] args) {
        ISubject sub = new Proxy(new RealSubject());
        sub.action();
    }
}
/*출력 결과
원본 객체 액션 !!
프록시 객체 액션 !!
*/</code></pre>
<br>

<h3 id="가상-프록시virtual-proxy">가상 프록시(Virtual Proxy)</h3>
<ul>
<li>지연 초기화 방식에 사용<ul>
<li>서비스가 시작될 때 객체를 생성하는 대신에 객체 초기화가 실제로 필요한 시점에 초기화될 수 있도록 지연 가능</li>
</ul>
</li>
<li>가끔 필요하지만 항상 메모리에 적재되어 있는 무거운 서비스 객체가 있는 경우<ul>
<li>실체 객체의 생성에 많은 자원이 소모되지만 사용 빈도는 낮을 때 사용</li>
</ul>
</li>
</ul>
<pre><code class="language-java">//Interface와 RealSubject는 생략
class Proxy implements ISubject {
    private RealSubject subject; // 대상 객체를 composition

    Proxy() {
    }

    public void action() {
            // 프록시 객체는 실제 요청(action(메소드 호출)이 들어 왔을 때 실제 객체를 생성한다.
        if(subject == null){
            subject = new RealSubject();
        }
        subject.action(); // 위임
        /* do something */
        System.out.println(&quot;프록시 객체 액션 !!&quot;);
    }
}
class Client {
    public static void main(String[] args) {
        ISubject sub = new Proxy();
        sub.action();
    }
}</code></pre>
<br>


<h3 id="보호-프록시protection-proxy">보호 프록시(Protection Proxy)</h3>
<ul>
<li>프록시가 대상 객체에 대한 자원으로의 Access 제어(접근 권한)<ul>
<li>특정 Client만 서비스 객체를 사용할 수 있도록 하는 경우 사용</li>
<li>프록시 객체를 통해 클라이언트의 자격 증명이 기준과 일치하는 경우에만 서비스 객체에 요청을 전달할 수 있게 한다.</li>
</ul>
</li>
</ul>
<pre><code class="language-java">//Interface와 RealSubject는 생략
class Proxy implements ISubject {
    private RealSubject subject; // 대상 객체를 composition
    boolean access; // 접근 권한

    Proxy(RealSubject subject, boolean access) {
        this.subject = subject;
        this.access = access;
    }

    public void action() {
        if(access) {
            subject.action(); // 위임
            /* do something */
            System.out.println(&quot;프록시 객체 액션 !!&quot;);
        }
    }
}
class Client {
    public static void main(String[] args) {
        ISubject sub = new Proxy(new RealSubject(), false);
        sub.action();
    }
}</code></pre>
<br>


<h3 id="로깅-프록시logging-proxy">로깅 프록시(Logging Proxy)</h3>
<ul>
<li>대상 객체에 대한 로깅을 추가하려는 경우<ul>
<li>프록시는 서비스 메서드를 실행하기(전달하기) 전에 로깅을 하는 기능을 추가하는 경우 사용</li>
</ul>
</li>
</ul>
<pre><code class="language-java">//Interface와 RealSubject는 생략
class Proxy implements ISubject {
    private RealSubject subject; // 대상 객체를 composition

    Proxy(RealSubject subject {
        this.subject = subject;
    }

    public void action() {
        System.out.println(&quot;로깅..................&quot;);

        subject.action(); // 위임
        /* do something */
        System.out.println(&quot;프록시 객체 액션 !!&quot;);

        System.out.println(&quot;로깅..................&quot;);
    }
}
class Client {
    public static void main(String[] args) {
        ISubject sub = new Proxy(new RealSubject());
        sub.action();
    }
}</code></pre>
<br>


<h3 id="원격-프록시remote-proxy">원격 프록시(Remote Proxy)</h3>
<ul>
<li>프록시 클래스는 로컬에 있고, 대상 객체는 원격 서버에 존재하는 경우<ul>
<li>프록시 객체는 네트워크를 통해 클라이언트의 요청을 전달하여 네트워크와 관련된 불필요한 작업들을 처리하고 결과값만 반환</li>
<li>클라이언트 입장에선 프록시를 통해 객체를 이용하는 것이니 원격이든 로컬이든 신경 쓸 필요가 없으며, 프록시는 진짜 객체와 통신을 대리하게 된다.</li>
</ul>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/theo-no/post/56fc5c45-f1be-4695-a202-849542822ce3/image.png" alt=""></p>
<pre><code>                             [출처 : https://blogshine.tistory.com/17]</code></pre><aside>
💡 프록시를 스터브라고도 부르며, 프록시로부터 전달된 명령을 이해하고 적합한 메소드를 호출해주는 역할을 하는 보조객체를 스켈레톤이라 한다.

</aside>
<br>

<h3 id="캐싱-프록시caching-proxy">캐싱 프록시(Caching Proxy)</h3>
<ul>
<li>데이터가 큰 경우 캐싱하여 재사용을 유도<ul>
<li>클라이어트 요청의 결과를 캐시하고 이 캐시의 수명 주기를 관리</li>
</ul>
</li>
<li>HTTP Proxy<ul>
<li>HTTP Proxy는 웹서버와 브라우저 사이에서 웹 페이지의 캐싱을 실행하는 소프트웨어이다.</li>
<li>웹 브라우저가 어떤 웹 페이지를 표시할 때 직접 웹 서버에서 그 페이지를 가져오는 것이 아니고, HTTP Proxy가 캐쉬해서 어떤 페이지를 대신해서 취득한다. 만일 최신 정보가 필요하거나 페이지의 유효기간이 지났을 때 웹 서버에 웹 페이지를 가지러 간다.</li>
<li>이를 패턴으로 따져보면, 웹 브라우저가 Client 역할, HTTP Proxy가 Proxy 역할, 그리고 웹 서버가 RealSubcjet 역할을 한다고 보면 된다.
<img src="https://velog.velcdn.com/images/theo-no/post/0946eabd-8401-426a-8c25-f02f9f14eab5/image.png" alt=""></li>
</ul>
</li>
</ul>
<pre><code>                         [출처 : http/blog.naver.com/hai0416]</code></pre><br>

<h2 id="proxy-패턴의-특징">Proxy 패턴의 특징</h2>
<br>

<h3 id="프록시-패턴-사용-시기">프록시 패턴 사용 시기</h3>
<ul>
<li>접근을 제어하거가 기능을 추가하고 싶은데, 기존의 특정 객체를 수정할 수 없는 상황일때</li>
<li>초기화 지연, 접근 제어, 로깅, 캐싱 등, 기존 객체 동작에 수정 없이 추가하고 싶을 때<br>

</li>
</ul>
<h3 id="프록시-패턴-장점">프록시 패턴 장점</h3>
<ul>
<li><strong>개방 폐쇄 원칙(OCP)Visit Website</strong> 준수<ul>
<li>기존 대상 객체의 코드를 변경하지 않고 새로운 기능을 추가할 수 있다.</li>
</ul>
</li>
<li><strong>단일 책임 원칙(SRP)Visit Website</strong> 준수<ul>
<li>대상 객체는 자신의 기능에만 집중 하고, 그 이외 부가 기능을 제공하는 역할을 프록시 객체에 위임하여 다중 책임을 회피 할 수 있다.</li>
</ul>
</li>
<li>원래 하려던 기능을 수행하며 그외의 부가적인 작업(로깅, 인증, 네트워크 통신 등)을 수행하는데 유용하다</li>
<li>클라이언트는 객체를 신경쓰지 않고, 서비스 객체를 제어하거나 생명 주기를 관리할 수 있다.</li>
<li>사용자 입장에서는 프록시 객체나 실제 객체나 사용법은 유사하므로 사용성에 문제 되지 않는다.<br>

</li>
</ul>
<h3 id="프록시-패턴-단점">프록시 패턴 단점</h3>
<ul>
<li>많은 프록시 클래스를 도입해야 하므로 코드의 복잡도가 증가한다.<ul>
<li>예를들어 여러 클래스에 로깅 기능을 가미 시키고 싶다면, 동일한 코드를 적용함에도 각각의 클래스에 해당되는 프록시 클래스를 만들어서 적용해야 되기 때문에 코드량이 많아지고 중복이 발생 된다.</li>
<li>자바에서는 리플렉션에서 제공하는 동적 프록시(Dynamic Proxy) 기법을 이용해서 해결할 수 있다. (후술)</li>
</ul>
</li>
<li>프록시 클래스 자체에 들어가는 자원이 많다면 서비스로부터의 응답이 늦어질 수 있다.
<br><br></li>
</ul>
<h2 id="실무에서의-프록시-패턴">실무에서의 프록시 패턴</h2>
<br>

<h3 id="java---dynamic-proxy">Java - Dynamic Proxy</h3>
<p>개발자가 직접 디자인 패턴으로서 프록시 패턴을 구현해도 되지만, 자바 JDK에서는 별도로 프록시 객체 구현 기능을 지원한다. 이를 동적 프록시(Dynamic Proxy) 기법이라고 불리운다.</p>
<p>동적 프록시는 개발자가 직접 일일히 프록시 객체를 생성하는 것이 아닌, 애플리케이션 실행 도중 java.lang.reflect.Proxy 패키지에서 제공해주는 API를 이용하여 동적으로 프록시 인스턴스를 만들어 등록하는 방법으로서, 자바의 Reflection APIVisit Website 기법을 응용한 연장선의 개념이다. 그래서 별도의 프록시 클래스 정의없이 런타임으로 프록시 객체를 동적으로 생성해 이용할 수 있다는 장점이 있다.</p>
<pre><code class="language-java">// 대상 객체와 프록시를 묶는 인터페이스
interface Animal {
    void eat();
}
// 프록시를 적용할 타겟 객체
class Tiger implements Animal{
    @Override
    public void eat() {
        System.out.println(&quot;호랑이가 음식을 먹습니다.&quot;);
    }
}
public class Client {
    public static void main(String[] arguments) {

        // newProxyInstance() 메서드로 동적으로 프록시 객체를 생성할 수 있다.
        Animal tigerProxy = (Animal) Proxy.newProxyInstance(
                Animal.class.getClassLoader(), // 대상 객체의 인터페이스의 클래스로더
                new Class[]{Animal.class}, // 대상 객체의 인터페이스
                new InvocationHandler() { // 프록시 핸들러
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        Object target = new Tiger();

                        System.out.println(&quot;----eat 메서드 호출 전----&quot;);

                        Object result = method.invoke(target, args); // 타겟 메서드 호출

                        System.out.println(&quot;----eat 메서드 호출 후----&quot;);

                        return result;
                    }
                }
        );
        tigerProxy.eat();
    }
}
/*출력결과
----eat 메서드 호출 전----
호랑이가 음식을 먹습니다.
----eat 메서드 호출 후----
*/</code></pre>
<br>

<h3 id="spring-framework---스프링-aop">Spring Framework - 스프링 AOP</h3>
<p>스프링 프레임워크에서는 내부적으로 프록시 기술을 정말 많이 사용하고 있다. (AOP, JPA 등)</p>
<p>스프링에서는 Bean을 등록할 때 SingletonVisit Website을 유지하기 위해 Dynamic Proxy 기법을 이용해 프록시 객체를 Bean으로 등록한다. 또한 Bean으로 등록하려는 기본적으로 객체가 Interface를 하나라도 구현하고 있으면 JDK를 이용하고 Interface를 구현하고 있지 않으면 내장된 CGLIB 라이브러리를 이용한다.</p>
<pre><code class="language-java">@Service
public class GameService {
    public void startDame() {
        System.out.println(&quot;이 자리에 오신 여러분을 진심으로 환영합니다.&quot;);
    }
}
@Aspect
@Comonent
public class PerfAspect {
    @Around(&quot;bean(gameService)&quot;)
    public void timestamp(ProceedingJoinPoint point) throws Throwable {
        System.out.println(&quot;프록시 실행 1&quot;);

        point.proceed(); // 대상 객체의 원본 메서드를 실행

        System.out.println(&quot;프록시 실행 2&quot;);
    }
}</code></pre>
<br>

<h3 id="javascript---proxy--reflect-객체">JavaScript - Proxy / Reflect 객체</h3>
<p>자바에서도 Proxy 객체를 별도로 지원하듯이, 자바스크립트 진영에서도 독립적인 Proxy 객체가 존재한다.</p>
<p>자바스크립트에서의 Proxy 객체의 역할은 대상 객체을 감싸서(wrapping), 속성 조회, 할당, 열거 및 함수 호출 등 여러 기본 동작을 가로채(trap) 특별한 다른 동작을 가미시키는 대리자 역할을 한다. 대상 객체는 Object, Array 등 자바스크립트의 모든 자료형이 대상이 될 수 있다.</p>
<pre><code class="language-jsx">let obj = {
    name: &#39;홍길동&#39;,
    print: function () {
        console.log(`My Name is ${this.name}`);
    },
};

// print 함수를 프록시로 감싸기
obj.print = new Proxy(obj.print, {
    apply(target, thisArg, args) {
        console.log(&#39;메서드 실행할 때 중간에 가로채어 로직 시행&#39;);

        console.log(&#39;target: &#39;, target); // 대상 함수
        console.log(&#39;thisArg: &#39;, thisArg); // this의 값
        console.log(&#39;args: &#39;, args); // 매개변수 목록 (배열)

        console.log(&#39;이름 바꿔 버리기 ~&#39;);
        thisArg.name = &#39;임꺽정&#39;;

        Reflect.apply(target, thisArg, args); // 대상 원본 함수 실행
    },
});

obj.print();
/*출력결과
메서드 실행할 때 중간에 가로채어 로직 시행
target : [Function: print]
thisArg: { name: &#39;홍길동&#39;, print: [Function: print] }
args: []
이름 바꿔 버리기 ~
My Name is 임꺽정
*/</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[Android(안드로이드) 5. 안드로이드 Component - Service]]></title>
            <link>https://velog.io/@theo-no/Android%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C-4.-%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C-Component-Service</link>
            <guid>https://velog.io/@theo-no/Android%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C-4.-%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C-Component-Service</guid>
            <pubDate>Thu, 15 Jun 2023 08:33:51 GMT</pubDate>
            <description><![CDATA[<h2 id="service">Service</h2>
<br>

<ul>
<li><p>일반적으로 화면 없이 동작하는 프로그램으로 Background 서비스</p>
</li>
<li><p>사용자와 상호작용 할 수 없음</p>
</li>
<li><p>액티비티의 생명주기에 종속되어 있지 않다. (각자 안드로이드 컴포넌트라서)</p>
</li>
<li><p>별도의 스레드에서 동작하지 않고 호스팅 프로세스의 메인 스레드에서 작동</p>
<ul>
<li>bindService는 연결할 때와 해제할 때만 백그라운드 스레드에서 처리되고 onServiceConnected와 onServiceDisconnected는 메인 쓰레드에서 호출</li>
</ul>
</li>
<li><p>액티비티가 비활성화 되면 액티비티보다 우선순위가 높음</p>
</li>
<li><p>8버전 이후로는 백그라운드에서 장시간 동작시 시스템에서 강제 종료</p>
<ul>
<li>회피하려면 APP의 작동을 Notification 영역에 표시하는 Foreground 서비스가 되어야 함</li>
</ul>
</li>
<li><p>startService 또는 bindService로 실행시킬 수 있음
<br><br></p>
<h2 id="startservice">startService</h2>
<br>

</li>
</ul>
<h3 id="동작-방식">동작 방식</h3>
<ul>
<li><p>앱 내의 액티비티 같은 컴포넌트가 호출했을 때 실행</p>
</li>
<li><p>백그라운드에서 한 가지 일을 하며, 결과를 호출했던 컴포넌트에게 보내지 않음</p>
</li>
<li><p>예 - 다운로드, 파일 업로드</p>
<br>

</li>
</ul>
<h3 id="생명-주기">생명 주기</h3>
<p><img src="https://velog.velcdn.com/images/theo-no/post/4665fc97-353b-4ea6-951f-289d6d1636f1/image.png" alt=""></p>
<ul>
<li><p>회색 부분 - 액티비티에서 호출</p>
</li>
<li><p>초록색 부분은 서비스 시작되고 순서대로 호출</p>
<ul>
<li><p>시작되면 onCreate( ) → onStrartCommand( )</p>
</li>
<li><p>중지되면 onDestory( )</p>
</li>
</ul>
</li>
<li><p>onCreate( )</p>
<ul>
<li>서비스가 최초 초기화 될 때 호출</li>
</ul>
</li>
<li><p>onStartCommand( )</p>
<ul>
<li><p>서비스를 다른 컴포넌트가 호출했을 때 수행</p>
</li>
<li><p>이 메서드를 통해 서비스가 백그라운드에서 동작</p>
</li>
<li><p>리턴 값</p>
<ul>
<li>START_NOT_STICKY - 서비스가 시스템에 의해 종료될 때 PendingIntent가 따로 있지 않다면 다시 생성하지 않음</li>
<li>START_STICKY(default) - 시스템에 의해 종료되어도 다시 생성(마지막 인텐트는 전해주지 않음)</li>
<li>START_REDELEVER_INTENT - 마지막 인텐트까지 모두 유지하며 다시 생성</li>
</ul>
</li>
</ul>
</li>
<li><p>onDestroy</p>
<ul>
<li><p>서비스가 소멸될 때 호출</p>
</li>
<li><p>stopService( )나 stopSelf( )가 호출되면 서비스가 동작을 멈추고 시스템이 onDestroy 함
<br><br></p>
</li>
</ul>
</li>
</ul>
<h2 id="bindservice">bindService</h2>
<br>

<h3 id="동작-방식-1">동작 방식</h3>
<ul>
<li><p>startService와 다르게 자신을 호출했던 컴포넌트와 인터랙션을 주고 받을 수 있음</p>
</li>
<li><p>처리한 결과를 주고 받을 수 있음</p>
</li>
<li><p>서로 다른 프로세스 상에 있어도 처리 가능</p>
</li>
<li><p>a 앱이 있고 b 앱이 있으면 프로세스도 다르고 VirtualMachine도 다르다. 이때, 서로 데이터를 주고 받으려면 프로세스 간 통신을 해야 한다.</p>
</li>
<li><p>startService( )와 달리 하나 이상의 클라이언트 컴포넌트 간의 통신을 구현 가능</p>
<br>

</li>
</ul>
<h3 id="생명-주기-1">생명 주기</h3>
<p><img src="https://velog.velcdn.com/images/theo-no/post/c0a33e5b-9e45-4e07-b0b5-d30d289f92b5/image.png" alt=""></p>
<ul>
<li><p>bindService( )로 실행</p>
</li>
<li><p>onCreat( ) → onBind( )가 호출되면서 Running 상태가 됨</p>
<ul>
<li><p>이때 Binder를 반환해준다.</p>
</li>
<li><p>액티비티 쪽에서onServiceConnected 함수에서 Binder를 받아서 사용</p>
</li>
</ul>
</li>
<li><p>unbindService( )를 호출하면 onUnbind( ) → onDestroy( ) 순서로 호출됨</p>
</li>
<li><p>액티비티의 onStart( )에서 bindService( ) 해주고 onStop( )에서 unbindService( ) 호출</p>
<br>

</li>
</ul>
<h3 id="bindservcie-구현-방법">bindServcie 구현 방법</h3>
<ul>
<li><p>Local</p>
<ul>
<li><p>Binder 클래스의 서브 클래스 생성해서 구현</p>
</li>
<li><p>onBind 함수에서 서비스의 IBinder 객체 반환</p>
</li>
</ul>
</li>
<li><p>Remote</p>
<ul>
<li><p>Messenger와 Handler 사용</p>
<ul>
<li><p>안드로이드 프레임워크에서 정형화로 제공하는 것</p>
</li>
<li><p>Handler 상속한 클래스 구현해서 현재 스레드에 할당된 looper 객체를 만들고 onBind에서 걔의 binder를 액티비티로 건네준다. 이때 Messenger의 객체를 통해서 주고 받는다.</p>
</li>
<li><p>액티비티는 Bundle에 키 값의 데이터를 넣고 Message 객체에 값을 세팅해서 반환 받은 service.send 함수를 통해 메시지를 전달</p>
</li>
<li><p>Handler 상속할 때 handleMessage 메서드 오버라이딩 하면서 메시지를 수신했을 때 처리할 동작 구현</p>
</li>
</ul>
</li>
<li><p>AIDL 사용</p>
<ul>
<li><p>Handler 방식은 순차적으로 Task를 처리하여 멀티 쓰레드가 안되지만 AIDL을 사용하면 멀티 쓰레드 지원 가능</p>
</li>
<li><p>AIDL 파일 생성</p>
</li>
<li><p>인터페이스 구현</p>
<ul>
<li><p>Android SDK는 AIDL 파일 기반으로 java 언어로 인터페이스 생성해 줌</p>
</li>
<li><p>해당 인터페이스는 Binder를 상속</p>
</li>
<li><p>AIDL 인터페이스 메서드를 구현해주는 Stub이라는 내부 추상 클래스가 있는데 이를 확장하고 메서드 구현해야 함</p>
</li>
</ul>
</li>
<li><p>Activity에서 서비스 바인딩</p>
<ul>
<li><p>Service를 구현하고 onBind( )를 오버라이딩하여 Stub 추상 클래스를 상속받은 클래스의 객체 생성하여 반환</p>
</li>
<li><p>Activity에서 구현한 서비스 바인딩</p>
<br>

</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<h2 id="foreground-service">Foreground Service</h2>
<ul>
<li><p>활성화된 액티비티와 동급의 우선순위를 가짐</p>
</li>
<li><p>상태바에 알림을 표시해야 함 - Notification</p>
<ul>
<li><p>알림콘텐츠 설정 및 알람의 탭 작업 설정 - NotificationBuilder, PendingIntent 사용</p>
</li>
<li><p>채널 만들기 및 중요도 설정</p>
</li>
<li><p>알림 표시</p>
</li>
</ul>
</li>
<li><p>API 28 이상 부터는 Manifest에 android.permission.FOREGROUND_SERVICE 명시해줘야 함</p>
</li>
<li><p>액티비티에서 startService로 호출하고 해당 서비스에서 onStartCommand에서 startForeground 호출하면 foreground service 시작</p>
<br>

</li>
</ul>
<h3 id="notification">Notification</h3>
<ul>
<li><p>화면을 사용하지 않고 사용자에게 알림 기능을 제공</p>
</li>
<li><p>Channel을 생성</p>
<ul>
<li>getSystemService를 통해 Manager 획득한 후 channel 등록</li>
</ul>
</li>
<li><p>Notification 생성 후 NotificationManager를 통해 전송</p>
<ul>
<li>PendingIntent, builder, icon, title 등을 세팅</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[정렬]]></title>
            <link>https://velog.io/@theo-no/%EC%A0%95%EB%A0%AC</link>
            <guid>https://velog.io/@theo-no/%EC%A0%95%EB%A0%AC</guid>
            <pubDate>Thu, 15 Jun 2023 08:23:01 GMT</pubDate>
            <description><![CDATA[<h2 id="정렬">정렬</h2>
<h3 id="arrayssort">Arrays.sort()</h3>
<ul>
<li><p>int, char와 같은 primitive type 배열 정렬 지원 (예외로 String도 지원)</p>
</li>
<li><p>해당 함수는 dual pivot quicksort 정렬 알고리즘을 활용. (primitive type일때)</p>
</li>
<li><p>일반 quickSort는 O(n^2) 복잡도를 지님
→ 이러한 퀵소트 속도를 보안하여 만든 것이 dual pivot quicksort.</p>
</li>
<li><p>dual pivot quick sort = 삽입 정렬 + 퀵 정렬</p>
</li>
<li><p>사용법</p>
</li>
</ul>
<pre><code class="language-java">**오름차순**
import java.util.Arrays;

public class Sort {
    public static void main(String[] args)  {    
        int[] array = {58, 32, 64, 12, 15, 99};

        Arrays.sort(array);
    }
}</code></pre>
<pre><code class="language-jsx">**일부 오름차순**
import java.util.Arrays;

public class Sort {
    public static void main(String[] args)  {    
        Integer[] array = {58, 32, 64, 12, 15, 99};

        Arrays.sort(array, 1, 4);
    }
}</code></pre>
<h3 id="내림차순-정렬">내림차순 정렬</h3>
<ul>
<li>내림차순 정렬은 Collections 내에 있는 reverseOrder()을 활용</li>
<li>primitive type 배열: wrapper 클래스로 변경해서 사용</li>
<li>primitive type boxing 하는법</li>
</ul>
<pre><code class="language-java">int[] arr = {4, 3, 6, 1, 2};
Integer[] arr2 = Arrays.stream(arr).boxed().toArray(Integer[]::new); //방법1
Arrays.sort(arr2, Collections.reverseOrder());

arr = Arrays.stream(arr).boxed().sorted(Collections.reverseOrder()).mapToInt(Integer::intValue).toArray(); //방법2</code></pre>
<ul>
<li>object type 배열: sort 내에 Collections.reverseOrder()을 바로 사용</li>
<li>사용법</li>
</ul>
<pre><code class="language-jsx">**내림차순**
import java.util.Arrays;
import java.util.Collections;

public class Sort {
    public static void main(String[] args)  {    
        Integer[] array = {58, 32, 64, 12, 15, 99};

        Arrays.sort(array, Collections.reverseOrder());
    }
}</code></pre>
<pre><code class="language-jsx">**일부 내림차순**
import java.util.Arrays;
import java.util.Collections;

public class Sort {
    public static void main(String[] args)  {    
        Intege array = {58, 32, 64, 12, 15, 99};

        Arrays.sort(array, 1, 4, Collections.reverseOrder());
    }
}</code></pre>
<h3 id="object-배열--n차원-배열-정렬">Object 배열 &amp; N차원 배열 정렬</h3>
<ul>
<li><p>object 정렬 → timSort</p>
</li>
<li><p>tim sort = 삽입정렬 + merge sort</p>
</li>
<li><p>Comparator 인터페이스로 int compare(T t1, T t2)를 구현</p>
<pre><code class="language-java">  List&lt;Student&gt; sList = new ArrayList&lt;&gt;();

  Comparator&lt;Student&gt; cp = new Comparator&lt;&gt;() {
      @Override
      public int compare(Student s1, Student s2) {
          return s2.age - s1.age;
      }
  };

  Collections.sort(sList, cp);</code></pre>
<ul>
<li>t1, t2 순서로 정렬 ⇒ return 음수</li>
<li>t1 == t2 ⇒ return 0</li>
<li>t2, t1 순서로 정렬 ⇒ return 양수</li>
</ul>
</li>
</ul>
<h3 id="lambda를-활용한-정렬">Lambda를 활용한 정렬</h3>
<ul>
<li>comparator 객체는 method 1개인 함수형 인터페이스를 구현 ⇒ lambda 함수로 대체 가능</li>
<li>간결한 코드</li>
<li>예시: 문자열 length 길이에 따른 정렬</li>
</ul>
<pre><code class="language-java">Arrays.sort(months,
            (String a, String b) -&gt; a.length() - b.length());</code></pre>
<p>→ 아래 코드: 더 깔끔한 방식</p>
<pre><code class="language-java">Arrays.sort(months, Comparator.comparingInt(String::length));</code></pre>
<h3 id="stream으로-정렬">Stream으로 정렬</h3>
<ul>
<li>Stream 클래스의 sorted() method도 Comparator 객체를 인자로 받아 정렬함</li>
<li>기존 객체의 순서를 변경하지 않고, 새롭게 정렬된 객체를 생성할 때 사용</li>
</ul>
<pre><code class="language-java">List&lt;Player&gt; sortedPlayers = players.stream()
        .sorted((a, b) -&gt; b.getScore() - a.getScore())
        .collect(Collectors.toList());</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[Android(안드로이드) 4. 안드로이드 Component - Activity]]></title>
            <link>https://velog.io/@theo-no/Android%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C-4.-%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C-Component-Activity</link>
            <guid>https://velog.io/@theo-no/Android%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C-4.-%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C-Component-Activity</guid>
            <pubDate>Mon, 15 May 2023 07:24:26 GMT</pubDate>
            <description><![CDATA[<h2 id="activity">Activity</h2>
<br>

<h3 id="생성">생성</h3>
<ul>
<li><p>모든 액티비티는 Manifest 파일에 선언되어야 함</p>
<ul>
<li><p>시작 액티비티는  <intent-filter>태그 안에</p>
</li>
<li><p>action은 android:name=”android.intent.action.MAIN”</p>
</li>
<li><p>category에는 android:name=”android.intent.category.LAUNCHER”를 추가해야 한다.</p>
</li>
</ul>
</li>
<li><p>AppCompatActivity( ) 상속해서 클래스 생성 → onCreate( ) 메서드 오버라이딩
<br><br></p>
</li>
</ul>
<h3 id="생명-주기">생명 주기</h3>
<ul>
<li><p>onCreate( )</p>
<ul>
<li><p>액티비티가 생성될 때 호출</p>
</li>
<li><p>UI 초기화에 사용 (주로 View를 만드는 작업을 수행)</p>
</li>
</ul>
</li>
<li><p>onStart( )</p>
<ul>
<li><p>액티비티가 사용자에게 표시되기 직전에 호출</p>
</li>
<li><p>onStop( )과 짝</p>
</li>
<li><p>액티비티가 실행되는 중에만 어떤 작업을 하고 싶으면 onStrart( )에서 실행되게 하고 onStop( )에서 중단되게 하면 된다.</p>
</li>
<li><p>onStart( )는 focus가 없는 상태</p>
</li>
<li><p>최초에 만들어 졌을 때 불린건지, background에서 있다가 와서 불린건지 구분이 필요</p>
<ul>
<li>최초에 만들어지면 초기화 같은 과정이 필요하기 때문에</li>
</ul>
</li>
</ul>
</li>
<li><p>onResume( )</p>
<ul>
<li><p>액티비티가 사용자와 상호작용하기 바로 직전에 호출됨</p>
</li>
<li><p>onResume( )은 focus가 있는 상태</p>
</li>
<li><p>onResume( ) 안에 함수들이 다 호출되고 나면 어플리케이션이 Activity Running 상태가 됨</p>
</li>
<li><p>이 시점에 현재 액티비티가 액티비티 스택의 최상위에 있다.</p>
</li>
<li><p>onPause( )와 짝</p>
</li>
</ul>
</li>
<li><p>onPause( )</p>
<ul>
<li><p>액티비티가 비활성화 되었을 때 호출</p>
</li>
<li><p>onResume( )과 짝</p>
</li>
<li><p>onPause( ) 호출될 때 View나 데이터를 Shared Preference를 통해 저장하고 나중에 onResume( ) 호출될 때 불러올 수 있다.</p>
</li>
</ul>
</li>
<li><p>onStop( )</p>
<ul>
<li><p>액티비티가 더 이상 사용자자에게 보여지지 않을 때 호출</p>
</li>
<li><p>이후에 onRestart( )를 거쳐서 onStart( )가 호출되면서 어플리케이션을 다시 호출할 수 있다.</p>
</li>
<li><p>액티비티가 완전히 소멸된 것은 아니다 화면에서 내려왔을 뿐</p>
</li>
</ul>
</li>
<li><p>onRestart( )</p>
<ul>
<li>onStop( )이 호출되었다가 액티비티가 화면에 다시 보여질 때 onRestart( )를 거쳐서 onStart( )가 호출된다.</li>
</ul>
</li>
<li><p>onDestory( )</p>
<ul>
<li><p>액티비티가 완전히 종료, 즉 어플리케이션을 완전히 종료했을 때 호출</p>
</li>
<li><p>어플리케이션을 다시 실행시키면 onCreate( ) 부터 다시 시작</p>
</li>
<li><p>finish( ) 메서드가 호출되거나 시스템 메모리 확보를 위해 액티비티 제거할 때 사용</p>
</li>
<li><p>메인 액티비티는 뒤로가기 해서 홈 화면으로 가도 작업 관리자에서 지우지 않는 이상 onDestory( ) 호출 안됨</p>
</li>
</ul>
</li>
<li><p>액티비티 전환 시 lifeCycle</p>
<ol>
<li><p>기존 액티비티의 <strong><code>onPause()</code></strong> 메서드가 호출됩니다. 이때, 액티비티는 더 이상 화면에 보이지 않고, 사용자와의 상호작용이 불가능해집니다.(focus 잃음)</p>
</li>
<li><p>바뀔 액티비티의 <strong><code>onCreate()</code></strong> 메서드가 호출됩니다. 이때, 액티비티가 생성되고 레이아웃을 구성하게 됩니다.</p>
</li>
<li><p>바뀔 액티비티의 <strong><code>onStart()</code></strong> 메서드가 호출됩니다. 이때, 액티비티가 화면에 보이기 시작합니다.</p>
</li>
<li><p>바뀔 액티비티의 <strong><code>onResume()</code></strong> 메서드가 호출됩니다. 이때, 액티비티가 사용자와 상호작용할 수 있는 상태가 되며, 애니메이션 등의 효과가 표시됩니다. (focus 획득)</p>
</li>
<li><p>만약 바뀐 액티비티가 이전에 생성된 액티비티와 서로 다른 태스크에 속하게 된다면, 이전 액티비티는 <strong><code>onStop()</code></strong> 메서드를 호출합니다. 이때, 액티비티는 더 이상 화면에 보이지 않게 됩니다.</p>
</li>
</ol>
</li>
<li><p>화면 회전 시 life Cycle</p>
<ul>
<li><p>화면 회전하면 기존 화면이 Destory 되었다가 rotation된 화면을 재생성한다.</p>
</li>
<li><p>기존 화면 destory : onPause( ) → onSaveInstanceState( ) → onStop( ) → on Destory( )</p>
</li>
<li><p>회전 화면 생성 : onCreate( ) → onStart( ) → onRestoreInstanceState( ) → onResume( )</p>
</li>
<li><p>finish( )나 뒤로가기로 종료하면 onSaveInstanceState( )는 호출되지 않음
<br><br></p>
</li>
</ul>
</li>
</ul>
<h2 id="intent">Intent</h2>
<ul>
<li>어플리케이션 구성요소 4가지 간에 작업 수행을 위한 정보를 전달
<br><br></li>
</ul>
<h3 id="명시적-인텐트">명시적 인텐트</h3>
<ul>
<li><p>실행하고자 하는 컴포넌트 이름과 클래스 명이 명시적으로 작성되어 호출할 대상을 확실히 알 수 있는 경우 사용</p>
<pre><code class="language-java">  val Intent = Intent(this, NextActivity::class.java)
  startActivity(intent)</code></pre>
<br>


</li>
</ul>
<h3 id="암시적-인텐트">암시적 인텐트</h3>
<ul>
<li><p>인텐트의 액션과 데이터를 저장하긴 했지만 호출할 대상이 달라질 수 있는 경우에 사용</p>
</li>
<li><p>특정 컴포넌트를 지정하지 않고, 원하는 작업 의도만 담고 컴포넌트를 실행할 수 있음</p>
<ul>
<li><p>액션과 데이터만 주고 어떤 컴포넌트를 사용할 지는 명시하지 않음</p>
</li>
<li><p>시스템이 해당 의도를 적절히 처리할 수 있는 컴포넌트를 찾아 해당 작업을 처리</p>
<ul>
<li><p>action, data, category만 비교한다.</p>
</li>
<li><p>나머지 putExtra로 넣어준 건 시스템이 알 수 없어서 비교하지 않음</p>
</li>
</ul>
</li>
<li><p>이때 처리할 수 있는 컴포넌트가 여러 개라면 chooser가 나옴</p>
<br>


</li>
</ul>
</li>
</ul>
<h3 id="intent-구성-요소">Intent 구성 요소</h3>
<ul>
<li><p>Action</p>
<ul>
<li>수행할 액션 이름 (ex - ACTION_DIAL)</li>
</ul>
</li>
<li><p>Data</p>
<ul>
<li>수행할 데이터의 URI</li>
</ul>
</li>
<li><p>Category</p>
<ul>
<li>수행할 액션에 대한 추가적인 정보</li>
</ul>
</li>
<li><p>Type</p>
<ul>
<li>수행할 인텐트 데이터의 명시적인 타입(MIME 타입) - video/mpeg</li>
</ul>
</li>
<li><p>Component name</p>
<ul>
<li>대상 컴포넌트의 완전한 클래스 이름</li>
</ul>
</li>
<li><p>Extras</p>
<ul>
<li>인텐트를 다루는 컴포넌트에 추가적으로 전달할 한 쌍의 키와 값</li>
</ul>
</li>
<li><p>Flag</p>
<ul>
<li>동작 방식 결정 → 뒤로가기 시에 어떻게 이동할 지(history에 남길지)
<br><br></li>
</ul>
</li>
</ul>
<h3 id="intent의-브로드캐스트-액션">Intent의 브로드캐스트 액션</h3>
<ul>
<li>브로드캐스트 리시버가 받을 수 있는 Action</li>
<li>registReceiver(BroadcastRecceiver, IntentFilter) 메소드의 IntentFilter에 정의하거나 Mainfest의 태그 안에 정의할 수 있음
<br><br></li>
</ul>
<h3 id="intent-filter">Intent Filter</h3>
<ul>
<li>특정 인텐트를 받을지 말지를 정의하는 역할을 수행 이를 통해 컴포넌트의 특징이 정해짐</li>
<li>Intent Filter를 구성하는 요소는 인텐트 구성 요소와 동일
<br><br></li>
</ul>
<h3 id="startactivity--requestactivitylaunch">startActivity / requestActivity.launch</h3>
<ul>
<li>startActivity<ul>
<li>단방향으로 실행 → 결과 돌려받지 못함</li>
</ul>
</li>
<li>Launcher<ul>
<li>결과를 다시 돌려 받을 수 있음
<br><br><br></li>
</ul>
</li>
</ul>
<h2 id="android-permission">Android Permission</h2>
  <br>

<h3 id="권한-종류">권한 종류</h3>
<ul>
<li><p>Install time permissions</p>
<ul>
<li><p>앱에서 설치 권한을 선언하면 설치할 때 권한 부여</p>
</li>
<li><p>플레이 스토어에 명시되어 있는 권한</p>
</li>
</ul>
</li>
<li><p>Runtime Permissions</p>
<ul>
<li><p>실행시 획득해야 하는 권한</p>
</li>
<li><p>나머지는 선언만 하면 되지만 얘는 <strong>코드상으로 구현해야 함</strong></p>
</li>
</ul>
</li>
<li><p>Special Permissions</p>
<ul>
<li>플랫폼과 OEM만이 정의할 수 있는 권한
<br><br></li>
</ul>
</li>
</ul>
<h3 id="순서">순서</h3>
<ul>
<li><p>Manifest에 선언</p>
</li>
<li><p>앱에 권한이 부여되어 있는지 확인</p>
<ul>
<li><p>사용하려는 권한을 이미 부여 받았다면 다시 요청하지 않음</p>
</li>
<li><p>checkSelfPermission( ) 메서드를 사용하여 이미 권한이 있는지 확인 가능</p>
<ul>
<li>PERMISSION_GRANTED or PERMISSION_DENIED를 반환 받음</li>
</ul>
</li>
</ul>
</li>
<li><p>권한 요청</p>
<ul>
<li><p>requestPermissions 메소드를 호출하면서 필요한 권한을 명시</p>
</li>
<li><p>요청하려는 권한이 한 개 이상이면 String 배열로 넘겨줄 수 있음</p>
</li>
</ul>
</li>
<li><p>응답 처리</p>
<ul>
<li><p>응답</p>
<ul>
<li>사용자가 권한 요청에 응답하면 콜백 메서드인 onRequestPermissionsResult( )가 호출되고 여기서 결과 작업 진행</li>
</ul>
</li>
<li><p>거부</p>
<ul>
<li><p>사용자가 권한 요청을 거부하면 앱이 비정상 종료될 수 있음</p>
</li>
<li><p>dialog 띄워서 설정 화면으로 안내하는 것이 적절</p>
</li>
</ul>
</li>
</ul>
<p><br><br><br></p>
</li>
</ul>
<h2 id="activity-task">Activity Task</h2>
<p>  <br><br></p>
<h3 id="task">Task</h3>
<ul>
<li>관련된 실행 액티비티들을 순서대로 묶어 관리하는 것<br></li>
<li>서로 다른 패키지의 액티비티가 실행되더라도 하나의 실행 흐름(Task) 안에 있게 됨
<br><br></li>
</ul>
<h3 id="구조">구조</h3>
<ul>
<li><p>Task는 스택의 형태로 구성 → 실행되는 액티비티들이 쌓이는 구조</p>
<br></li>
<li><p>뒤로가기 누르면 top 액티비티가 없어지고 다음 액티비티가 top이 됨</p>
<br></li>
<li><p>맨 마지막 root 액티비티가 없어지면 Task 완전 종료
<br><br></p>
<h3 id="task-전환">Task 전환</h3>
</li>
<li><p>홈 화면에서 새로운 앱을 실행시키면 새로운 Task 생성</p>
<br></li>
<li><p>최근 실행 앱 목록(작업 관리자)이 Task의 목록으로 top 액티비티들이 표시됨</p>
<br></li>
<li><p>앱 목록에서 원하는 Task 선택 시 해당 Task 동작
<br><br></p>
</li>
</ul>
<h3 id="task-제어의-필요성">Task 제어의 필요성</h3>
<ul>
<li><p>반복되는 액티비티 또는 중복 실행 방지</p>
</li>
<li><p>액티비티 실행 모드와 Flag로 제어</p>
<p><br><br><br></p>
<h2 id="activity-실행-모드">Activity 실행 모드</h2>
<p><br><br></p>
<h3 id="activity-실행-모드-종류">Activity 실행 모드 종류</h3>
</li>
<li><p>standard</p>
<ul>
<li>기본 값으로 task 내에 중복된 액티비티 허용</li>
</ul>
</li>
<li><p>singleTop</p>
<ul>
<li><p>task 내에 top 액티비티와 동일한 액티비티를 실행하면 쌓지 않고 기존 top 액티비티 <strong>재사용</strong></p>
</li>
<li><p>intent flag로 설정 가능 → Intent.FLAG_ACTIVITY_SINGLE_TOP</p>
</li>
<li><p>기존 lifeCycle로는 처음 호출된건지, 다시 호출된건지 확인할 방법이 없다.</p>
<ul>
<li><p>onPause( )와 onResume( )이 반복되서 실행될 것이다.</p>
</li>
<li><p>onNewIntent 함수 필요(onPause → onNewIntent → onResume)</p>
</li>
</ul>
</li>
</ul>
</li>
<li><p>singleTask</p>
<ul>
<li><p>위치와 상관없이 중복된 액티비티를 쌓지 않는다.</p>
</li>
<li><p>기존의 있는 액티비티까지 위에 있는 액티비티들 제거해서 이동</p>
</li>
<li><p>다른 Task에서 호출해도 무조건 자신의 Task로 오게 만들 수 있음</p>
<ul>
<li>외부에서 호출하게 하려면 exported = true 설정 필요</li>
</ul>
</li>
</ul>
</li>
<li><p>singleInstance</p>
<ul>
<li><p>중복을 허용하지 않을 뿐 아니라 혼자서 별도의 task 구성</p>
</li>
<li><p>task 내에는 오직 singleInstance로 설정된 액티비티 하나만 존재</p>
</li>
</ul>
</li>
<li><p>설정 방법</p>
<ul>
<li><p>Manifest에 등록 → 등록 시에 동장 방식 결정</p>
</li>
<li><p>intent의 Flag 이용 → 런타임 시에 동작 방식 결정</p>
</li>
</ul>
<p><br><br></p>
<h2 id="task-내-activity-정리-및-변경">Task 내 Activity 정리 및 변경</h2>
</li>
<li><p>액티비티 속성과 intent의 flag를 이용해 task 내의 특정 액티비티 제거 및 변경</p>
<ul>
<li><p>액티비티 속성 → Manifest 파일에 설정</p>
<ul>
<li>액티비티가 실행될 때마다 기본적으로 적용</li>
</ul>
</li>
<li><p>flag 속성 → Intent 생성 후 설정</p>
<ul>
<li>Manifest 파일에 선언된 액티비티의 속성을 재정의</li>
</ul>
</li>
</ul>
<p><br><br></p>
</li>
</ul>
<h3 id="nohistory--flag_activity_no_history">noHistory / FLAG_ACTIVITY_NO_HISTORY</h3>
<ul>
<li><p>해당 액티비티는 Task 스택에 쌓이지 않는다.</p>
<ul>
<li>다음 액티비티에도 뒤로가기 해도 얘는 없다 그 전의 액티비티로 이동</li>
</ul>
</li>
<li><p>Manifest 설정 → android:noHistory=”true”</p>
</li>
<li><p>flag 설정 → intent.flags = Intent.FLAG_ACTIVITY_NO_HISTORY
<br><br></p>
<h3 id="flag_activity_clear_task">FLAG_ACTIVITY_CLEAR_TASK</h3>
</li>
<li><p>FLAG_ACTIVITY_NEW_TASK와 같이 사용되며 Task 내에서 다른 액티비티를 모두 삭제</p>
<ul>
<li>intent.flags = intent.FLAG_ACTIVITY_CLEAR_TASK or intent.FLAG_ACTIVITY_NEW_TASK</li>
</ul>
</li>
<li><p>예시</p>
<p>  예를 들어, Task A가 있다고 가정하겠습니다. Task A에는 액티비티 A, 액티비티 B, 액티비티 C가 있습니다. 이때, 액티비티 C에서 FLAG_ACTIVITY_CLEAR_TASK와 FLAG_ACTIVITY_NEW_TASK 플래그를 사용하여 액티비티 D를 시작하면, Task B가 새로 생성되고 액티비티 D가 Task B에 포함됩니다. 그리고 이전 Task A의 모든 액티비티(A, B, C)는 삭제됩니다.</p>
<p>  FLAG_ACTIVITY_CLEAR_TASK 플래그를 사용하는 경우는 대개 로그아웃 기능을 구현할 때 사용됩니다. 로그아웃 기능을 구현할 때, 앱에서 사용자의 인증 토큰 등을 삭제하고 로그인 화면으로 이동해야 합니다. 이때, FLAG_ACTIVITY_CLEAR_TASK와 FLAG_ACTIVITY_NEW_TASK 플래그를 사용하여, 이전의 액티비티 스택을 모두 삭제하고 로그인 화면부터 새로운 Task를 시작합니다.</p>
</li>
</ul>
<p><br><br></p>
<h3 id="flag_activity_clear_top">FLAG_ACTIVITY_CLEAR_TOP</h3>
<ul>
<li><p>기존에 있던 액티비티 제거(상위 포함)하고 새로운 액티비티 생성</p>
</li>
<li><p>flag 설정 → intent.flags = intent.FLAG_ACTIVITY_CLEAR_TOP</p>
</li>
<li><p>FLAG_ACTIVITY_SINGLE_TOP과 조합하여 기존 액티비티 재활용</p>
<ul>
<li><p>액티비티 실행모드 singleTask과 동일해짐</p>
</li>
<li><p>intent.flags = intent.FLAG_ACTIVITY_CLEAR_TOP or intent.FLAG_ACTIVITY_SINGLE_TOP</p>
</li>
<li><p>해당 액티비티가 noHistory가 아닌지 확인해보고 실행</p>
</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Kotlin(코틀린) 심화문법 2. 고차 함수, 코틀린 표준 함수, Generic]]></title>
            <link>https://velog.io/@theo-no/Kotlin%EC%BD%94%ED%8B%80%EB%A6%B0-%EC%8B%AC%ED%99%94%EB%AC%B8%EB%B2%95-2.-%EA%B3%A0%EC%B0%A8-%ED%95%A8%EC%88%98-%EC%BD%94%ED%8B%80%EB%A6%B0-%ED%91%9C%EC%A4%80-%ED%95%A8%EC%88%98-Generic</link>
            <guid>https://velog.io/@theo-no/Kotlin%EC%BD%94%ED%8B%80%EB%A6%B0-%EC%8B%AC%ED%99%94%EB%AC%B8%EB%B2%95-2.-%EA%B3%A0%EC%B0%A8-%ED%95%A8%EC%88%98-%EC%BD%94%ED%8B%80%EB%A6%B0-%ED%91%9C%EC%A4%80-%ED%95%A8%EC%88%98-Generic</guid>
            <pubDate>Thu, 13 Apr 2023 13:32:25 GMT</pubDate>
            <description><![CDATA[<h2 id="고차-함수">고차 함수</h2>
<br>

<h3 id="정의">정의</h3>
<ul>
<li><p>매개 변수나 함수의 반환 값으로 함수가 사용되는 함수</p>
</li>
<li><p>코틀린에서는 람다나 함수 참조를 사용해 함수를 변수에 넘길 수도 있고 그 자체가 값이 되기도 함
<br><br></p>
</li>
</ul>
<h3 id="예시-1">예시 1</h3>
<ul>
<li>다른 함수를 인자로 사용하거나 함수를 결과값으로 반환하는 함수</li>
</ul>
<pre><code class="language-kotlin">private fun highOrderFunction(sum: (Int, Int) -&gt; Int, a: Int, b: Int): Int = sum(a, b)

fun main() {
    println(highOrderFunction({ x, y -&gt; x + y }, 20, 30))
}
&lt;--출력 결과--&gt;
50</code></pre>
<ul>
<li><p>highOrderFunction</p>
<ul>
<li><p>파라미터(Int, Int) → Int인 함수(sum)와 Int, Int 총 3개를 받는 함수</p>
</li>
<li><p>함수의 body에서는 전달받은 함수 sum을 실행하며 두 개의 변수 a, b를 넘겨줌
<br><br></p>
</li>
</ul>
</li>
</ul>
<h3 id="예시-2">예시 2</h3>
<ul>
<li>일반 함수를 인자나 반환 값으로 사용하는 함수</li>
</ul>
<pre><code class="language-kotlin">private fun sum(a: Int, b: Int): Int = a + b
private fun sumFunction(): Int = sum(40, 2)

fun main(){
    println($sumFunction()
}
&lt;--출력 결과--&gt;
42</code></pre>
<br>

<h3 id="예시-3">예시 3</h3>
<ul>
<li>람다식을 인자나 반환 값으로 사용하는 고차 함수</li>
</ul>
<pre><code class="language-kotlin">val multiply = {x: Int, y: Int -&gt; x*y}

println(${multiply(8,8)})
&lt;--출력 결과--&gt;
64</code></pre>
<br>

<h3 id="예시-4">예시 4</h3>
<ul>
<li>변환 자료형이 아예 없거나 매개변수가 하나만 있을 때의 람다식 함수</li>
</ul>
<pre><code class="language-kotlin">val helloWorld: () -&gt; {println(&quot;Hello World!&quot;)}
val outSelfSum: (Int) -&gt; Int = {a -&gt; a+a}
helloWorld()
println(ourSelfSum(10))
&lt;--출력 결과--&gt;
Hello World!
20</code></pre>
<br>

<h3 id="예시-5">예시 5</h3>
<ul>
<li>람다식 안에 람다식을 넣는 람다식 함수</li>
</ul>
<pre><code class="language-kotlin">val nestedLambda: () -&gt; () -&gt; Unit = {{print(&quot;nested&quot;)}}</code></pre>
<br>

<h3 id="예시-6">예시 6</h3>
<ul>
<li>인자와 반환 값이 없는 람다식 함수</li>
</ul>
<pre><code class="language-kotlin">val print: () -&gt; Unit = {print(&quot;print&quot;)}
val print2 = {println(&quot;print&quot;)}
print()
print2()
&lt;--출력 결과--&gt;
print
print</code></pre>
<br>

<h3 id="예시-7">예시 7</h3>
<ul>
<li>파라미터 1개의 람다식인 경우는 괄호 밖으로 빼서 표현 가능</li>
</ul>
<pre><code class="language-kotlin">fun main() {
    callFunction({println(&quot;hello&quot;)} )

    callFunction(){
        println(&quot;hello&quot;)
    }
    callFunction {
        println(&quot;hello&quot;)
    }
}

private fun callFunction( call:() -&gt; Unit )  = call()
&lt;--출력 결과--&gt;
hello
hello
hello</code></pre>
<br>

<h3 id="예시-8">예시 8</h3>
<ul>
<li><p>파라미터가 1개 이상인 람다식의 경우, 람다식을 제일 뒤로 이동해서 괄호 밖으로 빼서 표현 가능</p>
</li>
<li><p>제일 처음 살펴 본 highOrderFunction의 경우처럼 여러 개의 파라미터를 받는 경우, 람다식을 제일 마직막으로 이동시키면 메서드 밖으로 이동 가능</p>
</li>
</ul>
<pre><code class="language-kotlin">private fun highOrderFunction(a: Int, b: Int, sum: (Int, Int) -&gt; Int): Int = sum(a, b)

fun main() {
    println(highOrderFunction(20, 30, {x, y -&gt; x + y}))

    var result = highOrderFunction(20, 30){
            x, y -&gt; x + y
    }

    println(result)
}
&lt;--출력 결과--&gt;
50
50</code></pre>
<p><br><br></p>
<h2 id="코틀린-표준-함수">코틀린 표준 함수</h2>
<br>

<h3 id="표준-함수">표준 함수</h3>
<ul>
<li><p>코틀린에서 유틸리티성으로 제공하며 람다를 인자로 받아 동작하는 함수</p>
</li>
<li><p>확장함수의 형태로 모든 객체에서 호출 가능</p>
</li>
<li><p>객체를 초기화 할 때 실행할 코드가 있는 경우 등에서 자주 사용됨</p>
</li>
<li><p>java에서 객체의 내용을 참조하려면 object를 reference에 변수에 저장한 후 변수에 ‘ . ‘으로 접근했으나 코틀린에서는 표준함수를 사용하여 바로 접근 가능</p>
</li>
<li><p>let( ), apply( ), run( ), with( ), also( )</p>
<p>  <img src="https://velog.velcdn.com/images/theo-no/post/17a8ca8f-97f1-4e8c-84ec-c0d9e7332c29/image.png" alt=""></p>
</li>
</ul>
<h3 id="let-">let( )</h3>
<ul>
<li><p>let( )을 호출하는 객체의 람다식 안에 파라미터로 넘김</p>
</li>
<li><p>‘it’을 통해 호출 객체에 접근</p>
</li>
<li><p>{ } 의 결과값을 반환</p>
<ul>
<li>제일 마지막 줄을 return</li>
</ul>
</li>
</ul>
<pre><code class="language-kotlin">fun main() {
    letTest()
}

fun letTest() {
    var arr = arrayOf(1, 2, 3)
    // let은 젤 마지막 줄이 리턴
    var result = arr.let {
        println(&quot;${it[1] + it[2]}&quot;)
        it[1] + it[2]
    } //let 람다식 계산 결과를 리턴

    println(result)

    //let 람다식에서 계산한 arr[1] + arr[2] 를 반환하고 arr[0]을 더해서 출력
    val result2 = arr.let { it[1] + it[2] }.plus(arr[0])
    println(&quot;더하기 결과: $result2&quot;)
}
&lt;--출력 결과--&gt;
5
5
더하기 결과: 6</code></pre>
<br>

<h3 id="also-">also( )</h3>
<ul>
<li>also( )를 호출하는 객체의 람다식 안에 파라미터로 넘김</li>
<li>‘it’을 통해 호출 객체에 접근</li>
<li>호출 객체 자체를 반환<ul>
<li>받은 객체의 값을 바꿔서 그 객체 자체를 return</li>
</ul>
</li>
</ul>
<pre><code class="language-kotlin">fun main() {
    alsoTest()
}

fun alsoTest(){
        var student = Student(&quot;Park&quot;,11)

            // also는 return x
            var student2 = student.also {
        it.age = 15
        it.name = &quot;kim&quot;
    }

    println(student) //Student(name=kim, age=15)
    println(student2) //Student(name=kim, age=15)
}</code></pre>
<br>

<h3 id="apply-">apply( )</h3>
<ul>
<li>apply( )를 호출하는 객체의 람다식 안에 파라미터로 넘김</li>
<li>‘this’를 통해 호출 객체에 접근</li>
<li>this는 생략 가능</li>
<li>호출 객체 자체를 반환<ul>
<li>받은 객체의 값을 바꿔서 그 객체 자체를 return</li>
</ul>
</li>
</ul>
<pre><code class="language-kotlin">data class Student2(var name : String, var age : Int)
fun main() {
    applyTest()
}
fun applyTest() {
    var student = Student2(&quot;Park&quot;, 11)

    var student2 = student.apply {
        age = 15 //this 생략
        name = &quot;kim&quot; //this 생략
    }
    println(student) //Student2(name=kim, age=15)
    println(student2) //Student2(name=kim, age=15)
}</code></pre>
<br>

<h3 id="run-">run( )</h3>
<ul>
<li><p>호출 객체를 파라미터로 넘기는 방식과 객체 없이 사용하는 방식 모두 가능</p>
</li>
<li><p>{ }의 결과값을 반환</p>
<ul>
<li>제일 마지막 줄을 return</li>
</ul>
</li>
</ul>
<pre><code class="language-kotlin">fun main() {
    runTest()
}
fun runTest() {
    var a = 10
    var b = 15

    //객체없이 run 단독 사용
    var result = run {
        var c = a + b
        println(c) //25
        c
    }//더하기 작업 수행 후 결과 c 반환

    //객체에 run 사용.
    result = result.run {
        plus(5)
    }
    println(result) //30
}</code></pre>
<br>

<h3 id="with-">with( )</h3>
<ul>
<li><p>인자로 받는 객체를 블럭의 파라미터로 전달</p>
</li>
<li><p>run( ) 함수와 기능은 거의 동일</p>
</li>
<li><p>Safe Call 지원하지 않음 → 종종 let과 함께 사용됨</p>
</li>
<li><p>with은 ‘ . ‘ 없이 ( )로 인자를 받는다.</p>
<ul>
<li><p>변수?. 뒤에 함수가 나오면 변수가 null일 때 뒤에 함수를 실행하지 않아서 safe call이 가능한데 with은 위와 같이 호출하지 않기 때문에 Safe Call을 하지 못한다.</p>
<pre><code class="language-kotlin">  var newName = people?.let{
          with(it){
                  age = 20
                  name
          }
  }</code></pre>
</li>
</ul>
</li>
</ul>
<pre><code class="language-kotlin">data class People(var name : String, var age : Int)

fun main() {
    withTest()
}
fun withTest(){
    var people = People(&quot;Park&quot;, 15)

    var newAge = with(people){
        age = 20
        age
    }

    println(newAge) //20

}
</code></pre>
<p><br><br></p>
<h2 id="generic">Generic</h2>
<br>

<h3 id="정의-1">정의</h3>
<ul>
<li><p>클래스나 함수를 정의할 때 타입을 정하지 않고 포괄적으로 받아 들일 수 있는 상태로 선언</p>
</li>
<li><p>타입 매개 변수를 (&lt; &gt;)를 클래스나 인터페이스 이름 뒤에 붙이면 제네릭하게 만들 수 있음</p>
</li>
</ul>
<pre><code class="language-kotlin">class Box&lt;T&gt;(t: T){
        var value = t
}</code></pre>
<br>

<h3 id="예시-1-1">예시 1</h3>
<ul>
<li>제네릭 클래스 / 인터페이스 정의</li>
</ul>
<pre><code class="language-kotlin">// kotlin
class Car2 {
}

// 항목을 담거나 뺄 수 있는 제네릭 인터페이스 Container 정의
interface Container&lt;T&gt; {
    fun put(item: T)
    fun take(index: Int) : T
}

// 자동차(Car)를 담거나 뺄 수 있는 클래스 Garage 정의
class Garage : Container&lt;Car2&gt; {
    private val items:MutableList&lt;Car2&gt; = arrayListOf();
    override fun put(item: Car2) {
        items.add(item)
    }

    override fun take(index:Int): Car2 {
        return items.get(index)
    }
}</code></pre>
<br>

<h3 id="예시-2-1">예시 2</h3>
<ul>
<li>제네릭을 통한 Todo list 작성</li>
</ul>
<pre><code class="language-kotlin">data class ToDo(val title: String,
                val content: String,
                var idx: Int = todoIdx++,
                var completed: Boolean = false)

interface ToDoContainer&lt;T&gt; {
        companion object Todo{
                var todoIdx = 1
        }
    fun addNewItem(item: T)
    fun markCompleted(idx: Int)
}</code></pre>
<br>

<h3 id="예시-3-1">예시 3</h3>
<ul>
<li><p>제네릭을 통한 Todo list 작성</p>
<ul>
<li><p>ToDoContainer에 제네릭을 사용하고 매개변수로 Todo 클래스를 대입</p>
</li>
<li><p>filter 함수는 조건에 알맞은 리스트를 반환</p>
</li>
</ul>
</li>
</ul>
<pre><code class="language-kotlin">class ToDoContainerImpl : ToDoContainer&lt;ToDo&gt; {
    var todoItems: MutableList&lt;ToDo&gt; = arrayListOf()
    override fun addNewItem(item: ToDo) {
        println(&quot;addNewItem : $item&quot;)
        todoItems.add(item)
    }
    override fun markCompleted(idx: Int) {
        todoItems.filter { it.idx == idx }[0].let {
            it.completed = true
            println(&quot;$idx is marked as completed&quot;)
            println(&quot;$it&quot;)
        }
    }
}</code></pre>
<br>

<h3 id="예시-4-1">예시 4</h3>
<ul>
<li><p>제네릭을 통한 Todo list 작성</p>
<ul>
<li>아이템을 추가하고 완료한 일을 체크하는 메서드 markCompleted의 인자로 1을 넣고 호출</li>
</ul>
</li>
</ul>
<pre><code class="language-kotlin">fun main(){
    var todayTodoList = ToDoContainerImpl()
    todayTodoList.addNewItem(ToDo(&quot;자바공부&quot;, &quot;자바 기본은 마스터 했음.&quot;))
    todayTodoList.addNewItem(ToDo(&quot;코틀린공부&quot;, &quot;코틀린 공부를 시작하자!!!!&quot;))
    todayTodoList.markCompleted(1)
}
&lt;--출력 결과--&gt;
addNewItem : ToDo(title=자바공부, content=자바 기본은 마스터 했음., idx=1, completed=false)
addNewItem : ToDo(title=코틀린공부, content=코틀린 공부를 시작하자!!!!, idx=2, completed=false)
1 is marked as completed
ToDo(title=자바공부, content=자바 기본은 마스터 했음., idx=1, completed=true)</code></pre>
<br>

<h3 id="in--out">in / out</h3>
<ul>
<li><p>타입 매개변수의 업 혹은 다운 캐스팅을 할 수 있도록 지원되는 키워드</p>
<ul>
<li><p>out : B&lt;Sub 타입&gt;을 B&lt;Super 타입&gt;에 대입할 수 있도록 지원</p>
</li>
<li><p>in : C&lt;Super 타입&gt;을 C&lt;Sub 타입&gt;에 대입할 수 있도록 지원</p>
</li>
<li><ul>
<li>: A&lt;*&gt;은 타입 인수가 무엇이든 상관 없이 대입할 수 있도록 지원</li>
</ul>
</li>
</ul>
</li>
</ul>
<pre><code class="language-kotlin">class A&lt;T&gt;
class B&lt;out T&gt;
class C&lt;in T&gt;

fun main() {
    //T 로 선언된 경우
    val a: A&lt;Int&gt; = A&lt;Int&gt;() // 양쪽 자료형 일치해야 함.

    //out T 로 선언된 경우
    val b1: B&lt;Number&gt; = B&lt;Number&gt;(); // 양쪽 자료형 일치 -&gt; OK
    val b2: B&lt;Number&gt; = B&lt;Int&gt;(); // 왼쪽이 Super 면 -&gt; OK
//    val b3: B&lt;Int&gt; = B&lt;Number&gt;(); // 왼쪽이 Sub 면 -&gt; 컴파일 오류

    //in T 로 선언된 경우
    val c1: C&lt;Number&gt; = C&lt;Number&gt;() // 양쪽 자료형 일치 -&gt; OK
    val c2: C&lt;Int&gt; = C&lt;Number&gt;() // 오른쪽이 Super면 -&gt; OK
//    val c3: C&lt;Number&gt; = C&lt;Int&gt;() // 오른쪽이 Sub 면 -&gt; 컴파일 오류

    /* &lt;*&gt; 은 상관없이 대응 */
    val star1: A&lt;*&gt; = A&lt;Number&gt;()
    val star2: A&lt;*&gt; = A&lt;Int&gt;()
    val star3: A&lt;*&gt; = A&lt;String&gt;()
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[Android(안드로이드) 3. 안드로이드 UI 기본]]></title>
            <link>https://velog.io/@theo-no/Android%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C-3.-%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C-UI-%EA%B8%B0%EB%B3%B8</link>
            <guid>https://velog.io/@theo-no/Android%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C-3.-%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C-UI-%EA%B8%B0%EB%B3%B8</guid>
            <pubDate>Tue, 11 Apr 2023 12:29:41 GMT</pubDate>
            <description><![CDATA[<h2 id="ui-기본-구조">UI 기본 구조</h2>
<p><br><br></p>
<h3 id="activity">Activity</h3>
<ul>
<li>사용자 화면을 제공하는 컴포넌트
<br><br></li>
</ul>
<h3 id="view">View</h3>
<ul>
<li><p>화면에 보이는 대부분의 요소들은 View의 하위 클래스</p>
</li>
<li><p>액티비티 자체는 앱의 실행 단위인 컴포넌트</p>
<ul>
<li>액티비티에 버튼, 문자열, 이미지 등을 출력해줘야 화면에 보임
<br><br></li>
</ul>
</li>
</ul>
<h3 id="view의-계층-구조">View의 계층 구조</h3>
<ul>
<li><p>ViewGroup</p>
<ul>
<li>뷰 그룹은 레이아웃 및 뷰 컨테이너의 기본 클래스</li>
</ul>
</li>
<li><p>ViewGroup 종류</p>
<ul>
<li><p>뷰 컨테이너</p>
<ul>
<li>ViewPager<ul>
<li>유저가 페이지를 좌우로 넘길 수 있는 레이아웃 관리자 클래스</li>
</ul>
</li>
<li>Toolbar<ul>
<li>특정 화면에서 가능한 행동들을 제시하는 뷰</li>
<li>보통 안드로이드에서는 상단에 위치</li>
</ul>
</li>
</ul>
</li>
<li><p>기본 Layout 클래스</p>
<ul>
<li>LinearLayout(선형으로 배치)</li>
<li>RelativeLayout(상대 위치로 배치)</li>
<li>FrameLayout(겹쳐서 배치)</li>
<li>GridLayout(표 형태로 배치)</li>
<li>ConstraintLayout(계층 구조로 배치)
<br><br></li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="view의-대표적인-서브-클래스들">View의 대표적인 서브 클래스들</h3>
<ul>
<li><p>Button</p>
<ul>
<li><p>일반적으로 생각하는 버튼 모양의 뷰</p>
</li>
<li><p>주로 클릭 시 호출되는 setOnClickListener를 이용하여 사용</p>
</li>
</ul>
</li>
<li><p>EditText</p>
<ul>
<li>텍스트를 수정하면 입력할 수 있는 뷰</li>
</ul>
</li>
<li><p>CheckBox</p>
<ul>
<li>선택하거나 취소할 수 있는 특정 유형의 두 가지 상태를 가지고 있는 버튼</li>
</ul>
</li>
<li><p>RadioButton</p>
<ul>
<li>여러가지 동일한 형태의 선택할 수 있는 버튼 중 하나를 고르는 버튼</li>
</ul>
</li>
<li><p>ImageView</p>
<ul>
<li>이미지 파일을 화면에 보여줄 수 있는 뷰</li>
</ul>
</li>
<li><p>이 외에도 많은 View가 있고 각 View들은 공통 속성을 가짐</p>
<ul>
<li><p>Color, Dimensions Positioning</p>
</li>
<li><p>Focus</p>
</li>
<li><p>Interactive</p>
</li>
<li><p>Visible</p>
</li>
<li><p>다른 View와 관계를 가질 수 있음
<br><br></p>
</li>
</ul>
</li>
</ul>
<h3 id="레이아웃-편집기">레이아웃 편집기</h3>
<ul>
<li>안드로이드에는 View를 편하게 다룰 수 있는 레이아웃 편집기가 존재</li>
</ul>
<p><img src="https://velog.velcdn.com/images/theo-no/post/57d4f1c7-5b4a-4e29-a9ad-7b9059e51e02/image.png" alt=""></p>
<ol>
<li><p>Palette </p>
<ul>
<li>레이아웃으로 드래그해서 사용할 수 있는 다양한 뷰 및 뷰 그룹을 포함</li>
</ul>
</li>
<li><p>Component Tree</p>
<ul>
<li>레이아웃에서 구성요소의 계층 구조를 보여줌</li>
</ul>
</li>
<li><p>툴바</p>
<ul>
<li>편집기에서 레이아웃 모양을 구성하고</li>
</ul>
</li>
<li><p>디자인 편집기</p>
<ul>
<li>디자인 뷰나 청사진 뷰 또는 두 뷰 모두에서 레이아웃을 수정</li>
</ul>
</li>
<li><p>Attributes</p>
<ul>
<li>선택한 뷰의 속성을 제어할 수 있는 영역</li>
</ul>
</li>
<li><p>뷰 모드</p>
<ul>
<li>레이아웃을 코드 모드, 디자인 모드, 분할 모드 중 하나로 표시</li>
<li>분할 모드는 코드 모드와 디자인 모드 동시에 보여줌</li>
</ul>
</li>
<li><p>확대/축소 및 화면 이동 제어</p>
<ul>
<li>편집기 내에서 미리보기의 크기와 위치를 제어
<br><br></li>
</ul>
</li>
</ol>
<h3 id="android-resource">Android Resource</h3>
<ul>
<li><p>리소스</p>
<p>  <img src="https://velog.velcdn.com/images/theo-no/post/b39c4e47-8d18-45fc-842d-aa278c5621ba/image.png" alt=""></p>
</li>
</ul>
<pre><code>- 레이아웃의 코드에서 변하지 않는 데이터 분리

- 문자열, 치수, 이미지, 메뉴 텍스트, 색, 스타일
- drawable
    - 이미지, 이미지와 관련된 XML, 그림을 표현한 XML
- layout
    - 화면 UI를 정의한 레이아웃 XML
- values
    - 문자열, 색상, 크기 등 여러 가지 값
- menu
    - 액티비티의 메뉴를 구성하기 위한 XML
- mipmap
    - 앱 아이콘 이미지
    &lt;br&gt;&lt;br&gt;</code></pre><h3 id="안드로이드-치수">안드로이드 치수</h3>
<ul>
<li><p>dpi(Dots per Inch)</p>
<ul>
<li><p>1인치(2.54cm)에 들어 있는 픽셀의 수(안드로이드에서는 dpi 160이 기본)</p>
<ul>
<li>ldpi : 120dpi</li>
<li>mdpi : 160dpi (기본)</li>
<li>hdpi : 240dpi</li>
<li>xhdpi : 320dpi</li>
<li>xxhdpi : 480dpi</li>
<li>xxxhdpi : 640dpi</li>
</ul>
</li>
</ul>
</li>
<li><p>dp 또는 dip(Density-independent Pixels)</p>
<ul>
<li><p>픽셀에 독립적인 단위이면서 어떤 화면의 크기에서도 동일한 크기를 나타낼 수 있음</p>
</li>
<li><p>스크린의 픽셀과 dp가 160인 경우에는 1dp는 1pixel과 같으나 dpi가 240인 경우에는 1dp는 1.5pixel</p>
<ul>
<li>dp = pixel / (density / 160)</li>
</ul>
</li>
</ul>
</li>
<li><p>sp(Scale-independent Pixels)</p>
<ul>
<li>dp의 비슷한 부분이 있으나 사용자가 선택한 글꼴 크기에 의해 크기가 조절됨</li>
</ul>
</li>
<li><p>pt</p>
<ul>
<li>1/72 inch 기반의 물리적 화면 사이즈, 인쇄에서 쓰이던 크기, 안드로이드에서는 잘 사용하지 않음</li>
</ul>
</li>
<li><p>px(Pixels)</p>
<ul>
<li>스크린의 실제 픽셀 단위를 사용하고 실제 크기나 밀도와 관계 없음</li>
</ul>
</li>
<li><p>mm(Millimeters)</p>
<ul>
<li>화면의 물리적 사이즈 기반으로 millimeter를 사용</li>
</ul>
</li>
<li><p>in(Inches)</p>
<ul>
<li>화면의 물리적 사이즈 기반으로 inch를 사용</li>
</ul>
</li>
<li><p>보통 글꼴 크기만 sp를 사용하고 나머지는 모두 dp를 사용</p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Android(안드로이드) 2. 안드로이드 파일 구조]]></title>
            <link>https://velog.io/@theo-no/Android%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C-2.-%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C-%ED%8C%8C%EC%9D%BC-%EA%B5%AC%EC%A1%B0</link>
            <guid>https://velog.io/@theo-no/Android%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C-2.-%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C-%ED%8C%8C%EC%9D%BC-%EA%B5%AC%EC%A1%B0</guid>
            <pubDate>Mon, 10 Apr 2023 07:31:46 GMT</pubDate>
            <description><![CDATA[<h2 id="디렉터리-파일-구조">디렉터리 파일 구조</h2>
<p><img src="https://velog.velcdn.com/images/theo-no/post/40c1a9d7-b625-4bec-9dbf-e5b942e066a8/image.png" alt="">
<br></p>
<h3 id="androidmanifestxml">AndroidManifest.xml</h3>
<ul>
<li>앱의 메인 환경 파일이다.</li>
</ul>
<pre><code class="language-xml">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;manifest xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    xmlns:tools=&quot;http://schemas.android.com/tools&quot;&gt;

    &lt;application
        android:allowBackup=&quot;true&quot;
        android:dataExtractionRules=&quot;@xml/data_extraction_rules&quot;
        android:fullBackupContent=&quot;@xml/backup_rules&quot;
        android:icon=&quot;@mipmap/ic_launcher&quot;
        android:label=&quot;@string/app_name&quot;
        android:supportsRtl=&quot;true&quot;
        android:theme=&quot;@style/Theme.MyApplication&quot;
        tools:targetApi=&quot;31&quot;&gt;
        &lt;activity
            android:name=&quot;.MainActivity&quot;
            android:exported=&quot;true&quot;&gt;
            &lt;intent-filter&gt;
                &lt;action android:name=&quot;android.intent.action.MAIN&quot; /&gt;

                &lt;category android:name=&quot;android.intent.category.LAUNCHER&quot; /&gt;
            &lt;/intent-filter&gt;
        &lt;/activity&gt;
    &lt;/application&gt;

&lt;/manifest&gt;</code></pre>
<ul>
<li><p>manifest</p>
<ul>
<li><p>태그를 통해 이 문서가 manifest에 관련된 문서라는 것을 시스템이 알 수 있음</p>
</li>
<li><p>‘xmlns:android’는 android라는 네임스페이스를 선언</p>
<ul>
<li><a href="http://schemas.android.com/apk/res/android">http://schemas.android.com/apk/res/android</a></li>
</ul>
</li>
<li><p>‘package’의 경우 해당 어플리케이션이 속한 패키지 이름을 지정</p>
</li>
</ul>
</li>
<li><p>application</p>
<ul>
<li><p>애플리케이션의 정보 정의</p>
</li>
<li><p>android:allowBack</p>
<ul>
<li>백업 및 복구 기능을 사용할 것인가 여부(기본값 : true)</li>
</ul>
</li>
<li><p>android:icon</p>
<ul>
<li>어플리케이션 전체를 위한 아이콘과 각각의 컴포넌트를 위한 아이콘</li>
</ul>
</li>
<li><p>android:label</p>
<ul>
<li>어플리케이션을 나타내는 사용자가 읽을 수 있는 라벨</li>
<li>간단히 말해 어플 이름</li>
</ul>
</li>
<li><p>android:roundIcon</p>
<ul>
<li>적응형 아이콘 적용</li>
</ul>
</li>
<li><p>android:supportsRtl</p>
<ul>
<li>어플리케이션의 RTL(Right-To-Left) 지원 여부</li>
<li>RTL : 오른쪽에서 왼쪽으로 글씨를 읽는 경우 지원</li>
</ul>
</li>
<li><p>android:theme</p>
<ul>
<li>어플리케이션 안의 모든 기능들의 기본 테마 정의</li>
</ul>
</li>
<li><p>activity 태그</p>
<ul>
<li>어플리케이션의 시각적 사용자 인터페이스 요소인 액티비티 선언</li>
<li>모든 액티비티는 manifest의 activity 태그에 등록해야 함</li>
</ul>
</li>
<li><p>android:name</p>
<ul>
<li>액티비티의 클래스명 설정</li>
</ul>
</li>
<li><p>android:exported</p>
<ul>
<li>이 액티비티가 외부에서 실행될 수 있는지 없는지 설정</li>
<li>외부에서 호출할 수 있으면 true<ul>
<li>MainActivity는 런처에서 실행해야 하므로 항상 true</li>
</ul>
</li>
</ul>
</li>
<li><p>intent-filter 태그</p>
<ul>
<li>수신할 intent를 지정한다.</li>
<li>action 태그<ul>
<li>수신할 action명을 지정. 런처에서 클릭하는 아래 action의 Intent가 생성<ul>
<li>android.intent.action.MAIN</li>
</ul>
</li>
<li>런처에서 클릭하면 첫 액티비티로 해당 액티비티를 시작</li>
<li>action 태그는 하나만 존재 가능</li>
</ul>
</li>
<li>category 태그<ul>
<li>액션과 함께 수신할 Intent의 특징을 나타내는 항목</li>
<li>android.intent.category.LAUNCHER</li>
<li>이 액티비티가 최초 액티비티, 시스템의 애플리케이션 시작 관리자 목록으로 게재</li>
<li>category 태그는 여러 개 존재 가능</li>
</ul>
</li>
<li>런처에서 클릭하면 해당 액티비티를 실행한다는 뜻</li>
</ul>
</li>
</ul>
</li>
</ul>
<p><br><br>    </p>
<h3 id="mainactivitykt">MainActivity.kt</h3>
<pre><code class="language-kotlin">package com.ex1

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }
}</code></pre>
<ul>
<li><p>AppCompatActivity를 상속 받아 사용</p>
<ul>
<li>AppCompatActivity는 Activity의 서브 클래스</li>
</ul>
</li>
<li><p>onCreate( )</p>
<ul>
<li><p>액티비티가 실행될 때 시스템이 호출하는 함수</p>
</li>
<li><p>setContentView( ) 함수를 통해 화면을 출력</p>
</li>
<li><p>R.layout.activity_main을 매개변수로 지정하였으므로 res/layout/activity_main.xml을 사용하여 화면을 구성
<br><br><br></p>
</li>
</ul>
</li>
</ul>
<h3 id="activity_mainxml">activity_main.xml</h3>
<pre><code class="language-xml">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;androidx.constraintlayout.widget.ConstraintLayout xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    xmlns:app=&quot;http://schemas.android.com/apk/res-auto&quot;
    xmlns:tools=&quot;http://schemas.android.com/tools&quot;
    android:layout_width=&quot;match_parent&quot;
    android:layout_height=&quot;match_parent&quot;
    tools:context=&quot;.MainActivity&quot;&gt;

    &lt;TextView
        android:layout_width=&quot;wrap_content&quot;
        android:layout_height=&quot;wrap_content&quot;
        android:text=&quot;Hello World!&quot;
        app:layout_constraintBottom_toBottomOf=&quot;parent&quot;
        app:layout_constraintEnd_toEndOf=&quot;parent&quot;
        app:layout_constraintStart_toStartOf=&quot;parent&quot;
        app:layout_constraintTop_toTopOf=&quot;parent&quot; /&gt;

&lt;/androidx.constraintlayout.widget.ConstraintLayout&gt;</code></pre>
<ul>
<li><p>ConstraintLayout</p>
<ul>
<li><p>루트 요소인 ConstraintLayout은 자식 요소들의 위치를 상대적으로 배치</p>
</li>
<li><p>여기서는 자식인 TextView의 배치를 담당</p>
</li>
<li><p>추후 Layout에서 상세히 설명</p>
</li>
</ul>
</li>
<li><p>TextView</p>
<ul>
<li><p>문구를 화면에 표시하는 view</p>
</li>
<li><p>View 객체를 상속 받음</p>
</li>
<li><p>여기서는 Hello world!를 출력
<br><br></p>
</li>
</ul>
</li>
</ul>
<h3 id="gradle">Gradle</h3>
<ul>
<li><p>안드로이드 빌드 자동화 시스템</p>
</li>
<li><p>bulid.gralde 파일을 통해 여러가지 환경 설정</p>
</li>
<li><p>프로젝트를 위한 build.gradle과 모듈을 위한 build.gradle 존재</p>
</li>
<li><p>안드로이드 스튜디오 plugin과 Gradle은 항상 버전을 맞춰줘야 함</p>
</li>
<li><p>gradle-wrapper.properties에서 Gradle 버전 확인</p>
</li>
<li><p>project structure에서 plugin 정보 확인</p>
</li>
<li><p>안드로이드 공식 홈페이지에 plugin과 gradle 버전 매칭 정보 확인</p>
</li>
<li><p>프로젝트 수준의 Gradle</p>
<pre><code class="language-groovy">  plugins {
      id &#39;com.android.application&#39; version &#39;7.4.2&#39; apply false
      id &#39;com.android.library&#39; version &#39;7.4.2&#39; apply false
      id &#39;org.jetbrains.kotlin.android&#39; version &#39;1.8.0&#39; apply false
  }</code></pre>
<ul>
<li><p>모든 모듈을 위한 최상위 설정을 목적</p>
</li>
<li><p>plugins</p>
<ul>
<li>gradle이 build할 때 사용할 plugin 선언</li>
<li>kotlin 버전 지정</li>
<li>모듈 gradle 파일에서 버전 없이 이름만으로 사용. 대부분 application으로 생성하지만 library도 가능<br></li>
</ul>
</li>
</ul>
</li>
<li><p>모듈 수준의 Gradle</p>
<pre><code class="language-groovy">  plugins {
      id &#39;com.android.application&#39;
      id &#39;org.jetbrains.kotlin.android&#39;
  }

  android {
      namespace &#39;com.ex1&#39;
      compileSdk 33

      defaultConfig {
          applicationId &quot;com.ex1&quot;
          minSdk 24
          targetSdk 33
          versionCode 1
          versionName &quot;1.0&quot;

          testInstrumentationRunner &quot;androidx.test.runner.AndroidJUnitRunner&quot;
      }

      buildTypes {
          release {
              minifyEnabled false
              proguardFiles getDefaultProguardFile(&#39;proguard-android-optimize.txt&#39;), &#39;proguard-rules.pro&#39;
          }
      }
      compileOptions {
          sourceCompatibility JavaVersion.VERSION_1_8
          targetCompatibility JavaVersion.VERSION_1_8
      }
      kotlinOptions {
          jvmTarget = &#39;1.8&#39;
      }
  }
  dependencies {

      implementation &#39;androidx.core:core-ktx:1.7.0&#39;
      implementation &#39;androidx.appcompat:appcompat:1.6.1&#39;
      implementation &#39;com.google.android.material:material:1.8.0&#39;
      implementation &#39;androidx.constraintlayout:constraintlayout:2.1.4&#39;
      testImplementation &#39;junit:junit:4.13.2&#39;
      androidTestImplementation &#39;androidx.test.ext:junit:1.1.5&#39;
      androidTestImplementation &#39;androidx.test.espresso:espresso-core:3.5.1&#39;
  }</code></pre>
<ul>
<li><p>모듈에 대한 특성 정의</p>
</li>
<li><p>파일을 수정하면 Sync Now를 이용해 프로젝트에 반영해야 함</p>
</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Kotlin(코틀린) 심화문법 1. 추상 클래스/인터페이스/data 클래스/object 클래스/enum 클래스/sealed 클래스/inner 클래스]]></title>
            <link>https://velog.io/@theo-no/Kotlin%EC%BD%94%ED%8B%80%EB%A6%B0-%EC%8B%AC%ED%99%94%EB%AC%B8%EB%B2%95-1.-%EC%B6%94%EC%83%81-%ED%81%B4%EB%9E%98%EC%8A%A4%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4data-%ED%81%B4%EB%9E%98%EC%8A%A4object-%ED%81%B4%EB%9E%98%EC%8A%A4enum-%ED%81%B4%EB%9E%98%EC%8A%A4sealed-%ED%81%B4%EB%9E%98%EC%8A%A4inner-%ED%81%B4%EB%9E%98%EC%8A%A4</link>
            <guid>https://velog.io/@theo-no/Kotlin%EC%BD%94%ED%8B%80%EB%A6%B0-%EC%8B%AC%ED%99%94%EB%AC%B8%EB%B2%95-1.-%EC%B6%94%EC%83%81-%ED%81%B4%EB%9E%98%EC%8A%A4%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4data-%ED%81%B4%EB%9E%98%EC%8A%A4object-%ED%81%B4%EB%9E%98%EC%8A%A4enum-%ED%81%B4%EB%9E%98%EC%8A%A4sealed-%ED%81%B4%EB%9E%98%EC%8A%A4inner-%ED%81%B4%EB%9E%98%EC%8A%A4</guid>
            <pubDate>Wed, 05 Apr 2023 10:50:46 GMT</pubDate>
            <description><![CDATA[<h2 id="추상-클래스와-인터페이스">추상 클래스와 인터페이스</h2>
<br>

<h3 id="abstract-class">abstract class</h3>
<ul>
<li><p>상속 받을 클래스에서 구현해야 할 프로퍼티 및 메서드를 기술한 클래스</p>
</li>
<li><p>abstract 키워드와 함께 선언하며 추상 클래스는 객체 생성 불가</p>
</li>
<li><p>상속을 주기 위해서는 open 키워드를 선언해야 하는데 abstract class는 open이 기본적으로 적용됨</p>
</li>
<li><p>java와 달리 추상 프로퍼티를 가질 수 있음</p>
<ul>
<li>반드시 하위 클래스에서 재정의하여 초기화 해야 함</li>
</ul>
</li>
<li><p>예제 코드</p>
<pre><code class="language-kotlin">  // 추상 클래스, 주 생성자에는 비추상 프로퍼티 선언의 매개변수 3개가 있음
  abstract class Vehicle(val name: String, val color: String, val weight: Double) {
      // 추상 프로퍼티 (반드시 하위 클래스에서 재정의해 초기화해야 함) -&gt; 자바와 차이점
      abstract var maxSpeed: Double
      // 일반 프로퍼티 (초기 값인 상태를 저장할 수 있음)
      var year = &quot;2018&quot;
      // 추상 메서드 (반드시 하위 클래스에서 구현해야 함)
      abstract fun start()
      abstract fun stop()
      // 일반 메서드
      fun displaySpecs() {
          println(&quot;Name: $name, Color: $color, Weight: $weight, Year: $year, Max Speed: $maxSpeed&quot;) }
  }
  class Car(name: String, color: String, weight: Double, override var maxSpeed: Double) : Vehicle(name, color, weight) {
      override fun start() {
          println(&quot;Car Started&quot;) // 코드의 구현
      }
      override fun stop() {
          println(&quot;Car Stopped&quot;) // 코드의 구현
      }
  }
  class Motorcycle(name: String, color: String, weight: Double, override var maxSpeed: Double) : Vehicle(name, color, weight) {
      override fun start() {
          println(&quot;Bike Started&quot;) // 코드의 구현
      }
      override fun stop() {
          println(&quot;Bike Stopped&quot;) // 코드의 구현
      }
  }
  fun main() {
      val car = Car(&quot;SuperMatiz&quot;, &quot;yellow&quot;, 1110.0, 270.0)
      val motor = Motorcycle(&quot;DreamBike&quot;, &quot;red&quot;, 173.0, 100.0)
      car.year = &quot;2013&quot;
      car.displaySpecs()
      car.start()
      motor.displaySpecs()
      motor.start()
  }</code></pre>
  <br>


</li>
</ul>
<h3 id="interface">interface</h3>
<ul>
<li><p>자바와 동일하게 구현부가 없는 method + default method의 집합</p>
<ul>
<li>default 키워드는 따로 없음</li>
</ul>
</li>
<li><p>상속을 주기 위해 만들어진 클래스로 별도의 open 키워드는 필요 없음</p>
</li>
<li><p>상속 받는 interface에서 동일한 function이 있다면 반드시 구현해야 함</p>
</li>
<li><p>예제 코드</p>
<pre><code class="language-kotlin">  interface Clickable {
      fun click()
      fun showOff(){
          println(&quot;Clickable.showOff&quot;)
      }
  }
  interface Focusable{
      fun showOff(){
          println(&quot;Focusable.showOff&quot;)
      }
  }
  class Button : Clickable, Focusable {
      override fun click() {
          println(&quot;Button.click&quot;)
      }
      //showOff는 두 슈퍼에 모두 존재하므로, 동일하게 애매함을 없애기 위해서 반드시 선언.
      //super에 선언된 fun을 호출할때는 super&lt;Clickable&gt;.showOff()
      //java에서는 Clickable.super.showOff();
      override fun showOff() {
          println(&quot;Button.showOff&quot;)
      }
  }

  fun main() {
      var button = Button()
      button.click()
      button.showOff()
  }</code></pre>
<p>  <br><br></p>
</li>
</ul>
<h2 id="data-class">data class</h2>
<br>

<h3 id="특징">특징</h3>
<ul>
<li><p>data class 키워드로 선언해서 사용</p>
</li>
<li><p>변수나 상수를 선언할 수 있음 (구분은 쉼표( , ) 로)</p>
</li>
<li><p>프로퍼티를 일반 클래스 내의 프로퍼티를 기준으로 생성자가 만들어짐</p>
</li>
<li><p>DTO(Data Transfer Object)를 다룰 때 유용</p>
</li>
<li><p>자바와 다르게 getter, setter 만들 필요가 없고 초기화도 필요 없이 선언하기만 하면 끝</p>
<br>

</li>
</ul>
<h3 id="일반-클래스-vs-data-class">일반 클래스 vs data class</h3>
<ul>
<li><p>일반 클래스와 달리 소괄호로 프로퍼티를 선언하면 끝</p>
</li>
<li><p>자동으로 파라미터 생성자, toString( ), equals( ), hashCoode 등 제공</p>
</li>
<li><p>{ } 열어서 function 추가도 가능</p>
</li>
<li><p>예시 코드</p>
<pre><code class="language-kotlin">  //일반 클래스
  class Person20(var name: String) {
      private var type: String = &quot;&quot;
      private var age: Int = 0

      constructor(name: String, type: String, age: Int) : this(name) {
          this.type = type
          this.age = age
      }

      fun myMbTi() {
          println(&quot;my name is $name and type is $type&quot;)
      }
  }
  //data clas
  data class PersonData(val name: String, val type: String, var num: Int, var own: Boolean)

  fun main(args: Array&lt;String&gt;) {

      val person20 = Person20(&quot;김싸피&quot;, &quot;ENFP&quot;, 23)
      person20.myMbTi()

      val person = PersonData(&quot;김싸피&quot;, &quot;ENFP&quot;, 23, true)
      println(person)

      if (person.own)
          println(&quot;my name is  ${person.name}&quot;)
      else
          println(&quot;i&#39;m not human being&quot;)

  }</code></pre>
<p>  <br><br></p>
</li>
</ul>
<h2 id="object-class">object class</h2>
<br>

<h3 id="특징-1">특징</h3>
<ul>
<li><p>object 키워드로 선언</p>
<ul>
<li>class 키워드 위치에 object 키워드 선언 → 싱글톤 클래스가 됨</li>
</ul>
</li>
<li><p>생성자를 갖지 않음</p>
<ul>
<li>생성자가 private로 선언되므로 가질 수 없음 → 싱글톤</li>
</ul>
</li>
<li><p>어느 클래스, 함수에서든 별도의 객체화 과정 없이 접근 가능</p>
</li>
<li><p>프로그램이 실행되는 동안 저장된 데이터는 손실되지 않고, 프로그램이 종료되면 소멸</p>
</li>
<li><p>위 특징 덕분에 안드로이드에서는 액티비티, 프래그먼트 구분하지 않고 데이터 전달 가능</p>
</li>
<li><p>anonymous nested class를 생성할 때 사용</p>
<ul>
<li>익명 객체 = 재사용 없는 객체 = 일회성 객체</li>
</ul>
</li>
<li><p>예제 코드</p>
<pre><code class="language-kotlin">  object PersonObject {
      var name: String = &quot;&quot;
      var type: String = &quot;&quot;
      var age: Int = 0

      fun myType() {
          println(&quot;my name is $name and type is $type age is $age&quot;)
      }
  }

  fun main() {
      val name = &quot;samsung&quot;
      val type = &quot;ENFP&quot;
      val age = 23

      PersonObject.name = name
      PersonObject.type = type
      PersonObject.age = age
      PersonObject.myType()
      println(&quot;${PersonObject.name} and ${PersonObject.type} and ${PersonObject.age}&quot;)
  }</code></pre>
<p>  <br><br></p>
</li>
</ul>
<h2 id="enum-class">enum class</h2>
<br>

<h3 id="특징-2">특징</h3>
<ul>
<li><p>java와 동일한 열거형</p>
</li>
<li><p>[클래스 이름.name] 으로 이름 값 접근 가능</p>
</li>
<li><p>[클래스 이름.ordinal] 으로 해당 값이 몇 번째에 기록되어 있는지 순서 값 접근 가능</p>
</li>
<li><p>인자가 있는 열거형 클래스인 경우 열거 값들을 표현하는 방식을 다채롭게 할 수 있음</p>
<br>

</li>
</ul>
<h3 id="인자-없는-열거형-클래스">인자 없는 열거형 클래스</h3>
<ul>
<li><p>별도의 인자가 없는 가장 기본적인 형태의 열거형 클래스</p>
<pre><code class="language-kotlin">  enum class ExHandsome {
      EX, LOVE, PEACE
  }

  fun main() {
      val exEnum: ExHandsome = ExHandsome.LOVE
      println(&quot;${exEnum.name} ... ${exEnum.ordinal}&quot;)

      val exEnum2: Array&lt;ExHandsome&gt; = ExHandsome.values()

      for (i in exEnum2.indices) {
          println(exEnum2[i].name)
      }

  }</code></pre>
  <br>


</li>
</ul>
<h3 id="인자-있는-열거형-클래스">인자 있는 열거형 클래스</h3>
<pre><code class="language-kotlin">enum class Human(val age: Int) {
    KIM(25), CHOI(21)
}

fun main() {
    val human: Human = Human.KIM
    println(&quot;${human.name}, ${human.age}, ${human.ordinal}&quot;)

}</code></pre>
<p><br><br></p>
<h2 id="sealed-class">sealed class</h2>
<br>

<h3 id="특징-3">특징</h3>
<ul>
<li><p>부모 클래스의 상속을 받는 자식 클래스의 종류를 제한하는 클래스</p>
</li>
<li><p>sealed class에 정의된 하위 클래스 외의 다른 하위 클래스는 존재하지 않는다는 것을 컴파일러에게 알려줌</p>
</li>
<li><p>sealed class 키워드를 선언해서 사용</p>
</li>
<li><p>sealed class도 추상 클래스로 객체 생성 불가</p>
</li>
<li><p>sealed class와 그 하위 클래스는 동일한 파일에 정의되어야 함.</p>
</li>
<li><p>하위 클래스는 class, data class, object class로 정의 가능</p>
</li>
<li><p>예시 코드</p>
<pre><code class="language-kotlin">  sealed class Color {
      object Red : Color()
      object Green : Color()
      object Blue : Color()
  }
  fun main() {
      val color: Color = Color.Red

          val font = when (color) {
          is Color.Red -&gt; &quot;Noto Sans&quot;
          is Color.Green -&gt; &quot;Open Sans&quot;
          is Color.Blue -&gt; &quot;sans-serif&quot;
          // No error!
      }
      println(&quot;결정된 font는 : $font&quot;)

          val font2 = when (color) {
          is Color.Red -&gt; &quot;Noto Sans&quot;
          is Color.Green -&gt; &quot;Open Sans&quot;
          is Color.Blue -&gt; &quot;sans-serif&quot;
      }
      println(&quot;결정된 font는 : $font&quot;)
  }</code></pre>
  <br>



</li>
</ul>
<h3 id="sealed-class--vs--enum">sealed class  vs  enum</h3>
<ul>
<li><p>공통점</p>
<ul>
<li>둘 다 타입을 제한할 때 사용</li>
</ul>
</li>
<li><p>차이점</p>
<ul>
<li><p>enum은 하나의 객체만 생성 가능</p>
</li>
<li><p>sealed class는 여러 개의 객체 생성 가능</p>
</li>
</ul>
</li>
<li><p>예시 코드</p>
<pre><code class="language-kotlin">  sealed class Expr

  data class Const(val number: Double) : Expr()
  data class Sum(val e1: Expr, val e2: Expr) : Expr()
  object NotANumber : Expr()

  fun eval(expr: Expr): Double = when (expr) {
      is Const -&gt; {
          expr.number
      }
      is Sum -&gt; {
          eval(expr.e1) + eval(expr.e2)
      }
      is NotANumber -&gt; {
          Double.NaN
      }
  }

  fun main() {
      val num1 = Const(10.0)
      val num2 = Const(20.0)
      val sum = Sum(num1, num2)
      val result = eval(sum)
      println(&quot;result : $result&quot;)  //30.0

  }</code></pre>
<p>  <br><br></p>
</li>
</ul>
<h2 id="inner-class">inner class</h2>
<br>

<h3 id="특징-4">특징</h3>
<ul>
<li><p>자바에서는 클래스 안에 클래스를 정의하면 자동으로 내부 클래스가 되었지만 코틀린에서는 클래스 안에 클래스 선언하면 그냥 중첩 클래스가 됨</p>
</li>
<li><p>내부 클래스로 만드려면 inner 키워드로 선언해야 함</p>
</li>
<li><p>내부 클래스는 기본적으로 외부 클래스를 참조 할 수 있지만, 중첩 클래스는 선언이 클래스 내부에 있을 뿐 외부 클래스의 member에 접근 불가</p>
<br>

</li>
</ul>
<h3 id="nested-class--vs-inner-class">Nested class  vs Inner class</h3>
<pre><code class="language-kotlin">// nested class중첩 클래스
classOuter {
private valbar: Int = 1

classNested {
// nested class는 외부 클래스 멤버 참조 불가 (자바에선 가능했다.)
        //그냥 안에 있는 클래스 정도라 생각해라
// fun foo() = bar
funfoo() = 2
    }
}

// inner class내부 클래스
classOuterInner {
private valbar: Int = 1

inner classInner {
funfoo() = bar
//        fun foo() = this@OuterInner.bar
}
}

funmain() {

valdemo = Outer.Nested().foo()
valdemo2 = OuterInner().Inner().foo()
println(demo)// 2
println(demo2)// 1
}</code></pre>
<br>

<h3 id="가시성-지시자">가시성 지시자</h3>
<ul>
<li><p>가시성 지시자(Visibility modifiers)를 통해서 외부 접근 범위를 정할 수 있음</p>
<ul>
<li><p>private</p>
<ul>
<li>외부에서 접근 불가</li>
</ul>
</li>
<li><p>protected</p>
<ul>
<li>상속 관계에 있을 때만 외부에서 접근 가능</li>
</ul>
</li>
<li><p>internal</p>
<ul>
<li>같은 모듈 내에서 접근 가능</li>
</ul>
</li>
<li><p>public</p>
<ul>
<li>어디서든 접근 가능(기본값)</li>
</ul>
</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Android(안드로이드) 1. 안드로이드 구조]]></title>
            <link>https://velog.io/@theo-no/Android%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C-1.-%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C-%EA%B5%AC%EC%A1%B0</link>
            <guid>https://velog.io/@theo-no/Android%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C-1.-%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C-%EA%B5%AC%EC%A1%B0</guid>
            <pubDate>Tue, 04 Apr 2023 14:47:50 GMT</pubDate>
            <description><![CDATA[<h2 id="안드로이드-플랫폼-구조">안드로이드 플랫폼 구조</h2>
<br>

<h3 id="안드로이드-플랫폼-아키텍처">안드로이드 플랫폼 아키텍처</h3>
<p><img src="https://velog.velcdn.com/images/theo-no/post/1308bc0b-f929-41bd-a00f-1ca84cfe1461/image.png" alt=""></p>
<ul>
<li><p>Linux Kernel</p>
<ul>
<li>보안, 메모리 관리, 프로세스 관리, 파일 시스템 관리, 파워 관리, 네트워크 스택, 하드웨어 드라이버 등 하드웨어를 지원</li>
</ul>
</li>
<li><p>HAL</p>
<ul>
<li><p>Hardware Abstraction Layer(하드웨어 추상화 계층)</p>
<ul>
<li><p>상위 수준의 Java API 프레임워크에 기기 하드웨어 기능을 노출하는 표준 인터페이스를 제공</p>
</li>
<li><p>HAL은 여러 라이브러릴 모듈로 구성되어 있으며, 카메라 또는 블루투스 모듈과 같은 특정 유형의 하드웨어 구성 요소를 위한 인터페이스를 구현</p>
</li>
<li><p>프레임워크 API가 기기 하드웨어에 엑세스하기 위해 호출을 수행하면 Android 시스템이 해당 하드웨어 구성 요소에 대한 라이브러리 모듈을 로드</p>
</li>
</ul>
</li>
</ul>
</li>
<li><p>Native C / C++ Libraries</p>
<ul>
<li>안드로이드 프레임워크에서 필요한 C와 C++ 라이브러리를 제공</li>
</ul>
</li>
<li><p>Android Runtime</p>
<ul>
<li>코어 라이브러리 지원, Dalvik | ART Virtual Machine으로 안드로이드 애플리케이션 실행환경을 제공</li>
</ul>
</li>
<li><p>Java API Framework</p>
<ul>
<li>안드로이드 어플리케이션 개발 시 필요한 API를 제공</li>
</ul>
</li>
<li><p>System Apps</p>
<ul>
<li>Email 클라이언트, SMS 프로그램, 달력, 지도, 브라우저 등의 코어 어플리케이션을 제공<br>

</li>
</ul>
</li>
</ul>
<h3 id="app-components">App Components</h3>
<ul>
<li><p>컴포넌트란</p>
<ul>
<li><p>컴포넌트는 앱 내에서의 독립적인 실행 단위(구성 단위)</p>
<ul>
<li><p>컴포넌트 여러 개를 조합하여 하나의 앱을 만듦</p>
</li>
<li><p>일반 클래스와 달리 생명주기를 안드로이드 시스템이 관리</p>
</li>
<li><p>독립적인 실행 단위라는 말은 직접 코드로 결합해서 실행하는 것이 아니라 컴포넌트 간에 Intent라는 특정 클래스를 매개로 하여 결합하지 않은 상태로 실행하는 구조</p>
</li>
</ul>
</li>
<li><p>Main 함수 같은 애플리케이션의 진입 지점이 따로 없음</p>
<ul>
<li>런처의 아이콘을 클릭해서 실행하면, 최초 시작인 경우 메인 화면이 보이게 됨</li>
<li>알림을 눌러서 진입하면, 이때는 해당 알림이 원하는 화면이 보이게 됨</li>
</ul>
</li>
</ul>
</li>
<li><p>컴포넌트 종류</p>
<ul>
<li>Acitivity<ul>
<li>UI를 구성하기 위한 컴포넌트</li>
</ul>
</li>
<li>Service<ul>
<li>UI 없이 백그라운드에서 수행하는 컴포넌트</li>
</ul>
</li>
<li>Broadcast Receiver<ul>
<li>이벤트로 수행되는 컴포넌트(방송을 수신하는 컴포넌트)</li>
</ul>
</li>
<li>Content Provider<ul>
<li>어플리케이션 간 데이터를 공유하기 위한 컴포넌트</li>
</ul>
</li>
<li>이 4가지 컴포넌트는 서로 연관성이 하나도 없고 완전히 별개로 동작한다.
<br><br></li>
</ul>
</li>
</ul>
<h2 id="dvm-art">DVM, ART</h2>
<br>

<h3 id="dvmdalvik-virtual-machine">DVM(Dalvik Virtual Machine)</h3>
<ul>
<li><p>초기 안드로이드 런타임 시 사용됨</p>
</li>
<li><p>Android 2.2 이후 JIT 컴파일러로 처음 적용됨</p>
<ul>
<li>JIT는 Just In Time으로 자주 사용되는 부분에 대해 미리 컴파일해 기계어로 해석해놓음으로써 성능을 향상시키고 실행시에 인터프리팅을 시작함</li>
</ul>
</li>
</ul>
<h3 id="artandroid-run-time">ART(Android Run Time)</h3>
<ul>
<li><p>AOT 컴파일러 사용</p>
<ul>
<li>AOT는 Ahead On Time으로 설치 시점에 이미 컴파일을 완료하여 기계어로 해석을 끝내고 실행 시에는 해석 과정 없이 곧바로 기계어로 실행</li>
</ul>
</li>
<li><p>Android 4.4(API 19)에서 처음으로 등장, 도입</p>
<ul>
<li>이때는, DVM과 선택적 사용</li>
</ul>
</li>
<li><p>Android 5.5(API 21) 이후 기본 런타임으로 지정</p>
</li>
<li><p>Android 7.0 이후로는 AOT+JIT</p>
<ul>
<li>미리 기계어로 컴파일 해놓고 실행시에는 기계어를 실행</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Kotlin(코틀린) 기본문법 6. Inheritance(상속) / Polymorphism(다형성) / Delegation(위임)]]></title>
            <link>https://velog.io/@theo-no/Kotlin%EC%BD%94%ED%8B%80%EB%A6%B0-%EA%B8%B0%EB%B3%B8%EB%AC%B8%EB%B2%95-6.-Inheritance%EC%83%81%EC%86%8D-Polymorphism%EB%8B%A4%ED%98%95%EC%84%B1-Delegation%EC%9C%84%EC%9E%84</link>
            <guid>https://velog.io/@theo-no/Kotlin%EC%BD%94%ED%8B%80%EB%A6%B0-%EA%B8%B0%EB%B3%B8%EB%AC%B8%EB%B2%95-6.-Inheritance%EC%83%81%EC%86%8D-Polymorphism%EB%8B%A4%ED%98%95%EC%84%B1-Delegation%EC%9C%84%EC%9E%84</guid>
            <pubDate>Sun, 02 Apr 2023 12:35:47 GMT</pubDate>
            <description><![CDATA[<h2 id="inheritance상속">Inheritance(상속)</h2>
<br>

<h3 id="inheritance">Inheritance</h3>
<ul>
<li><p>모든 클래스는 Any의 하위 클래스이며, 기본적으로 상속 줄 수 없는 final class로 만들어짐</p>
</li>
<li><p>java와 반대로 기본이 final class로 선언(상속 불가)</p>
<ul>
<li>파생 클래스를 허용하려면 open 키워드를 사용하여 상속 가능한 상태로 선언해야 함</li>
</ul>
</li>
<li><p>extends 키워드 대신 콜론( : ) 사용</p>
<pre><code class="language-kotlin">  open class 부모 클래스 명{ //open으로 선언하여 파생 가능
  }
  class 자식 클래스 명: 부모 클래스 명( ){ //부모 클래스 상속, open 키워드 업음 -&gt; 파생 불가
  }</code></pre>
</li>
<li><p>java는 메소드만 오버라이딩 가능하지만 코틀린은 프로퍼티도 가능</p>
<br>

</li>
</ul>
<h3 id="상속-예제">상속 예제</h3>
<pre><code class="language-kotlin">open class Human(var name: String = &quot;홍길동&quot;, var age: Int){ //주생성자
    fun play() = println(&quot;name : $name&quot;)
    fun sing(vol: Int) = println(&quot;Sing age : $age&quot;)
}
//주생성자를 사용하는 상속
class Woman(name: String, age: Int): Human(name, age){
    fun singHitone() = println(&quot;Happy song!&quot;)
}
//부생성자를 사용하는 상속
class Man: Human{
    val race: String
    constructor(name: String, age: Int, race: String): super(name, age){
        this.race = race
    }
}
fun main() {
    var woman = Woman(&quot;사임당&quot;,20)
    var man = Man(&quot;이순신&quot;,20,&quot;아시아&quot;)
}</code></pre>
<h3 id="super-this">super, this</h3>
<ul>
<li><p>super</p>
<ul>
<li><p>상위 클래스의 메서드, 프로퍼티, 생성자를 사용하는 키워드</p>
</li>
<li><p>super.메서드명 / super.프로퍼티명 / super( )</p>
</li>
</ul>
</li>
<li><p>this</p>
<ul>
<li>현재 클래스의 메서드, 프로퍼티, 생성자를 사용하는 키워드</li>
<li>this.메서드명 / this.프로퍼티명 / this( )<br>
<br>

</li>
</ul>
</li>
</ul>
<h2 id="polymorphism다형성">Polymorphism(다형성)</h2>
<br>

<h3 id="polymorphism">Polymorphism</h3>
<ul>
<li><p>Type Polymorphism</p>
<ul>
<li>타입추론으로도 사용 가능</li>
</ul>
</li>
<li><p>Method Polymorphism</p>
</li>
<li><p>오버라이딩</p>
<ul>
<li>상속 받아서 선언부는 동일하나 구현부는 다르게 바꿔 재설계 가능</li>
</ul>
</li>
<li><p>오버로딩</p>
<ul>
<li>함수 명은 동일하나 인자를 다르게 하여 여러 경우를 처리<br>

</li>
</ul>
</li>
</ul>
<h3 id="오버라이딩">오버라이딩</h3>
<ul>
<li><p>method는 기본적으로 final method로 오버라이딩을 금지</p>
</li>
<li><p>open 키워드를 사용하여 오버라이딩 허용</p>
<pre><code class="language-kotlin">  open class Human(){
      fun play(){} //최종 method로 오버라이딩 불가
      open fun sing(){} //open mehtod로 오버라이딩 가능
      open fun sing2(){}
  }
  open class Animal: Human(){
      override fun sing() = println(&quot;override sing&quot;) //super 클래스 그대로 재정의하여 이 또한 open method
      final override fun sing2() = println(&quot;override sing2 final&quot;) //final method로 오버라이딩 불가
  }
  open class Animal2: Animal(){
      override fun sing() = println(&quot;override sing one more&quot;) //이 또한 마찬가지로 open method
  }</code></pre>
</li>
<li><p>런타임 시 만들어진 Object에서 최종적으로 오버라이딩된 메서드가 호출됨</p>
<pre><code class="language-kotlin">  open class Human(){
      fun play() = println(&quot;Human play&quot;) //최종 method로 오버라이딩 불가
      open fun sing() = println(&quot;Human sing&quot;) //open mehtod로 오버라이딩 가능
      open fun sing2() = println(&quot;Human sing2&quot;)
  }
  open class Animal: Human(){
      override fun sing() = println(&quot;Animal sing&quot;) //super 클래스 그대로 재정의하여 이 또한 open method
      final override fun sing2() = println(&quot;Animal sing2&quot;) //final method로 오버라이딩 불가
  }
  open class Animal2: Animal(){
      override fun sing() = println(&quot;Animal2 sing&quot;) //이 또한 마찬가지로 open method
  }
  fun main() {
      var animal = Animal2()
      animal.play()
      animal.sing()
      animal.sing2()
  }

  &lt;---실행 결과---&gt;
  Human play
  Animal2 sing
  Animal sing2</code></pre>
<p>  <br><br></p>
</li>
</ul>
<h2 id="property와-초기화">Property와 초기화</h2>
<br>

<h3 id="property">Property</h3>
<ul>
<li><p>자바에서 필드</p>
<ul>
<li><p>단순한 변수 선언만 가지기 때문에 접근을 위한 메서드를 따로 만들어야 함</p>
<ul>
<li>setter, getter를 개발자가 생성</li>
</ul>
</li>
</ul>
</li>
<li><p>코틀린의 프로퍼티</p>
<ul>
<li><p>변수 선언과 기본적인 접근 메서드를 모두 가지고 있음</p>
<ul>
<li>setter, getter는 개발자가 할 필요 없이 내부적으로 생성하게 됨</li>
</ul>
</li>
</ul>
</li>
<li><p>접근 메서드는 생략(내부적으로 생성)</p>
<pre><code class="language-kotlin">  class User(id: Int, name: String, age: Int){
      val id: Int = id // val로 선언 -&gt; 읽기 전용 
      var name: String = name // var로 선언 -&gt; 변경 가능
      var age: Int = age
  }</code></pre>
</li>
<li><p>간략화하면 아래와 같고, getter / setter가 기본적으로 동작</p>
<pre><code class="language-kotlin">  class User(val id: Int, var name: String, var age: Int){ }
  fun main() {
      val user = User(1,&quot;길동&quot;,30)
      user.age = 25
      println(&quot;${user.name}의 나이 = ${user.age}&quot;)
  }

  &lt;---실행 결과---&gt;
  길동의 나이 = 25</code></pre>
</li>
</ul>
<h3 id="setter-getter-직접-지정">setter, getter 직접 지정</h3>
<ul>
<li><p>값에 대한 validation(확인) 가능</p>
<ul>
<li><p>기본적인 getter, setter를 대신해 지정 가능</p>
</li>
<li><p>불변형인 val은 getter만 설정 가능</p>
</li>
<li><p>filed 변수를 활용하여 기존 값과 새로운 값 비교 가능</p>
<ul>
<li>filed는 원래 값을 가지는 가상의 변수</li>
</ul>
<pre><code class="language-kotlin">class User(id: Int, name: String, age: Int){
  val id: Int = id
      get() = field
  var name: String = name
      get() = field
      set(value){
          field = value
      }
  var age: Int = age
      get() = field
      set(value){
          println(&quot;현재값 : $field&quot;)
          if(value&lt;0 || value&gt;150) println(&quot;다시 확인 바람&quot;)
          else field = value
      }
}</code></pre>
</li>
</ul>
</li>
</ul>
<h3 id="지연-초기화">지연 초기화</h3>
<ul>
<li><p>지연 초기화가 필요한 이유</p>
<ul>
<li><p>변수나 객체의 값은 생성 시 반드시 초기화가 필요함</p>
</li>
<li><p>클래스 내에서 선언한 후 객체의 정보가 나중에 나타나는 경우 초기화 할 수 있는 방법이 필요함</p>
</li>
<li><p>지연 초기화를 위해 lateinit과 lazy 키워드 사용</p>
<br>

</li>
</ul>
</li>
</ul>
<h3 id="lateinit을-통한-지연-초기화">lateinit을 통한 지연 초기화</h3>
<ul>
<li><p>의존성이 있는 초기화나 unit 테스트를 위한 코드 작성 시 프로퍼티 지연 초기화가 필요</p>
<ul>
<li>예) Car 클래스의 초기화 부분에 Engine 클래스와 의존성을 가지는 경우, Engine 객체가 생성되지 않으면 완전하게 초기화 될 수 없음</li>
</ul>
</li>
<li><p>클래스를 선언할 때 프로퍼티 선언은 null을 허용하지 않음</p>
<ul>
<li><p>선언하려면 ? 형으로 선언하고 null 할당</p>
</li>
<li><p>lateinit 키워드를 사용하면 굳이 바로 할당하지 않아도 됨</p>
</li>
</ul>
</li>
<li><p>var로 선언된 프로퍼티만 가능</p>
</li>
<li><p>프로퍼티에 대한 getter, setter 사용 불가</p>
<pre><code class="language-kotlin">  class Person{
      lateinit var name: String
      fun test(){
          if(! ::name.isInitialized) { //초기화 여부 판단
              println(&quot;not initailized&quot;)
          }else{
              println(&quot;initialized&quot;)
          }

      }
  }
  fun main() {
      val gildong = Person()
      gildong.test()
      gildong.name = &quot;gildong&quot;
      gildong.test()
  }

  &lt;---실행 결과---&gt;
  not initailized
  initialized</code></pre>
</li>
</ul>
<h3 id="lazy를-통한-지연-초기화">lazy를 통한 지연 초기화</h3>
<ul>
<li><p>호출 시점에 by lazy{…} 부분의 초기화를 진행</p>
</li>
<li><p>불변의 변수 선언인 val에서만 사용 가능(읽기 전용)</p>
</li>
<li><p>val이므로 값을 다시 변경 불가</p>
<pre><code class="language-kotlin">  class Lazy{
      init{println(&quot;init block&quot;)}
      val subject by lazy{
          println(&quot;lazy initialized&quot;)
          &quot;lazy test&quot;//lazy 반환 값
      }
      fun flow(){
          println(&quot;not initialized&quot;)
          println(&quot;subject inital : $subject&quot;)
          println(&quot;subject initialized : $subject&quot;)
      }
  }
  fun main() {
      val test = Lazy()
      test.flow()
  }

  &lt;---실행 결과---&gt;
  init block
  not initialized
  lazy initialized
  subject inital : lazy test
  subject initialized : lazy test</code></pre>
</li>
<li><p>by lazy로 선언된 code block을 수행하는 것이므로, multi thread 동작 시 고려 필요</p>
</li>
<li><p>3가지 모드 지정 가능</p>
<ul>
<li><p>SYNCHRONIZED</p>
<ul>
<li>lock을 사용해 단일 스레드만이 사용하는 것을 보장(기본값)</li>
</ul>
</li>
<li><p>PUBLICATION</p>
<ul>
<li>여러 군데서 호출될 수 있으나 처음 초기화된 후 반환 값 사용</li>
</ul>
</li>
<li><p>NONE</p>
<ul>
<li>lock을 사용하지 않기 때문에 빠르지만 다중 스레드 접근 가능</li>
<li>값의 일관성을 보장할 수 없음
<br><br></li>
</ul>
</li>
</ul>
</li>
</ul>
<h2 id="delegation위임">Delegation(위임)</h2>
<br>

<h3 id="delegation">Delegation</h3>
<ul>
<li><p>위탁자 → 수탁자 형태로 어떤 일의 책임 및 처리를 다른 클래스 또는 메서드에게 넘긴다는 의미</p>
</li>
<li><p>한 객체가 기능 일부를 다른 객체로 넘겨주어 첫 번째 객체 대신 수행하도록 하는 일</p>
</li>
<li><p>다른 클래스의 기능을 그대로 사용하면 상속 대신 위임</p>
</li>
<li><p>위임을 활용하면 한 객체의 변경이 다른 객체에 미치는 영향이 적어짐</p>
<br>

</li>
</ul>
<h3 id="by를-이용한-클래스-위임">By를 이용한 클래스 위임</h3>
<ul>
<li><p>Interface 타입의 위임만 가능</p>
</li>
<li><p>하나의 클래스가 다른 클래스에 위임하도록 선언하고 위임된 클래스가 가지는 멤버를 참조 없이 호출</p>
</li>
<li><p>코틀린 라이브러리는 대부분 open되어 있지 않아 상속이나 직접 확장이 어려움</p>
<ul>
<li>위임을 통해 상속과 비슷하게 확장 가능</li>
</ul>
</li>
<li><p>다른 클래스의 멤버를 사용하도록 위임</p>
<pre><code class="language-kotlin">  interface Animal{
      fun eat() = println(&quot;Animal.eat()&quot;)
  }
  class Cat: Animal{}
  val cat = Cat()
  class Robot: Animal by cat
  fun main() {
      var robot = Robot()
      robot.eat()
      println(robot::class.java)
  }

  &lt;---실행 결과---&gt;
  Animal.eat()
  class com.android.example.kotlinproject.Robot</code></pre>
</li>
</ul>
<h3 id="observable--함수를-통한-위임">observable( ) 함수를 통한 위임</h3>
<ul>
<li><p>프로퍼티를 표준 위임 함수인 observable( )로 위임 가능</p>
<ul>
<li><p>콜백처럼 프로퍼티의 내용이 변경될 때 수행한 작업을 정의할 수 있음</p>
<pre><code class="language-kotlin">  class Observable{
      var name: String by Delegates.observable(&quot;처음&quot;){
          property, oldValue, newValue -&gt; println(&quot;$oldValue -&gt; $newValue&quot;)
      }
  }
  fun main() {
      var ob = Observable()
      ob.name = &quot;두 번째&quot;
      ob.name = &quot;세 번째&quot;
  }

  &lt;---실행 결과---&gt;
  처음 -&gt; 두 번째
  두 번째 -&gt; 세 번째</code></pre>
</li>
</ul>
</li>
</ul>
<h3 id="vetoable--함수를-통한-위임">vetoable( ) 함수를 통한 위임</h3>
<ul>
<li><p>프로퍼티를 표준 위임 함수인 vetoable( )로 위임 가능</p>
<ul>
<li><p>observable( )과 거의 동일하지만 조건에 맞지 않으면 새로운 값 할당을 거부할 수 있음</p>
<ul>
<li>observable( )은 단순히 바뀌는 것을 지켜보는 것이고, vetoable( )은 바뀔 때 할당할 지 결정할 수 있음</li>
</ul>
</li>
<li><p>true를 반환하면 새로운 값 할당, false를 반환하면 할당 거부</p>
<pre><code class="language-kotlin">  class Vetoable{
      var age: Int by Delegates.vetoable(22){
          property, oldValue, newValue -&gt;
          println(&quot;property : ${property.name}, $oldValue -&gt; $newValue, result : ${oldValue&gt;newValue}&quot;)
          oldValue&gt;newValue
      }
  }
  fun main() {
      var ve = Vetoable()
      ve.age = 20
      println(ve.age)
      ve.age = 25
      println(ve.age)
  }

  &lt;---실행 결과---&gt;
  property : age, 22 -&gt; 20, result : true
  20
  property : age, 20 -&gt; 25, result : false
  20</code></pre>
  <br>


</li>
</ul>
</li>
</ul>
<h2 id="companion-object">companion object</h2>
<br>

<h3 id="정적-변수와-컴페니언-객체">정적 변수와 컴페니언 객체</h3>
<ul>
<li><p>코틀린은 static 키워드가 없음</p>
<ul>
<li><p>대신 companion object로 사용</p>
<pre><code class="language-kotlin">class Person{
  var id: Int = 0
  var name: String = &quot;hong&quot;
  companion object{ //고정된 static 내부 클래스처럼 정의
      var language: String = &quot;Ko&quot;
      fun work() = println(&quot;work()...&quot;)
  }
}
fun main() {
  println(Person.language)
  Person.language = &quot;En&quot;
  println(Person.language)
  Person.work()
}

&lt;---실행 결과---&gt;
Ko
En
work()...</code></pre>
</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Kotlin(코틀린) 기본문법 5. 클래스와 객체]]></title>
            <link>https://velog.io/@theo-no/Kotlin%EC%BD%94%ED%8B%80%EB%A6%B0-%EA%B8%B0%EB%B3%B8%EB%AC%B8%EB%B2%95-4.-%ED%81%B4%EB%9E%98%EC%8A%A4%EC%99%80-%EA%B0%9D%EC%B2%B4</link>
            <guid>https://velog.io/@theo-no/Kotlin%EC%BD%94%ED%8B%80%EB%A6%B0-%EA%B8%B0%EB%B3%B8%EB%AC%B8%EB%B2%95-4.-%ED%81%B4%EB%9E%98%EC%8A%A4%EC%99%80-%EA%B0%9D%EC%B2%B4</guid>
            <pubDate>Sun, 02 Apr 2023 11:21:44 GMT</pubDate>
            <description><![CDATA[<h2 id="클래스와-객체">클래스와 객체</h2>
<br>

<h3 id="oop-object---oriented-programming">OOP (Object - Oriented Programming)</h3>
<ul>
<li><p>객체 지향 프로그래밍</p>
</li>
<li><p>절차적 프로그래밍의 한계를 극복하고자 나온 한 가지의 방법론</p>
</li>
<li><p>객체 간 상호작용으로서 표현하는 프로그래밍</p>
</li>
<li><p>객체의 관계를 표현하고 이를 통해 확장과 재사용이 용이</p>
</li>
<li><p>자바, 코틀린에서는 OOP를 지원</p>
<br>

</li>
</ul>
<h3 id="객체지향-용어">객체지향 용어</h3>
<ul>
<li><p>클래스(Class)</p>
<ul>
<li>대상들을 분류하고 특징(속성)과 동작(함수)을 작성한 것</li>
</ul>
</li>
<li><p>추상화</p>
<ul>
<li>목표로 하는 것에 대해 필요한 만큼 속성과 동작을 정의하는 과정</li>
</ul>
</li>
<li><p>객체지향 개념의 동의어들</p>
<ul>
<li><p>코틀린에서 사용하는 용어 그 밖에 용어</p>
<ul>
<li>프로퍼티(Property) / 속성(Attribute) / 변수(Variable) / 필드(Field) / 데이터(Data)</li>
<li>메서드(Method) / 함수(Function) / 동작(Operation) / 행동(Begivior)</li>
<li>객체(Object) / 인스턴스(Instance)</li>
</ul>
</li>
<li><p>자바에서 사용하는 필드는 코틀린에서 프로퍼티라 불림</p>
<br>

</li>
</ul>
</li>
</ul>
<h3 id="클래스-선언">클래스 선언</h3>
<ul>
<li><p>빈 형태의 선언</p>
<pre><code class="language-kotlin">  class Computer{ //내용이 비어있는 클래스 선언
  }</code></pre>
</li>
<li><p>클래스 내에 프로퍼티와 메서드가 정의된 경우</p>
<pre><code class="language-kotlin">  class Bird{
      //프로퍼티 저으이
      //메서드 정의
  }</code></pre>
  <br>

</li>
</ul>
<h3 id="클래스와-객체-1">클래스와 객체</h3>
<ul>
<li><p>Computer 클래스 만들기</p>
<pre><code class="language-kotlin">  class Computer{ //클래스 정의
      //프로퍼티(속성)
      var name: String = &quot;myComputer&quot;
      var part: Int = 2
      var color: String = &quot;blue&quot;

      //메소드(함수)
      fun play() = println(&quot;computer part : $part&quot;)
      fun playGame(vol: Int) = println(&quot;game vol: $vol&quot;)
  }
  fun main() {
      val computer = Computer() //생성자를 통한 객체 생성
      computer.color = &quot;blue&quot; //객체의 프로퍼티에 값 할당
      println(&quot;compter.color : ${computer.color}&quot;) //객체의 멤버 프로퍼티 읽기
      computer.play() //객체의 멤버 메서드 사용
      computer.playGame(3)
  }

  &lt;---실행 결과---&gt;
  compter.color : blue
  computer part : 2
  game vol: 3</code></pre>
  <br>

</li>
</ul>
<h3 id="인스턴스">인스턴스</h3>
<ul>
<li><p>Computer 클래스는 틀일 뿐 실제 메모리에서 실행되고 있는 것이 아님</p>
</li>
<li><p>Heap 메모리에 올라간 객체를 인스턴스라고 함</p>
</li>
<li><p>java에서는 new 키워드로 객체를 생성하지만, 코틀린은 별도의 키워드가 없음</p>
<pre><code class="language-kotlin">
  val computer = Computer() // 클래스 생성자를 통한 객체의 생성</code></pre>
  <br>

</li>
</ul>
<h3 id="생성자">생성자</h3>
<ul>
<li><p>클래스를 통해 객체가 만들어질 때 기본적으로 호출되는 함수</p>
</li>
<li><p>객체 생성 시 필요한 값을 인자로 설정 가능</p>
</li>
<li><p>생성자를 위해 특별한 함수인 constructor( )를 정의</p>
<pre><code class="language-kotlin">  class 클래스명 constructor(필요한 매개변수들...){ //주 생성자 위치
      ...
      constructor(필요한 매개변수들...){ //부 생성자의 위치
          //프로퍼티의 초기화
      }
  }</code></pre>
  <br>

</li>
</ul>
<h3 id="주-생성자primary-constructor">주 생성자(Primary Constructor)</h3>
<ul>
<li><p>클래스명과 함께 기술되며 보통의 경우 constructor 키워드를 생략 가능</p>
<pre><code class="language-kotlin">  class MyDate(var year: Int, var month: Int, var day: Int){ //주생성자
      override fun toString(): String {
          return &quot;MyDate(year=$year, month=$month, day=$day)&quot;
      }
  }
  fun main() {
      var mydate = MyDate(2002,2,2)
      println(mydate)
  }

  &lt;---실행 결과---&gt;
  MyDate(year=2002, month=2, day=2)</code></pre>
  <br>

</li>
</ul>
<h3 id="부-생성자secondary-constructor">부 생성자(Secondary Constructor)</h3>
<ul>
<li><p>클래스 본문에 기술되며 하나 이상의 부 생성자를 정의할 수 있음</p>
<pre><code class="language-kotlin">  class MyDate(var year: Int){ //주생성자
      var month: Int = 0
      var day: Int = 0
      constructor(year: Int, month: Int): this(year){
          this.month = month
      }
      constructor(year: Int, month: Int, day: Int): this(year, month){
          this.day = day
      }
      override fun toString(): String {
          return &quot;MyDate(year=$year, month=$month, day=$day)&quot;
      }
  }
  fun main() {
      var mydate1 = MyDate(2002)
      println(mydate1)
      var mydate2 = MyDate(2002,2)
      println(mydate2)
      var mydate3 = MyDate(2002,2,2)
      println(mydate3)
  }

  &lt;---실행 결과---&gt;
  MyDate(year=2002, month=0, day=0)
  MyDate(year=2002, month=2, day=0)
  MyDate(year=2002, month=2, day=2)</code></pre>
  <br>


</li>
</ul>
<h3 id="초기화-block--init-block">초기화 Block : init block</h3>
<ul>
<li><p>객체 생성 시 제일 먼저 호출되는 구문</p>
<pre><code class="language-kotlin">  class MyDate(year: Int){ //주생성자
      var year: Int = 0
      var month: Int = 0
      var day: Int = 0
      init{
          println(&quot;init 호출&quot;)
          this.year = year
      }
      constructor(year: Int, month: Int): this(year){ //부생성자
          println(&quot;부생성자 호출&quot;)
          this.month = month
      }
      override fun toString(): String {
          return &quot;MyDate(year=$year, month=$month, day=$day)&quot;
      }
  }
  fun main() {
      var mydate1 = MyDate(2002)
      println(mydate1)
      var mydate2 = MyDate(2002,2)
      println(mydate2)
  }

  &lt;---실행 결과---&gt;
  init 호출
  MyDate(year=2002, month=0, day=0)
  init 호출
  부생성자 호출
  MyDate(year=2002, month=2, day=0)</code></pre>
  <br>

</li>
</ul>
<h3 id="default-value-설정">default value 설정</h3>
<ul>
<li><p>생성자의 선언부에 값을 assign하여 값을 입력받지 않으면 default value로 사용</p>
<pre><code class="language-kotlin">  class MyDate(var year: Int = 2002, var month: Int, var day: Int){ //주생성자
      override fun toString(): String {
          return &quot;MyDate(year=$year, month=$month, day=$day)&quot;
      }
  }
  fun main() {
      var mydate1 = MyDate(2002,3,3)
      println(mydate1)
      var mydate2 = MyDate(month = 2, day = 2) //default 이외의 값은 &#39;변수명 = 값&#39; 형태로 선언
      println(mydate2)
  }

  &lt;---실행 결과---&gt;
  MyDate(year=2002, month=3, day=3)
  MyDate(year=2002, month=2, day=2)</code></pre>
</li>
<li><p>default value 선언할 때 var year = 2002로 해도 int로 유추 가능하다고 생각하여 타입 명시를 빼면 안됨!!</p>
<ul>
<li>외부에서 들어오는 값이기 때문에 어떤 값이 들어올 지 몰라 타입을 명시해줘야 함</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Kotlin(코틀린) 기본문법 4. 함수]]></title>
            <link>https://velog.io/@theo-no/Kotlin%EC%BD%94%ED%8B%80%EB%A6%B0-%EA%B8%B0%EB%B3%B8%EB%AC%B8%EB%B2%95-4.%ED%95%A8%EC%88%98</link>
            <guid>https://velog.io/@theo-no/Kotlin%EC%BD%94%ED%8B%80%EB%A6%B0-%EA%B8%B0%EB%B3%B8%EB%AC%B8%EB%B2%95-4.%ED%95%A8%EC%88%98</guid>
            <pubDate>Thu, 30 Mar 2023 12:47:44 GMT</pubDate>
            <description><![CDATA[<h2 id="함수">함수</h2>
<br>

<h3 id="일반-함수">일반 함수</h3>
<ul>
<li><p>일반 함수 선언과 간략화 표현</p>
<pre><code class="language-kotlin">  fun 함수이름([변수이름 : 자료형, ... ]): 리턴 타입{
          표현식,,,
          return 반환값
  }</code></pre>
<pre><code class="language-kotlin">  //일반함수 add
  fun add(x1: Int, x2: Int):Int{
          return x1+x2
  }
  //brace 생략하고 = 으로 assign
  fun add1(x1: Int, x2: Int):Int = x1+x2

  //return type 생략, 추론 가능
  fun add2(x1:Int, x2: Int) = x1+x2</code></pre>
  <br>


</li>
</ul>
<h3 id="람다">람다</h3>
<ul>
<li>람다 표현식<ul>
<li>람다 함수는 프로그래밍 언어에서 익명 함수를 뜻함</li>
<li>람다의 형태<ul>
<li>람다는 fun과 함수 이름을 명시하지 않고 축약형으로 선언</li>
</ul>
</li>
<li>{매개변수 → 함수 내용}<br></li>
</ul>
</li>
<li>람다 규칙<ul>
<li>람다 함수는 항상 { }으로 감싸서 표현</li>
<li>{ } 안에 ‘→ ‘표시가 있으며 ‘→’ 왼쪽은 매개변수, 오른쪽은 함수 내용</li>
<li>매개변수 타입을 선언해야 하며 추론할 수 있을 때는 생략 가능</li>
<li>함수의 반환 값은 함수 내용의 마지막 표현식</li>
<li>매개변수가 하나인 경우 생략 가능<ul>
<li>무조건 it으로 통일</li>
</ul>
</li>
<li>코드의 마지막 줄은 return type으로 추론<br>

</li>
</ul>
</li>
</ul>
<h3 id="일반함수-vs-람다함수">일반함수 vs 람다함수</h3>
<ul>
<li><p>일반함수</p>
<pre><code class="language-kotlin">  //일반함수
  fun sum(x1: Int, x2: Int): Int{
          return x1+ x2
  }</code></pre>
</li>
<li><p>람다함수 : 표현식이 한 줄일 때 - 예) {x,y→x+y}</p>
<pre><code class="language-kotlin">  //람다함수
  val add = {x1: Int, x2: Int -&gt; x1+x2}

  fun main(){
          val result = add(10, 20)
          println(result) //30
  }</code></pre>
  <br>

</li>
</ul>
<h3 id="람다식의-구성">람다식의 구성</h3>
<ul>
<li><p>표현식이 2줄 이상일 때</p>
<pre><code class="language-kotlin">  //람다식이 어려 줄일 때는 마지막 라인이 리턴
  val sumw: (Int, Int) -&gt; Int = {x1: Int, x2: Int -&gt;
          println(x1+x2)
          x1+x2 //이 줄(마지막 줄) 리턴
  }</code></pre>
</li>
<li><p>자료형의 생략</p>
<pre><code class="language-kotlin">  val multi: (Int, Int) → Int = {x: Int, y: Int → x*y} // 생략되지 않은 전체 표현
  val multi = {x: Int, y: Int -&gt; x*y} // 선언 자료형 생략
  val multi: (Int, Int) -&gt; Int = {x,y -&gt; x*y} // 람다식 매개변수 자료형의 생략
  val multi: {x,y -&gt; x*y} // 에러!! 추론 불가!</code></pre>
</li>
<li><p>반환 자료형이 없거나 매개변수가 하나 있을 때</p>
<pre><code class="language-kotlin">  val greet: () -&gt; Unit = {println(&quot;Hello World!&quot;)}
  val square: (Int) -&gt; Int = {x -&gt; x*x}</code></pre>
</li>
<li><p>람다식 안에 람다식이 있는 경우</p>
<pre><code class="language-kotlin">  val nestedLambda: () -&gt; () -&gt; Unit = {{println(&quot;nested&quot;)}}</code></pre>
</li>
<li><p>선언부의 자료형 생략</p>
<pre><code class="language-kotlin">  val greet2 = {println(&quot;Hello World!&quot;)} //추론가능
  val sqare2 = {x: Int -&gt; x*x} //선언부분 생략하면 x의 자료형을 명시해야 함
  val nestedLambda = {{println(&quot;nested&quot;)}} //추론가능</code></pre>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Kotlin(코틀린) 기본문법 3. 조건문과 분기]]></title>
            <link>https://velog.io/@theo-no/Kotlin%EC%BD%94%ED%8B%80%EB%A6%B0-%EA%B8%B0%EB%B3%B8%EB%AC%B8%EB%B2%95-3.-%EC%A1%B0%EA%B1%B4%EB%AC%B8%EA%B3%BC-%EB%B6%84%EA%B8%B0</link>
            <guid>https://velog.io/@theo-no/Kotlin%EC%BD%94%ED%8B%80%EB%A6%B0-%EA%B8%B0%EB%B3%B8%EB%AC%B8%EB%B2%95-3.-%EC%A1%B0%EA%B1%B4%EB%AC%B8%EA%B3%BC-%EB%B6%84%EA%B8%B0</guid>
            <pubDate>Wed, 29 Mar 2023 15:41:07 GMT</pubDate>
            <description><![CDATA[<h2 id="조건문과-분기">조건문과 분기</h2>
<br>

<h3 id="if">IF</h3>
<ul>
<li><p>형식</p>
<pre><code class="language-kotlin">  if (조건){
      실행
  }else if (조건2){
        실행
  }else{
          실행
  }</code></pre>
</li>
<li><p>실행할 문장이 한 줄이면 블록을 생략 가능.</p>
<br></li>
<li><p>자바와 달리 if문이 값 반환 가능.</p>
<pre><code class="language-kotlin">  var a = 3
  var b = 5
  val e = if(a&lt;b) a else b // 3</code></pre>
</li>
</ul>
<h3 id="when">when</h3>
<ul>
<li><p>자바에서의 switch문에 대응</p>
<br></li>
<li><p>값이 하나인 경우 콤마나 in 연산자로 값의 범위를 자유롭게 지정하고 싶을 때 사용</p>
<ul>
<li><p>코드를 작성할 때 블록으로 코드를 감쌀 수도 있고, 안 할 수도 있음</p>
<pre><code class="language-kotlin">val x = 1

when(x){
  1 -&gt; println(&quot;x=1&quot;)
  2,3 -&gt; println(&quot;x=2 or x=3&quot;)
  in 4..7 -&gt; println(&quot;4&lt;=x&lt;=7&quot;)
  else -&gt; println(&quot;else&quot;)
}</code></pre>
</li>
<li><p>else문은 반드시! 있어야 한다.</p>
<br></li>
</ul>
</li>
<li><p>if 문처럼 사용</p>
<ul>
<li><p>num % 2를 계산 → 짝인지 홀인지 결정 → 그 값을 num2에 할당</p>
</li>
<li><p>0, 1만 처리하면 될 것 같지만, 전체 조건을 처리하기 위해 else문 꼭 필요</p>
<pre><code class="language-kotlin">val num = 10
val num2 = when (num%2){
  0 -&gt; println(&quot;짝수&quot;)
  else -&gt; println(&quot;홀수&quot;)
}</code></pre>
</li>
</ul>
</li>
<li><p>조건식 반환</p>
<pre><code class="language-kotlin">  fun main() {
      doWhen(1) // 정수 1
      doWhen(&quot;hello&quot;) // world
      doWhen(100L) // Long type
      doWhen(&#39;x&#39;) // String type이 아님
  }
  fun doWhen(a:Any){
      var result = when (a){
          1 -&gt; &quot;정수 1&quot;
          &quot;hello&quot; -&gt; &quot;world&quot;
          is Long -&gt; &quot;Long type&quot;
          !is String -&gt; &quot;String type이 아님&quot;
          else -&gt; &quot;else&quot;
      }
  }</code></pre>
</li>
</ul>
<h3 id="for">for</h3>
<ul>
<li><p>in 연산자를 통해서 배열을 순회 할 수 있음</p>
<br></li>
<li><p>.. , downTo, step, until : 증가 범위, 증감 간격 조절</p>
<pre><code class="language-kotlin">  fun main() {
      val num = arrayOf(1,2,3,4)
      for(n in num){
          println(n) // 1; 2; 3; 4;
      }
      for(i in 1..4){ // .. 키워드
          println(i) // 1; 2; 3; 4;
      }
      for(i in 0..10 step 2){
          println(i) // 0; 2; 4; 6; 8; 10;
      }
      for(i in 10 downTo 0 step 2){
          println(i) // 10; 8; 6; 4; 2; 0;
      }
  }</code></pre>
<ul>
<li>step은 일정한 간격으로 증가<br></li>
<li>일정 간격 감소는 downTo와 step을 함께 써야 하기 때문에 for i in 10..0 step 2 는 작동하지 않음 → 감소할 때는 무조건 downTo 함께 써라!<br></li>
</ul>
</li>
<li><p>forEach</p>
<pre><code class="language-kotlin">  val num = arrayOf(1,2,3,4)
  num.forEach { println(it) } //1; 2; 3; 4;

  num.forEachIndexed { index, value -&gt;
      println(&quot;$index : $value&quot;) // 0 : 1; 1 : 2; 2 : 3; 3 : 4;
  }</code></pre>
</li>
</ul>
<h3 id="while--do-while">while &amp; do while</h3>
<ul>
<li>주어진 조건이 참일 때 반복<br></li>
<li>do while은 우선 do 구문들을 실행하고 나서, while 문 조건이 참이면 실행</li>
</ul>
<pre><code class="language-kotlin">var x = 5
while (x&gt;0){
    x--
    print(x) // 4; 3; 2; 1; 0;
}

var y = 5
do{
    y--
    print(y) // 4; 3; 2; 1; 0;
}while (y&gt;0)</code></pre>
<h3 id="break--continue">break &amp; continue</h3>
<ul>
<li><p>break</p>
<ul>
<li>반복문을 즉시 탈출</li>
</ul>
</li>
<li><p>conitnue</p>
<ul>
<li><p>아래 명령의 실행을 중단하고 다시 위로 올라가 반복문의 다음을 실행</p>
<pre><code class="language-kotlin">var i = 0
while(i&lt;10){
  i++
  if(i==7) break
  if(i%2==0) continue
  println(i) // 1; 3; 5;
}</code></pre>
</li>
</ul>
</li>
</ul>
<h3 id="label">label</h3>
<ul>
<li>레이블이 붙여진 곳으로 이동 가능 (레이블은 특정 반복문에 붙인 이름)<br></li>
<li>중첩된 반복문에서 원하는 반복문을 탈출하고 싶을 때 사용</li>
</ul>
<pre><code class="language-kotlin">out@
for(i in 1..5){
    for(j in 1..5){
        println(&quot;$i : $j&quot;)
        if(i+j &gt;= 5) break@out
    } 
}
println(&quot;end&quot;)
// 1 : 1; 1 : 2; 1 : 3; 1 : 4; 1: 5; end;</code></pre>
<h3 id="삼항-연산자가-없는-코틀린">삼항 연산자가 없는 코틀린</h3>
<ul>
<li><p>코틀린은 삼항 연산자가 없음</p>
<ul>
<li><p>if-else가 표현식이기 때문</p>
<ul>
<li><p>if와 else가 특정 값을 반환 할 수 있기 때문(when문도 동일)</p>
</li>
<li><p>따라서 삼항 연산자가 필요 없음</p>
<pre><code class="language-kotlin">var a = 10
var b = 5
var max = if(a&gt;b) a else b // 10</code></pre>
</li>
</ul>
</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Kotlin(코틀린) 기본문법 2. 연산자, Null]]></title>
            <link>https://velog.io/@theo-no/Kotlin%EC%BD%94%ED%8B%80%EB%A6%B0-%EA%B8%B0%EB%B3%B8%EB%AC%B8%EB%B2%95-2.-%EC%97%B0%EC%82%B0%EC%9E%90-Null</link>
            <guid>https://velog.io/@theo-no/Kotlin%EC%BD%94%ED%8B%80%EB%A6%B0-%EA%B8%B0%EB%B3%B8%EB%AC%B8%EB%B2%95-2.-%EC%97%B0%EC%82%B0%EC%9E%90-Null</guid>
            <pubDate>Tue, 28 Mar 2023 16:02:47 GMT</pubDate>
            <description><![CDATA[<h2 id="연산자">연산자</h2>
<br>

<h3 id="기본-연산자">기본 연산자</h3>
<ul>
<li><p>종류</p>
<ul>
<li>산술, 대입, 증가, 감소, 비교, 논리 연산자 등<br></li>
</ul>
</li>
<li><p>산술 연산자</p>
<ul>
<li>사칙연산에 사용되는 사칙연산자와 나머지 연산자를 산술 연산자</li>
<li>‘+’ : 덧셈, ‘ - ‘ : 뺄셈, ‘ * ’ : 곱셈, ‘ / ‘ : 나눗셈, ‘ % ‘ : 나머지<br></li>
</ul>
</li>
<li><p>대입 연산자</p>
<ul>
<li>대입 연산자는 변수에 값을 할당하는 연산자를 말함</li>
<li>대입 연산자는 이항 연산자 중 우선 순위가 가장 낮으므로 모든 연산이 끝난 이후 마지막에 동작<br></li>
</ul>
</li>
<li><p>증감 연산자</p>
<ul>
<li><p>증감 연산자는 항이 단항임</p>
</li>
<li><p>++, - -</p>
<pre><code class="language-kotlin">  var num1 = 10
  var num2 = 10
  val result1 = ++num1 // num1 증가 후 대입
  println(result1) // 11
  val result2 = num2++ // 대입 후 num2 증가
  println(result2) // 10</code></pre>
</li>
</ul>
</li>
</ul>
<ul>
<li>비교 연산자<ul>
<li>&#39;&gt;&#39;, &#39;&lt;&#39;, &#39;&gt;=&#39;, &#39;&lt;=&#39;, 등의 연산</li>
<li>==, ===, ! ==, ! ===<ul>
<li>== : 두 개 항의 값이 같으면 true, 다르면 false</li>
<li>! = : 두 개 항의 값이 다르면 true, 같으면 false</li>
<li>=== : 두 개 항의 참조가 같으면 true, 다르면 false</li>
<li>! == : 두 개 항의 참조가 다르면 true, 같으면 false<br></li>
</ul>
</li>
</ul>
</li>
<li>논리 연산자<ul>
<li>&amp;&amp;, ||, !<ul>
<li>&amp;&amp; : 논리곱으로 두 항이 모두 true일 때 true, 아니멸 false</li>
<li>|| : 논리합으로 두 항 중 하나의 항만 true여도 true, 둘 다 false면 false</li>
<li>! : 부정 단항 연산자로 true를 false로, false를 true로 바꿈
<br><br></li>
</ul>
</li>
</ul>
</li>
</ul>
<h2 id="null--null-safe">Null &amp; Null Safe</h2>
<br>

<h3 id="null">Null</h3>
<ul>
<li><p>코틀린의 변수 선언은 원래 null을 허용하지 않음</p>
<pre><code class="language-kotlin">  var str:String = &quot;Hello Kotlin&quot;
  str = null // 오류 발생</code></pre>
</li>
<li><p>null 가능한 선언 → ‘?’ 키워드 사용</p>
<pre><code class="language-kotlin">  var str:String? = &quot;Hello Kotlin&quot;
  str = null // null 허용</code></pre>
</li>
<li><p>NPE(NullPointerException)</p>
<ul>
<li>사용할 수 없는 null인 변수에 접근하면서 발생하는 예외<br>


</li>
</ul>
</li>
</ul>
<h3 id="safe-call--non-null">Safe-call &amp; Non Null</h3>
<ul>
<li><p>safe-call</p>
<ul>
<li><p>변수 뒤에 ‘?’를 붙혀 호출</p>
</li>
<li><p>값이 null일 경우 null이 입력됨</p>
<pre><code class="language-kotlin">fun main() {
  val x:String? = null
  println(strLenSafe(x)) // null
  println(strLenSafe(&quot;abc&quot;)) // 3
}
fun strLenSafe(s:String?): Int?{ //반환이 null로 될 수 있기 때문에 &#39;?&#39; 사용
  return s?.length
}</code></pre>
</li>
</ul>
</li>
<li><p>엘비스 연산자</p>
<ul>
<li><p>null인 경우 default를 주고 싶을 때 ‘ ?: ’ 키워드 사용</p>
<pre><code class="language-kotlin">fun main() {
  val x:String? = null
  println(getStr(x)) // Unknown
  println(getStr(&quot;abc&quot;)) // abc
}
fun getStr(str:String?): String{
  return str ?: &quot;Unknown&quot;
}</code></pre>
</li>
</ul>
</li>
<li><p>Non-null</p>
<ul>
<li><p>변수 뒤에 ‘!!’으로 표시(Not null 단정 기호)</p>
<ul>
<li><p>프로퍼티나 변수에 붙이면 null이 아니라고 강제로 선언</p>
</li>
<li><p>null이 들어올 경우 NPE 발생</p>
<pre><code class="language-kotlin">  fun main() {
      ignoreNulls(null)
  }
  fun ignoreNulls(s:String?){
      val notNull:String = s!! //!!키워드 때문에 그냥 String으로 선언 가능
      println(notNull.length)
  }</code></pre>
<p>  <img src="https://velog.velcdn.com/images/theo-no/post/2b3a2468-b087-4996-b005-97d895174dfd/image.png" alt=""></p>
</li>
</ul>
</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Kotlin(코틀린) 기본문법 1. 변수와 자료형]]></title>
            <link>https://velog.io/@theo-no/Kotlin%EC%BD%94%ED%8B%80%EB%A6%B0-%EA%B8%B0%EB%B3%B8%EB%AC%B8%EB%B2%95-1.-%EB%B3%80%EC%88%98%EC%99%80-%EC%9E%90%EB%A3%8C%ED%98%95</link>
            <guid>https://velog.io/@theo-no/Kotlin%EC%BD%94%ED%8B%80%EB%A6%B0-%EA%B8%B0%EB%B3%B8%EB%AC%B8%EB%B2%95-1.-%EB%B3%80%EC%88%98%EC%99%80-%EC%9E%90%EB%A3%8C%ED%98%95</guid>
            <pubDate>Tue, 28 Mar 2023 15:02:51 GMT</pubDate>
            <description><![CDATA[<h2 id="코틀린">코틀린</h2>
<br>

<h3 id="특징">특징</h3>
<ul>
<li>Intelllij IDEA(Android Strudio의 모체)로 유명한 JetBrains에서 개발하고 보급</li>
<li>Google IO 2017에서 Android 공식 언어로 추가 발표</li>
<li>변수는 Nullable(널 값 사용 가능)과 NotNull로 나뉘는데 변수 선언 시 ‘?’를 붙여 Nullable로 만들 수 있음</li>
</ul>
<h3 id="장점">장점</h3>
<ol>
<li>자료형에 대한 오류를 미리 잡을 수 있음<ol>
<li>컴파일러가 타입을 검증</li>
</ol>
</li>
<li>아예 없는 것은 아니지만 java에 비해 Nullpointer Exception에서 자유로움</li>
<li>데이터형 선언 시 Null 가능한 형식과 불가능한 형식 지원</li>
<li>자바와 완벽하게 상호호환</li>
<li>java와 비교했을 때 코드가 간결하고 효율적인 프로그래밍이 가능</li>
<li>함수형 프로그래밍과 객체 지향 프로그래밍이 모두 가능</li>
<li>세미클론은 생략 가능
<br><br></li>
</ol>
<h2 id="변수와-자료형">변수와 자료형</h2>
<br>

<h3 id="변수">변수</h3>
<ul>
<li>val (value) - 불변형(immutable)</li>
<li>var (variable) - 가변형(mutable)</li>
<li>변수명<ul>
<li>규칙 - java와 동일<ul>
<li>변수 이름은 1242abc와 같이 숫자로 시작불가</li>
<li>변수 이름에는 when, val와 같이 코틀린에서 사용되는 키워드는 사용할 수 없음</li>
<li>변수 이름은 의미 있는 단어를 사용하여 만드는 것이 좋음</li>
<li>여러 단어로 변수명을 지을 때는 카멜 표기법 사용을 권장</li>
<li>클래스, 인터페이스 등은 파스칼 케이스를 사용 - java와 동일</li>
</ul>
</li>
<li>변수 선언 예<ul>
<li>val userName = “hong” (O) → 자료형을 추론하여 String으로 결정</li>
<li>var username (X) → 자료형을 지정하지 않은 변수는 사용할 수 없음</li>
<li>val init: Int (O) → 먼저 선언하고 나중에 사용 전에 초기화 할 수 있음</li>
<li>val number = 10 (O) → 자료형을 추론하여 Int형으로 추론<br>

</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="자료형">자료형</h3>
<p><img src="https://velog.velcdn.com/images/theo-no/post/0f7adb0c-a170-4193-b2dc-dd6daeaad04c/image.png" alt=""></p>
<ul>
<li><p>코틀린의 기본 자료형은 모두 객체</p>
<ul>
<li>자바보다 엄격한 타입체크<ul>
<li>Double에 Int가 들어갈 수 없음 (.toDouble( )와 같은 메소드를 이용해서 명시적으로 형변환을 시켜야 함)<br></li>
</ul>
</li>
</ul>
</li>
<li><p>숫자형 : Byte/Short/Int/Long, Float/Double</p>
<pre><code class="language-kotlin">  val a = 5.toByte() // Byte
  val b = 65.toChar() // Char
  val c = 10.toShort() // Short
  val d = 10 // 정수 기본 자료형 Int
  val e = 10L // Long

  val f = 10.0f // Float
  val g = 10.0 // 실수 기본 자료형 double</code></pre>
</li>
<li><p>문자형 : String/Char</p>
<ul>
<li><p>코틀린은 유니코드(Unicode)를 사용</p>
<pre><code class="language-kotlin">  var ch = &#39;\uAC00&#39;
  print(ch) // 가</code></pre>
</li>
<li><p>String은 문자열 (double quotation), char는 글자 하나(single quotation)</p>
</li>
<li><p>여러 줄 문자열 표현은 큰 따음표 세 개로 감싸 줌</p>
<pre><code class="language-kotlin">  val str = &quot;&quot;&quot;
      Ssafy 여러분
      모두 화이팅!
  &quot;&quot;&quot;.trimIndent()</code></pre>
</li>
</ul>
</li>
<li><p>문자열 비교</p>
<ul>
<li>문자열이 같은지 비교할 때는 ==</li>
<li>오브젝트가 같은지 비교할 때는 ===<br></li>
</ul>
</li>
<li><p>문자열 템플릿</p>
<ul>
<li><p>‘+’ : 문자열 붙이기</p>
<pre><code class="language-kotlin">  val str1 = &quot;안녕&quot;
  val str2 = &quot;하세요&quot;
  println(str1+str2) // 안녕하세요</code></pre>
</li>
<li><p>$변수명 혹은 ${변수명} : 문자열 중간에 변수가 들어가야 할 경우</p>
<pre><code class="language-kotlin">  val a = 20
  println(&quot;저는 $a 살 입니다.&quot;) //저는 20 살 입니다.
  println(&quot;저는 ${a}살 입니다.&quot;) // 저는 20살 입니다.</code></pre>
</li>
</ul>
</li>
<li><p>타입 별명 붙이기 - typealias</p>
<ul>
<li><p>만약 타입의 이름이 너무 길거나 복잡한 경우, ‘typealias 별명 = 타입’ 과 같이 적어주면 그 타입에 새로운 이름을 부여해 줄 수 있음</p>
<pre><code class="language-kotlin">  typealias Num = Int
  fun main() {
      val num: Num = 10
      println(num) // 10
  }</code></pre>
<ul>
<li>alias 유효 범위는 접근지정자 - 코틀린에서 default는 public<ul>
<li>당연히 import하면 된다.<br></li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li><p>배열</p>
<ul>
<li><p>arrayOf( )</p>
</li>
<li><p>배열의 생성과 초기화를 함께 수행 (컴파일러가 자료형 유추 가능하면 이를 생략)</p>
</li>
<li><p>배열의 요소에 접근하려면 [ ] 대괄호를 사용</p>
<pre><code class="language-kotlin">fun main() {
  val num : Array&lt;Int&gt; = arrayOf(1,2,3,4)
  val num2 = arrayOf(5,&#39;a&#39;,&quot;hi!&quot;,8)
  println(num[0]) // 1
  println(num2[1]) // a
  println(num2[2]) // hi!
}</code></pre>
</li>
<li><p>num처럼 선언하면 Int형이 아닌 값들을 넣으면 오류가 발생한다.</p>
</li>
<li><p>num2처럼 선언하면 어떤 값을 넣어도 오류가 나지 않는다.
<br><br></p>
</li>
</ul>
</li>
</ul>
<h3 id="코틀린의-자료형-변환">코틀린의 자료형 변환</h3>
<br>

<ul>
<li>기존 java 자료형<ul>
<li>기본형(Primitive data type)<ul>
<li>가공되지 않은 순수한 자료형으로 프로그래밍 언어에 내장</li>
<li>int, long, float, double 등</li>
</ul>
</li>
<li>참조형(Reference type)<ul>
<li>동적 공간에 데이터를 둔 다음 이것을 참조하는 자료형</li>
<li>Int, Long, Float, Double 등<br></li>
</ul>
</li>
</ul>
</li>
<li>코틀린의 모든 데이터는 참조형.<ul>
<li>컴파일 후 내부적으로 primitive type으로 동작<ul>
<li>primitive type인 byte/short/int 등은 직접 사용할 수 없음<br></li>
</ul>
</li>
</ul>
</li>
<li>서로 다른 자료형은 변환 과정을 거친 후 비교<ul>
<li>val a :Int = 1 // 정수형 변수 a 선언 후 1을 할당</li>
<li>val b :Double = a // 자료형 불일치 오류</li>
<li>val c :Int = 1.12 // 자료형 불일치 오류<br></li>
</ul>
</li>
<li>변환 메서드 이용<ul>
<li>val b :Double = a.toDouble( ) // 변환 메서드 사용<br></li>
</ul>
</li>
<li>표현식에서 자료형의 자동 변환<ul>
<li>val result = 1L + 3 // Long + Int → Long<ul>
<li>큰 바이트형으로 전환된다.<br></li>
</ul>
</li>
</ul>
</li>
<li>변환 메서드 종류<ul>
<li>toByte : Byte</li>
<li>toLong : Long</li>
<li>toShort : Short</li>
<li>toFloat : Float</li>
<li>toInt : Int</li>
<li>toDouble : Double</li>
<li>toChar : Char
<br><br></li>
</ul>
</li>
</ul>
<h3 id="스마트-캐스트">스마트 캐스트</h3>
<br>

<ul>
<li><p>구체적으로 명시되지 않은 자료형을 자동 변환해줌</p>
<ul>
<li><p>값에 따라 자료형 결정</p>
<ul>
<li><p>Number - 숫자를 지정하기 위한 특수 자료형으로 스마트 캐스팅 됨</p>
<pre><code class="language-kotlin">var test1:Number = 6.2 // Double로 스마트 캐스팅 됨
println(test1.javaClass) // class.java.lang.Double
test1 = 12
println(test1.javaClass) // class.java.lang.Integer
test1 = 12L
println(test1.javaClass) // class.java.lang.Long
test1 += 12.0f
println(test1.javaClass) // class.java.lang.Float</code></pre>
</li>
</ul>
</li>
</ul>
</li>
<li><p>Is 키워드를 사용한 검사</p>
<ul>
<li><p>변수 is 자료형</p>
<pre><code class="language-kotlin">val number = 256
if(number is Int){ //num이 Int형일 때
  print(number)
}else if(number !is Int){ // number이 Int형이 아닐 때
  print(&quot;Not a Int&quot;)
}</code></pre>
</li>
<li><p>java에서는 instanceof를 하더라도 명시적으로 타입 캐스팅을 해야 하지만, 코틀린에서는 타입 체크와 동시에 자동으로 해줌
<br><br></p>
</li>
</ul>
</li>
</ul>
<h3 id="묵시적-변환">묵시적 변환</h3>
<br>

<ul>
<li><p>Any</p>
<ul>
<li><p>자료형이 정해지지 않은 경우</p>
</li>
<li><p>모든 클래스의 뿌리(Java의 java.lang.Object)</p>
<ul>
<li><p>Ex) Int나 String은 Any 형의 자식 클래스</p>
</li>
<li><p>Any는 언제든 필요한 자료형을 자동 변환(스마트 캐스트)</p>
<pre><code class="language-kotlin">var a:Any = 1
println(a.javaClass) // class.java.lang.Integer
a = 2L
println(a.javaClass) // class.java.lang.Long</code></pre>
</li>
</ul>
</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[자료구조_스택(Stack) / 큐(Queue)_JAVA]]></title>
            <link>https://velog.io/@theo-no/%EC%8A%A4%ED%83%9DStack-%ED%81%90Queue</link>
            <guid>https://velog.io/@theo-no/%EC%8A%A4%ED%83%9DStack-%ED%81%90Queue</guid>
            <pubDate>Tue, 28 Mar 2023 08:46:49 GMT</pubDate>
            <description><![CDATA[<h2 id="스택stack이란">스택(Stack)이란?</h2>
<p>데이터를 임시 저장할 때 사용하는 자료구조</p>
<p><strong>후입선출(FILO)</strong> 방식</p>
<h2 id="어떤-문제에서-스택을-써야할까">어떤 문제에서 스택을 써야할까?</h2>
<aside>
➡️ **기호 짝 맞추기**

<pre><code>괄호의 짝이 맞는지 확인하는 문제</code></pre></aside>

<aside>
➡️ **히스토그램, 주가 스팬, 트리 순회, 하노이의 타워와 같은 알고리즘**

</aside>
<br>
<aside>
➡️ **백트래킹이 필요한 문제**

<pre><code>만약 길이 효율적이지 않다면 다시 이전 상태로 돌아와 다른 길로 가기 위해 이전 상태가 저장되어 있는 스택을 사용
ex) 체스, 미로찾기, Knight-Tour 문제, N-Queen 문제</code></pre></aside>

<h2 id="스택-관련-코드">스택 관련 코드</h2>
<ul>
<li><p>[기본]</p>
<pre><code class="language-java">  public class Main {

      public static void main(String[] args) {

          Stack&lt;String&gt; stack = new Stack&lt;String&gt;();

          // 데이터 추가
          stack.push(&quot;0&quot;);
          stack.push(&quot;1&quot;);
          stack.push(&quot;2&quot;);
          stack.push(&quot;3&quot;);
          stack.push(&quot;4&quot;);
          stack.push(&quot;5&quot;);

          // 가장 상위(마지막에 추가된 원소)값 리턴
          stack.peek();

          // 데이터 위치 검색 - 가장 상위 위치 1 기준으로 +1씩 증가 
          stack.search(&quot;4&quot;); // 출력: 2

          // 크기
          stack.size();

          // 데이터 꺼내기(삭제) - 최상위부터 꺼냄  
          stack.pop(); // 출력:5

          // 비어있는지 검사 - true|false
          stack.empty(); 

                  // 출력 - 1
                  Iterator iter = stack.iterator();
                  while(iter.hasNext()) {
                      System.out.println(iter.next());
                  }

                  // 출력 - 2
                  stack.stream().forEach(S -&gt; System.out.println(S));

                  // 출력 -3
                  stack.forEach(System.out::println);
      }

</code></pre>
</li>
</ul>
<pre><code>}
```</code></pre><h2 id="큐queue란">큐(Queue)란?</h2>
<p>데이터를 임시 저장할 때 사용하는 자료구조</p>
<p><strong>선입선출(FIFO)</strong> 방식</p>
<h2 id="큐의-종류">큐의 종류</h2>
<p><strong>🔄 순환 큐</strong></p>
<p>front와 rear가 연결되어 계속 순환하는 큐
인덱스를 원형으로 돌려서 7이 0으로 가도록 %연산을 통해 구현
<img src="https://velog.velcdn.com/images/theo-no/post/14b5dea8-08ce-41e5-bb05-75e1f140f37d/image.png" alt=""></p>
<p><strong>🥇 우선순위 큐</strong></p>
<p>우선순위가 가장 높은 데이터를 가장 먼저 삭제하는 자료구조</p>
<p>보통의 큐와 같이 구현하면 데이터를 삽입하기 힘들다는 단점이 있어 주로 힙 자료구조를 사용해 구현</p>
<p><img src="https://velog.velcdn.com/images/theo-no/post/eb0e78ef-44d7-4189-a27c-3ac22efd1815/image.png" alt=""></p>
<h2 id="큐-관련-코드">큐 관련 코드</h2>
<ul>
<li>큐의 주요 메서드</li>
</ul>
<p><img src="https://velog.velcdn.com/images/theo-no/post/8734d319-c38c-495a-9bbb-04392b785a5b/image.png" alt=""></p>
<ul>
<li><p>[기본]</p>
<pre><code class="language-java">public class Main {

  public static void main(String[] args) {

      Queue&lt;Integer&gt; queue = new LinkedList&lt;&gt;(); //int형 queue 선언

      // 데이터 추가  add | offer
      queue.add(1);    
      queue.add(2);   
      queue.offer(3);
      queue.offer(2);
      queue.offer(4);

  // 가장 상위(가장 먼저 추가된 원소)값 리턴 element | peek
      queue.element();
      queue.peek();

      // 큐 데이터 삭제 remove | poll
      queue.remove(); // 가장 먼저 들어온 값 삭제
      queue.remove(2); // 동일한 값 중 가장 먼저 들어온 값 하나를 삭제 
      queue.poll(); 
      //queue.poll(2); // 원하는 값 삭제 불가능 

      // 큐 초기화 
      //queue.clear();

      // 출력 - 1
      Iterator iter = queue.iterator();
      while(iter.hasNext()) {
          System.out.println(iter.next());
      }
      // 출력 - 2
      queue.stream().forEach(S -&gt; System.out.println(S));

      // 출력 - 3
      queue.forEach(System.out::println);

  }

</code></pre>
</li>
</ul>
<p>}
```</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[자료구조_해시(Hash)_JAVA]]></title>
            <link>https://velog.io/@theo-no/%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0%ED%95%B4%EC%8B%9CHashJAVA</link>
            <guid>https://velog.io/@theo-no/%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0%ED%95%B4%EC%8B%9CHashJAVA</guid>
            <pubDate>Fri, 24 Mar 2023 06:41:59 GMT</pubDate>
            <description><![CDATA[<h2 id="해시란">해시란?</h2>
<p><strong>key : value</strong>의 값을 가지는 하나의 자료구조</p>
<p>예) 전화번호부 ⇒ 검색창에 <strong>이름</strong>을 입력하면 <strong>전화번호 결과</strong>가 나옴</p>
<p>무언가를 찾기 위한 검색어 <strong>(이름)</strong> = key</p>
<p>그 검색어로 나온 결과 <strong>(전화번호)</strong> = value</p>
<h2 id="해시가-왜-필요한가">해시가 왜 필요한가?</h2>
<p>배열로는 오직 정수로만 접근이 가능함</p>
<pre><code class="language-java">int[] phonebook = new int[5];
phonebook[0];</code></pre>
<p>친구의 이름을 알더라도 이름을 기반으로 전화번호를 찾을 수 없음</p>
<pre><code class="language-java">String name = &quot;hyunwoo&quot;;
phonebook[name] // error</code></pre>
<p>그렇기 때문에 해시가 없던 시절 유일하게 할 수 있었던 방법은 0부터 끝까지 하나하나 열어보며 찾는 친구가 맞는지 확인하는 방법뿐이었음</p>
<pre><code class="language-java">for (int i = 0; i &lt; n; i++) {
    // phonebookName[i] == name?
}</code></pre>
<p>해시는 배열과 달리 String 타입이나 <strong>다른 어떤 데이터형을 기반으로 자료구조를 접근</strong>하고 데이터를 관리할 수 있도록 해줌</p>
<aside>
⚠️ **코딩테스트에서 중요한 점**

<p><strong>해시는 모든 데이터 타입으로 접근이 가능함</strong>
get / put / getOrDefault 함수 꼭 기억할 것</p>
</aside>

<ul>
<li><p>getOrDefault함수!</p>
<pre><code class="language-java">  public String solution(String[] participant, String[] completion) {
          String answer = &quot;&quot;;
          HashMap&lt;String,Integer&gt; hm = new HashMap&lt;&gt;();
          for(String player : participant){
              hm.put(player,hm.getOrDefault(player,0)+1);
          }
          //for(int i=0;i&lt;completion.length;i++){
              //if(!hm.containsKey(completion[i])){
                  //hm.put(completion[i],1);
              //}else{
                  //hm.replace(completion[i],hm.get(completion[i])+1);
              //}
          //}
          for(int j=0;j&lt;participant.length;j++){
              if(!hm.containsKey(participant[j]) || hm.get(participant[j]) == 0){
                  answer = participant[j];
              }else{
                  hm.replace(participant[j],hm.get(participant[j])-1);
              }
          }
          return answer;
      }</code></pre>
<ul>
<li>위의 코드에서 주석된 부분처럼 키가 있는지 확인하고 없으면 초기값으로 넣고 있으면 1 더하는 코드를 한 줄로 간단하게 작성할 수 있다.</li>
</ul>
</li>
</ul>
<h2 id="어떤-문제에서-해시를-써야할까">어떤 문제에서 해시를 써야할까?</h2>
<aside>
➡️ **String을 기반으로 정보를 기록하고 관리해야 될 때**

</aside>

<p>String을 기준으로 정보를 기록하고 관리하려면 단순 배열을 쓸 수 없으니 Hash를 활용하자</p>
<h3 id=""></h3>
<h2 id="hash-관련-코드">Hash 관련 코드</h2>
<ul>
<li><p>[기본]</p>
<pre><code class="language-java">                  // 선언 
          HashMap&lt;타입 ,타입&gt; hm = new HashMap&lt;&gt;();

                  // 카피 -  타입이 모두 같아야 함.
                  HashMap&lt;타입, 타입&gt; hm2 = new HashMap&lt;&gt;(hm);

                  // 크기 지정
                  HashMap&lt;타입, 타입&gt; hm3 = new HashMap&lt;&gt;(크기);</code></pre>
<pre><code class="language-java">  package codingtest;

  import java.awt.print.Printable;
  import java.util.*;
  import java.util.Scanner;

  import org.omg.CORBA.PolicyListHelper;

  public class Main {

      public static void main(String[] args) {

          Map&lt;String, Integer&gt; hm = new HashMap&lt;&gt;();

          // 데이터 추가 
          hm.put(&quot;data1&quot;, 1);
          hm.put(&quot;data2&quot;, 2);
          hm.put(&quot;data3&quot;, 3);
          hm.put(&quot;data4&quot;, 4);
          hm.put(&quot;data5&quot;, 3);
          hm.put(&quot;data6&quot;, 6);

          // 데이터 삭제 - key
          hm.remove(&quot;data1&quot;);

          // 데이터 삭제 - values 
          // (**동일한 값이 존재하는 경우 가장 늦게 들어온 오직 한 개의 요소만 삭제**)
  //        hm.values().remove(3);   
          // 결과 : {data6=6, data4=4, data3=3, data2=2}

</code></pre>
</li>
</ul>
<pre><code>        // 데이터 삭제 - values - 한 번에 여러 요소 삭제 
        // value가 2,3인 모든 데이터를 삭제한다. 
    // hm.values().removeAll(Arrays.asList(2,3));

        // 크기 
            hm.size();

        // 모든 내용 삭제 
       // hm.clear();

        // 데이터 변경 
        hm.replace(&quot;data2&quot;, 10);
        hm.replace(&quot;data6&quot;, 6, 12); // 키의 값이 일치해야 값 변경 가능 

        // 데이터 추출 
        hm.get(&quot;data2&quot;); // 키로 값 추출 

        // 키 존재 유무 확인 true|false
        hm.containsKey(&quot;data6&quot;);  // 키 기준
        hm.containsValue(12); // 값 기준





    }


}
```</code></pre><ul>
<li><p>[정렬]</p>
<pre><code class="language-java">  public class Main {

      public static void main(String[] args) {
          Map&lt;String, Integer&gt; hm = new HashMap&lt;&gt;();

          Map&lt;String, String&gt; map = new HashMap&lt;&gt;();
          map.put(&quot;Nepal&quot;, &quot;Kathmandu&quot;);
          map.put(&quot;United States&quot;, &quot;Washington&quot;);
          map.put(&quot;India&quot;, &quot;New Delhi&quot;);
          map.put(&quot;England&quot;, &quot;London&quot;);
          map.put(&quot;Australia&quot;, &quot;Canberra&quot;);

          List&lt;String&gt; valueList = new ArrayList&lt;&gt;(map.values());
          valueList.sort(String::compareTo); // 알파벳 순으로 정렬 

          for (String value : valueList) {
              System.out.println(&quot;Value: &quot; + value);
          }

      }

  }

  /*
  Value: Canberra
  Value: Kathmandu
  Value: London
  Value: New Delhi
  Value: Washington
  */</code></pre>
<pre><code class="language-java">  public class Main {

      public static void main(String[] args) {

          Map&lt;String, Integer&gt; hm = new HashMap&lt;&gt;();
          hm.put(&quot;data1&quot;, 5);
          hm.put(&quot;data2&quot;, 6);
          hm.put(&quot;data3&quot;, 4);
          hm.put(&quot;data4&quot;, 4);
          hm.put(&quot;data5&quot;, 7);
          hm.put(&quot;data6&quot;, 1);

          List&lt;Integer&gt; valueList = new ArrayList&lt;&gt;(hm.values());
          valueList.sort(Integer::compareTo);

          for (int value : valueList) {
              System.out.println(&quot;Value: &quot; + value);
          }
      }
  }

  /*
  Value: 1
  Value: 4
  Value: 4
  Value: 5
  Value: 6
  Value: 7
  */</code></pre>
</li>
<li><p>HashSet</p>
<pre><code class="language-java">  package codingtest;

  import java.awt.print.Printable;
  import java.util.*;
  import java.util.Scanner;

  import org.omg.CORBA.PolicyListHelper;

  public class Main {

      public static void main(String[] args) {

          // HashSet 선언
          HashSet&lt;Integer&gt; setTest = new HashSet&lt;&gt;();

          // 데이터 삽입
          setTest.add(10);
          setTest.add(20);
          setTest.add(30);
          setTest.add(40);
          setTest.add(50);

          // 중복을 허용하지 않음
          setTest.add(10);
          setTest.add(20);
          setTest.add(30);

          System.out.println(setTest); // [50, 20, 40, 10, 30]

          // remove Element
          setTest.remove(40);

          // Element 존재 확인
          System.out.println(setTest.contains(10)); // true

          // isEmpty()
          System.out.println(setTest.isEmpty()); // false

          // size()
          System.out.println(setTest.size()); // 4

          // get iterator()
          Iterator setIter = setTest.iterator();
          while (setIter.hasNext()) {
              System.out.println(setIter.next());
          }

          // Removes all of the elements from this set.
          setTest.clear();




</code></pre>
</li>
</ul>
<pre><code>    }


}
```</code></pre>]]></description>
        </item>
    </channel>
</rss>