<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>h-swon.log</title>
        <link>https://velog.io/</link>
        <description>끄적끄적</description>
        <lastBuildDate>Sun, 03 Apr 2022 06:23:02 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <copyright>Copyright (C) 2019. h-swon.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/h-swon" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[Kotlin] 클래스, 객체, 인터페이스(4)]]></title>
            <link>https://velog.io/@h-swon/Kotlin-%ED%81%B4%EB%9E%98%EC%8A%A4-%EA%B0%9D%EC%B2%B4-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A44</link>
            <guid>https://velog.io/@h-swon/Kotlin-%ED%81%B4%EB%9E%98%EC%8A%A4-%EA%B0%9D%EC%B2%B4-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A44</guid>
            <pubDate>Sun, 03 Apr 2022 06:23:02 GMT</pubDate>
            <description><![CDATA[<h3 id="1-object--클래스-선언과-인스턴스-생성">1. object : 클래스 선언과 인스턴스 생성</h3>
<ul>
<li><p><strong>object</strong> 키워드를 통해 클래스를 정의하는 동시에 객체를 생성한다.</p>
</li>
<li><p>싱글턴을 정의하는 방법 중 하나이다.</p>
</li>
<li><p><strong>companion object</strong>는 인스턴스 메소드는 아니지만 어떤 클래스와 관련 있는 메소드와 팩토리 메소드를 담을 때 쓰인다. compainon object 메소드에 접근할 때는 companion object가 포함된 클래스의 이름을 사용할 수 있다.</p>
</li>
<li><p>객체 식은 자바의 anonymous inner class 대신 쓰인다.</p>
</li>
<li><p>lazy하게 초기화 된다.</p>
</li>
</ul>
<p><br/><br/></p>
<h3 id="2-object-declaration--싱글턴을-쉽게-만들기">2. object declaration : 싱글턴을 쉽게 만들기</h3>
<ul>
<li><p>Kotlin은 <strong>object declaration</strong> 기능을 통해 싱글턴을 언어에서 기본 지원한다.
object declaration = 클래스 선언 + 그 클래스에 속한 단일 인스턴스의 선언</p>
</li>
<li><p>object declaration에 생성자 정의는 필요 없다. object declaration이 있는 위치에서 생성자 호출 없이 즉시 만들어지기 때문이다.</p>
</li>
<li><p>object declaration도 클래스나 인터페이스를 상속할 수 있다.</p>
</li>
</ul>
<pre><code class="language-kotlin">object Payroll {
    val allEmployees = arrayListOf&lt;Person&gt;()
    fun calculateSalary() {...}
}

Payroll.allEmployees.add(Person(...))
Payroll.calculateSalary()</code></pre>
<ul>
<li>클래스 안에서 객체를 선언할 수 있다. 마찬가지로 이 객체의 인스턴스는 1개다.<pre><code class="language-kotlin">data class Person(val name: String) {
  object NameComparator : Comparator&lt;Person&gt; {
      override fun compare(p1: Person, p2: Person): Int =
          p1.name.compareTo(p2.name)
  }
}
</code></pre>
</li>
</ul>
<blockquote>
<blockquote>
<blockquote>
<p>val persons = listOf(Person(&quot;Bob&quot;), Person(&quot;Alice&quot;))
println(persons.sortedWith(Person.NameComparator))</p>
</blockquote>
</blockquote>
</blockquote>
<pre><code>&lt;br/&gt;&lt;br/&gt;

### 3. companion object : 팩토리 메소드와 정적 멤버가 들어갈 장소
- 어떤 클래스의 모든 인스턴스가 공유하는 객체를 만들고 싶을 때 사용하며, 클래스당 한 개만 가질 수 있다.

- 자신을 둘러싼 클래스의 모든 `private` 멤버에 접근할 수 있다.

- companion object의 프로퍼티나 메소드에 접근하려면 그 companion object가 정의된 클래스 이름을 사용한다.

- 이름을 생략할 수 있고 생략하게 되면 Companion이란 이름으로 접근할 수 있다.
```kotlin
class Obj {
    companion object{
        fun hi() = println(&quot;HI&quot;)
    }
}
&gt;&gt;&gt; Obj.hi()
&gt;&gt;&gt; Obj.Companion.hi()
HI
HI
// Obj.멤버는 Obj.Companion.멤버의 축약표현!!!!

class Person(val name: String) {
    companion object Loader {
        fun fromJSON(jsonText: String) : Person { ... }
    }
}
&gt;&gt;&gt; person = Person.Loader.fromJSON(&quot;{name: &#39;Dmitry&#39;}&quot;)
&gt;&gt;&gt; person.name
Dmitry

&gt;&gt;&gt; person = Person.fromJSON(&quot;{name: &#39;Brent&#39;}&quot;)
&gt;&gt;&gt; person.name
Brent</code></pre><ul>
<li><code>팩토리 패턴</code>을 구현하기 가장 적합한 위치이다.</li>
</ul>
<pre><code class="language-kotlin">class User private constructor(val nickname: String) {
    companion object {
        fun newSubscribingUser(email: String) = User(email.substringBefore(&#39;@&#39;))
        fun newFacebookUser(accountId: Int) = User(getFacebookName(accountId))
    }
}</code></pre>
<ul>
<li>인터페이스 구현이 가능하다.<pre><code class="language-kotlin">interface JSONFactory&lt;T&gt; {
  fun fromJSON(jsonText: String): T
}
</code></pre>
</li>
</ul>
<p>class Person(val name: String) {
    companion object : JSONFactory<Person> {
        override fun fromJSON(jsonText: String): Person {...}
    }
}</p>
<pre><code>- companion object는 객체이기 때문에 변수에 할당이 가능하다.
```kotlin
class Obj {
    companion object{
        fun hi() = println(&quot;HI&quot;)
    }
}

&gt;&gt;&gt; val obj = Obj.Companion
&gt;&gt;&gt; obj.hi()
HI

&gt;&gt;&gt; val obj2 = Obj
&gt;&gt;&gt; obj2.hi()
HI</code></pre><ul>
<li>자바에서 사용하기 위해 코틀린 클래스의 멤버를 static하게 만들려면 <code>@JvmStatic</code> 애노테이션을 코틀린 멤버에 붙이면 된다. static field가 필요하면 <code>@JvmField</code> 애노테이션을 붙인다.
<br/><br/></li>
</ul>
<h3 id="4-객체-표현식-익명-내부-클래스를-다른-방식으로-작성">4. 객체 표현식: 익명 내부 클래스를 다른 방식으로 작성</h3>
<ul>
<li>객체 선언과 달리 익명 객체는 싱글턴이 아니다. 객체 식이 쓰일 때마다 새로운 인스턴스가 생성된다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Kotlin] 클래스, 객체, 인터페이스(3)]]></title>
            <link>https://velog.io/@h-swon/Kotlin-%ED%81%B4%EB%9E%98%EC%8A%A4-%EA%B0%9D%EC%B2%B4-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A43</link>
            <guid>https://velog.io/@h-swon/Kotlin-%ED%81%B4%EB%9E%98%EC%8A%A4-%EA%B0%9D%EC%B2%B4-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A43</guid>
            <pubDate>Tue, 29 Mar 2022 10:17:24 GMT</pubDate>
            <description><![CDATA[<h3 id="1-모든-클래스가-정의해야-하는-메소드">1. 모든 클래스가 정의해야 하는 메소드</h3>
<ul>
<li><strong>문자열 표현:  toString()</strong>
주로 디버깅이나 로깅 시 이 메소드를 사용한다.<pre><code class="language-kotlin">class Client(val name: String, val postalCode: Int){
  override fun toString() = &quot;Client(name=${name}, postalCode=${postalCode})&quot;
}
</code></pre>
</li>
</ul>
<blockquote>
<blockquote>
<blockquote>
<p>val client = Client(&quot;홍길동&quot;, 2022)
println(client)
Client(name=홍길동, postalCode=2022)</p>
</blockquote>
</blockquote>
</blockquote>
<pre><code>&lt;br/&gt;

- **객체의 동등성: equals()**
코틀린에서 `==` 연산자는 참조 동일성을 검사하지 않고 객체의 동등성을 검사한다. 따라서 `==` 연산은 equals를 호출하는 식으로 컴파일 된다. 참조 비교를 위해서는 `===` 연산자를 사용한다.
```kotlin
&gt;&gt;&gt; val client1 = Client(&quot;홍길동&quot;, 1111)
&gt;&gt;&gt; val client2 = Client(&quot;홍길동&quot;, 1111)
&gt;&gt;&gt; println(client1 == client2)
false</code></pre><p>Client 클래스의 객체 동등성을 만족시키려면 equals를 오버라이드 해야 한다.</p>
<pre><code class="language-kotlin">class Client(val name: String, val postalCode: Int) {
    override fun equals(other: Any?): Boolean {
        if (other == null || other !is Client)
            return false
        return name == other.name &amp;&amp; postalCode == other.postalCode
    }
}</code></pre>
<br/>

<ul>
<li><p><strong>해시 컨테이너: hashCode()</strong></p>
<blockquote>
<p><strong>hash code란</strong></p>
</blockquote>
<p>객체를 식별하는 하나의 정수 값. hashCode() 메소드는 <strong>객체의 메모리 번지</strong>를 이용해서 해시코드를 만들기 때문에 객체마다 다른 값을 가지고 있다.</p>
<p><strong>hashCode 규약</strong>
equals()가 true를 반환하는 두 객체는 반드시 같은 hashCode()를 반환해야 한다.</p>
<br/>

<p><strong>equals()와 hashCode()를 같이 override해야 하는 이유</strong>
<code>HashSet</code>, <code>HashMap</code>, <code>HashTable</code>은 </p>
</li>
<li><p><em>1.*</em> hashCode() 메소드를 실행해서 리턴된 해시코드 값이 같은지를 본다. 해시 코드값이 다르면 다른 객체로 판단한다.</p>
</li>
<li><p><em>2.*</em> 해시 코드값이 같으면<code>equals()</code> 메소드로 다시 비교한다. 
이 2개 조건을 모두 만족해야 같은 객체로 판단하고 해시코드가 다르면 equals() 메소드로 비교해보지도 않는다.</p>
</li>
</ul>
<pre><code class="language-kotlin">class Client(val name: String, val postalCode: Int) {
    ...
    override fun hashCode(): Int = name.hashCode() * 31 + postalCode
}</code></pre>
<p><br/><br/></p>
<h3 id="2-data-class">2. Data Class</h3>
<ul>
<li><p>데이터를 저장하는 클래스로 <code>toString</code>, <code>equals</code>, <code>hashCode</code>를 생성할 필요도 없이 컴파일러가 <strong>자동으로 만들어준다.</strong></p>
</li>
<li><p><code>equals</code>와 <code>hashCode</code>는 주 생성자에 나열된 모든 프로퍼티를 고려해 만들어진다.</p>
</li>
<li><p><em>(주 생성자 밖에 정의된 프로퍼티는 고려 대상이 x)*</em></p>
<pre><code class="language-kotlin">data class Client(val name: String, val postalCode: Int)</code></pre>
<br/>
</li>
<li><p><strong>불변성 : copy() 메소드</strong>
copy() 메소드는 객체를 복사하면서 일부 프로퍼티를 바꿀수 있게 해주는 메소드이며 자동으로 만들어진다.
데이터 클래스의 프로퍼티에 <code>var</code>를 써도되지만 <strong>모든 프로퍼티를 읽기 전용으로 만들어서 데이터 클래스를 불변 클래스</strong>로 만들라고 권장한다.</p>
<blockquote>
<p><strong>Why?</strong></p>
</blockquote>
<p>HashMap 등의 컨테이너에 데이터 클래스 객체를 담는 경우 <strong>불변성</strong>이 필수적이다. Key로 쓰인 데이터 객체의 프로퍼티를 변경했을 때 컨테이너 상태가 잘못될 수 있기 때문이다. 또한 다중 스레드 프로그램의 경우 불변 객체를 사용하면 스레드가 사용 중인 데이터를 다른 스레드가 변경할 수 없으므로 스레드를 동기화해야 할 필요가 줄어든다. </p>
</li>
</ul>
<pre><code class="language-kotlin">&gt;&gt;&gt; val client = Client(&quot;홍길동&quot;, 1111)
&gt;&gt;&gt; println(client.copy(postalCode = 2222).postalCode)
2222</code></pre>
<p><br/><br/></p>
<h3 id="3-클래스-위임--by-키워드-사용">3. 클래스 위임 : by 키워드 사용</h3>
<ul>
<li><p>인터페이스를 구현할 때 <strong>by</strong> 키워드를 통해 그 인터페이스에 대한 구현을 다른 객체에 위임 중이라는 사실을 명시할 수 있다. 다시 말하면, 클래스를 다른 클래스에 위임하면 위임 클래스가 가지는 인터페이스 메소드를 참조 없이 호출하게 해준다.</p>
</li>
<li><p>메소드 중 일부의 동작을 변경하고 싶은 경우 메소드를 오버라이드하면 컴파일러가 생성한 메소드 대신 오버라이드한 메소드가 사용된다.</p>
</li>
</ul>
<pre><code class="language-kotlin">class DelegatingCollection&lt;T&gt; : Collection&lt;T&gt; {
    private val innerList = arrayListOf&lt;T&gt;()

    override val size: Int get() = innerList.size

    override fun contains(element: T): Boolean = innerList.contains(element)

    override fun containsAll(elements: Collection&lt;T&gt;): Boolean 
    = innerList.containsAll(elements)

    override fun isEmpty(): Boolean = innerList.isEmpty()

    override fun iterator(): Iterator&lt;T&gt; = innerList.iterator()
}

// by 키워드를 사용한다면 아래와 같이 쓸 수 있다.
class DelegatingCollection&lt;T&gt; (
    innerList: Collection&lt;T&gt;
) : Collection&lt;T&gt; by innerList {

    // 컴파일러가 생성한 메소드 대신 오버라이드한 메소드가 사용된다.
    override fun isEmpty(): Boolean {
        println(&quot;Empty!!!!&quot;)
        innerList.isEmpty()
    }
}</code></pre>
<p><br/><br/></p>
<h4 id="reference">Reference</h4>
<ul>
<li><a href="https://medium.com/til-kotlin-ko/kotlin%EC%9D%98-%ED%81%B4%EB%9E%98%EC%8A%A4-%EC%9C%84%EC%9E%84%EC%9D%80-%EC%96%B4%EB%96%BB%EA%B2%8C-%EB%8F%99%EC%9E%91%ED%95%98%EB%8A%94%EA%B0%80-c14dcbbb08ad">Kotlin의 클래스 위임은 어떻게 동작하는가</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[OS] 프로세스와 스레드]]></title>
            <link>https://velog.io/@h-swon/OS-%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4%EC%99%80-%EC%8A%A4%EB%A0%88%EB%93%9C-2blexgde</link>
            <guid>https://velog.io/@h-swon/OS-%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4%EC%99%80-%EC%8A%A4%EB%A0%88%EB%93%9C-2blexgde</guid>
            <pubDate>Mon, 14 Mar 2022 16:13:28 GMT</pubDate>
            <description><![CDATA[<h3 id="들어가기에-앞서">들어가기에 앞서</h3>
<ul>
<li><strong>프로그램이란?</strong>
파일이 저장 장치에 저장되어 있지만 메모리에 올라와 있지 않는 정적인 상태
(실행시킬 수 있는 파일)<br/>
<br/>

</li>
</ul>
<h3 id="1-프로세스">1. 프로세스</h3>
<ul>
<li>운영체제로부터 시스템 자원을 할당받는 작업의 단위</li>
<li>실행 중인 프로그램
<img src="https://images.velog.io/images/h-swon/post/207c8747-e768-4093-914f-6a1b114b49a0/image.png" alt=""></li>
<li>위 그림은 프로세스가 실행될 때, 메모리에 생기는 주소 공간이다.
<code>Text 영역</code> - 사용자가 작성한 코드가 기계어 명령 형태로 변경되어 저장되는 공간.
<code>Data 영역</code> - Static 변수 or Global 변수를 저장하는 공간.
<code>Heap 영역</code> - 동적 메모리 영역 (런타임 동안 늘어나기도 하고 줄어들기도 한다)
<code>Stack 영역</code> - 함수 복귀주소, 지역변수, 매개변수, 반환 값 등 일시적인 데이터를 저장하는 공간. (컴파일 타임에 크기가 결정)<blockquote>
<p><strong>메모리 영역을 나누는 이유</strong></p>
<p>우리가 어떠한 프로그램을 구현할 때, 각각의 변수, 함수, 클래스 등이 호출되고 해제되는 시기가 다르기 때문이다. 
ex) 어떠한 함수 내에서 한 번 사용되는 변수가 프로그램의 처음부터 끝까지 메모리에 남아있다면 메모리가 낭비된다.</p>
</blockquote>
결국 유사한 성향의 데이터를 묶어서 저장하면 관리가 용이해지고 접근속도가 향상되기 때문에 메모리 영역을 나누는 것이다.</li>
</ul>
<p><img src="https://images.velog.io/images/h-swon/post/1e805449-fa44-4fd8-8668-5db69d9474ec/image.png" alt=""></p>
<ul>
<li>위 그림과 같이 해당 프로세스에 대한 정보를 가지고 있는 PCB블록이 프로세스 생성과 동시에 만들어진다.</li>
</ul>
<p><br/><br/></p>
<h3 id="2-스레드">2. 스레드</h3>
<p>한 프로세스 내에도 여러 갈래의 작업들이 동시에 진행될 필요가 있다. ex) 웹 서버의 동시 요청 처리</p>
<ul>
<li>프로세스가 할당받은 자원을 이용하는 실행의 단위</li>
<li>프로세스 내에서 실제로 작업을 수행하는 주체</li>
<li>프로세스는 1개 이상의 스레드를 가질 수 있다.</li>
<li>cpu에서 실행되는 단위(unit of execution)</li>
<li>Heap, Data, Code영역을 공유하고 별도의 Stack 영역을 가진다.</li>
<li>같은 프로세스의 스레들끼리 context-switching은 가볍다.</li>
</ul>
<br/>
<br/>

<h3 id="3-멀티프로그래밍">3. 멀티프로그래밍</h3>
<p>cf.) 등장배경 : 단일 프로세스 시스템에서는 한 번에 하나의 프로그램만 실행할 수 있어서 cpu 사용률이 좋지 않았다. 그래서 여러 개의 프로그램을 메모리에 올려놓고 동시에 실행시키자는 멀티프로그래밍 아이디어가 나옴.</p>
<ul>
<li>단일 프로세서 상에서 여러 프로그램을 메모리에 동시에 올려서 수행하는 것</li>
<li>프로세서가 IO 작업의 종료를 기다리는 동안 다른 프로그램을 수행할 수 있도록 하는 것</li>
<li>CPU 사용률을 극대화 시킨다</li>
<li><strong>단점:</strong> CPU 사용 시간이 길어지면 다른 프로세스는 계속 대기
<img src="https://images.velog.io/images/h-swon/post/8441feb2-d086-4264-a94c-3cb61e372897/image.png" alt=""></li>
</ul>
<h3 id="4-멀티태스킹">4. 멀티태스킹</h3>
<p>cf.) 등장배경 : 멀티프로그래밍의 단점을 보완하고자 프로세스(혹은 스레드)는 한 번 CPU를 사용할 때 아주 짧은 시간(=quantum)만 CPU에서 실행되도록 하자는 멀티태스킹 개념이 나옴.</p>
<ul>
<li>멀티 태스킹은 시분할 시스템에서 사용되며, 사용자에게 다수의 작업이 동시에 처리되는 것처럼 느끼게 할 수 있다.</li>
<li>프로세스(혹은 스레드)의 응답 시간을 최소화시킨다</li>
<li><strong>단점:</strong> 하나의 프로세스가 동시에 여러 작업 수행을 하지는 못한다.
<img src="https://images.velog.io/images/h-swon/post/02056fe7-af3d-485b-8b89-16613f22b881/image.png" alt=""></li>
</ul>
<h3 id="3-멀티-프로세싱">3. 멀티 프로세싱</h3>
<ul>
<li>두 개 이상 다수의 프로세서(CPU)가 협력적으로 1개 이상의 작업(Task)을 동시에 처리하는 것</li>
<li>부모 프로세스가 fork()를 하여 자식 프로세스를 여러 개 만들어 작업을 처리한다.</li>
<li>프로세스간 메모리 공유는안되기 때문에, IPC를 이용해 소통한다.</li>
<li>하나의 프로세스에서 문제가 생겨도 다른 프로세스는 계속 진행할 수 있다.</li>
<li><strong>단점:</strong> 컨텍스트 스위칭 비용이 높다
<img src="https://images.velog.io/images/h-swon/post/f33fd8a2-d57e-4edb-a667-5a599f70c60d/image.png" alt=""></li>
</ul>
<h3 id="4-멀티-스레딩">4. 멀티 스레딩</h3>
<ul>
<li>하나의 프로세스에 여러 스레드로 자원을 공유하며 작업을 나누어 수행하는 것.</li>
<li>단일 프로세스 내에서 여러 쓰레드로 나누어 동시에 실행</li>
<li>컨텍스트 스위칭 비용이 거의 없음</li>
<li>스택을 제외한 데이터,코드,힙 영역을 공유하기 때문에 공유하는데 편리함</li>
<li><strong>단점</strong><ol>
<li>스레드 하나가 프로세스 내 자원을 망쳐버린다면 모든 프로세스가 종료될 수 있다. </li>
<li>자원을 공유하므로 동기화 문제가 발생한다.
<img src="https://images.velog.io/images/h-swon/post/9dc7aa51-0cf3-4234-ae91-179c2811323b/image.png" alt=""></li>
</ol>
</li>
</ul>
<br/>

<h4 id="reference">Reference</h4>
<ul>
<li><a href="https://www.geeksforgeeks.org/difference-between-multitasking-multithreading-and-multiprocessing/">Difference between Multiprogramming, multitasking, multithreading and multiprocessing</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[OS] 동시성과 병렬성]]></title>
            <link>https://velog.io/@h-swon/OS-%EB%8F%99%EC%8B%9C%EC%84%B1%EA%B3%BC-%EB%B3%91%EB%A0%AC%EC%84%B1</link>
            <guid>https://velog.io/@h-swon/OS-%EB%8F%99%EC%8B%9C%EC%84%B1%EA%B3%BC-%EB%B3%91%EB%A0%AC%EC%84%B1</guid>
            <pubDate>Mon, 14 Mar 2022 10:19:35 GMT</pubDate>
            <description><![CDATA[<h3 id="1-동시성-concurrency">1. 동시성 (Concurrency)</h3>
<ul>
<li>동시에 실행되는 것 처럼 보이는 것</li>
<li>싱글 코어에서 멀티쓰레드를 동작시키는 방식
(다른 작업으로 바꿀 때 Context Switching 발생)</li>
<li>논리적인 개념</li>
</ul>
<p>참고) <code>CPU는 한 순간에 1개의 프로세스만 실행 가능하다.</code> 그래서 Context-Switch가 필요하다.
<br/></p>
<h3 id="2-병렬성-parallelism">2. 병렬성 (Parallelism)</h3>
<ul>
<li>실제로 동시에 여러 작업이 처리되는 것</li>
<li>멀티 코어에서 멀티 쓰레드를 동작시키는 방식</li>
<li>물리적인 개념</li>
</ul>
<p><img src="https://images.velog.io/images/h-swon/post/cd8dab2f-ca20-481a-a7a1-4f0aa8b91df2/image.png" alt=""></p>
<h4 id="references">References</h4>
<ul>
<li><a href="https://www.codeproject.com/Articles/1267757/Concurrency-vs-Parallelism">Concurrency vs Parallelism</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Kotlin] 클래스, 객체, 인터페이스(2)]]></title>
            <link>https://velog.io/@h-swon/Kotlin-%ED%81%B4%EB%9E%98%EC%8A%A4-%EA%B0%9D%EC%B2%B4-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A42</link>
            <guid>https://velog.io/@h-swon/Kotlin-%ED%81%B4%EB%9E%98%EC%8A%A4-%EA%B0%9D%EC%B2%B4-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A42</guid>
            <pubDate>Mon, 07 Feb 2022 10:55:23 GMT</pubDate>
            <description><![CDATA[<h3 id="1-내부-클래스와-중첩-클래스-기본적으로-중첩-클래스">1. 내부 클래스와 중첩 클래스: 기본적으로 중첩 클래스!!</h3>
<ul>
<li>코틀린의 중첩 클래스는 명시적으로 요청하지 않는 한 외부 클래스 인스턴스에 대한 접근 권한이 없다. ( Java의 정적 중첩 클래스와 대응한다 )</li>
</ul>
<pre><code class="language-kotlin">interface State: Serializable

interface View {
    fun getCurrentState(): State
    fun restoreState(state: State)
}</code></pre>
<pre><code class="language-java">// Java
public class Button implements View{
    @Override
    public State getCurrentState(){
        return new ButtonState();
    }

    @Override
    public void restoreState(State state){
    ...
    }
    public class ButtonState implements State{
    ...
    }
}</code></pre>
<p>Java의 경우 Button을 직렬화하면 <code>java.io.NotSerializableException: Button</code>이라는 오류가 발생한다. Java에서는 다른 클래스 안에 정의한 클래스는 자동으로 <code>inner class</code>가 된다. 그래서 ButtonState클래스는 외부 Button 클래스에 대한 참조를 묵시적으로 포함한다. 그 참조로 인해 Button State를 직렬화할 수 없다. 이 문제를 해결하려면 ButtonState를 <code>static class</code>로 선언해야 한다.
<br/></p>
<pre><code class="language-kotlin">// Kotlin
class Button: View{
    override fun getCurrentState(): State = ButtonState()
    override fun restoreState(state: State){
    ...
    }
    class ButtonState: State{
    ...
    }
}</code></pre>
<p>코틀린의 경우 중첩 클래스에 아무런 변경자도 붙지 않으면 자바의 <code>static class</code>와 같다. 만일 외부 클래스에 대한 참조를 포함하게 만들고 싶으면 <code>inner</code> 변경자를 붙여서 <code>inner class</code>를 만든다.</p>
<table>
<thead>
<tr>
<th align="left">클래스 B안에 정의된 클래스 A</th>
<th align="left">Java</th>
<th align="left">Kotlin</th>
</tr>
</thead>
<tbody><tr>
<td align="left">중첩 클래스(외부 클래스에 대한 참조를 저장 X)</td>
<td align="left">static class A</td>
<td align="left">class A</td>
</tr>
<tr>
<td align="left">내부 클래스(외부 클래스에 대한 참조를 저장 O)</td>
<td align="left">class A</td>
<td align="left">inner class A</td>
</tr>
</tbody></table>
<br/>

<p>내부 클래스 Inner 안에서 외부 클래스 Outer의 참조에 접근하려면 <code>this@Outer</code>라고 써야 한다.</p>
<pre><code class="language-kotlin">class Outer{
    var num = 10
    inner class Inner{
        fun getOuterNumber(): Int = this@Outer.num
    }
}</code></pre>
<p><br/><br/></p>
<h3 id="2-sealed-클래스-클래스-계층-정의-시-계층-확장-제한">2. Sealed 클래스: 클래스 계층 정의 시 계층 확장 제한</h3>
<pre><code class="language-kotlin">interface Expr
class Num(val value: Int) : Expr
class Sum(val left: Expr, val right: Expr): Expr

fun eval(e: Expr): Int = 
    when(e){
        is Num -&gt; e.value
        is Sum -&gt; eval(e.left) + eval(e.right)
        else -&gt;
            throw IllegalArgumentException(&quot;Unknown expression&quot;)
    }</code></pre>
<p>항상 디폴트 분기를 추가하는게 편하지는 않다. 또 실수로 새로운 클래스 처리를 잊어버리면 디폴트 분기가 선택되기 때문에 심각한 버그가 발생할 수 있다.</p>
<p>이를 위해 <code>sealed class</code>를 사용한다. 상위 클래스에 <code>sealed</code> 변경자를 붙이면 그 상위 클래스를 상속한 하위 클래스 정의를 제한할 수 있다. 또 <code>sealed class</code>는 항상 열려있기 때문에 <code>open</code> 변경자를 붙일 필요가 없다.</p>
<pre><code class="language-kotlin">sealed class Expr {
    class Num(val value: Int) : Expr()
    class Sum(val left: Expr, val right: Expr) : Expr()
}

fun eval(e: Expr): Int =
    when (e) {
        is Expr.Num -&gt; e.value
        is Expr.Sum -&gt; eval(e.left) + eval(e.right)
    }
    // 컴파일러가 sealed class의 자식 클래스에 누가 있는지 알고 있다.</code></pre>
<p><br/><br/></p>
<h3 id="3-주-생성자와-초기화-블록">3. 주 생성자와 초기화 블록</h3>
<ul>
<li><strong>주 생성자</strong>
생성자 파라미터를 지정하고 그 생성자 파라미터에 의해 초기화되는 프로퍼티를 정의한다. 클래스 옆에 괄호 표기로 정의된 것을 말하며 클래스에 최대 1개만 존재한다.</li>
</ul>
<ul>
<li><p><strong>constructor</strong>
주 생성자나 부 생성자 정의를 시작할 때 사용한다.</p>
</li>
<li><p><strong>init</strong>
초기화 블록을 시작한다. 초기화 블록에는 <code>클래스가 인스턴스화</code>될 때 실행되는 초기화 코드가 들어가며 주 생성자와 함께 사용된다. 한 클래스 안에 여러 초기화 블록을 선언할 수 있다. <strong>초기화 블록은 주 생성자 직후에 실행되며 부 생성자보다는 먼저 실행된다.</strong></p>
<pre><code class="language-kotlin">class User constructor(_nickname: String){    // 파라미터가 1개인 주 생성자
  val nickname: String            // 프로퍼티

  init {                    // 초기화 블록
      nickname =_nickname
  }
}</code></pre>
<p>nickname 프로퍼티를 초기화하는 코드를 프로퍼티 선언과 동시에 할 수 있고, 주 생성자 앞에 별다른 <code>annotation</code>이나 <code>visibility modifer</code>가 없으면 <code>constructor</code>를 생략 할 수 있다. </p>
</li>
<li><p><em>주 생성자의 파라미터는 프로퍼티의 초기화 식이나 초기화 블록 안에서만 참조할 수 있다.*</em> </p>
<pre><code class="language-kotlin">class User(_nickname: String){
   val nickname = _nickname
}</code></pre>
<p>아래와 같이 더 간결하게 쓸 수 있다.</p>
<pre><code class="language-kotlin">class User(val nickname: String)</code></pre>
</li>
</ul>
<br/>

<ul>
<li>클래스에 부모 클래스가 있다면 <strong>주 생성자에서 부모 클래스의 생성자를 호출해야 한다.</strong> 부모 클래스를 초기화하려면 부모 클래스 이름 뒤에 괄호를 치고 생성자 인자를 넘긴다.</li>
</ul>
<pre><code class="language-kotlin">open class User(val nickname: String) {...}
class TwitterUser(nickname: String) : User(nickname) {...}</code></pre>
<br/>


<ul>
<li><p>클래스를 정의할 때 별도로 생성자를 정의하지 않으면 컴파일러가 자동으로 <code>디폴트 생성자</code>를 만든다.</p>
<pre><code class="language-kotlin">open class Button
class RadiButton: Button()    
// Button 생성자는 아무 인자도 받지 않지만 
// 하위 클래스는 반드시 Button 클래스의 생성자를 호출해야 한다.</code></pre>
<br/>
</li>
<li><p><strong>비공개 생성자</strong>
어떤 클래스를 클래스 외부에서 인스턴스화하지 못하게 막고 싶다면 모든 생성자를 <code>private</code>로 만들면 된다.</p>
<pre><code class="language-kotlin">class SecretObject private constructor() {}</code></pre>
<p><br/><br/></p>
</li>
</ul>
<h3 id="4-부-생성자--상위-클래스를-다른-방식으로-초기화">4. 부 생성자 : 상위 클래스를 다른 방식으로 초기화</h3>
<ul>
<li><p>클래스에 여러 개의 부 생성자를 가질 수 있다. <code>constructor</code> 키워드를 사용하며 주 생성자와 달리 생략할 수 없다.</p>
</li>
<li><p>주 생성자가 정의된 경우, 부 생성자에서 호출하는 생성자를 따라가면 반드시 주 생성자를 호출해줘야 한다. 클래스의 다른 생성자를 클래스 내부에서 호출할 때는 <code>:this()</code>를 이용한다.</p>
<pre><code class="language-kotlin">class Person(val name: String) {
  var age: Int = 0
  var weight: Int = -1

  constructor(_name: String, _age: Int) : this(_name) {
      age = _age
  }

  constructor(_name: String, _age: Int, _weight: Int) : this(_name, _age) {
      weight = _weight
  }
}</code></pre>
<blockquote>
<p>인자에 대한 디폴트 값을 제공하기 위해 부 생성자를 여러 개 만들지 말자. </p>
</blockquote>
</li>
<li><p><em>대신 파라미터에 default값을 줌으로써 해결할 수 있다.*</em></p>
<blockquote>
</blockquote>
<p>부 생성자가 필요한 주된 이유는 <strong>Java와의 상호운용성</strong> 때문이다. 이외에도 클래스 인스턴스를 생성할 때 파라미터 목록이 다른 생성 방법이 여러 개인 경우 사용한다.</p>
</li>
</ul>
<pre><code class="language-kotlin">open class View {    // 주 생성자 없이 부 생성자만 2개
    constructor(ctx: Context) {...}
    constructor(ctx: Context, attr: AttributeSet) {...}
}

class MyButton : View {
    constructor(ctx: Context) : super(ctx) {...}
    constructor(ctx: Context, attr: AttributeSet) : super(ctx, attr) {...}
}

// super 키워드를 통해 자신에 대응하는 상위 클래스 생성자를 호출한다.</code></pre>
<br/>

<ul>
<li>클래스에 주 생성자가 없다면 모든 부 생성자는 반드시 상위 클래스를 초기화하거나 다른 생성자에게 생성을 위임해야 한다.</li>
</ul>
<pre><code class="language-kotlin">class MyButton: View{
    constructor(ctx: Context) : this(ctx, MY_STYLE) { ... }
    constructor(ctx: Context, attr: AttributeSet) : super(ctx, attr) { ... }
}</code></pre>
<p><br/><br/></p>
<h3 id="5-인터페이스에-선언된-프로퍼티-구현">5. 인터페이스에 선언된 프로퍼티 구현</h3>
<ul>
<li>Kotlin에서는 인터페이스에 추상 프로퍼티 선언을 할 수 있다. 하지만 인터페이스는 뒷받침 하는 필드를 가질 수 없기 때문에 초기화가 불가능하다. 대신 인터페이스를 구현하는 클래스에서 getter나 setter를 구현해야 한다.</li>
</ul>
<pre><code class="language-kotlin">interface User {
    val nickname: String
}

class PrivateUser(override val nickname: String) : User
// 주 생성자 안에 프로퍼티를 직접 선언

class SubscribingUser(val email: String) : User {
    override val nickname: String
        get() = email.substringBefore(&#39;@&#39;)
}
// 뒷받침하는 필드에 값을 저장하지 않고 매번 이메일 주소에서 nickname을 계산한다.

class FacebookUser(val accountId: Int) : User {
    override val nickname = getFacebookName(accountId)
}
// 객체 초기화할 때 데이터를 뒷받침하는 필드에 저장하고 그 값을 불러온다.</code></pre>
<br/>

<ul>
<li>인터페이스에 getter와 setter가 있는 프로퍼티를 선언할 수 있다. 물론 상태를 저장할 수는 없다.</li>
</ul>
<pre><code class="language-kotlin">interface User{
    val email: String
    val nickname: String
        get() = email.substringBefore(&#39;@&#39;)    // 매번 결과를 계산해서 리턴
}

// email은 반드시 구현해야 하지만 
// nickname은 구현하지 않으면 인터페이스에서 정의된 default getter를 사용한다.</code></pre>
<p><br/><br/></p>
<h3 id="6-getter와-setter에서-뒷받침-하는-필드에-접근">6. getter와 setter에서 뒷받침 하는 필드에 접근</h3>
<ul>
<li><p>프로퍼티에는 getter / setter와 같은 함수가 내장되어 있고, 프로퍼티가 가진 값은 <code>field</code>에 저장된다. 프로퍼티 외부에서는 get()이나 set()을 호출하지만 get(), set() 내부에서는 <code>field</code>를 통해 프로퍼티가 가지고 있는 값에 접근한다. </p>
</li>
<li><p><em>( field는 get(), set()에서만 사용 가능하다. )*</em></p>
</li>
<li><p><code>field</code>를 통해서 뒷받침하는 필드에 접근할 수 있다. getter는 <code>field</code> 값을 읽을 수만 있고 setter는 <code>field</code> 값을 읽거나 쓸 수 있다. </p>
<pre><code class="language-kotlin">class User(val name: String) {
  var address: String = &quot;unspecified&quot;
      set(value) {
          println(&quot;&quot;&quot;
              Address was changed for $name:
              &quot;$field&quot; -&gt; &quot;$value&quot;.&quot;&quot;&quot;.trimIndent())
          field = value
      }
}
</code></pre>
</li>
</ul>
<blockquote>
<blockquote>
<blockquote>
<p>val user = User(&quot;Alice&quot;)
user.address = &quot;Seoul&quot;</p>
</blockquote>
</blockquote>
</blockquote>
<p>Address was changed for Alice:
&quot;unspecified&quot; -&gt; &quot;Seoul&quot;.</p>
<pre><code>
```kotlin
class Person {
    var name: String = &quot;F&quot;
    var age: Int=0
        get() = age
}
&gt;&gt;&gt; Person().age
// 주의! 무한 재귀에 빠진다.</code></pre><br/>

<ul>
<li><p>get(), set()의 가시성 변경</p>
<pre><code class="language-kotlin">class LengthCounter {
  var counter: Int = 0
    private set                // 이 클래스 밖에서 counter의 값을 변경할 수 없다.

  fun addWord(word: String) {
      counter += word.length
  }
}</code></pre>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Kotlin] Serializable vs Parcelable]]></title>
            <link>https://velog.io/@h-swon/Kotlin-Parcelable-vs-Serializable</link>
            <guid>https://velog.io/@h-swon/Kotlin-Parcelable-vs-Serializable</guid>
            <pubDate>Sun, 30 Jan 2022 11:31:36 GMT</pubDate>
            <description><![CDATA[<h3 id="1-serializable이란">1. Serializable이란?</h3>
<ul>
<li>Java의 마커 인터페이스
: Serialization(직렬화)을 위해 구현해야 하는 인터페이스이다.</li>
</ul>
<pre><code class="language-java">public interface Serializable {}</code></pre>
<blockquote>
<p><strong>Java Serialization(직렬화)</strong></p>
</blockquote>
<p>자바 내부에서 사용하는 객체나 데이터를 외부 자바시스템에서 사용할 수 있도록 <code>바이트 스트림</code> 형태로 만드는 것을 의미한다. 
프로그램에서 사용되는 데이터들은 연속적으로 위치해 있지 않고 내부적으로 포인터에 의해 참조되고 있기 때문에 흩어진 데이터를 한 곳에 모아 일련의 바이트 형태로 보내야한다.</p>
<blockquote>
<p>** Byte Stream**</p>
</blockquote>
<p>데이터를 Byte 단위로 주고받는 것. </p>
<br/>

<p> -<code>Serializable</code>은 내부에서 <code>Reflection</code>을 사용해서 직렬화 처리를 하는데 처리 과정 중에 많은 추가 객체를 생성한다. 이 쓰레기들은 <code>Garbage Collector</code>의 타겟이 되고 <code>Garbage Collector</code>의 과도한 동작으로 성능 저하 및 배터리 소모가 발생한다.
<br/><br/></p>
<h3 id="2-parcelable이란">2. Parcelable이란?</h3>
<ul>
<li><p>안드로이드 SDK의 인터페이스로  <code>Reflection</code>을 사용하지 않게 설계되어 있다. <code>Serializable</code>과 달리 직렬화 처리 방법을 사용자가 명시적으로 작성하기 때문에 자동으로 처리하기 위한 <code>Reflection</code>이 필요없다.</p>
</li>
<li><p><code>Parcelable</code>을 직접 구현하는 건 보일러 플레이트 코드가 생기게 된다.
그래서 <code>kotlin-parcelize plugin</code>을 사용해 <code>Parcelable</code> 구현을 자동으로 처리한다.</p>
</li>
</ul>
<pre><code class="language-kotlin">plugins {
    id &#39;kotlin-parcelize&#39;
}</code></pre>
<pre><code class="language-kotlin">@Parcelize
data class Person(
    val name: String,
    val age: Int
): Parcelable</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Android] 클린 아키텍처]]></title>
            <link>https://velog.io/@h-swon/Android-%ED%81%B4%EB%A6%B0-%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98</link>
            <guid>https://velog.io/@h-swon/Android-%ED%81%B4%EB%A6%B0-%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98</guid>
            <pubDate>Mon, 24 Jan 2022 14:42:06 GMT</pubDate>
            <description><![CDATA[<h3 id="1-클린-아키텍처">1. 클린 아키텍처</h3>
<blockquote>
<p>로버트 C. 마틴이 만든 소프트웨어 관심사를 계층별로 분리하는 소프트웨어 디자인 철학.
<code>Use Case</code>를 중심으로 설계..!!!!</p>
</blockquote>
<p><img src="https://images.velog.io/images/h-swon/post/e5c821b5-0523-4e0d-a2d7-517282fb6655/image.png" alt=""></p>
<ul>
<li>내부원에 있는 것은 정책이고 바깥으로 갈수록 정책을 수행하는 메커니즘으로 구성된다.</li>
</ul>
<p><strong>주요 원칙</strong></p>
<ol>
<li><p>의존성이 <code>외부 -&gt; 내부</code> 방향으로 존재한다. 
( 내부 계층은 외부 계층을 알 수 없다. )</p>
</li>
<li><p>외부 계층에 존재하는 변수, 함수 및 클래스는 내부에서 사용할 수 없다.</p>
</li>
<li><p>데이터 형식도 <code>Layer</code> 간에 별도로 유지하는 것이 좋다. </p>
</li>
</ol>
<p>** 장점 **</p>
<ol>
<li>코드 재사용성이 용이해진다.</li>
<li>유닛 테스트가 쉬워진다.</li>
</ol>
<p>** 구성 요소 **</p>
<ol>
<li><code>Entities</code></li>
</ol>
<p>-애플리케이션에서 핵심적인 기능인 업무규칙(비즈니스 규칙)을 캡슐화한다.</p>
<ol start="2">
<li><code>Use Cases</code></li>
</ol>
<p>-특정 애플리케이션과 관련된 비즈니스 규칙을 포함한다.
-Entity 내부의 핵심 업무 규칙을 어떻게, 언제 호출할지를 명시하는 규칙을 담는다.</p>
<ol start="3">
<li><code>Interface Adapters</code></li>
</ol>
<p>-Entites나 Use Cases로부터 얻은 데이터를 가공하는 Layer다.
-데이터를 Layer에 맞는 형식으로 변환한다.
-Presenter, View, Viewmodel, Controller가 여기에 속한다.
-비즈니스 로직과 프레임워크 코드를 연결</p>
<ol start="4">
<li><code>Frameworks와 Drivers</code></li>
</ol>
<p>-Activity, Fragment, Intent 전달, 데이터베이스, Contents Provider, Retrofit과 같은 네트워크 관련된 프레임워크 코드가 포함된다.
<br/><br/></p>
<h3 id="2-android에서의-클린-아키텍처">2. Android에서의 클린 아키텍처</h3>
<p><img src="https://images.velog.io/images/h-swon/post/2ed4706c-c2d0-4635-b118-8e0a0b260e03/image.png" alt=""></p>
<p><strong>Presentation Layer</strong></p>
<ul>
<li>화면 조작 or 사용자의 입력을 처리하기 위한 관심사를 모아놓은 Layer.</li>
<li>UI (activity, fragment), Controller(Presenter, ViewModel)를 포함한다.</li>
<li>Controller는 1개 이상의 <code>Use case</code>를 실행한다.</li>
<li>UI는 각각의 Controller에 의해 조작된다.</li>
<li><code>Domain Layer</code>에 의존성을 가진다.</li>
</ul>
<p><strong>Domain Layer</strong></p>
<ul>
<li><p>비즈니스 로직을 포함한다.</p>
</li>
<li><p>가장 안쪽의 <code>Layer</code>로 어떤 <code>Layer</code>에 대해서도 의존성을 가지지 않는다. 오직 언어(Kotlin)에 대해서만 의존성을 가진다.</p>
</li>
<li><p><code>Entity</code>, <code>Use case</code>, <code>Repository Interface</code>를 포함한다.</p>
</li>
<li><p><code>Use case</code>는 data와 1개 이상의 Repository Interface를 받아 비즈니스 로직을 처리한다.</p>
<ul>
<li><code>Use Case</code>는 행동들의 최소 단위이다.</li>
<li><code>Use Case</code>는 보통 1개의 행동을 담당하며 이름만 보고도 무슨 기능을 하는지 짐작 가능해야 한다.<blockquote>
<p>*<em>Domain Layer가 Data Layer에 대해 의존성을 가지지 않기 위해선? *</em></p>
<p>의존성 역전 법칙을 이용해 interface를 사용한 추상화를 적용한다.
Domain Layer는 Data Layer에 대한 의존성 회피를 위해 Repository를 추상화시켜 사용하고 있다.</p>
</blockquote>
</li>
</ul>
</li>
</ul>
<p><strong>Data Layer</strong></p>
<ul>
<li><code>Repository Implementation</code>, 1개 이상의 <code>Data Source</code>, <code>Mapper</code>(Mapper 대신 Interface 구현으로 대체 가능), <code>Data Model</code>을 포함한다.</li>
<li><code>Repository</code>는 다른 <code>Data Source</code>들을 결합 / 조정한다.</li>
<li><code>Domain Layer</code>에 의존성을 가진다.<blockquote>
<p><strong>Data Source와 DataSourceImpl</strong></p>
</blockquote>
Data Soruce 역시 의존성 역전 법칙을 적용해 추상화된다. Repository가 Data Source에 대해 의존성을 가지지 않게 한다. 따라서 Data Source가 변경되더라도 Repository에 대한 영향을 줄일 수 있다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Kotlin] 클래스, 객체, 인터페이스(1)]]></title>
            <link>https://velog.io/@h-swon/Kotlin-%ED%81%B4%EB%9E%98%EC%8A%A4-%EA%B0%9D%EC%B2%B4-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A41</link>
            <guid>https://velog.io/@h-swon/Kotlin-%ED%81%B4%EB%9E%98%EC%8A%A4-%EA%B0%9D%EC%B2%B4-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A41</guid>
            <pubDate>Mon, 17 Jan 2022 16:47:55 GMT</pubDate>
            <description><![CDATA[<h3 id="1-인터페이스">1. 인터페이스</h3>
<ul>
<li>코틀린 인터페이스는 자바 8의 인터페이스와 비슷한데 추상 메소드뿐 아니라 구현이 있는 메소드도 정의할 수 있다. 단, 필드는 들어갈 수 없다.<pre><code class="language-kotlin">interface Clickable{
  fun click()
}
</code></pre>
</li>
</ul>
<p>class Button: Clickable{
    override fun click() {
        println(&quot;Button Clicked&quot;)
    }
}</p>
<blockquote>
<blockquote>
<blockquote>
<p>Button().click()
Button Clicked</p>
</blockquote>
</blockquote>
</blockquote>
<pre><code>
- 자바는 `extends`와 `implements`를 사용하지만 코틀린에서는 콜론`:`으로 클래스 상속과 인터페이스 구현을 모두 처리한다. 자바와 마찬가지로 클래스는 1개만 상속 가능하고 인터페이스는 제한 없이 구현할 수 있다.

- 자바는 오버라이드할 때 `@Override`를 생략해도 상관 없지만 코틀린은 `override` 메소드를 반드시 사용해야 한다.
- 자바 8에서는 `default` 키워드를 써줘야 디폴트 구현이 가능하지만 코틀린은 써줄 필요가 없다.
```kotlin
interface Clickable{
    fun click()
    fun showOff() = println(&quot;I&#39;m clickable!&quot;)
}
// 이 인터페이스를 구현하는 클래스는 click에 대해서는 무조건 구현해야하지만
// showOff의 경우 그대로 사용 or 오버라이드할 수 있다.</code></pre><ul>
<li>이름과 시그니처가 같은 멤버 메소드에 대해 둘 이상의 <code>default</code> 구현이 있는 경우 인터페이스를 구현하는 하위 클래스에서 명시적으로 새로운 구현을 제공해야 한다.<blockquote>
<p><strong>메소드 시그니처</strong> : 메소드 이름 + 메소드 매개변수 리스트의 조합</p>
</blockquote>
<pre><code class="language-kotlin">interface Clickable{
  fun click()
  fun showOff() = println(&quot;I&#39;m clickable&quot;)
}
</code></pre>
</li>
</ul>
<p>interface Focusable{
    fun showOff() = println(&quot;I&#39;m focusable!&quot;)
}</p>
<p>class Button: Clickable, Focusable{
    override fun click() {
        println(&quot;Button Clicked&quot;)
    }</p>
<pre><code>override fun showOff() {
    super&lt;Clickable&gt;.showOff()
    super&lt;Focusable&gt;.showOff()
}

// 상위 타입 호출 시 super를 사용한다.</code></pre><p>}</p>
<pre><code>&gt; **자바에서 코틀린의 default 메소드가 있는 인터페이스 구현하기**
&gt;
&gt;코틀린은 자바 6과 호환되게 설계됐다. 따라서 자바 8에서 지원하고 있는 default 메소드를 지원하지 않는다. 그래서 디폴트 메소드가 있는 인터페이스를 `일반 인터페이스` + `디폴트 메소드 구현이 static 메소드로 들어있는 클래스`로 조합해 구현한다. 인터페이스에는 메소드 선언만 들어간다. 
그러므로 디폴트 메소드가 포함된 코틀린 인터페이스를 자바 클래스에서 구현하고 싶으면 모든 메소드에 대해 구현해야 한다.
( = 자바에서는 코틀린의 default 메소드 구현에 의존할 수 없다. )

&lt;br/&gt;&lt;br/&gt;

### 2. open, final, abstract: 기본적으로 final !!!!
- 코틀린의 기본 클래스와 메소드, 프로퍼티는 기본적으로 `final`로 상속을 허용하지 않고 있다. 상속을 허용하려면 `open` 변경자를 앞에 붙여줘야 한다.
```kotlin
open class RichButton: Clickable{
    fun disable(){} // final이므로 하위 클래스에 이 메소드 override 불가

    open fun animate(){} // 하위 클래스에 이 메소드 override 가능

    override fun click() {} // override한 메소드는 기본적으로 open이다.
    // final override fun click()으로 다시 상속을 막을 수 있다.
}</code></pre><ul>
<li><p><code>abstract</code>로 추상 클래스를 선언할 수 있고 인스턴스화할 수는 없다. 추상 멤버의 경우는 하위클래스 override해야하기 때문에 항상 열려있다. 그래서 추상 멤버 앞에는 <code>open</code>을 명시할 필요가 없다.</p>
<pre><code class="language-kotlin">abstract class Animated{
  abstract fun animate() // 추상 함수이기 때문에 항상 open

  open fun stopAnimatint(){...} 
  // 추상 함수가 아니지만 원한다면 open으로 오버라이드 허용할 수 있다.

  fun animateTwice(){...}
  // final이므로 override 불가
}</code></pre>
<p><br/><br/></p>
</li>
</ul>
<h3 id="3-visibility-modifier가시성-변경자">3. Visibility Modifier(가시성 변경자)</h3>
<ul>
<li><p><code>visibility modifer</code>는 코드 기반에 있는 선언에 대해 클래스 외부 접근을 제어한다.</p>
</li>
<li><p>코틀린의 기본 <code>visiblity modifer</code>는 <code>public</code>이다. (모두 공개)</p>
</li>
</ul>
<table>
<thead>
<tr>
<th align="left">변경자</th>
<th align="left">클래스 멤버</th>
<th align="left">최상위 선언</th>
</tr>
</thead>
<tbody><tr>
<td align="left">public</td>
<td align="left">모든 곳에서 볼 수 있다.</td>
<td align="left">모든 곳에서 볼 수 있다.</td>
</tr>
<tr>
<td align="left">internal</td>
<td align="left">같은 모듈 안에서만 볼 수 있다.</td>
<td align="left">같은 모듈 안에서만 볼 수 있다.</td>
</tr>
<tr>
<td align="left">protected</td>
<td align="left">하위 클래스 안에서만 볼 수 있다.</td>
<td align="left">(최상위 선언에 적용할 수 없다.)</td>
</tr>
<tr>
<td align="left">private</td>
<td align="left">같은 클래스 안에서만 볼 수 있다.</td>
<td align="left">같은 파일( .kt ) 안에서만 볼 수 있다.</td>
</tr>
</tbody></table>
<blockquote>
<p><strong>최상위 선언</strong></p>
</blockquote>
<ul>
<li>파일 최상위에 선언되는 클래스, 메소드, 변수를 뜻한다.</li>
<li>자바에서는 최상위 선언에 <code>class</code>만 가능하지만 코틀린에서는 <code>class</code>, <code>method(fun)</code>, <code>변수(val, var)</code> 모두 가능하다.
<img src="https://images.velog.io/images/h-swon/post/79f3e3f6-a395-4ebb-bce9-4186f02b352b/image.png" alt=""></li>
<li>a.kt 파일에 아래와 같이 각각 최상위 선언을 하게되면 <code>class</code>는 패키지 레벨에 최상위 선언으로 그대로 감싸진다. 그리고 <code>method</code>와 <code>변수</code>는 파일 이름에 해당하는 클래스가 만들어진 후 그 클래스 내부에 변수와 메소드로 들어가게 된다.( 자바와 호환 )<pre><code class="language-kotlin">// a.kt
package a
&gt;
class Example {
&gt;
}
&gt;
val ex = 10
&gt;
fun hi(){
  println(&quot;hi&quot;)
}
&gt;
// DeCompile 결과
package a;
&gt;
public final class Example {}
&gt;
public final class AKt {
 private static final int ex = 10;
&gt;
 public static final int getEx() {
    return ex;
 }
&gt;
 public static final void hi() {
    String var0 = &quot;hi&quot;;
    System.out.println(var0);
 }
}
&gt;</code></pre>
</li>
<li>최상위 선언의 기본 <code>visibility modifier</code>는 <code>public</code>이므로 전부 <code>public</code>으로 선언된다. 단, 변수의 경우는 <code>private</code>으로 선언된 다음 <code>get</code> 메소드를 <code>public</code>으로 둔다.</li>
<li>최상위 선언을 <code>private</code>으로 선언하면 그 선언이 들어있는 파일 내부에서만 사용할 수 있기 때문에 하위 시스템의 자세한 구현 사항을 외부에 감추고 싶을 때 유용하다.</li>
</ul>
<br/>

<p><strong>최상위 선언에서의 visibility modifier</strong></p>
<ul>
<li><p><code>public</code>
: 모든 곳에서 접근 가능하다.</p>
</li>
<li><p><code>internal</code>
: 같은 모듈 내부에서만 접근 가능하다. 또 접근하는 변수나 메소드는 <code>internal</code>과 비교했을때 <code>visibility</code>가 같거나 더 높아야한다.(<code>internal</code>, <code>private</code>) 
모듈이란 한 번에 컴파일되는 코틀린 파일들을 의미한다.</p>
<pre><code class="language-kotlin">internal open class TalkativeButton : Focusable {
  private fun yell() = println(&quot;Hey!&quot;)
  protected fun whisper() = println(&quot;Let&#39;s talk!&quot;)
}
</code></pre>
</li>
</ul>
<p>fun TalkativeButton.giveSpeech(){    // 에러(public 멤버가 internal 타입인 TalkativeButton 노출)
    ...
}</p>
<pre><code>
- `private`
: 같은 파일 내부에서만 접근 가능하다.

&lt;br/&gt;

**클래스 멤버의 visibility modifier**
- `public`
: 모든 곳에서 접근 가능하다.

- `internal`
: 모듈 내부에서만 접근 가능하다.
![](https://images.velog.io/images/h-swon/post/f24bde98-0479-48e5-853b-536c61e7075e/image.png)
```kotlin
// Module1.class
class Module1 {
    internal fun hi() = println(&quot;hi&quot;)
    fun bye() = println(&quot;bye&quot;)
}

// Example1.kt(모듈 내부)
fun main(){
    val module = Module1()
    module.hi()
    module.bye()        // 모두 접근 가능
}

// Example2.kt(모듈 외부)
fun main(){
    val module = Module1()
    // module.hi() ---&gt; internal 메소드에는 접근할 수 없다.
    module.bye()
}</code></pre><ul>
<li><code>protected</code>
: 상속할 때만 접근 가능하다.<pre><code class="language-kotlin">// Person.class
open class Person {
  protected fun hello() = println(&quot;Hello~&quot;)
}
</code></pre>
</li>
</ul>
<p>// Example.kt
fun main() {
    val person = Person()
    // person.hello() 접근 불가능!</p>
<pre><code>val student = Student()
student.hi()
// student.hello() 접근 불가능!</code></pre><p>}</p>
<p>class Student : Person() {
    fun hi() {
        hello()    // 접근 가능
    }
}</p>
<pre><code>
- `private`
: 같은 클래스 내부에서만 접근 가능하다.

&lt;br/&gt;

&gt; **코틀린 -&gt; 자바로의 visibility modifier**
- 코틀린의 `public`, `protected`, `private` 변경자는 컴파일된 자바 바이트 코드 안에서도 그대로 유지된다.
단, 최상위 선언으로 `private`을 선언했다면 자바에서는 클래스를 `private`으로 만들 수 없기 때문에 `private` 클래스를 패키지-전용 클래스로 컴파일한다.
&lt;br/&gt;
&gt;
- `internal` 같은 경우는 바이트 코드 상 `public`이 된다. 이 때 코틀린 컴파일러가 `internal` 멤버의 이름을 나쁘게 바꾼다. 이는 모듈에 속한 클래스를 모듈 외부에서 상속할 때, 
1. 우연히 하위 클래스의 메소드 이름과 `internal`메소드의 이름이 같아져 오버라이드하는 경우를 방지 
2. 실수로 `internal`클래스를 모듈 외부에서 사용하는걸 막기 위해서다. </code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[Android] Jetpack 컴포넌트 - LiveData(1)]]></title>
            <link>https://velog.io/@h-swon/Android-Jetpack-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-LiveData1</link>
            <guid>https://velog.io/@h-swon/Android-Jetpack-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-LiveData1</guid>
            <pubDate>Thu, 13 Jan 2022 14:17:51 GMT</pubDate>
            <description><![CDATA[<h3 id="1-livedata">1. LiveData</h3>
<blockquote>
<p>관찰 가능한(Observable) 데이터 클래스로 Lifecycle을 통해 생명주기를 인식하고 activity나 fragment, service와 컴포넌트들의 생명 주기를 따른다.</p>
</blockquote>
<ul>
<li><p><code>LiveData</code>는 데이터 변경을 활성화된 <code>Observer</code>를 통해서 알려주는데 주어진 <code>LifecycleOwner</code>의 생명주기가 <code>STARTED</code> 또는 <code>RESUME</code>인 경우에만 <code>Observer</code>를 <code>활성(active)</code> 상태로 간주한다.</p>
</li>
<li><p><code>LiveData</code>의 <code>observe</code> 메소드를 통해 <code>Observer</code>를 등록할 수 있고, <code>LifecycleOwner</code> 구현체가 <code>DESTROYED</code> 상태가 되면 자동으로 <code>Observer</code>는 내부에서 제거된다.</p>
<br/>
</li>
<li><p><strong>장점</strong></p>
<ol>
<li>UI와 데이터 상태의 동기화<ul>
<li><code>LiveData</code>는 변화를 <code>Observer</code>에게 알리고 <code>Observer</code> 객체에서 데이터 변경에 따른 UI를 갱신할 수 있다.<br/></li>
</ul>
</li>
<li>메모리 누수를 방지한다.<ul>
<li><code>Observer</code>는 <code>Lifecycle</code>에 바인딩되며, 생명 주기 상태가 <code>DESTROYED</code>되면 스스로 제거되므로 별도의 리소스를 해제하는 코드를 작성할 필요가 없다<br/></li>
</ul>
</li>
<li>액티비티가 갑자기 종료될 때도 안전하다.<ul>
<li><code>Activity</code>가 백스택으로 들어가는 경우와 같이 <code>Observer</code>가 비활성화된 상태일 때는 <code>LiveData</code>로 부터 어떠한 이벤트도 받지 않아 안전하다.<br/></li>
</ul>
</li>
<li>생명 주기에 대한 고민을 안해도 된다.<ul>
<li><code>LiveData</code>에 <code>LifecycleOwner</code>를 위임한 후로 자동으로 생명 주기 상태에 따라 관리한다.<br/></li>
</ul>
</li>
<li>최신의 데이터를 유지한다.<ul>
<li>생명 주기가 비활성화되면 데이터의 변경을 감지하지 않지만, 다시 활성화 되는 시점에 최신 데이터를 다시 가져온다.<br/></li>
</ul>
</li>
<li>구성 변경에 대응한다.<ul>
<li>화면 회전 등과 같은 구성 변경으로 인해 재생성 되더라도 즉시 최신 데이터를 받을 수 있다.<br/></li>
</ul>
</li>
<li>자원 공유하기<ul>
<li><code>LiveData</code>를 상속하여 싱글턴 패턴으로 사용할 수도 있다. 안드로이드 서비스 같은 곳에 한 번만 연결하고, 애플리케이션 내 어디에서나 다중으로 접근하여 이 서비스를 관찰할 수 있다.<br/>
### 2. LiveData 사용</li>
</ul>
</li>
</ol>
</li>
</ul>
<ol>
<li><p>특정 유형의 데이터를 보유할 <code>LiveData</code>의 인스턴스를 생성한다. 이 작업은 일반적으로 <code>ViewModel</code> 클래스 내에서 이루어진다.</p>
</li>
<li><p><code>onChanged</code> 메소드를 정의하는 <code>Observer</code>객체를 만든다. 이 메소드는 <code>LiveData</code>가 보유한 데이터가 변경될 때 발생하는 작업을 제어한다.  일반적으로 activity나 fragment 같은 UI 컨트롤러에 <code>Observer</code> 객체를 만든다.</p>
</li>
<li><p><code>observe(LifecycleOwner, Observer)</code> 메소드를 이용해 <code>LiveData</code>에 <code>Observer</code>를 연결한다. 일반적으로 activity나 fragment 같은 UI 컨트롤러에 <code>Observer</code> 객체를 연결한다.</p>
<blockquote>
<p> <code>observeForever(Observer)</code> 메소드를 사용하면 연결된 <code>LifecycleOwner</code> 객체가 없는 <code>Observer</code>를 등록할 수 있다. 이 경우 <code>Observer</code>는 항상 <code>active</code>로 간주되어 항상 데이터 변경에 관한 알림을 받는다. 
<code>removeObserver(Observer)</code> 메소드를 호출하여 이러한 <code>Observer</code>를 삭제할 수 있다.</p>
</blockquote>
</li>
</ol>
<p>-&gt; <code>LiveData</code> 에 저장된 데이터 값이 업데이트되면 연결된 <code>LifecycleOwner</code>가 <code>active</code> 상태에 있는 모든 등록된 <code>Observer</code>를 트리거한다. 이로 인해 <code>LiveData</code> 에서 보유한 데이터가 변경되면 UI가 자동으로 업데이트 된다.</p>
<p><br/><br/></p>
<h3 id="3-livedata-객체-생성">3. LiveData 객체 생성</h3>
<ul>
<li><p><code>LiveData</code>는 일반적으로 <code>ViewModel</code> 객체 내에 저장되며 getter 메소드를 통해 액세스된다. 초깃값은 <code>null</code>이다.</p>
<pre><code class="language-kotlin">class NameViewModel : ViewModel() {

  // Create a LiveData with a String
  val currentName: MutableLiveData&lt;String&gt; by lazy {
      MutableLiveData&lt;String&gt;()
  }

  // Rest of the ViewModel...
}</code></pre>
</li>
<li><p>일반적으로 <code>ViewModel</code>에 <code>LiveData</code>객체를 저장하는 이유는</p>
<blockquote>
<ol>
<li>Activity나 Fragment가 커지는 걸 방지
(UI 컨트롤러는 데이터 표시 담당만!! 데이터 상태 보유는 x)</li>
<li><code>LiveData</code> 인스턴스를 특정 activity나 fragment에 의존하는걸 분리시켜서 구성 변경에도 <code>LiveData</code>객체가 유지되도록 하기 위해서!</li>
</ol>
</blockquote>
</li>
</ul>
<p><br/><br/></p>
<h3 id="4-livedata-관찰">4. LiveData 관찰</h3>
<ul>
<li><code>onCreate</code>에서 <code>LiveData</code>를 관찰하기 적합한데 그 이유는<blockquote>
<ol>
<li><code>onResume()</code>에서 중복 호출을 하지 않기 위해서</li>
<li>activity나 fragment가 <code>active</code> 상태가 되는 즉시 표시할 수 있는 데이터가 포함되도록 하기 위해서다.
(앱 컴포넌트는 <code>STARTED</code> 상태가 되는 즉시 관찰하고 있던 <code>LiveData</code>의 가장 최신 값을 받게 된다. 이는 관찰할 <code>LiveData</code> 객체가 설정된 경우에만 발생한다)</li>
</ol>
</blockquote>
</li>
</ul>
<pre><code class="language-kotlin">class NameActivity : AppCompatActivity() {

    // Use the &#39;by viewModels()&#39; Kotlin property delegate
    // from the activity-ktx artifact
    private val model: NameViewModel by viewModels()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // Other code to setup the activity...

        // Create the observer which updates the UI.
        val nameObserver = Observer&lt;String&gt; { newName -&gt;
            // Update the UI, in this case, a TextView.
            nameTextView.text = newName
        }

        // Observe the LiveData, passing in this activity as the LifecycleOwner and the observer.
        model.currentName.observe(this, nameObserver)
    }
}</code></pre>
<p><br/><br/></p>
<h3 id="5-livedata-업데이트">5. LiveData 업데이트</h3>
<ul>
<li><p><code>LiveData</code>는 읽기만 가능하므로 데이터를 쓰려면 <code>MutableLiveData</code>를 사용해야 한다. <code>MutableLiveData</code>도 생성한 직후의 초깃값은 <code>null</code>이다.</p>
</li>
<li><p><code>setValue()</code>, <code>postValue()</code>로 데이터를 수정한다.
단, <code>setValue()</code>는 메인 스레드에서만 호출해야 한다. <code>postValue()</code>는 주로 백그라운드 스레드에서 호출하는 용도로 사용된다.</p>
</li>
<li><p><code>postValue()</code>의 경우 값을 설정하는 task를 내부에서 handler를 통해 메인스레드로 전달하는데, 그래서 메인 스레드가 실행되기 전에 <code>postValue()</code>를 여러 번 호출해도 가장 마지막에 설정된 값만 가져온다.</p>
</li>
</ul>
<pre><code class="language-kotlin">button.setOnClickListener {
    val anotherName = &quot;John Doe&quot;
    model.currentName.setValue(anotherName)
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Android] Jetpack 컴포넌트 - Lifecycles]]></title>
            <link>https://velog.io/@h-swon/Android-Jetpack-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-Lifecycles</link>
            <guid>https://velog.io/@h-swon/Android-Jetpack-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-Lifecycles</guid>
            <pubDate>Thu, 13 Jan 2022 09:53:13 GMT</pubDate>
            <description><![CDATA[<h3 id="1-lifecycle-aware-컴포넌트란">1. Lifecycle-aware 컴포넌트란?</h3>
<blockquote>
<p>Activity나 Fragment 같은 다른 컴포넌트의 <code>Lifecycle</code>이 변경될 때 이에 대응하는 라이브러리.
<code>Component</code>(안드로이드 component가 아닌 자신 만의 역할이 있는 코드 component)가 <code>lifecycleOwner</code>의 상태변화를 <code>observe</code>하여 필요한 작업을 스스로 하는 기능</p>
</blockquote>
<p>** 왜 필요할까?** 
-&gt; 일반적으로는 Activity나 Fragment의 생명 주기 메소드에 데이터를 불러오거나 리소스를 정리한다. 하지만 프로그램 규모가 커지면서 코드가 광범위해지고 잠재적인 에러 유발 요소가 된다.
그래서 생명 주기에 의존적이었던 코드를 걷어 내고 <code>lifecycle-aware 컴포넌트</code>에 이에 대한 처리를 위임함으로써 유지보수성을 높인다. 
component가 <code>lifecycle</code>에 따른 작업을 소유할 수 있도록 하며, 이런 component를 <code>Lifecycle aware</code>하다고 한다.
<br/></p>
<ul>
<li><p><code>androidx.appcomapt:appcompat</code>을 이미 사용하고 있다면 <code>Lifecycle-aware</code> 컴포넌트들이 포함되어 별도의 작업이 필요없다.</p>
</li>
<li><p><code>androidx.lifecycle</code> 패키지는 activity나 fragment의 생명 주기 상태에 따라 자동으로 동작을 조정할 수 있는 클래스와 인터페이스를 제공한다.</p>
</li>
</ul>
<br/>

<h3 id="2-lifecycle-클래스">2. Lifecycle 클래스</h3>
<blockquote>
<p>Activity나 Fragment 같은 컴포넌트의 생명 주기 상태에 대한 정보를 가지고 <span style="color:orange">다른 객체가 이를 관찰할 수 있도록</span> 돕는 클래스</p>
</blockquote>
<p>Event와 State를 통해 연관된 컴포넌트들의 생명 주기 상태를 추적한다. 생명 주기에 변화가 생기면 등록된 <code>Observer</code>를 실행해주는 역할을 한다.</p>
<p><strong>2-1. Event</strong> </p>
<ul>
<li><code>Framework</code>와 <code>Lifecycle</code>클래스로부터 얻는 생명 주기 이벤트를 말한다. 이런 이벤트들은 activity와 fragment의 콜백 이벤트에 매핑된다. </li>
<li><code>ON_ANY</code>,<code>ON_CREATE</code>, <code>ON_DESTROY</code>, <code>ON_PAUSE</code>, <code>ON_RESUME</code> , <code>ON_START</code>, <code>ON_STOP</code></li>
</ul>
<br/>

<p><strong>2-2. State</strong></p>
<ul>
<li><code>Lifecycle</code> 객체가 추적한 컴포넌트의 현재 상태를 뜻한다.</li>
<li><code>State</code>는 그래프의 노드이고, <code>Event</code>는 두 노드 사이를 이동하는 사건이라고 생각하자!!!!
<img src="https://images.velog.io/images/h-swon/post/da21e128-85e8-4421-b80e-75f6dc5c38f0/image.png" alt=""></li>
</ul>
<br/>

<p><strong>2-3. 구조</strong>
<img src="https://images.velog.io/images/h-swon/post/c826aa3f-f150-48d0-854d-760920e0579f/image.png" alt="">
<code>Lifecycle</code> 객체에 <code>Observer</code>를 등록해 놓으면 activity나 fragment의 생명주기 변경 시 <code>Lifecycle</code> 객체가 등록된 <code>Observer</code>를 실행하는 구조.
<br/></p>
<h3 id="3-lifecycleowner">3. LifecycleOwner</h3>
<blockquote>
<p>클래스에 <code>Lifecycle</code>이 있음을 나타내는 함수인 <code>getLifecycle()</code>메소드 하나만 가진 인터페이스</p>
</blockquote>
<pre><code class="language-java">public interface LifecycleOwner {
    /**
     * Returns the Lifecycle of the provider.
     *
     * @return The lifecycle of the provider.
     */
    @NonNull
    Lifecycle getLifecycle();
}</code></pre>
<p>반환값이 되는 <code>Lifecycle</code>은 <code>abstract class</code>로 <code>Lifecycle Observer</code>를 추가하고 제거하며 현재 <code>state</code>를 확인할 수 있는 인터페이스를 제공한다.</p>
<pre><code class="language-java">public abstract class Lifecycle {

 @MainThread
 public abstract void addObserver(@NonNull LifecycleObserver observer);

 @MainThread
 public abstract void removeObserver(@NonNull LifecycleObserver observer);

 @MainThread
 @NonNull
 public abstract State getCurrentState();

 public enum Event {
     // ...
 }

 public enum State {
     // ...
 }
}</code></pre>
<ul>
<li><p>다시 말해 <code>Lifecycle</code>의 소유권을 추상화하는 인터페이스로 <code>Lifecycle</code>을 반환하는 <code>getLifecycle()</code>메소드 하나만을 가진다.</p>
</li>
<li><p><code>AppCompatyActivity</code>나 <code>Fragment</code>는 <code>LifecycleOwner</code>가 이미 구현되어 있어 <code>getLifeCycle()</code> 메소드로 쉽게 <code>Lifecycle</code>을 사용할 수 있다. 다른 클래스들은 <code>LifecycleOwner</code>를 구현해야 한다.</p>
</li>
<li><p>사용자 정의 <code>LifecycleOwner</code>를 구현하려면 <code>LifecycleRegistry</code>를 사용하면 된다.</p>
<br/>

</li>
</ul>
<p><strong>LifecycleRegistry</strong> 
<code>Lifecycle</code>의 구현체가 바로 <code>LifecycleRegistry</code>인데 등록된 여러 <code>Observer</code>를 handle할 수 있다. <code>override</code>한 주요 메소드는 <code>addObserver</code>, <code>removeObserver</code> 등 Observer 객체를 관리하기 위한 것과 <code>Lifecycle</code>의 <code>State</code>를 지정하거나 변경할 수 있는 메소드들이다.</p>
<pre><code class="language-kotlin">class MyActivity : Activity(), LifecycleOwner {

    private lateinit var lifecycleRegistry: LifecycleRegistry

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        lifecycleRegistry = LifecycleRegistry(this)
        lifecycleRegistry.currentState = Lifecycle.State.CREATED
    }

    public override fun onStart() {
        super.onStart()
        lifecycleRegistry.currentState = Lifecycle.State.STARTED
    }

    override fun getLifecycle(): Lifecycle {
        return lifecycleRegistry
    }
}</code></pre>
<p><br/><br/></p>
<h3 id="4-observer">4. Observer</h3>
<ul>
<li><code>LifecycleObserver</code> 인터페이스를 사용하면 되지만 해당 인터페이스를 직접 사용하지 않고 이를 구현하여 작성된 인터페이스인 <code>DefaultLifeCycleObserver</code>나 <code>LifecycleEventObserver</code>를 사용한다.</li>
</ul>
<p>** 4-1. DefaultLifeCycleObserver**
<img src="https://images.velog.io/images/h-swon/post/ecd98a3c-576e-4e1c-818e-e265b3adfe11/image.png" alt=""><img src="https://images.velog.io/images/h-swon/post/edf3e996-cbcf-4974-847d-23f189f9f89d/image.png" alt=""></p>
<ul>
<li><code>LifeCycleOwner</code>의 상태 변경을 관찰하는 콜백 인터페이스
만약 <code>DefaultLifeCycleObserver</code>와 <code>LifecycleEventObserver</code>를 모두 구현했다면 <code>DefaultLifecycleObserver</code>의 메소드들이 먼저 호출되고 나서 <code>LifecycleObserver.onStateChanged()</code>의 호출이 따라온다.</li>
</ul>
<p>** 4-2. LifecycleEventObserver**
<img src="https://images.velog.io/images/h-swon/post/e1627752-1984-4cc8-a3de-f5b2c2fb93b0/image.png" alt=""><img src="https://images.velog.io/images/h-swon/post/0e9afc5a-9120-47ae-87aa-f1a4059ed6d2/image.png" alt=""></p>
<ul>
<li>생명주기의 변화를 수신하여 <code>receiver</code>에게 보낼 수 있는 클래스
<code>LifecycleEventObserver</code>의 메소드는 1개 존재하고 생명주기가 변할 때 <code>Event</code>가 넘어오게 되고 해당 <code>Event</code>를 분기해서 필요한 코드를 호출하는 구조이다.</li>
</ul>
<pre><code class="language-kotlin">class MyLifeCycleObserver : DefaultLifecycleObserver, LifecycleEventObserver {

    override fun onCreate(owner: LifecycleOwner) {
        super.onCreate(owner)
        Log.d(owner.toString(), &quot;onCreate&quot;)
    }

    override fun onResume(owner: LifecycleOwner) {
        super.onResume(owner)
        Log.d(owner.toString(), &quot;onResume&quot;)
    }

    override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
        when (event) {
            Lifecycle.Event.ON_CREATE -&gt; {
                Log.d(source.toString(), &quot;onCreateEvent&quot;)

            }
            Lifecycle.Event.ON_START -&gt; {
                Log.d(source.toString(), &quot;onStartEvent&quot;)
            }
            else -&gt; {}
        }
    }
}

//MainActivity.kt
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        lifecycle.addObserver(MyLifeCycleObserver())
        // Observer를 activity에 연결하면 MainActivity의 생명 주기를 
        // MyLifecycleObserver 클래스에서 받을 수 있다.
        // lifecycle은 개발자가 작성한 클래스가 아니므로 getLifecycle()메소드 이용
    }
}</code></pre>
<img src="https://images.velog.io/images/h-swon/post/8671e2f1-b091-4923-a27a-64d6b6772342/image.png">]]></description>
        </item>
        <item>
            <title><![CDATA[[Android] Jetpack 컴포넌트 - Data Binding(1)]]></title>
            <link>https://velog.io/@h-swon/Android-Jetpack-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-Data-Binding1</link>
            <guid>https://velog.io/@h-swon/Android-Jetpack-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-Data-Binding1</guid>
            <pubDate>Mon, 10 Jan 2022 14:00:49 GMT</pubDate>
            <description><![CDATA[<h3 id="1-jetpack-컴포넌트">1. Jetpack 컴포넌트</h3>
<blockquote>
<p>생산성을 높여 개발할 수 있게 돕는 라이브러리, 도구, 가이드의 모음</p>
</blockquote>
<ul>
<li><code>androidx.*</code> 패키지 라이브러리로 제공된다.</li>
<li><code>Foundation</code>, <code>Architecture</code>, <code>Behavior</code>, <code>User Interface</code> 4개 카테고리로 분류된다.</li>
</ul>
<br/>

<p>먼저 <code>Jetpack Architecture</code>에 속한 부분부터 살펴보자.</p>
<h3 id="2-data-binding">2. Data Binding</h3>
<blockquote>
<p>명령형 방식이 아닌 선언적 형식으로 레이아웃의 UI 구성 요소를 앱의 데이터와 결합할 수 있는 라이브러리</p>
</blockquote>
<pre><code class="language-kotlin">// 명령형 방식
val textView = findViewById&lt;TextView&gt;(R.id.sample_text)
textView.text = viewModel.userName

// 선언형 방식
&lt;TextView
    android:text=&quot;@{viewmodel.userName}&quot;/&gt;
</code></pre>
<ul>
<li>데이터 바인딩 라이브러리는 레이아웃의 변수와 뷰를 참조할 수 있는 바인딩 클래스를 생성한다.</li>
<li>모든 생성되는 바인딩 클래스는 <code>ViewDataBinding</code>을 상속한다.</li>
<li>바인딩 클래스를 생성하는 방법은 xml 레이아웃 파일에서 가장 상위 레이아웃을 <code>&lt;layout&gt;</code> 태그로 감싸면 자동으로 생성된다.</li>
</ul>
<h4 id="2-1-바인딩-클래스로-바인딩-객체-생성하기">2-1. 바인딩 클래스로 바인딩 객체 생성하기</h4>
<ul>
<li><p>바인딩 클래스의 <code>inflate</code> 메소드 사용</p>
<pre><code class="language-kotlin">val binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)</code></pre>
</li>
<li><p><code>DataBindingUtil</code> 클래스 사용
( 바인딩 클래스의 이름을 미리 알지 못할 때 - 이름 변경이 가능하므로)</p>
<pre><code class="language-kotlin">// 1.
val binding = DataBindingUtil.inflate(
  layoutInflater,
  R.layout.activity_main,
  parent,
  attachToParent)
setContentView(binding.root)

// 2.    
val binding = DataBindingUtil.setContentView(
  this, R.layout.activity_main)</code></pre>
<h4 id="2-2-바인딩-클래스-이름-사용자화하기">2-2. 바인딩 클래스 이름 사용자화하기</h4>
</li>
<li><p>기본적으로 바인딩 클래스 이름은 레이아웃 파일명을 바탕으로 생성된다. 만약 변경하고 싶다면 <code>&lt;data&gt;</code> 태그 내에 <code>class</code> 속성을 사용하면 된다.</p>
<pre><code class="language-kotlin">// 현재 모듈의 패키지명이 com.swon일 때
// com.swon.databinding 패키지에 CustomName 바인딩 클래스 생성
&lt;data class = &quot;CustomName&quot;&gt;
 ...
&lt;/data&gt;

// com.swon 패키지에 CustomName 바인딩 클래스 생성
// 온점(.)을 통해 databinding 패키지가 아닌 다른 패키지에 저장 가능
&lt;data class = &quot;.CustomName&quot;&gt;
 ...
&lt;/data&gt;</code></pre>
<h4 id="2-3-id로-view-참조하기">2-3. ID로 View 참조하기</h4>
<ul>
<li>데이터 바인딩 클래스에는 <code>View</code>에 대한 바인딩 정보뿐만아니라 <code>&lt;data&gt;</code> 태그에 정의된 변수들에 대한 바인딩 정보도 포함되어 있다.<br/>

</li>
</ul>
</li>
</ul>
<h4 id="2-4-레이아웃에-변수-선언하기">2-4. 레이아웃에 변수 선언하기</h4>
<ul>
<li><p>변수 선언은 <code>&lt;data&gt;</code> 태그 내에 <code>&lt;variable&gt;</code> 태그를 사용해서 선언한다.</p>
</li>
<li><p><code>name</code>과 <code>type</code> 속성을 가진다.</p>
</li>
<li><p>선언한 변수를 뷰에 바인딩하려면 <code>@{변수명}</code>을 사용한다.
POJO 클래스도 변수로 사용할 수 있다.</p>
<pre><code class="language-kotlin"> &lt;data&gt;
     &lt;variable
         name = &quot;myText&quot;
         type = &quot;String&quot;/&gt;

     &lt;variable
         name=&quot;user&quot;
         type=&quot;com.swon.databinding_example.User&quot; /&gt;
 &lt;/data&gt;

 &lt;TextView
     android:layout_width=&quot;wrap_content&quot;
     android:layout_height=&quot;wrap_content&quot;
     android:text=&quot;@{myText}&quot;/&gt;

 &lt;TextView
     android:layout_width=&quot;wrap_content&quot;
     android:layout_height=&quot;wrap_content&quot;
     android:text=&quot;@{user.name}&quot;/&gt;</code></pre>
<ul>
<li><p>선언한 변수에 값을 대입하려면 <code>setter</code> 메소드를 사용하면 된다.</p>
<pre><code class="language-kotlin">override fun onCreate(savedInstanceState: Bundle?) {
   super.onCreate(savedInstanceState)

   binding = DataBindingUtil.setContentView(
       this, R.layout.activity_main)

   binding.user = User(&quot;sungwon&quot;, 29)
   binding.myText = &quot;하이&quot;
}</code></pre>
</li>
<li><p>변수가 <code>Observable</code> 타입을 구현했거나 <code>Observable</code>을 접두어로 갖는 타입은 컴파일 타임에 따로 계산되어 반영된다.</p>
<br/>

</li>
</ul>
</li>
</ul>
<h4 id="2-5-observable-데이터-객체로-작업하기">2-5. Observable 데이터 객체로 작업하기</h4>
<ul>
<li><p><code>Observable</code> 데이터 객체란 데이터의 변경 사항을 감지하고 알려 주는 객체이다. 데이터 바인딩 라이브러리는 <code>Observable</code> 데이터 타입을 제공하고 지원한다.</p>
</li>
<li><p>데이터 바인딩만으로는 수정 사항에 대해 UI를 자동으로 갱신시키지 못한다.</p>
</li>
<li><p><code>Observable</code> 클래스에는 <code>필드</code>, <code>객체</code>, <code>컬렉션</code> 3가지 타입이 있다.</p>
</li>
</ul>
<br/>

<h4 id="2-6-ovservable-필드-사용">2-6. Ovservable 필드 사용</h4>
<ul>
<li><p><code>Observable</code>한 클래스를 만드려면 <code>Observable</code> 인터페이스를 구현해야 하는데, 데이터 바인딩 라이브러리에서 이미 해당 인터페이스를 구현한 몇몇 클래스를 제공한다.</p>
</li>
<li><p><code>Observable</code> 필드는 하나의 필드를 가진 <code>Observable</code> 객체이다.</p>
</li>
<li><p>박싱과 언박싱을 방지하기위해 <code>primitive type</code>만을 사용한다.</p>
</li>
<li><p>바인딩된 <code>Observable</code>객체의 변경을 막고자 멤버 변수 선언 시에 자바에서는 <code>public final</code>프로퍼티를, 코틀린에서는 <code>val</code> 프로퍼티를 사용한다.</p>
</li>
<li><p>필드 값에 접근하려면 set() or get() 메소드를 사용한다.</p>
<pre><code class="language-kotlin">data class User(
  val name: ObservableField&lt;String&gt;,
  val age: ObservableInt
)

</code></pre>
</li>
</ul>
<p>class MainActivity : AppCompatActivity() {</p>
<pre><code>private lateinit var binding: ActivityMainBinding

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
    binding.user = User(ObservableField(&quot;sungwon&quot;), ObservableInt(20))
    binding.myText = &quot;Hello&quot;

    binding.userNameText.setOnClickListener {    // 클릭 UI 데이터 변경
        binding.user?.name?.set(&quot;clicked&quot;)
    }
}</code></pre><p>}</p>
<pre><code>
&lt;br/&gt;

#### 2-7. Observable 컬렉션 사용
- `ObservableArrayMap&lt;K, V&gt;`
```kotlin
    // activity_main.xml
    &lt;data&gt;
        &lt;variable
            name=&quot;student&quot;
            type=&quot;androidx.databinding.ObservableMap&quot; /&gt;
    &lt;/data&gt;

    &lt;TextView
        android:id=&quot;@+id/student_age_text&quot;
        android:layout_width=&quot;wrap_content&quot;
        android:layout_height=&quot;wrap_content&quot;
        android:text=&quot;@{String.valueOf(student.age)}&quot;/&gt;


    // MainActivity
    val student = ObservableArrayMap&lt;String, Any&gt;()
    student[&quot;name&quot;] = &quot;sungwon&quot;
    student[&quot;age&quot;] = 29
    binding.student = student</code></pre><ul>
<li><code>ObservableArrayList&lt;T&gt;</code><pre><code class="language-kotlin">  // activity_main.xml
  &lt;data&gt;
      &lt;variable
          name=&quot;student2&quot;
          type=&quot;androidx.databinding.ObservableList&quot; /&gt;
  &lt;/data&gt;    
  &lt;TextView
      android:id=&quot;@+id/student_name_text&quot;
      android:layout_width=&quot;wrap_content&quot;
      android:layout_height=&quot;wrap_content&quot;
      android:text=&quot;@{String.valueOf(student2[1])}&quot; /&gt;

</code></pre>
</li>
</ul>
<pre><code>// MainActivity
val student2 = ObservableArrayList&lt;Any&gt;()
student2.add(3)
student2.add(&quot;sungwon&quot;)
binding.student2 = student2</code></pre><pre><code>&lt;br/&gt;

#### 2-8. Observable 객체 사용
- `Observable` 인터페이스를 구현한 클래스는 데이터의 변경에 대한 알림을 받으려는 리스너를 등록할 수 있다. 
반드시 데이터 변경 알림 시기는 직접 정의해야 한다.

- 개발의 편의성을 위해 `BaseObservable` 클래스를 제공한다. 해당 클래스는 리스너 등록에 대한 방법을 이미 구현한 클래스이다.
- `@Bindable`을 `getter`에 적용하고 `notifyPropertyChange()`를 `setter`에서 호출하는 것으로 적용 가능하다.
- 데이터 바인딩은 `BR`이라는 클래스를 모듈 패키지 내에 생성하고, 여기에는 데이터 바인딩을 위해 사용하는 리소스 ID들을 포함한다. `@Bindable`을 통해 컴파일 타임에 `BR`클래스에 들어갈 프로퍼티들을 생성한다.

```kotlin
// ObservableData.class
class ObservableData : BaseObservable() {

    @get:Bindable
    var name: String = &quot;&quot;
        set(value) {
            field = value
            notifyPropertyChanged(BR.name)
        }
}</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[Kotlin] 함수(3)]]></title>
            <link>https://velog.io/@h-swon/Kotlin-%ED%95%A8%EC%88%983</link>
            <guid>https://velog.io/@h-swon/Kotlin-%ED%95%A8%EC%88%983</guid>
            <pubDate>Tue, 04 Jan 2022 11:23:38 GMT</pubDate>
            <description><![CDATA[<h4 id="1-가변-인자-함수">1. 가변 인자 함수</h4>
<ul>
<li>파라미터 앞에 <code>vararg</code>를 붙이면 가변 인자를 사용할 수 있다.</li>
<li>코틀린에서는 배열을 명시적으로 풀어서 배열의 각 원소가 인자로 전달되게 해야 한다. 배열 앞에     <code>*</code>를 붙이면 <code>스프레드 연산자</code>가 해당 작업을 진행한다.<pre><code class="language-kotlin">fun listOf&lt;T&gt; (vararg values: T): List&lt;T&gt; {...}
</code></pre>
</li>
</ul>
<p>fun main(args: Array<String>) {
    val list = listOf(&quot;args: &quot;, *args)
    println(list)
}</p>
<pre><code>
&lt;br/&gt;

#### 2. 중위 호출(infix call)과 구조 분해 선언
- 중위 호출 : 수신 객체와 유일한 메소드 인자 사이에 메소드 이름을 넣는다.
```kotlin
val map = mapOf(1 to &quot;one&quot;, 7 to &quot;seven&quot;)
// 중위 호출 방식으로 to라는 일반 메소드를 호출한다.

/* 아래 두 호출은 동일 */
4.to(&quot;one&quot;)
4 to &quot;one&quot;

// to 함수의 정의를 간략히 하면..
infix fun Any.to(other: Any): Pair(this, other)

// 구조 분해 선언으로 변수 초기화
val (number, name) = 1 to &quot;one&quot;

// 루프에서의 구조 분해
for((index, element) in collection.withIndex()) {
    println(&quot;$index: $element&quot;)
}</code></pre><br/>
<br/>

<h4 id="3-로컬-함수와-확장">3. 로컬 함수와 확장</h4>
<ul>
<li>좋은 코드의 중요한 특징 중 하나는 중복이 없는 것이다.
<code>DRY 원칙 : Don&#39;t Repeat Yourself</code></li>
<li>많은 경우 메소드 추출 리팩토링을 적용하는데, 그렇게 하면 클래스 안에 작은 메소드가 많아지고 각 메소드 간의 관계 파악이 힘들어서 가독성이 더 떨어질 수 있다.</li>
<li>리팩토링 진행 후에 추출한 메소드를 별도의 <code>inner class</code>에 넣으면 코드가 깔끔해지지만 불필요한 준비 코드가 늘어난다.</li>
</ul>
<p>-&gt; 코틀린에는 함수에서 추출한 함수를 원 함수 내부에 중첩시킬 수 있다. 
<br/>
** 코드 중복을 보여주는 예제 **</p>
<pre><code class="language-kotlin">class User(val id: Int, val name: String, val address: String)

fun saveUser(user: User){
    if(user.name.isEmpty()){...}

    if(user.address.isEmpty()){...}

    // 필드 검증이 중복된다. 필드가 늘어날수록 중복 증가
    ...
}</code></pre>
<p><strong>로컬 함수를 사용해 코드 중복 줄이기</strong></p>
<pre><code class="language-kotlin">class User(val id: Int, val name: String, val address: String)

fun saveUser(user: User){

    fun validate(value: String, fieldName: String) {
        if (value.isEmpty()) {
            throw IllegalArgumentException(
                &quot;Can&#39;t save user ${user.id}: empty $fieldName&quot;
            )
        }
    }

    validate(user.name, &quot;Name&quot;)
    validate(user.address, &quot;Address&quot;)

    // 로컬 함수를 호출해서 각 필드를 검증한다.
    // 로컬 함수는 자신이 속한 바깥 함수의 모든 파라미터와 변수를 사용할 수 있다.
    ...
}</code></pre>
<p><strong>검증 로직을 확장 함수로 추출하기</strong></p>
<pre><code class="language-kotlin">class User(val id: Int, val name: String, val address: String)

fun User.validateBeforeSave() {
    fun validate(value: String, fieldName: String) {
        if (value.isEmpty()) {
            throw IllegalArgumentException(
                &quot;Can&#39;t save user $id: empty $fieldName&quot;
            )
        }
    }

    // User의 프로퍼티를 직접 사용할 수 있다.
    validate(name, &quot;Name&quot;)
    validate(address, &quot;Address&quot;)
}

fun saveUser(user: User){
    user.validateBeforeSave()
    ...
}</code></pre>
<p>-&gt; 검증 로직은 User를 사용하는 다른 곳에는 쓰이지 않기 때문에 User에 포함시키지 않는다. User를 간결하게 유지하면 생각해야할 내용이 줄어들어 가독성이 좋아진다.</p>
<p>-&gt; 확장 함수를 로컬 함수로 정의할 수도 있다. 즉, <code>User.validateBeforeSave</code>를 <code>saveUser()</code> 내부에 넣을 수 있지만 중첩된 함수의 깊이가 깊어지면 가독성이 떨어진다. 일반적으로 한 단계만 함수를 중첩시키라고 권장한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Kotlin] 함수(2)]]></title>
            <link>https://velog.io/@h-swon/Kotlin-%ED%95%A8%EC%88%982</link>
            <guid>https://velog.io/@h-swon/Kotlin-%ED%95%A8%EC%88%982</guid>
            <pubDate>Tue, 04 Jan 2022 10:18:19 GMT</pubDate>
            <description><![CDATA[<h4 id="1-확장함수">1. 확장함수</h4>
<blockquote>
<p>어떤 클래스의 멤버 메소드인 것처럼 호출할 수 있지만 그 클래스의 밖에 선언된 함수이다.</p>
</blockquote>
<ul>
<li>확장 함수를 만들려면 추가하려는 함수 이름 앞에 그 함수가 확장할 클래스의 이름을 덧붙이기만 하면 된다.<pre><code class="language-kotlin">fun String.lastChar(): Char = this.get(this.length-1)
// this 생략 가능
fun String.lastChar(): Char = get(length-1)
</code></pre>
</li>
</ul>
<blockquote>
<blockquote>
<blockquote>
<p>println(&quot;abc&quot;.lastChar())    // &quot;abc&quot;는 수신 객체, String은 수신 객체 타입
c</p>
</blockquote>
</blockquote>
</blockquote>
<pre><code>- `수신 객체 타입 (receiver type)` : 확장이 정의될 클래스
- `수신 객체 (receiver object)` : 그 클래스에 속한 인스턴스 객체 
- 확장 함수가 `캡슐화`를 깨진 않는다
-&gt; 클래스 내부에서만 사용할 수 있는 `private`이나 `protected`로 선언된 멤버는 사용할 수 없다.

&lt;br/&gt;

#### 2. import와 확장 함수
- 확장 함수를 사용하기 위해서는 다른 클래스나 함수와 마찬가지로 import해야 한다.
- `as` 키워드를 사용하면 import한 클래스나 함수를 다른 이름으로 부를 수 있다. (다른 여러 패키지에 속해있는 이름이 같은 함수를 가져와 사용해야 하는 경우 충돌 방지)
```kotlin
import strings.lastChar as last

val c = &quot;Kotlin&quot;.last()</code></pre><blockquote>
<p><strong>자바에서 확장 함수 호출</strong></p>
</blockquote>
<ul>
<li>내부적으로 확장 함수는 <code>수신 객체</code>를 첫 번째 인자로 받는 정적 메소드(static method)이다. 그래서 확장 함수를 호출해도 부가 비용이 들지 않는다.</li>
<li>static method를 호출하면서 첫 번째 인자로 <code>수신 객체</code>를 넘기기만 하면 된다.<pre><code class="language-java">/* 자바 */
// 확장 함수를 StringUtil.kt파일에 정의
char c = StringUtilKt.lastChar(&quot;Java&quot;);</code></pre>
</li>
</ul>
<br/>

<h4 id="3-확장-함수로-유틸리티-함수-정의">3. 확장 함수로 유틸리티 함수 정의</h4>
<pre><code class="language-kotlin">fun &lt;T&gt; Collection&lt;T&gt;.joinToString(
    separator: String = &quot;, &quot;,
    prefix: String = &quot;&quot;,
    postfix: String = &quot;&quot;
): String {
    val result = StringBuilder(prefix)
    for ((index, element) in this.withIndex()) {
        if (index &gt; 0) result.append(separator)
        result.append(element)
    }
    result.append(postfix)
    return result.toString()
}

&gt;&gt;&gt; val list = arrayListOf(1, 2, 3)
&gt;&gt;&gt; println(list.joinToString(&quot; &quot;)
1 2 3


// 구체적인 타입을 수신 객체 타입으로 지정할 수도 있다.
fun Collection&lt;String&gt;.join(
    separator: String = &quot;, &quot;,
    prefix: String = &quot;&quot;,
    postfix: String = &quot;&quot;
) = joinToString(separator, prefix, postfix)

&gt;&gt;&gt; println(listOf(&quot;one&quot;, &quot;two&quot;, &quot;eight&quot;).join(&quot; &quot;))
one two eight</code></pre>
<br/>

<h4 id="4-확장-함수는-오버라이드할-수-없다">4. 확장 함수는 오버라이드할 수 없다.</h4>
<blockquote>
<p><strong>Method Dispatch</strong> : 어떤 메소드를 호출할지 결정해서 실행시키는 과정</p>
</blockquote>
<ul>
<li><p>Static Dispatch: 컴파일 시점에서 컴파일러가 특정 메소드를 호출할 것이라고 명확히 알고 있는 경우이다.</p>
</li>
<li><p>Dynamic Dispatch: 컴파일러가 어떤 메소드를 호출할 지 모르는 경우이다. 호출할 메소드를 런타임 시점에 결정한다.</p>
</li>
<li><p>동적 디스패치 예시</p>
<pre><code class="language-kotlin">open class View{
  open fun click() = println(&quot;View Clicked&quot;)
}
</code></pre>
</li>
</ul>
<p>class Button: View(){
    override fun click() = println(&quot;Button Clicked&quot;)
}</p>
<blockquote>
<blockquote>
<blockquote>
<p>val view: View = Button()
view.click()
Button Clicked</p>
</blockquote>
</blockquote>
</blockquote>
<pre><code>- 이에 반해, 확장 함수는 수신 객체로 지정한 변수의 정적 타입에 의해 어떤 확장 함수가 호출될지 결정된다. 코틀린은 호출될 확장 함수를 `static`하게 결정하기 때문에 오버라이드 할 수 없다.
```kotlin
fun View.showOff() = println(&quot;I&#39;m a view!&quot;)
fun Button.showOff() = println(&quot;I&#39;m a button!&quot;)

&gt;&gt;&gt; val view: View = Button()
&gt;&gt;&gt; view.showOff()
I&#39;m a view!</code></pre><br/>

<h4 id="5-확장-프로퍼티">5. 확장 프로퍼티</h4>
<ul>
<li>상태를 저장할 적절한 방법이 없기 때문에 실제로 아무 상태도 가질 수 없다. 초기화도 불가능!</li>
<li><code>getter</code>는 필수적으로 정의 해야 한다.<pre><code class="language-kotlin">val String.lastChar: Char
  get() = get(length-1)
</code></pre>
</li>
</ul>
<p>var StringBuilder.lastChar: Char
    get() = get(length-1)
    set(value: Char){
        this.setCharAt(length-1, value)
    }
```</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Kotlin] 함수(1)]]></title>
            <link>https://velog.io/@h-swon/Kotlin-%ED%95%A8%EC%88%981</link>
            <guid>https://velog.io/@h-swon/Kotlin-%ED%95%A8%EC%88%981</guid>
            <pubDate>Sat, 01 Jan 2022 06:32:11 GMT</pubDate>
            <description><![CDATA[<h4 id="들어가기에-앞서">들어가기에 앞서..</h4>
<ul>
<li>코틀린은 자체 <code>collection</code>을 제공하지 않는데 이는 표준 자바 <code>collection</code>을 활용하면 자바 코드와 상호작용하기가 훨씬 쉽기 때문이다.</li>
<li>다시 말해서, 코틀린 <code>collection</code>은 자바 <code>collection</code>과 똑같은 <code>class</code>이다. 
하지만 <code>확장함수</code>를 통해 자바보다 더 많은 기능을 쓸 수 있다.</li>
</ul>
<br/>

<h4 id="1-함수-호출을-쉽게-만들기">1. 함수 호출을 쉽게 만들기</h4>
<ul>
<li>자바 <code>collection</code>에는 디폴트 <code>toString</code>구현이 들어있다. 
이 디폴트 구현을 (1; 2; 3)처럼 원소 사이를 세미콜론으로 구분하고 괄호로 구분하려면 어떻게 해야 할까?? </li>
<li><blockquote>
<p>자바와 달리 코틀린에서는 이런 요구 사항을 처리할 수 있는 함수가 표준 라이브러리에 있다.</p>
</blockquote>
</li>
</ul>
<pre><code class="language-kotlin">fun main() {
    val list = listOf(1, 2, 3)
    println(joinToString(list, &quot;; &quot;, &quot;(&quot;, &quot;)&quot;))
}


fun &lt;T&gt; joinToString(
    collection: Collection&lt;T&gt;,
    separator: String,
    prefix: String,
    postfix: String
): String {
    val result = StringBuilder(prefix)

    for ((index, element) in collection.withIndex()) {
        if (index &gt; 0) result.append(separator)
        result.append(element)
    }
    result.append(postfix)
    return result.toString()
}</code></pre>
<p> -&gt; 해당 함수를 그대로 써도 좋으나 함수를 호출할 때마다 매번 4개의 인자를 모두 전달해야하는 단점이 있다.
 <br/><br/></p>
<h4 id="2-이름-붙인-인자">2. 이름 붙인 인자</h4>
<pre><code class="language-kotlin">joinToString(collection,&quot; &quot;, &quot; &quot;, &quot;.&quot;)
// 인자로 전달한 각 문자열이 어떤 역할을 하는지 알 수 없다.

joinToString(collection, separator = &quot; &quot;, prefix = &quot; &quot;, postfix = &quot;.&quot;)
// 인자의 이름을 명시함으로써 가독성이 좋아진다.</code></pre>
<p>-&gt;단, 자바로 작성한 코드를 호출할 땐 이름 붙인 인자를 사용할 수 없다.
 <br/><br/></p>
<h4 id="3-디폴트-파라미터-값">3. 디폴트 파라미터 값</h4>
<pre><code class="language-kotlin">fun &lt;T&gt; joinToString(
    collection: Collection&lt;T&gt;,
    separator: String = &quot;, &quot;,
    prefix: String = &quot;&quot;,
    postfix: String = &quot;&quot;
): String

&gt;&gt;&gt; joinToString(list, &quot;, &quot;, &quot;&quot;, &quot;&quot;)
&gt;&gt;&gt; joinToString(list)
&gt;&gt;&gt; joinToString(list,&quot;; &quot;)</code></pre>
<ul>
<li><p>함수 호출 시 모든 인자를 쓸 수도 있고, 일부를 생략할 수도 있다.</p>
</li>
<li><p>만약 중간에 있는 인자를 생략하고 싶다면 다음과 같이 <code>이름 붙인 인자</code>를 사용하면 된다.</p>
<pre><code class="language-kotlin">&gt;&gt;&gt; joinToString(list, postfix=&quot;;&quot;, prefix=&quot;# &quot;)
# 1, 2, 3;</code></pre>
<blockquote>
<p><strong>디폴트 값과 자바</strong></p>
</blockquote>
</li>
<li><p>자바에는 디폴트 파라미터 값이라는 개념이 없어서 자바 쪽에서 좀 더 편하게 코틀린 함수를 호출하려면 <code>@JvmOverloads</code>를 함수에 추가하면 된다.</p>
</li>
<li><p><code>@JvmOverloads</code>를 함수에 추가하면 코틀린 컴파일러가 자동으로 맨 마지막 파라미터로부터 파라미터를 하나씩 생략한 오버로딩한 자바 메소드를 추가해준다.</p>
<pre><code class="language-java">/* 자바 */
String joinToString(Collection&lt;T&gt; collection, String separator, 
  String prefix, String postfix);
String joinToString(Collection&lt;T&gt; collection, String separator,
  String prefix);
String joinToString(Collection&lt;T&gt; collection, String separator);
String joinToString(Collection&lt;T&gt; collection);</code></pre>
<br/>

</li>
</ul>
<h4 id="4-정적인-유틸리티-클래스-없애기-최상위-함수와-프로퍼티">4. 정적인 유틸리티 클래스 없애기: 최상위 함수와 프로퍼티</h4>
<ol>
<li>최상위 함수<pre><code>  - 코틀린에서는 Util 성격의 정적인 메소드만 모아져 있는 의미없는 클래스들을 없앨 수 있다.
 - 함수를 소스 파일의 최상위 수준, 모든 다른 클래스의 밖에 위치시키면 된다.
 ![](https://images.velog.io/images/h-swon/post/6996abbd-6e12-4ea1-bc57-671b83bbe80c/image.png)</code></pre>joinToString 함수를 top 패키지에 넣고 join.kt파일을 작성하자.</li>
</ol>
<pre><code class="language-kotlin">/* join.kt */
package top

fun &lt;T&gt; joinToString(...): String {...}</code></pre>
<pre><code class="language-kotlin">/* main.kt */
package top.bottom

import top.joinToString

fun main(){
    val list = listOf(1,2,3)
    joinToString(list)
}</code></pre>
<ul>
<li>JVM은 클래스 안에 들어있는 코드만을 실행할 수 있기 때문에 컴파일러는 <code>join.kt</code> 파일을 컴파일할 때 새로운 클래스를 정의해준다.<pre><code class="language-java">/* 자바 */
</code></pre>
</li>
</ul>
<p>package top;</p>
<p>public class JoinKt{
    public static String joinToString(...) {...}
}
// 클래스의 이름은 최상위 함수가 들어있던 코틀린 소스 파일과 대응한다.</p>
<pre><code>```java
/* 자바 */

import top.JoinKt;

...

JoinKt.joinToString(list,&quot;, &quot;, &quot;&quot;, &quot;&quot;);
// joinToString 호출</code></pre><blockquote>
<p><strong>파일에 대응하는 클래스의 이름 변경하기</strong></p>
</blockquote>
<ul>
<li>코틀린 최상위 함수가 포함되는 클래스의 이름을 바꾸고 싶다면 파일에 <code>@JvmName</code>을 추가하면 된다. 
단, 파일의 맨 앞, 패키지 이름 선언 이전에 위치해야 한다.<pre><code class="language-kotlin">@file:JVmName(&quot;StringFunctions&quot;)    // 클래스 이름 지정
package top
fun joinToString(...): String {...}</code></pre>
<pre><code class="language-java">/* 자바 */
import top.StringFunctions;
StringFunctions.joinToString(list,&quot;, &quot;, &quot;&quot;, &quot;&quot;);</code></pre>
</li>
</ul>
<ol start="2">
<li>최상위 프로퍼티</li>
</ol>
<ul>
<li><p>함수와 마찬가지로 프로퍼티도 파일의 최상위 수준에 놓을 수 있다. 
이를 활용해 코드에 상수를 추가할 수 있다.</p>
<pre><code class="language-kotlin">val UNIX_LINE_SEPARATOR = &quot;\n&quot;</code></pre>
</li>
<li><p>최상위 프로퍼티도 다른 모든 프로퍼티처럼 접근자 메소드를 통해 자바 코드에 노출된다.( val은 getter, var은 getter, setter가 생긴다. )
겉으로는 상수처럼 보이는데 실제로 <code>getter</code>를 사용한다면 자연스럽지 못하기 때문에 상수를 <code>public static final</code>필드로 컴파일 해야 한다.</p>
</li>
<li><p><code>const</code>를 추가하면 프로퍼티를 <code>public static final</code> 필드로 컴파일하게 만들 수 있다. ( 단, 원시 타입과 String만 const로 지정 가능)</p>
<pre><code class="language-kotlin">const val UNIX_LINE_SEPARATOR = &quot;\n&quot;</code></pre>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Kotlin] 코틀린 기초(5) - 예외 처리]]></title>
            <link>https://velog.io/@h-swon/Kotlin-%EC%BD%94%ED%8B%80%EB%A6%B0-%EA%B8%B0%EC%B4%885-%EC%98%88%EC%99%B8-%EC%B2%98%EB%A6%AC</link>
            <guid>https://velog.io/@h-swon/Kotlin-%EC%BD%94%ED%8B%80%EB%A6%B0-%EA%B8%B0%EC%B4%885-%EC%98%88%EC%99%B8-%EC%B2%98%EB%A6%AC</guid>
            <pubDate>Sun, 26 Dec 2021 12:44:04 GMT</pubDate>
            <description><![CDATA[<ul>
<li><p>코틀린에서 <code>Exception</code> 처리는 Java나 다른 언어와 비슷하다.
함수를 정상적으로 종료할 수 있지만 오류가 발생하면 <code>Exception</code>을 <code>throw</code>할 수 있다.
함수를 호출하는 쪽에서 그 <code>Exception</code>을 잡아 처리하거나 함수 호출 단에서 <code>catch</code>하지 않는다면 함수 호출 스택을 거슬러 올라가면서 <code>Exception</code>을 처리하는 부분이 나올 때까지 <code>Exception</code>을 <code>rethrow</code>한다.</p>
</li>
<li><p>코틀린의 <code>throw</code>는 <code>expression</code>이므로 다른 <code>expression</code>에 포함될 수 있다.</p>
<pre><code class="language-kotlin">val percentage =
  if (number in 1..100)
      number
  else 
      throw IllegalArgumentException(
      &quot;A percentage value must be between 0 and 100: $number&quot;)</code></pre>
</li>
<li><p><code>try</code>, <code>catch</code>, <code>finally</code>
Java와 마찬가지로 <code>Exception</code>을 처리하려면 <code>try</code>와 <code>catch</code>, <code>finally</code>절을 함께 사용한다.</p>
<pre><code class="language-kotlin">fun readNumber(reader: BufferedReader): Int? {  // 함수가 던질 수 있는 Exception을 명시할 필요가 없다.
  try {
      val line = reader.readLine()
      return line.toInt()
  } catch (e: NumberFormatException) {
      return null
  } finally {                                 // finally는 Java와 똑같이 작동한다.
      reader.close()
  }
}</code></pre>
</li>
<li><blockquote>
<p>Java 코드와 가장 큰 차이는 <code>throws</code>절이 코드에 없다는 점이다. Java에서는 함수 선언 뒤에 <code>throws IOException</code>을 붙여야한다. 왜냐하면 <code>IOException</code>이 체크 예외이기 때문이다. 
<strong>Java에서는..</strong><br/></p>
</blockquote>
</li>
<li><p><em>체크 예외(Check Exception)*</em>
RuntimeExeception 클래스를 상속하지 않은 Exception 클래스들이다. 체크 예외는 예외가 발생할 수 있는 메소드를 사용할 경우 반드시 예외를 처리하는 코드를 함께 작성해야 한다. 예외를 처리하기 위해서 catch문으로 잡거나 throws를 통해 메소드 밖으로 던질 수 있다. 만약 예외를 처리하지 않으면 컴파일 에러가 발생한다.<br/></p>
</li>
<li><p><em>언체크 예외(Uncheck Exception)*</em>
RuntimeException 클래스를 상속한 Exception 클래스들은 예외 처리를 강제하지 않기 때문에 언체크 예외라고 불린다. 에러를 처리하지 않아도 컴파일 에러가 발생하지 않는다. RuntimeException은 주로 프로그램에 문제가 있을 때 오류가 발생하도록 의도된 것으로 대표적으로 NullPointerException이 있다. 즉, RuntimeException은 예상치 못했던 상황에서 발생하는 것이 아니므로 굳이 예외 처리를 강제하지 않는다.</p>
</li>
<li><p>이에 반해 코틀린에서는 체크 예외와 언체크 예외를 구별하지 않는다. 그래서 함수가 던지는 <code>Exception</code>을 잡아내도 되고 잡아내지 않아도 된다. 그리고 Java 7의 자원을 사용하는 <code>try-with-resource</code>의 경우 코틀린에선 그런 경우를 위한 특별한 문법을 제공하진 않지만 라이브러리 함수로 같은 기능을 구현한다.</p>
</li>
<li><p>try를 Expression으로 사용하기</p>
<pre><code class="language-kotlin">fun readNumber(reader: BufferedReader) {
  val number = try {
      reader.readLine().toInt()
  } catch (e: NumberFormatException) {
      null
  }

  println(number)
}</code></pre>
</li>
<li><blockquote>
<p><code>try</code> 키워드는 <code>if</code>나 <code>when</code>과 마찬가지로 <code>expression</code>이다. 그러나 <code>if</code>와 달리 <code>try</code>의 본문은 반드시 중괄호로 둘러싸야 한다.</p>
</blockquote>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Kotlin] 코틀린 기초(4) - Iteration]]></title>
            <link>https://velog.io/@h-swon/Kotlin-%EC%BD%94%ED%8B%80%EB%A6%B0-%EA%B8%B0%EC%B4%884-Iteration</link>
            <guid>https://velog.io/@h-swon/Kotlin-%EC%BD%94%ED%8B%80%EB%A6%B0-%EA%B8%B0%EC%B4%884-Iteration</guid>
            <pubDate>Sun, 26 Dec 2021 08:11:10 GMT</pubDate>
            <description><![CDATA[<ul>
<li>while 루프
코틀린에는 <code>while</code>과 <code>do-while</code> 루프가 있다. 두 루프의 문법은 자바와 같다.<pre><code class="language-kotlin">while (조건){
  ...
}
// 조건이 참인 동안 본문을 반복 실행한다.
</code></pre>
</li>
</ul>
<p>do{
    ...
}while (조건) 
// 맨 처음에 무조건 본문을 한 번 실행시킨 후에 조건이 참인 동안 본문을 반복 실행한다.</p>
<pre><code>
- 코틀린에서는 자바의 for 루프( 초깃값, 증가 값, 최종 값)를 대신하기 위해 `range`를 사용한다. `range`는 기본적으로 두 값으로 이뤄진 구간이며 양끝을 포함한다.
```kotlin
for (i in 1..5){
    println(i)
}

/*
출력
1
2
3
4
5
*/</code></pre><ul>
<li>증가 값을 갖고 <code>range</code> 이터레이션하기<pre><code class="language-kotlin">for (i in 10 downTo 1 step 3){    
  println(i)
}
// 10 downTo 1은 역방향 수열을 만든다.
// step 2를 붙이면 증가 값의 절댓값이 2로 바뀐다.
</code></pre>
</li>
</ul>
<p>/*
출력
10
7
4
1
*/</p>
<pre><code>- 끝 값을 포함하지 않는 `range`에 대해 이터레이션하기
```kotlin
for (i in 1 until 5){
    println(i)
}

/*
출력
1
2
3
4
*/
</code></pre><ul>
<li><p>Map에 대한 이터레이션</p>
<pre><code class="language-kotlin">  val binaryReps = TreeMap&lt;Char, String&gt;()    // 키에 대해 정렬하기 위해 TreeMap 사용

  for (c in &#39;A&#39;..&#39;F&#39;) {
      val binary = Integer.toBinaryString(c.code)
      binaryReps[c] = binary
  }
  for((letter, binary) in binaryReps){    // Map에 대해 이터레이션
      println(&quot;$letter = $binary&quot;)
  }

  // .. 연산자를 숫자 타입의 값뿐 아니라 문자 타입의 값에도 적용할 수 있다.
  // binaryReps[c] = binary는 binaryReps.put(c,binary)와 같다.</code></pre>
</li>
<li><p>컬렉션에 대한 이터레이션</p>
<pre><code class="language-kotlin">val list = arrayListOf(&quot;10&quot;, &quot;11&quot;, &quot;1001&quot;)
for ((index, element) in list.withIndex()) {    // index와 함께 컬렉션을 이터레이션
  println(&quot;$index: $element&quot;)
}</code></pre>
</li>
</ul>
<h3 id="--in으로-컬렉션이나-range의-원소-검사">- in으로 컬렉션이나 range의 원소 검사</h3>
<ul>
<li><p><code>in</code> 연산자를 사용해 어떤 값이 범위에 속하는지 검사할 수 있다.</p>
</li>
<li><p><code>!in</code> 연산자를 사용해 어떤 값이 범위에 속하지 않는지 검사할 수 있다.</p>
<pre><code class="language-kotlin">fun recognize(c: Char) = when (c) {
  in &#39;0&#39;..&#39;9&#39; -&gt; &quot;숫자&quot;
  in &#39;a&#39;..&#39;z&#39;, in &#39;A&#39;..&#39;Z&#39; -&gt; &quot;문자&quot;
  else -&gt; &quot;해당 없음&quot;
}</code></pre>
</li>
<li><p>비교가 가능한 클래스라면( java.lang.Comparable 인터페이스를 구현한 클래스라면 ) 그 클래스의 인스턴스 객체를 사용해 범위를 만들 수 있다. Comparable을 사용하는 범위의 경우 그 범위 내의 모든 객체를 항상 이터레이션하지는 못한다. 
ex) &quot;Java&quot;와 &quot;Kotlin&quot; 사이의 모든 문자열을 이터레이션하는건 불가능하다.
하지만 <code>in</code> 연산자를 사용하면 값이 범위 안에 속하는지 항상 결정할 수 있다.</p>
<pre><code class="language-kotlin">&gt;&gt;&gt; println(&quot;Kotlin&quot; in &quot;Java&quot;..&quot;Scala&quot;)
true</code></pre>
</li>
<li><p>컬렉션에도 <code>in</code> 연산을 사용할 수 있다.</p>
<pre><code class="language-kotlin">&gt;&gt;&gt; println(&quot;Kotlin&quot; in setOf(&quot;Java&quot;, &quot;Scala&quot;))
false</code></pre>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Kotlin] 코틀린 기초(3) - when]]></title>
            <link>https://velog.io/@h-swon/Kotlin-%EC%BD%94%ED%8B%80%EB%A6%B0-%EA%B8%B0%EC%B4%883-when</link>
            <guid>https://velog.io/@h-swon/Kotlin-%EC%BD%94%ED%8B%80%EB%A6%B0-%EA%B8%B0%EC%B4%883-when</guid>
            <pubDate>Sun, 26 Dec 2021 07:00:29 GMT</pubDate>
            <description><![CDATA[<h3 id="1-사용법">1. 사용법</h3>
<ul>
<li><p>when도 if문과 마찬가지로 값을 만들어내는 <code>expression</code>이므로 다음과 같이 쓸 수 있다.
Java와 달리 분기의 끝에 <code>break</code>를 넣지 않아도 된다.</p>
<pre><code class="language-kotlin">enum class Color(val r: Int, val g: Int, val b: Int) {  // 상수의 프로퍼티를 정의한다.
  RED(255, 0, 0),
  GREEN(0, 255, 0),
  BLUE(0, 0, 255); // 메소드 구분을 위해 세미콜론 사용

  fun rgb() = (r * 256 + g) * 256 + b
</code></pre>
</li>
</ul>
<p>}</p>
<p>fun getColor(color: Color) =
    when (color) {
        Color.RED -&gt; &quot;빨강&quot;
        Color.GREEN -&gt; &quot;초록&quot;
        Color.BLUE -&gt; &quot;파랑&quot;
    }</p>
<pre><code>- 여러 값을 매치 패턴으로 사용할 경우, 값 사이에 콤마( , )로 구분한다.
```kotlin
fun getColor(color: Color) =
    when (color) {
        Color.RED, Color.GREEN-&gt; &quot;빨초&quot;
        Color.BLUE -&gt; &quot;파랑&quot;
    }</code></pre><ul>
<li><p>Kotlin when의 분기 조건은 <code>임의의 객체</code>를 허용한다.</p>
<pre><code class="language-kotlin">fun getColor(c1: Color, c2: Color) =
  when (setOf(c1, c2)) {
      setOf(Color.RED, Color.BLUE) -&gt; &quot;PURPLE&quot;
      setOf(Color.RED, Color.GREEN) -&gt; &quot;YELLOW&quot;
      else -&gt; &quot;NOTHING&quot;
  }</code></pre>
</li>
<li><p>인자 없는 when 사용
위에 코드는 호출될 때마다 여러 set 인스턴스를 생성한다. 만약 이 함수가 자주 호출돼서 불필요한 가비지 객체가 늘어나는 것을 방지하기 위해 다음과 같이 사용하면 된다. 단, 가독성은 떨어진다.</p>
<pre><code class="language-kotlin">fun mixOptimized(c1: Color, c2: Color) =
  when {
      (c1 == Color.RED &amp;&amp; c2 == Color.BLUE) ||
              (c1 == Color.BLUE &amp;&amp; c1 == Color.RED) -&gt; &quot;PURPLE&quot;
      (c1 == Color.RED &amp;&amp; c2 == Color.GREEN) ||
              (c1 == Color.GREEN &amp;&amp; c1 == Color.RED) -&gt; &quot;YELLOW&quot;
      else -&gt; &quot;NOTHING&quot;
  }</code></pre>
</li>
</ul>
<br/>

<h3 id="2-스마트-캐스트-타입-검사--타입-캐스트">2. 스마트 캐스트 (타입 검사 + 타입 캐스트)</h3>
<ul>
<li>코틀린에서는 <code>is</code>를 사용해 변수 타입을 검사한다. (Java의 <code>instanceof</code>와 비슷하다)
어떤 변수가 원하는 타입인지 일단 <code>is</code>로 검사하고 나면 굳이 변수를 원하는 타입으로 캐스팅하지 않아도 컴파일러가 대신 캐스팅을 해주기 때문에 바로 사용 가능하다. 이를 <code>스마트 캐스트</code>라고 한다.<pre><code class="language-kotlin">interface Expr  
// 단지 여러 타입의 expression 객체를 아우르는 공통 타입 역할
</code></pre>
</li>
</ul>
<p>class Num(val value: Int) : Expr
// value 라는 프로퍼티만 존재하는 단순한 클래스로 Expr 인터페이스를 구현한다.</p>
<p>class Sum(val left: Expr, val right: Expr) : Expr
// Expr 타입의 객체라면 어떤 것이나 Sum 연산의 인자가 될 수 있다.</p>
<p>fun eval(e: Expr): Int =
    when (e) {
        is Num -&gt; e.value
        is Sum -&gt; eval(e.left) + eval(e.right)
        else -&gt; throw IllegalArgumentException(&quot;Unknown expression&quot;)
    }</p>
<pre><code>- `스마트 캐스트`는 `is`로 변수에 든 값의 타입을 검사한 다음에 그 값이 바뀔 수 없는 경우에만 작동한다. 
ex) 클래스의 프로퍼티에 대해 `스마트 캐스트`를 사용한다면 그 프로퍼티는 반드시 `val`이어야 하고 커스텀 접근자를 사용한 것이어도 안된다. 해당 프로퍼티를 다른 클래스가 상속하면서 커스텀 접근자를 정의함으로써 스마트 캐스트의 요구 사항을 깰 수 있기 때문이다.

- 원하는 타입으로 명시적으로 타입 캐스팅하려면 `as` 키워드를 사용한다.
```kotlin
    val name = e as Num</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[Kotlin] 코틀린 기초(2) - enum]]></title>
            <link>https://velog.io/@h-swon/Kotlin-%EC%BD%94%ED%8B%80%EB%A6%B0-%EA%B8%B0%EC%B4%882-enum</link>
            <guid>https://velog.io/@h-swon/Kotlin-%EC%BD%94%ED%8B%80%EB%A6%B0-%EA%B8%B0%EC%B4%882-enum</guid>
            <pubDate>Sun, 26 Dec 2021 05:48:47 GMT</pubDate>
            <description><![CDATA[<h3 id="1-enum-클래스">1. enum 클래스</h3>
<blockquote>
<p>Enum은 열거형이라 불리며, 서로 연관된 상수들의 집합이다.</p>
</blockquote>
<h3 id="2-enum을-사용하지-않고-상수를-정의하는-다양한-방법">2. enum을 사용하지 않고 상수를 정의하는 다양한 방법</h3>
<ol>
<li>const val 사용</li>
</ol>
<pre><code class="language-kotlin">// fruit
const val APPLE = 1
const val PEACH = 2
const val BANANA = 3
// company
// const val APPLE = 1
const val GOOGLE =2
const val NAVER = 3 

fun main() {
    val type = APPLE
    when (type) {
        APPLE -&gt; println(&quot;사과&quot;)
        PEACH -&gt; println(&quot;복숭아&quot;)
        BANANA -&gt; println(&quot;바나나&quot;)
    }
}</code></pre>
<p>-&gt; 상수가 늘어날수록 가독성이 떨어지고, 각각의 상수 집합에서 같은 이름으로 정의된 상수가 있다면 중복된 이름이기 때문에 컴파일 단계에서 오류가 발생한다.</p>
<br/>

<ol start="2">
<li>인터페이스 사용
<strong>- Kotlin에서는 interface에 상수를 정의할 수 없기 때문에 아래 코드부터는 Java로 작성했다!</strong></li>
</ol>
<pre><code class="language-java">// fruit
interface FRUIT{
    int APPLE = 1, PEACH =2, BANANA =3;
}

interface COMPANY{
    int APPLE = 1, GOOGLE = 2, NAVER = 3;
}

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

        int type = COMPANY.APPLE;

        switch(type) {
        case FRUIT.APPLE:
            System.out.println(&quot;사과&quot;);
            break;

        case FRUIT.PEACH:
            System.out.println(&quot;복숭아&quot;);
            break;

        case FRUIT.BANANA:
            System.out.println(&quot;바나나&quot;);
            break;
        }

    }
}
</code></pre>
<p>-&gt; <code>FRUIT.APPLE</code>과 <code>COMPANY.APPLE</code> 모두 값이 정수 1이기 때문에 type이 <code>COMPANY.APPLE</code>임에도 에러를 발생시키지 않고 사과를 출력해주고 있다. 이렇게 코드를 구현하게 되면 런타임 단계에서 예기치 못한 문제를 마주치게 된다.
<br/></p>
<ol start="3">
<li>Fruit과 Company 클래스를 만들고 클래스 변수로 해당 클래스의 인스턴스를 사용<pre><code class="language-java">class Fruit{
 public static final Fruit APPLE  = new Fruit();
 public static final Fruit PEACH  = new Fruit();
 public static final Fruit BANANA = new Fruit();
}
</code></pre>
</li>
</ol>
<p>class Company{
    public static final Company GOOGLE = new Company();
    public static final Company APPLE = new Company();
    public static final Company ORACLE = new Company();
}</p>
<p>public class EnumExample {</p>
<pre><code>public static void main(String[] args) {
    if(Fruit.APPLE == Company.APPLE){
        System.out.println(&quot;type이 같다.&quot;);
    }    
    // 컴파일 오류 발생
}</code></pre><p>}</p>
<pre><code>-&gt; 서로 다른 타입의 상수에 대해서는 비교를 금지시키지만 switch문에서 사용할 수 없고 선언이 너무 복잡하다는 문제점이 있다.
```java
enum Fruit{
    APPLE, PEACH, BANANA;
}
// 열거형을 사용하게 되면 다음과 같이 간단히 사용할 수 있다. 
// 위의 코드는 아래코드와 사실상 같다.

class Fruit{
    public static final Fruit APPLE  = new Fruit();
    public static final Fruit PEACH  = new Fruit();
    public static final Fruit BANANA = new Fruit();
    private Fruit(){}
}</code></pre><p><br/><br/></p>
<h3 id="3-enum-사용">3. enum 사용</h3>
<pre><code class="language-kotlin">// fruit
enum class Fruit {
    APPLE, PEACH, BANANA
}

// company
enum class Company {
    APPLE, GOOGLE, NAVER
}

fun main() {
    /*
        if(Fruit.APPLE == Company.APPLE){
            println(&quot;type이 같다.&quot;)
        }   // 컴파일 오류 발생
    */

    val type = Fruit.APPLE
    when (type) {
        Fruit.APPLE -&gt;
            println(&quot;사과&quot;)
        Fruit.PEACH -&gt;
            println(&quot;복숭아&quot;)
        Fruit.BANANA -&gt;
            println(&quot;바나나&quot;)

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

<p>enum에서도 일반적인 클래스와 마찬가지로 생성자와 프로퍼티를 선언한다. enum 클래스 안에 메소드를 정의하는 경우 반드시 enum 상수 목록과 메소드 정의 사이에 세미콜론(;)을 넣어야 한다.</p>
<pre><code class="language-kotlin">enum class Color(val r: Int, val g: Int, val b: Int) {  // 상수의 프로퍼티를 정의한다.
    RED(255, 0, 0),
    GREEN(0, 255, 0),
    BLUE(0, 0, 255); // 메소드 구분을 위해 세미콜론 사용

    fun rgb() = (r * 256 + g) * 256 + b

}

fun main() {

    println(Color.GREEN.rgb())

}</code></pre>
<h3 id="4-enum을-사용하는-이유">4. enum을 사용하는 이유</h3>
<ol>
<li>코드의 가독성이 높아진다.</li>
<li>인스턴스 생성과 상속을 방지해서 타입 안정성이 보장된다.</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Kotlin] 코틀린 기초(1)]]></title>
            <link>https://velog.io/@h-swon/Kotlin-%EC%BD%94%ED%8B%80%EB%A6%B0-%EA%B8%B0%EC%B4%881</link>
            <guid>https://velog.io/@h-swon/Kotlin-%EC%BD%94%ED%8B%80%EB%A6%B0-%EA%B8%B0%EC%B4%881</guid>
            <pubDate>Sun, 26 Dec 2021 02:38:17 GMT</pubDate>
            <description><![CDATA[<h3 id="1-함수">1. 함수</h3>
<ul>
<li>함수를 선언할 땐 fun 키워드를 사용한다.</li>
<li>함수를 최상위 수준에 정의할 수 있다. 즉, 자바와 달리 클래스 안에 함수를 넣어야 할 필요가 없다.<pre><code class="language-kotlin">fun max(a: Int, b: Int): Int {
  return if (a &gt; b) a else b
}</code></pre>
</li>
<li><blockquote>
<p>코틀린에서 if문은 statement가 아니라 expression이다.
<strong>expression</strong> : 값을 만들어내며 다른 expression의 하위 요소로 계산에 참여할 수 있다.<br/></p>
</blockquote>
</li>
<li><em>statement*</em> : 자신을 둘러싸고 있는 가장 안쪽 블록의 최상위 요소로 존재하며 아무런 값을 만들어내지 않는다.</li>
</ul>
<p>-&gt; 자바에서는 모든 제어구조가 <code>statement</code>이지만 코틀린에서는 Loop를 제외한 대부분의 제어 구조가 <code>expression</code>이다. 반면 대입문의 경우 자바에서는 <code>expression</code>이였지만 코틀린에서는 <code>statement</code>이다.</p>
<h4 id="--식expression이-본문인-함수">- 식(expression)이 본문인 함수</h4>
<p>위의 함수를 다음과 같이 간결하게 표현할 수 있다.</p>
<pre><code class="language-kotlin">fun max(a: Int, b: Int): Int = if (a &gt; b) a else b</code></pre>
<p>본문이 중괄호로 둘러싸인 함수를 <code>블록이 본문인 함수</code>라 부르고, 등호와 식으로 이뤄진 함수를 <code>식이 본문인 함수</code>라고 부른다. 코틀린에서는 <code>식이 본문인 함수</code>가 자주 쓰인다.
여기서 반환 타입을 생략하면 더 간단히 함수를 만들 수 있다.</p>
<pre><code class="language-kotlin">fun max(a: Int, b: Int) = if (a &gt; b) a else b</code></pre>
<p>반환타입이 생략가능한 이유는 <code>식이 본문인 함수</code>의 경우 굳이 사용자가 반환 타입을 적지 않아도 컴파일러가 함수 본문 식을 분석해서 식의 결과 타입을 함수 반환 타입으로 정해준다. 이런 기능을 <code>타입 추론</code>이라고 한다.</p>
<br/>

<h3 id="2-변수">2. 변수</h3>
<p>변수 선언 시 사용하는 키워드는 다음과 같은 2가지가 있다.</p>
<ul>
<li><code>val</code>: 변경 불가능한 참조를 저장하는 변수</li>
<li><code>var</code>: 변경가능한 참조를 저장하는 변수</li>
</ul>
<p>타입을 지정하지 않으면 컴파일러가 초기화 식을 분석해서 초기화 식의 타입을 변수 타입으로 지정한다.</p>
<pre><code class="language-kotlin">val a = 1
val b: Int = 2</code></pre>
<p>기본적으로 모든 변수를 <code>val</code>키워드를 사용해 불변 변수로 선언하고, 나중에 꼭 필요한 때에만 <code>var</code>로 변경하자. 
<code>val</code> 변수는 블록을 실행할 때 정확히 1번만 초기화돼야 한다. 하지만 어떤 블록이 실행될 때 오직 한 초기화 문장만 실행된다는 걸 컴파일러가 확인할 수 있다면 조건에 따라 <code>val</code> 값을 다른 여러 값으로도 초기화할 수 있다.</p>
<pre><code class="language-kotlin">val message: String

if (isTrue()) {
    message = &quot;참&quot;
} else {
    message = &quot;거짓&quot;
}</code></pre>
<p><code>val</code> 참조 자체는 불변이라도 그 참조가 가리키는 객체의 내부 값은 변경될 수 있다.</p>
<pre><code class="language-kotlin">val languages = arrayListOf(&quot;Java&quot;)
languages.add(&quot;Kotlin&quot;)</code></pre>
<p>또한 <code>var</code> 키워드를 사용하면 변수의 값을 변경할 수 있지만 변수의 타입은 고정돼 바뀌지 않는다.</p>
<pre><code class="language-kotlin">var answer = 42
answer = &quot;HI&quot;    // 컴파일 오류 발생</code></pre>
<p><strong>- 문자열 템플릿</strong>
코틀린에서도 변수를 문자열 안에 사용할 수 있는데, 변수 앞에 <code>$</code>를 추가해주면 된다. 복잡한 식도 중괄호로 둘러싸서 문자열 템플릿 안에 넣을 수 있다. $문자를 문자열에 넣고 싶으면 \를 사용해 $를 이스케이프시켜야 한다. </p>
<pre><code class="language-kotlin">val name = &quot;Kotlin&quot;
println(&quot;Hello, $name!&quot;)

val a = 3
val b = 4
println(&quot;sum: ${a+b}&quot;)
println(&quot;max: ${if(a&gt;b) a else b}&quot;)</code></pre>
<br/>

<h3 id="3-클래스">3. 클래스</h3>
<pre><code class="language-kotlin">class Person(val name: String)</code></pre>
<p>이런 유형의 클래스를 값 객체(Value Object)라고 부른다. 코틀린의 기본 visibility modifier는 <code>public</code>이다. 여기서 visibility modifier는 &quot;누구에게 공개할 것인가?&quot; 정도로 이해하면 된다.</p>
<p><strong>- Property</strong>
클래스라는 개념의 목적은 데이터를 <code>캡슐화</code>하고 캡슐화한 데이터를 다루는 코드를 한 주체 아래 가두는 것이다. </p>
<p>자바에서는 데이터를 <code>field</code>에 저장하며, 멤버 필드의 access modifier는 보통 <code>private</code>이다. 클래스는 자신을 사용하는 클라이언트가 그 데이터에 접근하는 통로로 쓸 수 있는 접근자 메소드(accessor method)를 제공한다. 
ex) getter, setter 메소드</p>
<p>필드와 접근자를 한데 묶어 <code>property</code>라고 한다. 
코틀린은 <code>property</code>를 언어 기본 기능으로 제공하며, 자바의 필드와 접근자 메소드를 완전히 대신한다. 클래스에서 <code>property</code>를 선언할 때는 변수를 선언할 때와 마찬가지로 <code>val</code>이나 <code>var</code>를 사용한다. <code>val</code>은 읽기 전용, <code>var</code>은 변경 가능하다.</p>
<pre><code class="language-kotlin">class Person(
    val name: String,// 읽기 전용 property
                     // 코틀린은 (비공개)필드와 (공개)getter를 만들어낸다.

    var age: Int     // 쓸 수 있는 property
                     // (비공개)필드, (공개)getter, (공개)setter를 만들어낸다.
)

fun main(){
    val person = Person(&quot;Bob&quot;,20)
    println(person.age) 
}
// property 이름을 직접 사용해도 코틀린이 자동으로 getter를 호출해준다. 
// setter도 마찬가지 방식으로 동작한다.</code></pre>
<p>대부분의 <code>propertry</code>에는 그 <code>property</code> 값을 저장하기 위한 필드가 있다. 이를 <code>backing field</code>라고 한다. 원한다면 <code>property</code> 값을 그때그때 계산할 수도 있다.</p>
<p><strong>- 커스텀 접근자</strong></p>
<pre><code class="language-kotlin">class Rectangle(val height: Int, val width: Int) {
    val isSquare: Boolean
        get() {
            return height == width
        }
}</code></pre>
<p>isSquare <code>property</code>는 자체 값을 저장하는 필드가 필요 없다. 클라이언트가 <code>property</code>에 접근할 때마다 getter가 <code>property</code> 값을 매번 다시 계산한다.
파라미터가 없는 함수를 정의하는 방식 vs 커스텀 게터를 정의하는 방식 모두 구현이나 성능상 차이는 없다. 차이가 나는 부분은 가독성뿐이다.
일반적으로 클래스의 특성을 정의하고 싶다면 <code>property</code>로 그 특성을 정의해야 한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Android] FragmentManager]]></title>
            <link>https://velog.io/@h-swon/Android-FragmentManager</link>
            <guid>https://velog.io/@h-swon/Android-FragmentManager</guid>
            <pubDate>Mon, 20 Dec 2021 11:08:06 GMT</pubDate>
            <description><![CDATA[<h3 id="1-fragmentmanager란">1. FragmentManager란</h3>
<blockquote>
<p>Fragment에서 작업을 추가, 삭제 또는 교체하고 백 스택에 추가하는 등의 작업을 실행하는 클래스</p>
</blockquote>
<br/>

<h3 id="2-fragmentmanager에-액세스하는-방법">2. FragmentManager에 액세스하는 방법</h3>
<ol>
<li><p>Activity에서 액세스
<code>getSupportFragmentManager()</code>메서드를 통해 <code>FragmentManager</code>를 사용할 수 있다. (Kotlin에서는 supportFragmentManager() 사용)</p>
</li>
<li><p>Fragment에서 액세스
Activity뿐만 아니라 Fragment도 하위 Fragment를 1개 이상 호스팅할 수 있다. 하위요소를 관리하는 <code>FragmentManager</code>에는 <code>getChildFragmentManager()</code>로, 호스트 <code>FragmentManager</code>에 액세스할 땐 <code>getParentFragmentManager()</code>를 사용한다.</p>
</li>
</ol>
<br/>
<br/>

<h3 id="3-fragment와-fragmentmanager의--관계">3. Fragment와 FragmentManager의  관계</h3>
<p><img src="https://images.velog.io/images/h-swon/post/b57ce258-2d21-4115-9d7a-27d4d48f6443/image.png" alt=""></p>
<ul>
<li><p>연두색은 Fragment의 Host Activity이다.</p>
</li>
<li><p>Example 1에서는 하늘색으로 표시된 Fragment가 하위의 Fragment 2개를 호스팅하고 있다. </p>
</li>
<li><p>Example 2에서는 하늘색으로 표시된 Fragment가 <code>ViewPager2</code>를 구현한 하위 Fragment 1개를 호스팅하고 있다.</p>
</li>
<li><p>Fragment와 <code>FragmentManager</code>의 관계는 아래와 같다
<img src="https://images.velog.io/images/h-swon/post/efdb73ea-976b-4509-8432-b882907d75ba/image.png" alt=""></p>
<br/>
<br/>
### 4. FragmentManager 사용</li>
<li><p><code>FragmentManager</code>는 Fragment 백스택을 관리한다. 백스택이란 현재 실행하는 <code>FragmentTransaction</code>의 상태를 기억하기 위해 만들어진 개념이다. Fragment를 추가/삭제하는 작업은 <code>FragmentTransaction</code>이란 단위로 commit된다.</p>
</li>
<li><p>뒤로가기 버튼이나 <code>FragmentManager.popBackStack()</code>을 호출하는 경우 최상위 <code>FragmentTransaction</code>이 스택에서 사라진다.</p>
</li>
<li><p><code>FragmentTransaction</code>에서 <code>addToBackStack()</code>을 호출하면 ex) 여러 개의 Fragment 추가,교체 등 많은 작업들이 1개의 <code>FragmentTransaction</code>에 포함되고 <code>popBackStack()</code>로 한 번에 취소할 수 있다.</p>
</li>
<li><p>기존 Fragment 찾기</p>
</li>
</ul>
<ol>
<li><p><code>findFragmentById()</code>를 이용해서 Fragment Container의 현재 참조하고 있는 Fragment를 가져올 수 있다.</p>
<pre><code class="language-kotlin">supportFragmentManager.commit {
    replace&lt;ExampleFragment&gt;(R.id.fragment_container)
    setReorderingAllowed(true)
    addToBackStack(null)
 }

 ... 
val fragment: ExampleFragment =
supportFragmentManager.findFragmentById(R.id.fragment_container) as ExampleFragment</code></pre>
</li>
<li><p>Fragment에 고유한 Tag를 부여하고 <code>findFragmentByTag()</code>를 사용.layout 내에서 정의되거나 <code>FragmentTransaction</code>내에서 add(), replace()할 때 <code>android:tag</code> XML 속성을 사용해서 태그를 할당한다.</p>
<pre><code class="language-kotlin">supportFragmentManager.commit {
replace&lt;ExampleFragment&gt;(R.id.fragment_container, &quot;tag&quot;)
setReorderingAllowed(true)
addToBackStack(null)
}
</code></pre>
</li>
</ol>
<p>...</p>
<p>val fragment: ExampleFragment =
        supportFragmentManager.findFragmentByTag(&quot;tag&quot;) as ExampleFragment</p>
<pre><code>

&lt;br/&gt;
&lt;br/&gt;

### 5. FragmentTransaction 실행
- layout 내에 Fragment를 표시하려면 `FragmentManager`를 사용해 `FragmentTransaction`을 만들고 add()나 replace()를 한다.
```kotlin
supportFragmentManager.commit {
   replace&lt;ExampleFragment&gt;(R.id.fragment_container)
   setReorderingAllowed(true)
   addToBackStack(&quot;name&quot;) // name can be null
}</code></pre><ul>
<li><p><code>setReorderingAllowed(true)</code>는 Fragment 전환을 최적화시킨다. commit 시 해당 속성을 지정해주는게 좋다.</p>
</li>
<li><p><code>addToBackStack()</code>호출하면 <code>FragmentTransaction</code>이 백스택에 commit된다. <code>addToBackStack()</code>호출할 때 매개변수로 name을 지정하게 되면 <code>popBackStack()</code>시 해당 name을 이용해 특정 Transaction으로 돌아갈 수 있다.</p>
</li>
<li><p>Fragment를 삭제할 때 <code>addToBackStack()</code>을 호출하지 않으면 삭제된 Fragment는 commit시 없어지므로 다시 탐색할 수 없다. 만약에 삭제할 때<code>addToBackStack()</code>을 호출했다면 Fragment는 <code>STOPPED</code>상태에 머물렀다가 나중에 사용자가 뒤로 탐색했을 때 <code>RESUMED</code>상태가 된다.</p>
</li>
<li><p><code>FragmentTransaction</code>내에서 기본 탐색 Fragment를 지정하려면 Transaction에서 <code>setPrimaryNavigationFragment()</code> 메서드를 호출해서 <code>childFragmentManager</code>에 기본 컨트롤이 있어야하는 Fragment 인스턴스를 전달한다.</p>
</li>
</ul>
]]></description>
        </item>
    </channel>
</rss>