Jekyll에 Giscus로 comment 기능 추가
Jekyll에 Giscus를 추가하는 방법은 간단하며, 아래 단계를 따르면 됩니다.
Giscus란?
Giscus는 GitHub Discussions를 기반으로 한 오픈소스 댓글 시스템입니다. 기존의 Disqus나 utterances와 비교하여 여러 장점이 있습니다:
| 비교 항목 | Giscus | Disqus | utterances |
|---|---|---|---|
| 가격 | 무료 | 무료(광고)/유료 | 무료 |
| 데이터 저장 | GitHub Discussions | Disqus 서버 | GitHub Issues |
| 광고 | 없음 | 무료 플랜에 있음 | 없음 |
| 반응(리액션) | 지원 | 지원 | 미지원 |
| 댓글 스레딩 | 지원 | 지원 | 미지원 |
| 다크 모드 | 지원 | 제한적 | 지원 |
| 데이터 소유권 | 사용자 | Disqus | 사용자 |
Giscus는 댓글이 GitHub Discussions에 저장되므로 데이터의 소유권이 사용자에게 있으며, 언제든지 마이그레이션이 가능합니다.
사전 준비
Giscus를 사용하기 전에 아래 조건을 충족해야 합니다:
- 공개 GitHub 저장소: 댓글이 저장될 저장소가 공개(public)여야 합니다.
- Discussions 기능 활성화: 저장소 Settings → General → Features에서 Discussions를 체크합니다.
- Giscus 앱 설치: giscus app을 저장소에 설치합니다.
1. Giscus 설정하기
- Giscus 공식 웹사이트에 접속합니다.
- 아래 정보를 입력합니다:
- Repository: 댓글을 저장할 GitHub 저장소 선택 (예: your-username/your-repo)
- Discussion Category: Giscus에서 사용할 Discussion 카테고리 선택 (Announcements 추천)
- Mapping: 페이지와 댓글을 연결하는 방식 선택 (예: pathname)
- Reaction: 사용자가 댓글에 반응할 수 있도록 활성화할지 여부 설정
- Theme: Giscus 위젯의 테마 설정 (예: light, dark, preferred_color_scheme)
- 기타 필요 옵션 설정 후 Code Snippet 복사.
Mapping 옵션 설명
- pathname: URL 경로로 매핑. 가장 일반적이고 안정적인 방식입니다.
- URL: 전체 URL로 매핑. 도메인 변경 시 댓글이 분리될 수 있습니다.
- title: 페이지 제목으로 매핑. 제목 변경 시 댓글이 분리될 수 있습니다.
- og:title: Open Graph 제목으로 매핑.
- 특정 용어: 직접 지정한 용어로 매핑.
대부분의 경우 pathname 방식을 권장합니다.
2. Jekyll 테마 수정
Giscus 스크립트를 Jekyll 블로그의 적절한 위치에 추가합니다.
(1) _layouts 파일 수정
Giscus를 추가할 위치에 따라 주로 post.html 또는 default.html 파일을 수정합니다.
예: _layouts/post.html
<article>
<article class="post h-entry" itemscope itemtype="http://schema.org/BlogPosting">
<header class="post-header">
<h1 class="post-title p-name" itemprop="name headline">Kotlin 클래스와 객체: Class, Data Class, Sealed Class, Object</h1>
<p class="post-meta">
<time class="dt-published" datetime="2025-01-25T04:35:00+00:00" itemprop="datePublished">Jan 25, 2025
</time></p><div class="post-categories"><a href="/Programming/" class="post-category-badge">Programming</a><span class="category-separator">›</span><a href="/Kotlin/" class="post-category-badge">Kotlin</a></div></header><img src="/assets/images/posts/thumbnails/2025-12-28-kotlin-classes-objects.png" alt="Kotlin 클래스와 객체: Class, Data Class, Sealed Class, Object" class="post-thumbnail" itemprop="image"><div class="post-content e-content" itemprop="articleBody">
<p>Kotlin은 객체 지향 프로그래밍을 위한 풍부한 기능을 제공합니다. 이 포스트에서는 다양한 클래스 유형과 객체에 대해 알아보겠습니다.</p>
<h2 id="클래스-선언">클래스 선언</h2>
<h3 id="기본-클래스">기본 클래스</h3>
<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// 파라미터 없는 경우</span>
<span class="kd">class</span> <span class="nc">Greeter</span><span class="p">()</span> <span class="p">{</span>
<span class="k">fun</span> <span class="nf">greet</span><span class="p">()</span> <span class="p">{</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="c1">// read only, mutable 파라미터</span>
<span class="kd">class</span> <span class="nc">Greeter</span><span class="p">(</span><span class="kd">val</span> <span class="py">name</span><span class="p">:</span> <span class="nc">String</span><span class="p">,</span> <span class="kd">var</span> <span class="py">age</span><span class="p">:</span> <span class="nc">Int</span><span class="p">)</span> <span class="p">{</span>
<span class="k">fun</span> <span class="nf">greet</span><span class="p">()</span> <span class="p">{</span>
<span class="nf">println</span><span class="p">(</span><span class="s">"Hello, ${name}"</span><span class="p">)</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="c1">// body가 없는 경우 중괄호 생략 가능</span>
<span class="kd">class</span> <span class="nc">A</span><span class="p">(</span><span class="n">a</span><span class="p">:</span> <span class="nc">Int</span><span class="p">)</span>
<span class="c1">// visibility modifier와 annotation이 있는 생성자</span>
<span class="kd">class</span> <span class="nc">Customer</span> <span class="k">public</span> <span class="nd">@Inject</span> <span class="k">constructor</span><span class="p">(</span><span class="n">name</span><span class="p">:</span> <span class="nc">String</span><span class="p">)</span> <span class="p">{</span> <span class="o">..</span><span class="p">.</span> <span class="p">}</span>
</code></pre></div></div>
<h3 id="상속">상속</h3>
<p>기본적으로 Kotlin의 모든 클래스는 <code class="language-plaintext highlighter-rouge">final</code>입니다. 상속을 허용하려면 <code class="language-plaintext highlighter-rouge">open</code> 키워드를 사용해야 합니다.</p>
<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">open</span> <span class="kd">class</span> <span class="nc">A</span> <span class="c1">// 상속 가능</span>
<span class="kd">class</span> <span class="nc">B</span> <span class="p">:</span> <span class="nc">A</span><span class="p">()</span> <span class="p">{</span>
<span class="k">override</span> <span class="k">fun</span> <span class="nf">foo</span><span class="p">(</span><span class="n">i</span><span class="p">:</span> <span class="nc">Int</span><span class="p">)</span> <span class="p">{</span> <span class="o">..</span><span class="p">.</span> <span class="p">}</span>
<span class="p">}</span>
<span class="c1">// 파라미터가 있는 클래스 상속</span>
<span class="kd">class</span> <span class="nc">Rectangle</span><span class="p">(</span>
<span class="kd">var</span> <span class="py">height</span><span class="p">:</span> <span class="nc">Double</span><span class="p">,</span>
<span class="kd">var</span> <span class="py">length</span><span class="p">:</span> <span class="nc">Double</span>
<span class="p">)</span> <span class="p">:</span> <span class="nc">Shape</span><span class="p">(</span><span class="nf">listOf</span><span class="p">(</span><span class="n">height</span><span class="p">,</span> <span class="n">length</span><span class="p">,</span> <span class="n">height</span><span class="p">,</span> <span class="n">length</span><span class="p">))</span> <span class="p">{</span> <span class="o">..</span><span class="p">.</span> <span class="p">}</span>
</code></pre></div></div>
<h3 id="추상-클래스">추상 클래스</h3>
<p>추상 클래스는 <code class="language-plaintext highlighter-rouge">open</code> 키워드가 필요 없습니다.</p>
<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">abstract</span> <span class="kd">class</span> <span class="nc">Shape</span><span class="p">(</span><span class="kd">val</span> <span class="py">sides</span><span class="p">:</span> <span class="nc">List</span><span class="p"><</span><span class="nc">Double</span><span class="p">>)</span> <span class="p">{</span>
<span class="kd">val</span> <span class="py">perimeter</span><span class="p">:</span> <span class="nc">Double</span> <span class="k">get</span><span class="p">()</span> <span class="p">=</span> <span class="n">sides</span><span class="p">.</span><span class="nf">sum</span><span class="p">()</span>
<span class="k">abstract</span> <span class="k">fun</span> <span class="nf">calculateArea</span><span class="p">():</span> <span class="nc">Double</span>
<span class="p">}</span>
<span class="c1">// 비추상 멤버를 추상으로 오버라이드</span>
<span class="k">open</span> <span class="kd">class</span> <span class="nc">Base</span> <span class="p">{</span>
<span class="k">open</span> <span class="k">fun</span> <span class="nf">f</span><span class="p">()</span> <span class="p">{}</span>
<span class="p">}</span>
<span class="k">abstract</span> <span class="kd">class</span> <span class="nc">Derived</span> <span class="p">:</span> <span class="nc">Base</span><span class="p">()</span> <span class="p">{</span>
<span class="k">override</span> <span class="k">abstract</span> <span class="k">fun</span> <span class="nf">f</span><span class="p">()</span>
<span class="p">}</span>
</code></pre></div></div>
<h3 id="생성자">생성자</h3>
<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Secondary constructor</span>
<span class="kd">class</span> <span class="nc">Person</span> <span class="p">{</span>
<span class="k">constructor</span><span class="p">(</span><span class="n">parent</span><span class="p">:</span> <span class="nc">Person</span><span class="p">)</span> <span class="p">{</span>
<span class="n">parent</span><span class="p">.</span><span class="n">children</span><span class="p">.</span><span class="nf">add</span><span class="p">(</span><span class="k">this</span><span class="p">)</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="c1">// Primary constructor가 있는 경우 delegation 필수</span>
<span class="kd">class</span> <span class="nc">Person</span><span class="p">(</span><span class="kd">val</span> <span class="py">name</span><span class="p">:</span> <span class="nc">String</span><span class="p">)</span> <span class="p">{</span>
<span class="k">constructor</span><span class="p">(</span><span class="n">name</span><span class="p">:</span> <span class="nc">String</span><span class="p">,</span> <span class="n">parent</span><span class="p">:</span> <span class="nc">Person</span><span class="p">)</span> <span class="p">:</span> <span class="k">this</span><span class="p">(</span><span class="n">name</span><span class="p">)</span> <span class="p">{</span>
<span class="n">parent</span><span class="p">.</span><span class="n">children</span><span class="p">.</span><span class="nf">add</span><span class="p">(</span><span class="k">this</span><span class="p">)</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="c1">// super 생성자 호출</span>
<span class="kd">class</span> <span class="nc">MyView</span> <span class="p">:</span> <span class="nc">View</span> <span class="p">{</span>
<span class="k">constructor</span><span class="p">(</span><span class="n">ctx</span><span class="p">:</span> <span class="nc">Context</span><span class="p">)</span> <span class="p">:</span> <span class="k">super</span><span class="p">(</span><span class="n">ctx</span><span class="p">)</span>
<span class="k">constructor</span><span class="p">(</span><span class="n">ctx</span><span class="p">:</span> <span class="nc">Context</span><span class="p">,</span> <span class="n">attrs</span><span class="p">:</span> <span class="nc">AttributeSet</span><span class="p">)</span> <span class="p">:</span> <span class="k">super</span><span class="p">(</span><span class="n">ctx</span><span class="p">,</span> <span class="n">attrs</span><span class="p">)</span>
<span class="p">}</span>
<span class="c1">// private constructor</span>
<span class="kd">class</span> <span class="nc">C</span> <span class="k">private</span> <span class="k">constructor</span><span class="p">(</span><span class="n">a</span><span class="p">:</span> <span class="nc">Int</span><span class="p">)</span> <span class="p">{</span> <span class="o">..</span><span class="p">.</span> <span class="p">}</span>
<span class="c1">// private property in constructor</span>
<span class="kd">class</span> <span class="nc">ParameterizedClass</span><span class="p"><</span><span class="nc">A</span><span class="p">>(</span><span class="k">private</span> <span class="kd">val</span> <span class="py">value</span><span class="p">:</span> <span class="nc">A</span><span class="p">)</span> <span class="p">{</span>
<span class="k">fun</span> <span class="nf">getValue</span><span class="p">():</span> <span class="nc">A</span> <span class="p">=</span> <span class="n">value</span>
<span class="p">}</span>
</code></pre></div></div>
<h3 id="초기화-블록">초기화 블록</h3>
<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="nc">Customer</span><span class="p">(</span><span class="n">name</span><span class="p">:</span> <span class="nc">String</span><span class="p">)</span> <span class="p">{</span>
<span class="nf">init</span> <span class="p">{</span>
<span class="n">logger</span><span class="p">.</span><span class="nf">info</span><span class="p">(</span><span class="s">"Customer initialized with value ${name}"</span><span class="p">)</span>
<span class="p">}</span>
<span class="kd">val</span> <span class="py">customerKey</span> <span class="p">=</span> <span class="n">name</span><span class="p">.</span><span class="nf">toUpperCase</span><span class="p">()</span>
<span class="p">}</span>
</code></pre></div></div>
<h3 id="중첩-클래스">중첩 클래스</h3>
<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Static nested class (기본)</span>
<span class="kd">class</span> <span class="nc">Outer</span> <span class="p">{</span>
<span class="k">private</span> <span class="kd">val</span> <span class="py">bar</span><span class="p">:</span> <span class="nc">Int</span> <span class="p">=</span> <span class="mi">1</span>
<span class="kd">class</span> <span class="nc">Nested</span> <span class="p">{</span>
<span class="k">fun</span> <span class="nf">foo</span><span class="p">()</span> <span class="p">=</span> <span class="mi">2</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="kd">val</span> <span class="py">demo</span> <span class="p">=</span> <span class="nc">Outer</span><span class="p">.</span><span class="nc">Nested</span><span class="p">().</span><span class="nf">foo</span><span class="p">()</span> <span class="c1">// == 2</span>
<span class="c1">// Inner class (외부 클래스 참조 가능)</span>
<span class="kd">class</span> <span class="nc">Outer</span> <span class="p">{</span>
<span class="k">private</span> <span class="kd">val</span> <span class="py">bar</span><span class="p">:</span> <span class="nc">Int</span> <span class="p">=</span> <span class="mi">1</span>
<span class="k">inner</span> <span class="kd">class</span> <span class="nc">Inner</span> <span class="p">{</span>
<span class="k">fun</span> <span class="nf">foo</span><span class="p">()</span> <span class="p">=</span> <span class="n">bar</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="kd">val</span> <span class="py">demo</span> <span class="p">=</span> <span class="nc">Outer</span><span class="p">().</span><span class="nc">Inner</span><span class="p">().</span><span class="nf">foo</span><span class="p">()</span> <span class="c1">// == 1</span>
</code></pre></div></div>
<h3 id="메서드-오버라이딩">메서드 오버라이딩</h3>
<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">open</span> <span class="kd">class</span> <span class="nc">Base</span> <span class="p">{</span>
<span class="k">open</span> <span class="k">fun</span> <span class="nf">v</span><span class="p">()</span> <span class="p">{}</span>
<span class="k">fun</span> <span class="nf">nv</span><span class="p">()</span> <span class="p">{}</span> <span class="c1">// final by default</span>
<span class="p">}</span>
<span class="kd">class</span> <span class="nc">Derived</span><span class="p">()</span> <span class="p">:</span> <span class="nc">Base</span><span class="p">()</span> <span class="p">{</span>
<span class="k">override</span> <span class="k">fun</span> <span class="nf">v</span><span class="p">()</span> <span class="p">{}</span>
<span class="c1">// 추가 오버라이드 방지</span>
<span class="k">final</span> <span class="k">override</span> <span class="k">fun</span> <span class="nf">v</span><span class="p">()</span> <span class="p">{}</span>
<span class="p">}</span>
</code></pre></div></div>
<h3 id="다중-상속에서의-충돌-해결">다중 상속에서의 충돌 해결</h3>
<p>인터페이스와 클래스에서 같은 시그니처의 메서드가 있을 경우:</p>
<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">open</span> <span class="kd">class</span> <span class="nc">A</span> <span class="p">{</span>
<span class="k">open</span> <span class="k">fun</span> <span class="nf">f</span><span class="p">()</span> <span class="p">{</span> <span class="nf">print</span><span class="p">(</span><span class="s">"A"</span><span class="p">)</span> <span class="p">}</span>
<span class="k">fun</span> <span class="nf">a</span><span class="p">()</span> <span class="p">{</span> <span class="nf">print</span><span class="p">(</span><span class="s">"a"</span><span class="p">)</span> <span class="p">}</span>
<span class="p">}</span>
<span class="kd">interface</span> <span class="nc">B</span> <span class="p">{</span>
<span class="k">fun</span> <span class="nf">f</span><span class="p">()</span> <span class="p">{</span> <span class="nf">print</span><span class="p">(</span><span class="s">"B"</span><span class="p">)</span> <span class="p">}</span> <span class="c1">// interface members are 'open' by default</span>
<span class="k">fun</span> <span class="nf">b</span><span class="p">()</span> <span class="p">{</span> <span class="nf">print</span><span class="p">(</span><span class="s">"b"</span><span class="p">)</span> <span class="p">}</span>
<span class="p">}</span>
<span class="kd">class</span> <span class="nc">C</span><span class="p">()</span> <span class="p">:</span> <span class="nc">A</span><span class="p">(),</span> <span class="nc">B</span> <span class="p">{</span>
<span class="c1">// 컴파일러가 f() 오버라이드를 요구함</span>
<span class="k">override</span> <span class="k">fun</span> <span class="nf">f</span><span class="p">()</span> <span class="p">{</span>
<span class="k">super</span><span class="p"><</span><span class="nc">A</span><span class="p">>.</span><span class="nf">f</span><span class="p">()</span> <span class="c1">// A.f() 호출</span>
<span class="k">super</span><span class="p"><</span><span class="nc">B</span><span class="p">>.</span><span class="nf">f</span><span class="p">()</span> <span class="c1">// B.f() 호출</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<h3 id="프로퍼티-오버라이딩">프로퍼티 오버라이딩</h3>
<p>Kotlin에서는 프로퍼티도 오버라이드할 수 있습니다. <code class="language-plaintext highlighter-rouge">val</code>을 <code class="language-plaintext highlighter-rouge">var</code>로 오버라이드할 수 있지만, 그 반대는 불가능합니다.</p>
<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">open</span> <span class="kd">class</span> <span class="nc">Foo</span> <span class="p">{</span>
<span class="k">open</span> <span class="kd">val</span> <span class="py">x</span><span class="p">:</span> <span class="nc">Int</span> <span class="k">get</span><span class="p">()</span> <span class="p">{</span> <span class="o">..</span><span class="p">.</span> <span class="p">}</span>
<span class="p">}</span>
<span class="kd">class</span> <span class="nc">Bar1</span> <span class="p">:</span> <span class="nc">Foo</span><span class="p">()</span> <span class="p">{</span>
<span class="k">override</span> <span class="kd">var</span> <span class="py">x</span><span class="p">:</span> <span class="nc">Int</span> <span class="p">=</span> <span class="o">..</span><span class="p">.</span> <span class="c1">// val -> var 가능</span>
<span class="p">}</span>
<span class="c1">// Primary constructor에서 오버라이드</span>
<span class="kd">interface</span> <span class="nc">Foo</span> <span class="p">{</span>
<span class="kd">val</span> <span class="py">count</span><span class="p">:</span> <span class="nc">Int</span>
<span class="p">}</span>
<span class="kd">class</span> <span class="nc">Bar1</span><span class="p">(</span><span class="k">override</span> <span class="kd">val</span> <span class="py">count</span><span class="p">:</span> <span class="nc">Int</span><span class="p">)</span> <span class="p">:</span> <span class="nc">Foo</span>
</code></pre></div></div>
<h3 id="this와-super-레이블">this와 super 레이블</h3>
<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="nc">A</span> <span class="p">{</span>
<span class="k">inner</span> <span class="kd">class</span> <span class="nc">B</span> <span class="p">{</span>
<span class="k">fun</span> <span class="nc">Int</span><span class="p">.</span><span class="nf">foo</span><span class="p">()</span> <span class="p">{</span>
<span class="kd">val</span> <span class="py">a</span> <span class="p">=</span> <span class="k">this</span><span class="nd">@A</span> <span class="c1">// A's this</span>
<span class="kd">val</span> <span class="py">b</span> <span class="p">=</span> <span class="k">this</span><span class="nd">@B</span> <span class="c1">// B's this</span>
<span class="kd">val</span> <span class="py">c</span> <span class="p">=</span> <span class="k">this</span> <span class="c1">// foo()'s receiver, an Int</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="kd">class</span> <span class="nc">Bar</span> <span class="p">:</span> <span class="nc">Foo</span><span class="p">()</span> <span class="p">{</span>
<span class="k">override</span> <span class="k">fun</span> <span class="nf">f</span><span class="p">()</span> <span class="p">{</span> <span class="cm">/* ... */</span> <span class="p">}</span>
<span class="k">inner</span> <span class="kd">class</span> <span class="nc">Baz</span> <span class="p">{</span>
<span class="k">fun</span> <span class="nf">g</span><span class="p">()</span> <span class="p">{</span>
<span class="k">super</span><span class="nd">@Bar</span><span class="p">.</span><span class="nf">f</span><span class="p">()</span> <span class="c1">// Foo의 f() 호출</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<h2 id="인터페이스">인터페이스</h2>
<h3 id="선언과-구현">선언과 구현</h3>
<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">interface</span> <span class="nc">RectangleProperties</span> <span class="p">{</span>
<span class="kd">val</span> <span class="py">isSquare</span><span class="p">:</span> <span class="nc">Boolean</span>
<span class="p">}</span>
<span class="c1">// 메서드 기본 구현 가능</span>
<span class="kd">interface</span> <span class="nc">B</span> <span class="p">{</span>
<span class="k">fun</span> <span class="nf">f</span><span class="p">()</span> <span class="p">{</span> <span class="nf">print</span><span class="p">(</span><span class="s">"B"</span><span class="p">)</span> <span class="p">}</span>
<span class="k">fun</span> <span class="nf">b</span><span class="p">()</span> <span class="p">{</span> <span class="nf">print</span><span class="p">(</span><span class="s">"b"</span><span class="p">)</span> <span class="p">}</span>
<span class="p">}</span>
<span class="c1">// 구현</span>
<span class="kd">class</span> <span class="nc">Rectangle</span> <span class="p">:</span> <span class="nc">Shape</span><span class="p">(),</span> <span class="nc">RectangleProperties</span> <span class="p">{</span>
<span class="k">override</span> <span class="kd">val</span> <span class="py">isSquare</span><span class="p">:</span> <span class="nc">Boolean</span> <span class="k">get</span><span class="p">()</span> <span class="p">=</span> <span class="n">length</span> <span class="p">==</span> <span class="n">height</span>
<span class="p">}</span>
</code></pre></div></div>
<h2 id="data-class">Data Class</h2>
<p>Data class는 데이터를 보관하기 위한 클래스로, 다음 함수들을 자동 생성합니다:</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">equals()</code> / <code class="language-plaintext highlighter-rouge">hashCode()</code></li>
<li><code class="language-plaintext highlighter-rouge">toString()</code> - “User(name=John, age=42)” 형식</li>
<li><code class="language-plaintext highlighter-rouge">componentN()</code> 함수들</li>
<li><code class="language-plaintext highlighter-rouge">copy()</code> 함수</li>
</ul>
<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">data class</span> <span class="nc">User</span><span class="p">(</span><span class="kd">val</span> <span class="py">name</span><span class="p">:</span> <span class="nc">String</span><span class="p">,</span> <span class="kd">val</span> <span class="py">age</span><span class="p">:</span> <span class="nc">Int</span><span class="p">)</span>
<span class="c1">// copy 사용</span>
<span class="kd">val</span> <span class="py">jack</span> <span class="p">=</span> <span class="nc">User</span><span class="p">(</span><span class="n">name</span> <span class="p">=</span> <span class="s">"Jack"</span><span class="p">,</span> <span class="n">age</span> <span class="p">=</span> <span class="mi">1</span><span class="p">)</span>
<span class="kd">val</span> <span class="py">olderJack</span> <span class="p">=</span> <span class="n">jack</span><span class="p">.</span><span class="nf">copy</span><span class="p">(</span><span class="n">age</span> <span class="p">=</span> <span class="mi">2</span><span class="p">)</span>
</code></pre></div></div>
<h3 id="destructuring-declarations">Destructuring Declarations</h3>
<p><code class="language-plaintext highlighter-rouge">componentN()</code> 함수가 있는 클래스에서 사용 가능합니다.</p>
<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">val</span> <span class="p">(</span><span class="py">name</span><span class="p">,</span> <span class="py">age</span><span class="p">)</span> <span class="p">=</span> <span class="n">person</span>
<span class="c1">// 아래와 동일</span>
<span class="kd">val</span> <span class="py">name</span> <span class="p">=</span> <span class="n">person</span><span class="p">.</span><span class="nf">component1</span><span class="p">()</span>
<span class="kd">val</span> <span class="py">age</span> <span class="p">=</span> <span class="n">person</span><span class="p">.</span><span class="nf">component2</span><span class="p">()</span>
<span class="c1">// for 문에서</span>
<span class="k">for</span> <span class="p">((</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">)</span> <span class="k">in</span> <span class="n">collection</span><span class="p">)</span> <span class="p">{</span> <span class="o">..</span><span class="p">.</span> <span class="p">}</span>
<span class="k">for</span> <span class="p">((</span><span class="n">key</span><span class="p">,</span> <span class="n">value</span><span class="p">)</span> <span class="k">in</span> <span class="n">map</span><span class="p">)</span> <span class="p">{</span> <span class="o">..</span><span class="p">.</span> <span class="p">}</span>
<span class="c1">// 사용하지 않는 변수</span>
<span class="kd">val</span> <span class="p">(</span><span class="py">_</span><span class="p">,</span> <span class="py">status</span><span class="p">)</span> <span class="p">=</span> <span class="nf">getResult</span><span class="p">()</span>
</code></pre></div></div>
<h3 id="여러-값-반환하기">여러 값 반환하기</h3>
<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">data class</span> <span class="nc">Result</span><span class="p">(</span><span class="kd">val</span> <span class="py">result</span><span class="p">:</span> <span class="nc">Int</span><span class="p">,</span> <span class="kd">val</span> <span class="py">status</span><span class="p">:</span> <span class="nc">Status</span><span class="p">)</span>
<span class="k">fun</span> <span class="nf">function</span><span class="p">(</span><span class="o">..</span><span class="p">.):</span> <span class="nc">Result</span> <span class="p">{</span>
<span class="c1">// computations</span>
<span class="k">return</span> <span class="nc">Result</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="n">status</span><span class="p">)</span>
<span class="p">}</span>
<span class="kd">val</span> <span class="p">(</span><span class="py">result</span><span class="p">,</span> <span class="py">status</span><span class="p">)</span> <span class="p">=</span> <span class="nf">function</span><span class="p">(</span><span class="o">..</span><span class="p">.)</span>
</code></pre></div></div>
<h2 id="sealed-class">Sealed Class</h2>
<p>Sealed class는 같은 파일 내에서만 상속이 가능합니다. 이를 통해 제한된 클래스 계층을 정의할 수 있습니다.</p>
<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">sealed</span> <span class="kd">class</span> <span class="nc">Expr</span>
<span class="kd">data class</span> <span class="nc">Const</span><span class="p">(</span><span class="kd">val</span> <span class="py">number</span><span class="p">:</span> <span class="nc">Double</span><span class="p">)</span> <span class="p">:</span> <span class="nc">Expr</span><span class="p">()</span>
<span class="kd">data class</span> <span class="nc">Sum</span><span class="p">(</span><span class="kd">val</span> <span class="py">e1</span><span class="p">:</span> <span class="nc">Expr</span><span class="p">,</span> <span class="kd">val</span> <span class="py">e2</span><span class="p">:</span> <span class="nc">Expr</span><span class="p">)</span> <span class="p">:</span> <span class="nc">Expr</span><span class="p">()</span>
<span class="kd">object</span> <span class="nc">NotANumber</span> <span class="p">:</span> <span class="nc">Expr</span><span class="p">()</span>
</code></pre></div></div>
<h3 id="when과-함께-사용">when과 함께 사용</h3>
<p>Sealed class의 모든 하위 클래스가 처리되면 <code class="language-plaintext highlighter-rouge">else</code> 절이 필요 없습니다.</p>
<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">fun</span> <span class="nf">eval</span><span class="p">(</span><span class="n">expr</span><span class="p">:</span> <span class="nc">Expr</span><span class="p">):</span> <span class="nc">Double</span> <span class="p">=</span> <span class="k">when</span><span class="p">(</span><span class="n">expr</span><span class="p">)</span> <span class="p">{</span>
<span class="k">is</span> <span class="nc">Const</span> <span class="p">-></span> <span class="n">expr</span><span class="p">.</span><span class="n">number</span>
<span class="k">is</span> <span class="nc">Sum</span> <span class="p">-></span> <span class="nf">eval</span><span class="p">(</span><span class="n">expr</span><span class="p">.</span><span class="n">e1</span><span class="p">)</span> <span class="p">+</span> <span class="nf">eval</span><span class="p">(</span><span class="n">expr</span><span class="p">.</span><span class="n">e2</span><span class="p">)</span>
<span class="nc">NotANumber</span> <span class="p">-></span> <span class="nc">Double</span><span class="p">.</span><span class="nc">NaN</span>
<span class="c1">// else 절이 필요 없음!</span>
<span class="p">}</span>
</code></pre></div></div>
<h2 id="object">Object</h2>
<h3 id="object-expression-익명-클래스">Object Expression (익명 클래스)</h3>
<p>Java의 anonymous inner class와 유사합니다.</p>
<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">window</span><span class="p">.</span><span class="nf">addMouseListener</span><span class="p">(</span><span class="kd">object</span> <span class="err">: </span><span class="nc">MouseAdapter</span><span class="p">()</span> <span class="p">{</span>
<span class="k">override</span> <span class="k">fun</span> <span class="nf">mouseClicked</span><span class="p">(</span><span class="n">e</span><span class="p">:</span> <span class="nc">MouseEvent</span><span class="p">)</span> <span class="p">{</span> <span class="o">..</span><span class="p">.</span> <span class="p">}</span>
<span class="k">override</span> <span class="k">fun</span> <span class="nf">mouseEntered</span><span class="p">(</span><span class="n">e</span><span class="p">:</span> <span class="nc">MouseEvent</span><span class="p">)</span> <span class="p">{</span> <span class="o">..</span><span class="p">.</span> <span class="p">}</span>
<span class="p">})</span>
<span class="c1">// 여러 인터페이스/클래스 상속</span>
<span class="k">open</span> <span class="kd">class</span> <span class="nc">A</span><span class="p">(</span><span class="n">x</span><span class="p">:</span> <span class="nc">Int</span><span class="p">)</span> <span class="p">{</span>
<span class="k">public</span> <span class="k">open</span> <span class="kd">val</span> <span class="py">y</span><span class="p">:</span> <span class="nc">Int</span> <span class="p">=</span> <span class="n">x</span>
<span class="p">}</span>
<span class="kd">interface</span> <span class="nc">B</span> <span class="p">{</span> <span class="o">..</span><span class="p">.</span> <span class="p">}</span>
<span class="kd">val</span> <span class="py">ab</span><span class="p">:</span> <span class="nc">A</span> <span class="p">=</span> <span class="kd">object</span> <span class="err">: </span><span class="nc">A</span><span class="p">(</span><span class="mi">1</span><span class="p">),</span> <span class="nc">B</span> <span class="p">{</span>
<span class="k">override</span> <span class="kd">val</span> <span class="py">y</span> <span class="p">=</span> <span class="mi">15</span>
<span class="p">}</span>
</code></pre></div></div>
<h3 id="간단한-object">간단한 Object</h3>
<p>타입 없이 간단한 객체를 생성할 수 있습니다.</p>
<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">fun</span> <span class="nf">foo</span><span class="p">()</span> <span class="p">{</span>
<span class="kd">val</span> <span class="py">adHoc</span> <span class="p">=</span> <span class="kd">object</span> <span class="err">{
var x: </span><span class="nc">Int</span> <span class="p">=</span> <span class="mi">0</span>
<span class="kd">var</span> <span class="py">y</span><span class="p">:</span> <span class="nc">Int</span> <span class="p">=</span> <span class="mi">0</span>
<span class="p">}</span>
<span class="nf">print</span><span class="p">(</span><span class="n">adHoc</span><span class="p">.</span><span class="n">x</span> <span class="p">+</span> <span class="n">adHoc</span><span class="p">.</span><span class="n">y</span><span class="p">)</span>
<span class="p">}</span>
</code></pre></div></div>
<h3 id="object-declaration-singleton">Object Declaration (Singleton)</h3>
<p>Kotlin에서 싱글톤을 선언하는 가장 쉬운 방법입니다.</p>
<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">object</span> <span class="nc">Resource</span> <span class="p">{</span>
<span class="kd">val</span> <span class="py">name</span> <span class="p">=</span> <span class="s">"Name"</span>
<span class="p">}</span>
<span class="c1">// 사용</span>
<span class="kd">val</span> <span class="py">resourceName</span> <span class="p">=</span> <span class="nc">Resource</span><span class="p">.</span><span class="n">name</span>
</code></pre></div></div>
<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">object</span> <span class="nc">DataProviderManager</span> <span class="p">{</span>
<span class="k">fun</span> <span class="nf">registerDataProvider</span><span class="p">(</span><span class="n">provider</span><span class="p">:</span> <span class="nc">DataProvider</span><span class="p">)</span> <span class="p">{</span> <span class="o">..</span><span class="p">.</span> <span class="p">}</span>
<span class="kd">val</span> <span class="py">allDataProviders</span><span class="p">:</span> <span class="nc">Collection</span><span class="p"><</span><span class="nc">DataProvider</span><span class="p">></span>
<span class="k">get</span><span class="p">()</span> <span class="p">=</span> <span class="o">..</span><span class="p">.</span>
<span class="p">}</span>
<span class="nc">DataProviderManager</span><span class="p">.</span><span class="nf">registerDataProvider</span><span class="p">(</span><span class="o">..</span><span class="p">.)</span>
</code></pre></div></div>
<h3 id="companion-object">Companion Object</h3>
<p>클래스 내부에 static 멤버를 정의하는 방법입니다.</p>
<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="nc">MyClass</span> <span class="p">{</span>
<span class="k">companion</span> <span class="k">object</span> <span class="nc">Factory</span> <span class="p">{</span>
<span class="k">fun</span> <span class="nf">create</span><span class="p">():</span> <span class="nc">MyClass</span> <span class="p">=</span> <span class="nc">MyClass</span><span class="p">()</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="kd">val</span> <span class="py">instance</span> <span class="p">=</span> <span class="nc">MyClass</span><span class="p">.</span><span class="nf">create</span><span class="p">()</span>
<span class="c1">// 이름 생략 가능</span>
<span class="kd">class</span> <span class="nc">MyClass</span> <span class="p">{</span>
<span class="k">companion</span> <span class="k">object</span> <span class="p">{</span> <span class="p">}</span>
<span class="p">}</span>
<span class="kd">val</span> <span class="py">x</span> <span class="p">=</span> <span class="nc">MyClass</span><span class="p">.</span><span class="nc">Companion</span>
</code></pre></div></div>
<h3 id="companion-object와-인터페이스">Companion Object와 인터페이스</h3>
<p>Companion object도 인터페이스를 구현할 수 있습니다.</p>
<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">interface</span> <span class="nc">Factory</span><span class="p"><</span><span class="nc">T</span><span class="p">></span> <span class="p">{</span>
<span class="k">fun</span> <span class="nf">create</span><span class="p">():</span> <span class="nc">T</span>
<span class="p">}</span>
<span class="kd">class</span> <span class="nc">MyClass</span> <span class="p">{</span>
<span class="k">companion</span> <span class="k">object</span> <span class="p">:</span> <span class="nc">Factory</span><span class="p"><</span><span class="nc">MyClass</span><span class="p">></span> <span class="p">{</span>
<span class="k">override</span> <span class="k">fun</span> <span class="nf">create</span><span class="p">():</span> <span class="nc">MyClass</span> <span class="p">=</span> <span class="nc">MyClass</span><span class="p">()</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<h2 id="표준-라이브러리의-데이터-클래스">표준 라이브러리의 데이터 클래스</h2>
<p>Kotlin 표준 라이브러리에서 제공하는 데이터 클래스들:</p>
<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">Pair</span> <span class="c1">// 두 값을 담는 클래스</span>
<span class="nc">Triple</span> <span class="c1">// 세 값을 담는 클래스</span>
<span class="kd">val</span> <span class="py">pair</span> <span class="p">=</span> <span class="nc">Pair</span><span class="p">(</span><span class="s">"key"</span><span class="p">,</span> <span class="s">"value"</span><span class="p">)</span>
<span class="kd">val</span> <span class="p">(</span><span class="py">key</span><span class="p">,</span> <span class="py">value</span><span class="p">)</span> <span class="p">=</span> <span class="n">pair</span>
</code></pre></div></div>
<h2 id="다음-단계">다음 단계</h2>
<p>클래스와 객체에 대해 알아보았습니다. 다음으로 <a href="/kotlin/kotlin-functions-lambda">함수와 람다</a>에 대해 알아보세요.</p>
</div>
<div class="related-posts">
<h2>Related Posts</h2>
<ul class="related-posts-list">
<li class="related-post-item">
<a href="/backend/kotlin/2025/12/31/kotlin-classes-and-objects.html">
<span class="related-post-title">Kotlin Classes and Objects: Complete OOP Guide</span>
<span class="related-post-meta">
<span class="related-post-category">backend</span>
<span class="related-post-date">2025-12-31</span>
</span>
</a>
</li>
<li class="related-post-item">
<a href="/backend/kotlin/2025/12/30/kotlin-types-and-collections.html">
<span class="related-post-title">Kotlin Types and Collections: Numbers, Strings, Arrays, and Maps</span>
<span class="related-post-meta">
<span class="related-post-category">backend</span>
<span class="related-post-date">2025-12-30</span>
</span>
</a>
</li>
<li class="related-post-item">
<a href="/backend/kotlin/2025/12/30/kotlin-functions-and-lambdas.html">
<span class="related-post-title">Kotlin Functions and Lambdas: Complete Guide</span>
<span class="related-post-meta">
<span class="related-post-category">backend</span>
<span class="related-post-date">2025-12-30</span>
</span>
</a>
</li>
<li class="related-post-item">
<a href="/backend/kotlin/2025/12/29/kotlin-basic-syntax.html">
<span class="related-post-title">Kotlin Basic Syntax: Variables, Operators, Control Flow, and Ranges</span>
<span class="related-post-meta">
<span class="related-post-category">backend</span>
<span class="related-post-date">2025-12-29</span>
</span>
</a>
</li>
</ul>
</div>
<style>
.related-posts {
margin-top: 50px;
padding-top: 30px;
border-top: 1px solid #e0e0e0;
}
.related-posts h2 {
margin-bottom: 20px;
font-size: 1.4em;
color: #333;
}
.related-posts-list {
list-style: none;
padding: 0;
margin: 0;
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 15px;
}
.related-post-item {
background: #f8f9fa;
border-radius: 8px;
transition: transform 0.2s, box-shadow 0.2s;
}
.related-post-item:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}
.related-post-item a {
display: block;
padding: 15px;
text-decoration: none;
color: inherit;
}
.related-post-title {
display: block;
font-weight: 600;
color: #0366d6;
margin-bottom: 8px;
font-size: 0.95em;
line-height: 1.4;
}
.related-post-meta {
display: flex;
justify-content: space-between;
font-size: 0.8em;
color: #666;
}
.related-post-category {
background: #e0e0e0;
padding: 2px 8px;
border-radius: 4px;
text-transform: capitalize;
}
@media (max-width: 600px) {
.related-posts-list {
grid-template-columns: 1fr;
}
}
</style>
<section class="post-comments">
<h2>Comments</h2>
<script src="https://giscus.app/client.js"
data-repo="dss99911/dss99911.github.io"
data-repo-id="R_kgDOK1J8gQ"
data-category="Announcements"
data-category-id="DIC_kwDOK1J8gc4C0Sct"
data-mapping="pathname"
data-strict="0"
data-reactions-enabled="1"
data-emit-metadata="0"
data-input-position="top"
data-theme="preferred_color_scheme"
data-lang="ko"
data-loading="lazy"
crossorigin="anonymous"
async>
</script>
</section>
<style>
.post-comments {
margin-top: 60px;
padding-top: 30px;
border-top: 1px solid #e0e0e0;
}
.post-comments h2 {
margin-bottom: 20px;
font-size: 1.5em;
}
</style>
<a class="u-url" href="/programming/kotlin/2025/01/25/kotlin-classes-objects.html" hidden></a>
</article>
</article>
<div id="giscus-comments"></div>
<script src="https://giscus.app/client.js"
data-repo="your-username/your-repo"
data-repo-id="your-repo-id"
data-category="General"
data-category-id="category-id"
data-mapping="pathname"
data-reactions-enabled="1"
data-theme="light"
data-lang="en"
crossorigin="anonymous"
async>
</script>
(2) 다크 모드 자동 전환
블로그에 다크 모드가 있다면, Giscus 테마도 자동으로 전환할 수 있습니다:
<script>
const theme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
document.querySelector('[data-theme]').setAttribute('data-theme', theme);
</script>
(3) CSS 수정 (선택 사항)
Giscus 위젯이 블로그의 디자인과 잘 어울리도록 필요 시 추가 CSS를 작성합니다.
/* Giscus 컨테이너 간격 조정 */
#giscus-comments {
margin-top: 2rem;
padding-top: 2rem;
border-top: 1px solid #eee;
}
(4) 특정 페이지에서만 댓글 표시
front matter에 변수를 추가하여 특정 페이지에서만 댓글을 표시할 수 있습니다:
{% unless page.no_comments %}
<!-- giscus script here -->
{% endunless %}
3. Jekyll 블로그 빌드 및 확인
-
변경 사항을 저장한 후 Jekyll 블로그를 빌드합니다.
bundle exec jekyll serve - 로컬 서버를 열어 페이지가 제대로 렌더링되었는지 확인합니다.
- giscus가 작동하지 않는다면 GitHub Discussions 설정 또는 repo, category 등의 매개변수를 다시 확인하세요.
문제 해결
- 댓글이 안 보이는 경우: 저장소가 public인지, Discussions가 활성화되어 있는지, giscus 앱이 설치되어 있는지 확인하세요.
- 로컬에서 안 되는 경우: localhost에서는 정상 작동하지 않을 수 있습니다. 배포 후 확인해보세요.
- 잘못된 Discussion에 매핑되는 경우: mapping 설정과 실제 URL 경로가 일치하는지 확인하세요.
4. 배포
변경 사항을 저장소에 푸시하고 배포 사이트에서도 Giscus가 잘 동작하는지 확인합니다.
참고: Giscus는 GitHub Discussions를 기반으로 하기 때문에 저장소에서 Discussions가 활성화되어 있어야 합니다. 댓글이 작성되면 해당 저장소의 Discussions 탭에서 모든 댓글을 관리하고 모더레이션할 수 있습니다.
Comments