<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://parkjunhee9327.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://parkjunhee9327.github.io/" rel="alternate" type="text/html" /><updated>2026-04-02T11:22:17+00:00</updated><id>https://parkjunhee9327.github.io/feed.xml</id><title type="html">베르의 개발세상</title><subtitle>유익하고 재미있는 개발 정보들의 세상</subtitle><author><name>베르</name></author><entry><title type="html">사회복지부터 백엔드 개발까지</title><link href="https://parkjunhee9327.github.io/insight/from-major-to-developer/" rel="alternate" type="text/html" title="사회복지부터 백엔드 개발까지" /><published>2026-04-01T00:00:00+00:00</published><updated>2026-04-01T00:00:00+00:00</updated><id>https://parkjunhee9327.github.io/insight/from-major-to-developer</id><content type="html" xml:base="https://parkjunhee9327.github.io/insight/from-major-to-developer/"><![CDATA[<h1 id="-많은-이들이-통과하는-대입의-문-근데-어느-문으로-들어가지">✨ 많은 이들이 통과하는 “대입”의 문. 근데… 어느 문으로 들어가지?</h1>
<p><a href="https://media.kookmin.ac.kr/news/articleView.html?idxno=103879">우리나라 고등학생의 70% 이상은 대학에 진학한다.</a> 대부분의 학부모와 학생들은 “어느 대학교에 갈 수 있을까”를 가장 주요하게 신경쓴다. 우리나라 대학교는 서열이 있고, 그들은 이 서열에 민감하다. <br />
나도 대학 진학을 희망하는 70%의 고등학생 중 하나였다. 그러나 나의 관심은 달랐다.</p>

<p><br /></p>

<blockquote>
  <p><em>어느 학과로 진학하지?</em></p>
</blockquote>

<p><br /></p>

<p>고등학교 학년이 하나씩 올라갈수록 진학할 수 있는 대학이 어디인지는 비교적 명확해진다. 성적과 생활기록부로 겨냥할 수 있는 대학을 가늠할 수 있기 때문이다. 따라서 대학교 서열 표와 같은 자료를 뒤적이던 나의 친구들과는 달리, ‘어느 대학에 갈 수 있는지’는 나의 주된 관심사가 아니었다.</p>

<p><br /></p>

<p>나에게 중대한 문제는 ‘어느 학과로 진학해야 하는가’였다. 이건 성적과 생활기록부로 파악할 수 없는 문제였다.</p>
<ul>
  <li>대학에서 가르치는 분야는 정규 교육 과정(국/수/사/과/영)과 다르게 현실과 맞닿아있다. 본인의 전공 및 연관 분야의 직업을 택하는 사람도 많다.</li>
  <li>고등 교육기관이니만큼 배움에도 깊이가 있을 것이라 생각했다. 전문 분야를 깊이 익힐 수 있다는 건 곧 역량 상의 차별성이다.</li>
  <li>어느 분야의 고등 교육 과정을 이수할 것인가는 나의 정체성과도 맞닿아 있다. 내가 관심도, 소질도 없는 현대 무용 같은 학과에 진학할 수는 없는 노릇이다.</li>
</ul>

<p><br /></p>

<p>🚩 내가 내린 판단은 다음과 같다.</p>
<ul>
  <li><em>나는 사람 그 자체에 관심이 많다.</em> 국어 과목의 비문학 문제에 심리학자들의 주요 이론이 나오면 지문을 읽지 않고 문제의 답을 다 맞출 정도였다.</li>
  <li><em>사람을 돕는 데에도 관심이 많다.</em> 고등학교 친구들이 고민을 들어줘서 고맙다고, 친구들 간 갈등을 중재해줘서 고맙다고 준 쪽지가 아직도 서랍 한 켠에 보관되어 있다.</li>
  <li>사람에 대한 이해를 바탕으로 + 사람을 도울 수 있는 학과. 사회복지학과였다.</li>
</ul>

<p><br /></p>

<hr />

<h1 id="-냉정한-이타주의자">✨ 냉정한 이타주의자</h1>
<p>내가 사회복지학과를 전공했다고 하면 흔하게 볼 수 있는 반응이 있다.</p>
<ol>
  <li>좋은 일 하시네요. (사회복지사의 이미지를 가장 분명하게 나타내는 말 아닐까 한다)</li>
  <li>사람 돕는 거 아냐? 뭐… 봉사하고 그러냐?</li>
  <li>너가 착한가보다. 그런 학과도 가고.</li>
</ol>

<p><br /></p>

<p>이런 반응들의 공통점이 있다. <strong>감정이나 성품에 기반한 반응이라는 것.</strong> <br />
“사회복지학과”라고 했을 때 흔히 떠올리는 이미지는 “친절하게 미소 짓는 봉사자가 형편이 어려운 어르신께 연탄을 드리는”… 이런 이미지다.</p>

<p><br /></p>

<p>물론 내게도 어려운 이들을 돕고자 하는 사명감이 있다. 나 하나가 아닌 공동체 전체를 위한 삶을 지향한다. 나는 여름마다 홍수로 인해 큰 피해를 입은 지역의 농경지를 복구하는 수해 복구 봉사활동을 3년 간 개근하고 있다. <br />
그러나 사회복지의 관점에서 나의 주된 관심사는 그런 <em>감성적인</em> 것들이 아니었다. 지극히 이성적인, <em>측정 가능하고 객관적인</em> 것들이었다. <br />
-&gt; 지원 대상자가 지닌 욕구 중 가장 시급하며 중요한 욕구를 파악하는 방법 <br />
-&gt; 욕구를 실현 가능한 요구사항으로 설계하는 전략 <br />
-&gt; 성과에 대한 명확하고 객관적인 지표(자기기입식 설문지, 측정한 지표 등)</p>

<p><br /></p>

<p>사람에 대한 관심도 좋고, 어려운 분들을 돕는 것도 좋다. 그러나 그건 <u>감성적으로 막연하게</u> 이뤄져서는 안 된다. 사회복지사는 사회적 약자의 삶의 질을 끌어올리고 보편적 복지를 실현하는 <strong>전문가</strong>다. 전문가에게는 <strong>니즈를 파악하는 역량, 달성 가능한 목표로 치환하는 능력, 프로젝트 계획 능력, 프로젝트의 효과/효율을 측정하는 능력</strong>이 필요하다.</p>

<p><br /></p>

<p><br /></p>

<p>혹자는 나에게 “사회적 약자들을 돕는 숭고한 일을 돈벌이 사업처럼 바꾸려는 거냐!”라고 반문할지도 모르겠다. 나의 관점을 더욱 펼치기 전에 오해를 풀 필요성을 느낀다.</p>

<p>나는 사회적 약자를 돕고 전반적인 삶의 질을 높이는 숭고한 활동을 “돈벌이 같은 활동”이라고 한 적이 없다. 그런 활동들이 얼마나 효과가 있었는지, 투입한 자원 대비 효율이 어땠는지는 반드시 측정해야 한다고 말할 뿐이다. 나는 그렇게 반문하는 사람들에게 묻고 싶다. <br /></p>

<p><strong>“가용한 자원은 한정되어 있고, 그렇기에 복지를 실현하는 활동에 신중하게 접근해야 한다. 이성적이고 객관적인 측정 방법이 없으면 그 활동이 정말로 가치가 있었는지 어떻게 증명할건가?”</strong></p>

<p><br /></p>

<p><br /></p>

<p>감정보다 논리나 이성에 기반하여 판단하고 행동하는 나의 모습은 같은 학과의 친구들 내에서 “별종” 취급을 받았다. <br />
-&gt; 너는 상황을 논리적으로 판단하는 것 같다. <br />
-&gt; 감정적인 다른 친구들과는 다르다. <br /></p>

<p>때로는 이런 반응도 보였다. (나의 무엇을 보고 그렇게 생각하나?라고 물었을 때 뚜렷한 답을 한 친구가 없었다. 말로 설명하기 어려운 나의 인상인 듯 하다.) <br />
-&gt; 인상은 새내기인데 말하는 건 4학년이다. <br />
-&gt; 말하는 단어에서 지성이 느껴진다.</p>

<p><br /></p>

<p>내 관점이 사회복지에 대한 일반적인 이미지와 다소 다르다는 것은 안다. 그러나 어쩌겠나. 분명 필요한 관점인 것을.</p>

<p><br /></p>

<hr />

<h1 id="-요구사항-파악-프로젝트-설계-성과-측정-매력적인데">✨ 요구사항 파악, 프로젝트 설계, 성과 측정… 매력적인데!</h1>
<p>나와 다른 학교를 나온 친구 중에서 개발자를 준비하던 친구가 있다. 그 친구는 내가 어떤 성격의 사람인지 잘 안다. 그렇기에 내게 “마침 유행하는데 논리적 사고력도 필요한” 개발자를 권유했다.</p>

<p><br /></p>

<p>코로나가 유행했던 시기라 Youtube를 조금만 둘러봐도 “00언어 기초 문법”같은 영상이 많았던 시기였다. 나는 패기롭게 C언어를 독학하기 시작했다. <em>가장 어려운 언어를 해도 재미가 있고 이해할 수 있으면 할 만 하겠지.</em> 라는게 나의 생각이었다. <br />
-&gt; 처음으로 “Hello, World!”를 출력했다. <br />
-&gt; 간단한 사칙연산을 수행했다. <br />
-&gt; 터미널로 입력값을 넣은 뒤 의도했던 출력값을 얻었다.</p>

<p><br /></p>

<p>수치와 정해진 종류로 한정된 입력과 출력. 논리적인 로직 설계. 추상적인 요구를 구체적인 코드로 바꾸는 구조. 매력적이었다! 더 발전시키고 싶었다. 그런데 뭔가 부족했다. 직관적으로 봐도 이건 “프로그램”이 아니었다.</p>
<ul>
  <li>DB에 데이터를 넣는다던데. 그건 어떻게 하지?</li>
  <li>파일 하나에서만 뭔가를 하는 건 아닌 거 같은데. 각각 역할이 다른 여러 파일들을 만들 수 없나?</li>
  <li>기능을 더 고도화하고 싶은데. 어떤 구조로 해야 할 지 모르겠네.</li>
</ul>

<p><br /></p>

<p><br /></p>

<p>당시에는 ChatGPT를 필두로 하는 LLM이 갓 등장한 시기였다. 환각도 지금보다 월등히 많았고, 초보적인 수준의 나는 아직 스스로 학습할 수 있는 관점을 기르지 못했다. 나 스스로 학습하고 성장할 수 있는 개발자가 되기 위해서는 “프로젝트 전체의 맥락과 개발자의 감각”을 학습해야 했다.</p>

<p><br /></p>

<p>그게 “풀스택 개발자 학원”에 등록하게 된 이유였다. 프로그램의 전체 흐름을 이해하기에는 6개월도 짧다는 것을 알았으나, 내게는 충분히 가치 있는 시간이었다.</p>
<ul>
  <li>FE부터 BE까지 이어지는 전체 흐름을 파악했다. 어떤 데이터가 어디서 출발해서 어디를 거쳤다가 응답이 되는지를 안다. 개발자의 기틀이 쌓였다.</li>
  <li>언어의 문법을 익히는 것 그 이상의 구조를 배웠다. 여러가지 라이브러리를 사용하고 API도 설계해보니 프로그램에 무엇이 부족하고, 뭐가 필요한지 알게 되었다.</li>
  <li>스스로 학습할 수 있다. 언어의 기초 문법만 알았을 때는 프로그램에 뭐가 부족한지도 몰랐다. ‘클래스 간 커플링’, ‘클래스의 책임’같은 기본 개념을 알고 있으니 이제 프로그램에 무엇이 부족한지도 보인다. (예시: JSON을 수동으로 파싱하는 게 번거로운데, 관련 도구는 뭐지?)</li>
</ul>

<p><br /></p>

<hr />

<h1 id="-지금의-나는-어떠한가">✨ 지금의 나는 어떠한가</h1>
<p>나는 프론트엔드도, 백엔드도 좋다. 둘 다 데이터를 다루고, 검증하고, 결과를 산출하는 <strong>논리적이고 정확하며 객관적인</strong> 성격이 가미되어 있다.</p>

<p><br /></p>

<p>나는 아무래도 백엔드가 더 좋기는 하다.</p>
<ul>
  <li>더욱 치밀한 수준의 검증과 보안이 요구된다. (화면 깨지기 vs 회원 정보 유출)</li>
  <li>시각적 요소 및 사용자의 편의를 고려하는 것 보다 데이터 처리를 더 선호한다.</li>
</ul>

<p><br /></p>

<p>단순한 기능 개발 뿐 아니라 인프라, 횡단 관심사를 개발하는 것도 좋다.</p>
<ul>
  <li>횡단 관심사: 프로젝트에 있는 모든 기능이 의존하는 기능. 애플리케이션 자체를 이해해야 하기에 단편적인 기능 그 이상의 넓은 시야를 기를 수 있다.</li>
  <li>인프라: 서버를 지탱하는 역할. 백엔드 개발자는 “기능만 만드는 사람”이 아니라 “서버를 관리/유지/확장하는 사람”이다. 모니터링, 로깅 등 기능을 관리하는 기능이 있어야 좋은 기능이 개발된다.</li>
  <li>백엔드 개발자는 기능을 넘어 서버 그 자체를 다루는 직군이다. 그러니 단순한 기능 구현을 넘은, 넓은 범주를 관리하는 영역들이 매력적이다. (나로 인해 로그인이 막혀 프로젝트 전체의 일정이 지연되는 경험은 힘들고도 뜻 깊은 경험이었다)</li>
</ul>

<p><br /></p>

<p>습득하고 싶은 역량이 많아서 우선순위 조정 후 차근차근 익히려고 한다.</p>
<ul>
  <li>(1순위) Docker + 모니터링 기능 기반 프로파일링(Pyroscope) 개발</li>
  <li>대량 트래픽 발생 도구: 프로파일링 기능을 검증할 목적으로 학습 예정.</li>
  <li>CI/CD 기능: GitHub Actions, Jenkins. 현재 사이드 프로젝트에서 개발한 팀원이 있어서 참고할 예정</li>
  <li>비동기 요청: 사이드 프로젝트 팀에 WebSocket 기반 실시간 채팅 기능의 도입을 추진할 계획.</li>
  <li>AWS: 사이드 프로젝트의 Confluence에 관련 문서가 있음을 확인. 참고할 예정.</li>
</ul>

<p><br /></p>

<p>나는 너무 섵부른 계획까지는 세우지 않는다. 위의 항목들을 거친 후에는 자연히 또 새롭게 익힐 역량들이 나타나리라고 생각한다. 기능 개발에서 인프라/횡단 관심사까지 나아간 나의 발자취처럼 말이다.</p>]]></content><author><name>베르</name></author><category term="insight" /><summary type="html"><![CDATA[✨ 많은 이들이 통과하는 “대입”의 문. 근데… 어느 문으로 들어가지? 우리나라 고등학생의 70% 이상은 대학에 진학한다. 대부분의 학부모와 학생들은 “어느 대학교에 갈 수 있을까”를 가장 주요하게 신경쓴다. 우리나라 대학교는 서열이 있고, 그들은 이 서열에 민감하다. 나도 대학 진학을 희망하는 70%의 고등학생 중 하나였다. 그러나 나의 관심은 달랐다.]]></summary></entry><entry><title type="html">신입 개발자가 필요할까?</title><link href="https://parkjunhee9327.github.io/insight/why-junior-is-needed/" rel="alternate" type="text/html" title="신입 개발자가 필요할까?" /><published>2026-04-01T00:00:00+00:00</published><updated>2026-04-01T00:00:00+00:00</updated><id>https://parkjunhee9327.github.io/insight/why-junior-is-needed</id><content type="html" xml:base="https://parkjunhee9327.github.io/insight/why-junior-is-needed/"><![CDATA[<h1 id="-신입-개발자가-필요할까">🚀 신입 개발자가 필요할까?</h1>
<p>취업을 고민하는 신입 개발자라면 누구나 떠올리는 질문이다.</p>

<blockquote>
  <p><em>AI도 있고, 시니어 개발자도 많은데. 신입인 당신을 왜 뽑아야 합니까?</em></p>
</blockquote>

<p>“너가 어떤 가치를 창출할 수 있는가?”라는 질문은 매우 합당하다. 모든 일에는 이유가 있고, 개발자의 구인 구직도 “이유”가 있다. &lt;/br&gt;</p>

<p>따라서 관련 생각을 정리해보았다.</p>

<p><br /></p>

<h2 id="-가장-큰-이유-시니어의-인지적-부담-경감--ai-네이티브-시니어의-씨앗">🧠 가장 큰 이유: 시니어의 인지적 부담 경감 + AI 네이티브 시니어의 씨앗</h2>

<h3 id="시니어의-인지-부하-경감">시니어의 인지 부하 경감</h3>
<p>AI는 개발자에게 필요한 정보를 매우 신속하게 제공한다. 이는 <strong>시니어의 인지 에너지를 빠르게 고갈하는 원인이다.</strong> <br /></p>

<p>사람이 하루에 활용할 수 있는 인지적 에너지는 AI로 늘어난 생산성과 같이 늘어나지 않는다. 사람의 신체 구조는 예전이나 지금이나 비슷하기 때문이다. 이 상황에서 AI가 고도의 판단이 필요한 정보를 쉴 새 없이 전달해주면?</p>

<p><br /></p>

<ol>
  <li>AI가 없었을 때
    <ul>
      <li>개발 경험 + 관련 서적 + 전문 기술 플랫폼 활용 -&gt; <strong>고도의 판단 과정</strong> -&gt; 직접 코드 작성 -&gt; <strong>코드 리뷰</strong> -&gt; 인지 과부하 없음</li>
    </ul>
  </li>
  <li>AI와 협업할 때
    <ul>
      <li>개발 경험 + AI가 제공한 방대한 자료 -&gt; <strong>더 많은 판단 과정</strong> -&gt; AI로 코드 작성 가속화 -&gt; <strong>더 많은 코드 리뷰</strong> -&gt; 인지 과부하</li>
    </ul>
  </li>
</ol>

<p><br /></p>

<table>
  <thead>
    <tr>
      <th>시니어</th>
      <th>신입</th>
      <th style="text-align: center">경감되는 부분</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>비즈니스 요구사항 해석, 구조 결정</td>
      <td>관련 기술 스택의 최신 문서 및 AI로 사례조사</td>
      <td style="text-align: center">자료 조사 및 대안 탐색 시간</td>
    </tr>
    <tr>
      <td>핵심 로직 리뷰, 보안 및 성능 가이드</td>
      <td>AI를 활용한 로직 및 테스트 코드 작성</td>
      <td style="text-align: center">단순 코딩 및 반복 작업</td>
    </tr>
    <tr>
      <td>최종 아키텍처 적합성 판단</td>
      <td>AI 결과물의 런타임 오류 수정</td>
      <td style="text-align: center">디버깅 및 Edge Case 확인</td>
    </tr>
  </tbody>
</table>

<p><br /></p>

<h3 id="시니어-네이티브-ai-개발자의-씨앗">시니어 네이티브 AI 개발자의 씨앗</h3>
<p>신입 개발자는 당장의 실무자이기도 하지만, 3~5년 뒤 회사를 지탱할 <strong>미래 자산</strong>이기도 하다. <br /></p>

<p>과거 어셈블리어를 하던 세대는 C언어를 ‘학습’해야 했다. <br />
수동으로 코드를 작성하던 세대는 AI로 코드 작성을 대리하는 방법을 ‘학습’해야 한다.</p>

<p><br /></p>

<p>AI가 ‘학습의 대상’이 아닌 ‘기본적으로 주어진 환경’인 신입 개발자는 시니어가 되었을 때 <strong>어디를 자동화하고, 어디에 인간의 리소스를 투입해야 하는지</strong> 본능적으로 알 수 있다. <br />
<strong>AI 친화적인 코드</strong>를 작성하는 능력을 길러 AI를 적극 활용하여 얻는 생산성을 극적으로 높일 수 있다.</p>

<p><br /></p>

<table>
  <thead>
    <tr>
      <th>특징</th>
      <th>설명</th>
      <th style="text-align: center">창출하는 가치</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>사고 방식</td>
      <td>코드 작성보다 문제 정의와 시스템 설계에 집중</td>
      <td style="text-align: center">복잡한 비즈니스 문제를 기술적 솔루션으로 빠르게 치환</td>
    </tr>
    <tr>
      <td>개발 프로세스</td>
      <td>프롬프트 엔지니어링을 통한 빠른 프로토타입 개발</td>
      <td style="text-align: center">개발 속도의 혁신적 향상</td>
    </tr>
    <tr>
      <td>품질 관리</td>
      <td>자동화된 테스트 케이스 생성, 실시간 코드 리뷰</td>
      <td style="text-align: center">인간의 실수를 조기에 발견하여 전체적인 시스템 안전성 향상</td>
    </tr>
  </tbody>
</table>

<p><br /></p>

<h2 id="-빠르게-익히고-적용하는-능력">🌱 빠르게 익히고 적용하는 능력</h2>
<p>AI가 도래한 이후의 기술 변화 속도는 확연하게 빨라졌다. 신입 개발자들이 개발을 배우는 시기가 이러한 세상의 흐름과 맞물린다. <br />
즉, <strong>신입 개발자는 빠른 흐름에 익숙하며, 그것을 적용하는 것도 익숙하다.</strong></p>

<ul>
  <li>빠른 흐름에 익숙함 -&gt; 새로운 기술에 대한 심리적 저항 낮음</li>
  <li>기존의 방식에 대한 집착이 적음</li>
</ul>

<p><br /></p>

<p>📢 <strong>나의 경험담</strong></p>
<ol>
  <li>Read 작업에 ORM 기반 도구(JPA/QueryDSL)를 쓰면
    <ul>
      <li>영속성 맥락에 따라 필요 없는 데이터를 불러올 위험도 있고</li>
      <li>그걸 고치려고 하면 코드가 부자연스러워지네?</li>
      <li>-&gt; jOOQ 도입, 영속성 맥락 없는 정확하고 직관적인 쿼리 작성</li>
    </ul>
  </li>
  <li>DB 스키마의 변경 이력을 애플리케이션 외부에서 수작업으로 관리하니까
    <ul>
      <li>문서 작업에 소홀해질 위험이 높아.</li>
      <li>문서가 유실되거나 체계가 부족해져.</li>
      <li>-&gt; Flyway 도입, 애플리케이션 실행 시 알아서 DB 스키마 변경사항 반영</li>
    </ul>
  </li>
</ol>

<p><br /></p>

<h2 id="-ai와-함께-성장한-개발자">🌱 AI와 함께 성장한 개발자</h2>
<p>프롬프트 엔지니어링으로 단순 반복 작업을 빠르게 처리하고, 개발자 자신은 서비스 로직 설계와 비즈니스 요구사항 분석에 더 많은 시간을 할애할 수 있다.</p>

<p><br /></p>

<p>신입 개발자는 시니어의 숙련도를 이길 수 없다. 다만, AI와 함께 개발한 인원들이니만큼 <strong>투자 대비 효율</strong>을 얻을 수 있다.</p>

<p><br /></p>

<p>📢 <strong>나의 경험담</strong></p>
<ol>
  <li>비속어 필터 개발
    <ul>
      <li>엔티티에 포함되어야 할 필드 구조, 쓰임새(도메인의 Service에서 적용되어야 함)를 기반으로 AI를 통한 비속어 필터 Service와 JPA 엔티티 생성</li>
      <li>애플리케이션의 요구사항에 맞춰 JPA 엔티티와 SwearService 생성</li>
      <li>-&gt; AI가 생성한 엔티티에 @Enumerated 등 세부 기능, SwearService에 비속어를 변형한 단어를 추가로 필터링하는 기능 등 세부사항을 덧붙여서 단기간에 완성함</li>
    </ul>
  </li>
</ol>

<p><br /></p>

<h2 id="-ai와-시니어-사이의-중립적-관점">🌱 AI와 시니어 사이의 중립적 관점</h2>
<p>공신력 있는 지식 채널에서 “요즘은 배워가는 것 보다 버리는 것이 더 중요할 때가 있다”는 말을 들은 적이 있다. 과거의 경험이 현재의 발목을 잡을 수 있다는 통찰에서 비롯된 말이었다. <br />
신입 개발자는 버려야 할 지식이 없다. 새로운 패러다임이 등장했을 때, 신입은 <strong>기존의 지식과의 갈등 없이 신기술을 흡수</strong>해 활용하는 민첩성이 있다.</p>

<p><br /></p>

<p>AI는 방대한 정보를 바탕으로 가장 확률이 높은 방안을 제시하는 능력이 뛰어나다. AI 시대에 생산성이 비약적으로 늘어난 이유이다. <br />
대신 AI는 특정 의견에 동조하거나 환각을 일으킬 위험이 있다. 신입 개발자는 팀의 맥락 + 클라이언트 요구사항 + 애플리케이션의 관례의 맥락을 더해 <strong>논리적/객관적인 근거를 바탕으로 소통</strong>할 수 있다.</p>

<p><br /></p>

<p>📢 <strong>나의 경험담</strong></p>
<ol>
  <li>QueryDSL vs jOOQ
    <ul>
      <li>커뮤니티 웹사이트 전용 서버 내에서 게시글 데이터를 PostgreSQL의 JSONB로 관리함 + 커뮤니티는 게시글의 비중이 매우 큼</li>
      <li>AI가 게시글 Read 작업에 쓸 기술로 QueryDSL과 jOOQ 제시</li>
      <li>QueryDSL은 표준 SQL 추상화에 집중하며, JSONB를 직접적으로 지원하지 않음 (치명적 문제)</li>
      <li>jOOQ는 JSONB 관련 함수와 연산자를 DSL로 직접 표현 가능 (애플리케이션 관점에서 이점)</li>
      <li>-&gt; AI가 제공한 정보 + 애플리케이션 맥락 분석 후 QueryDSL 대신 jOOQ 채택</li>
    </ul>
  </li>
</ol>]]></content><author><name>베르</name></author><category term="insight" /><summary type="html"><![CDATA[🚀 신입 개발자가 필요할까? 취업을 고민하는 신입 개발자라면 누구나 떠올리는 질문이다.]]></summary></entry><entry><title type="html">접근 제어자 종류, 사용시 주의사항</title><link href="https://parkjunhee9327.github.io/theory/access-modifier/" rel="alternate" type="text/html" title="접근 제어자 종류, 사용시 주의사항" /><published>2026-03-24T00:00:00+00:00</published><updated>2026-03-24T00:00:00+00:00</updated><id>https://parkjunhee9327.github.io/theory/access-modifier</id><content type="html" xml:base="https://parkjunhee9327.github.io/theory/access-modifier/"><![CDATA[<h2 id="개요">개요</h2>

<ul>
  <li>클래스, 변수, 메서드 등의 접근성을 설정하는 키워드이다.</li>
  <li>OOP의 4가지 원칙 중 캡슐화와 밀접한 관련이 있다.</li>
</ul>

<h2 id="private">private</h2>

<ul>
  <li>자신이 선언된 클래스 내에서만 접근 가능하도록 설정한다.</li>
  <li>자식 클래스를 포함한 모든 다른 클래스들이 접근할 수 없다.</li>
  <li>인스턴스 변수들, 내부적으로 사용되는 로직에 쓰인다.</li>
</ul>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">BankAccount</span> <span class="o">{</span>
    <span class="kd">private</span> <span class="kt">double</span> <span class="n">balance</span><span class="o">;</span> <span class="c1">// Only accessible inside BankAccount</span>

    <span class="kd">private</span> <span class="kt">void</span> <span class="nf">logTransaction</span><span class="o">()</span> <span class="o">{</span> <span class="c1">// A helper method only for this class</span>
        <span class="c1">// ...</span>
    <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<h2 id="default">default</h2>

<ul>
  <li>동일한 패키지 내에서만 접근 가능하게 설정한다.</li>
  <li>아무런 접근 제어자도 사용하지 않았을 때의 기본적인 값이다.</li>
  <li>자식 클래스라고 해도 패키지 외부에 있으면 접근 불가능하다.</li>
  <li>패키지 내에 서로 관련된 클래스들을 구성하는 경우, 외부에 드러내지 않도록 사용한다.</li>
</ul>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="nc">Logger</span> <span class="o">{</span> <span class="c1">// No modifier = default access</span>
    <span class="nc">String</span> <span class="n">format</span><span class="o">;</span> <span class="c1">// Accessible within the 'com.utilities' package</span>

    <span class="kt">void</span> <span class="nf">logMessage</span><span class="o">(</span><span class="nc">String</span> <span class="n">msg</span><span class="o">)</span> <span class="o">{</span> <span class="c1">// Accessible within the package</span>
        <span class="c1">// ...</span>
    <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<h2 id="protected">protected</h2>

<ul>
  <li>동일한 패키지 내부 또는 자식 클래스가 접근 할 수 있게 한다.</li>
  <li>default와 비슷하지만 패키지 외부에 있는 자식 클래스도 접근할 수 있다는 점에서 차이가 있다.</li>
  <li>상속을 사용할 때 유용한 접근 제어자이다.</li>
</ul>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">Vehicle</span> <span class="o">{</span>
    <span class="kd">protected</span> <span class="nc">String</span> <span class="n">engineType</span><span class="o">;</span> <span class="c1">// Accessible in package and to subclasses</span>

    <span class="kd">protected</span> <span class="kt">void</span> <span class="nf">startEngine</span><span class="o">()</span> <span class="o">{</span>
        <span class="c1">// Subclasses like Car or Bike can use or override this.</span>
    <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<h2 id="public">public</h2>

<ul>
  <li>프로그램 내의 어디서든지간에 접근 가능하다.</li>
  <li>접근하기 쉬우므로 신중하게 사용해야 한다.</li>
</ul>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">Calculator</span> <span class="o">{</span>
    <span class="kd">public</span> <span class="kt">int</span> <span class="nf">add</span><span class="o">(</span><span class="kt">int</span> <span class="n">a</span><span class="o">,</span> <span class="kt">int</span> <span class="n">b</span><span class="o">)</span> <span class="o">{</span> <span class="c1">// Accessible from anywhere</span>
        <span class="k">return</span> <span class="n">a</span> <span class="o">+</span> <span class="n">b</span><span class="o">;</span>
    <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<h2 id="유의사항">유의사항</h2>

<ul>
  <li>최고 레벨의 클래스 또는 인터페이스는 public이거나 default이어야 한다.</li>
  <li>생성자는 모든 접근 제어자를 사용할 수 있다. Singleton 패턴을 사용할 때는 private 생성자를 사용한다.</li>
  <li>메서드를 오버라이딩 할 때 접근성을 축소할 수 없다. 다만, 접근성을 늘릴 수는 있다.
    <ul>
      <li>❌ public 메서드 → private 메서드로 오버라이딩</li>
      <li>✅ private 메서드 → public 메서드로 오버라이딩</li>
    </ul>
  </li>
  <li>자식 클래스와 부모 클래스가 서로 다른 패키지에 위치할 때, 부모 클래스의 요소가 protected 혹은 public이어야만 자식 클래스가 접근 가능함을 유의한다.</li>
</ul>]]></content><author><name>베르</name></author><category term="theory" /><summary type="html"><![CDATA[개요]]></summary></entry><entry><title type="html">equals() 메서드와 == 연산자 비교</title><link href="https://parkjunhee9327.github.io/theory/equals-and-equal-operator/" rel="alternate" type="text/html" title="equals() 메서드와 == 연산자 비교" /><published>2026-03-24T00:00:00+00:00</published><updated>2026-03-24T00:00:00+00:00</updated><id>https://parkjunhee9327.github.io/theory/equals-and-equal-operator</id><content type="html" xml:base="https://parkjunhee9327.github.io/theory/equals-and-equal-operator/"><![CDATA[<h2 id="equals">equals()</h2>

<ul>
  <li>객체의 내용물을 비교한다. 객체들을 논리적으로 비교했을 때 동등하다면 동등하다고 판단한다.</li>
  <li>Object 클래스에 속한 메서드이므로 기본 자료형에 사용할 수 없다.</li>
  <li>클래스마다 오버라이딩하여 작동 방식이 다 다를 수 있으므로 ==보다 실행 속도가 느릴 수 있다.</li>
  <li>커스텀 객체의 동등성 비교, 컬렉션 등에 사용한다.</li>
</ul>

<h2 id="-연산자">== 연산자</h2>

<ul>
  <li>객체의 참조값을 비교한다. 객체들의 메모리 위치가 동일하면 동등하다고 판단한다.</li>
  <li>자바가 기본적으로 제공하는 연산자이므로 기본 자료형에 사용할 수 있다.
    <ul>
      <li>기본 자료형에 적용할 경우 값을 비교한다.</li>
    </ul>
  </li>
  <li>언제나 동일한 방식(값 비교)으로 작동하므로 실행 속도가 빠르다.</li>
  <li>기본 자료형의 동등성 비교, null 확인 등에 사용한다.</li>
  <li>예외적인 경우
    <ul>
      <li>Enum은 언제나 singleton 패턴으로 상수를 생성하므로 == 연산자를 사용할 수 있다.</li>
      <li>String의 경우 String Pool에 저장되었느냐 아니냐에 따라 결과가 달라질 수 있다.</li>
    </ul>
  </li>
</ul>

<h2 id="-equals를-오버라이딩할-때-지켜야-할-규칙">➕ equals()를 오버라이딩할 때 지켜야 할 규칙</h2>

<ul>
  <li>재귀성: x.equals(x)가 true여야 한다.</li>
  <li>대칭성: x.equals(y)와 y.equals(x)의 결과가 동일해야 한다.</li>
  <li>이행성: x.equals(y)이고 y.equals(z)인 경우, x.equals(z)는 앞선 식들과 결과가 동일해야 한다.</li>
  <li>일관성: 여러 번 호출해도 그 결과가 동일해야 한다.</li>
  <li>null 확인: x.equals(null)가 false여야 한다.</li>
</ul>]]></content><author><name>베르</name></author><category term="theory" /><summary type="html"><![CDATA[equals()]]></summary></entry><entry><title type="html">equals()와 hashcode()를 함께 오버라이딩해야 하는 이유</title><link href="https://parkjunhee9327.github.io/theory/overriding-equals-and-hashcode/" rel="alternate" type="text/html" title="equals()와 hashcode()를 함께 오버라이딩해야 하는 이유" /><published>2026-03-24T00:00:00+00:00</published><updated>2026-03-24T00:00:00+00:00</updated><id>https://parkjunhee9327.github.io/theory/overriding-equals-and-hashcode</id><content type="html" xml:base="https://parkjunhee9327.github.io/theory/overriding-equals-and-hashcode/"><![CDATA[<h2 id="jlsjava-language-specification에-따른-이유">JLS(Java Language Specification)에 따른 이유</h2>

<ul>
  <li>두 객체들이 equals()에 따라 동등하다면 그 객체들은 반드시 동일한 hashcode()를 지녀야 한다.
    <ul>
      <li>그래서 equals()와 hashCode()를 모두 오버라이딩 해야 한다.</li>
    </ul>
  </li>
  <li>두 객체들이 동일한 hashcode()를 지녔다고 해서 반드시 그 객체들이 동일해야 하는 것은 아니다. (hash collision 때문)</li>
</ul>

<h2 id="equals와-hashcode를-동시에-오버라이딩하지-않으면-발생하는-일">equals()와 hashCode()를 동시에 오버라이딩하지 않으면 발생하는 일</h2>

<ul>
  <li>equals()만 오버라이딩 할 경우: 객체들이 동등하기는 하지만 해시 값은 달라서 HashMap, HashSet같은 자료형을 의도대로 사용할 수 없다.</li>
  <li>hashcode()만 오버라이딩 할 경우: equals()가 객체들의 메모리 주소를 비교하기 때문에 실무에 맞지 않은 방식으로 동등성을 비교할 수 있다.
    <ul>
      <li>equals()는 오버라이딩되지 않으면 객체들의 메모리 주소를 비교한다. equals()의 기본 동작이다. (==의 작동 방식과 동일)</li>
    </ul>
  </li>
</ul>

<p>➕ 두 메서드들을 오버라이딩하는, 권장되는 방식</p>

<ul>
  <li>equals()와 hashCode()에 동일한 필드를 사용하여 결과의 일관성을 유지한다.</li>
  <li>final로 설정된 필드들을 사용한다.
    <ul>
      <li>필드의 값이 바뀌면 동등성도 달라질 수 있고 해시 값도 달라질 수 있다.</li>
      <li>특히 Hash와 연관된 자료형(HaspMap 등)을 사용할 때 치명적이다.</li>
    </ul>
  </li>
  <li>객체의 신원을 나타내거나 주요한 의미를 지니는 필드를 사용한다.
    <ul>
      <li>equals()가 객체들의 논리적인 동등성을 따지기 때문이다.</li>
      <li>✅ Account 객체들의 email, password 값이 동일하니까 동일한 객체들이야.</li>
      <li>❌ Account 객체들의 updatedAt, isActive 값이 동일하니까 동일한 객체들이야.</li>
    </ul>
  </li>
</ul>

<h2 id="-hash-collision">➕ Hash Collision</h2>

<ul>
  <li>질문 배경
    <ul>
      <li>왜 equals()로 동등하면 객체들의 해시 값이 동일해야 하는데, 해시 값이 동일하다고 equals()로 동등하리라는 보장은 없음?</li>
    </ul>
  </li>
  <li>서로 다른 내용물을 지닌 객체들의 해시 값이 동일한 경우이다.</li>
  <li>발생 이유
    <ul>
      <li>유한한 결과값 공간: 해시 코드는 자바에서 32비트의 정수다. (약 40억 개의 값이 가용함)</li>
      <li>무한한 입력값 공간: 객체의 상태로 가능한 경우는 무한에 가깝다. (객체의 필드를 구성하는 경우의 수 + 해시를 생성할 때 쓰는 필드의 경우의 수)</li>
      <li>비둘기장 칸(pigeonhold) 원칙: 해시 값보다 많은 수의 객체가 있다면 해시 값의 충돌은 불가피하다.</li>
    </ul>
  </li>
  <li>가능한 해시 값이 40억개나 된다면서, 객체들의 해시 값이 겹칠 수 있다고?
    <ul>
      <li>40억이 직관적으로는 많아 보이지만, 사실은 그렇게 많지 않다.</li>
      <li>23명의 사람만 있어도 그 중 두 명이 생일을 공유할 확률이 50%나 된다는 걸 생각해보자. (생일의 역설)</li>
      <li>생일의 역설에 따르면 객체 77,000개 정도만 있어도 두 객체가 해시 값을 공유할 확률이 50% 정도가 된다.</li>
    </ul>
  </li>
  <li>해시 충돌을 해소하는 방법
    <ul>
      <li>
        <p>HashMap의 내부적인 구조</p>

        <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="c1">// Simplified HashMap bucket structure</span>
  <span class="nc">HashMap</span><span class="o">&lt;</span><span class="no">K</span><span class="o">,</span> <span class="no">V</span><span class="o">&gt;</span> <span class="o">{</span>
      <span class="nc">Node</span><span class="o">&lt;</span><span class="no">K</span><span class="o">,</span> <span class="no">V</span><span class="o">&gt;[]</span> <span class="n">table</span><span class="o">;</span>  <span class="c1">// Array of buckets</span>
            
      <span class="c1">// Each bucket can contain multiple entries (linked list or tree)</span>
      <span class="kd">class</span> <span class="nc">Node</span><span class="o">&lt;</span><span class="no">K</span><span class="o">,</span> <span class="no">V</span><span class="o">&gt;</span> <span class="o">{</span>
          <span class="kd">final</span> <span class="kt">int</span> <span class="n">hash</span><span class="o">;</span>
          <span class="kd">final</span> <span class="no">K</span> <span class="n">key</span><span class="o">;</span>
          <span class="no">V</span> <span class="n">value</span><span class="o">;</span>
          <span class="nc">Node</span><span class="o">&lt;</span><span class="no">K</span><span class="o">,</span> <span class="no">V</span><span class="o">&gt;</span> <span class="n">next</span><span class="o">;</span>  <span class="c1">// For collisions</span>
      <span class="o">}</span>
  <span class="o">}</span>
</code></pre></div>        </div>
      </li>
      <li>
        <p>Chaining</p>

        <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="c1">// What happens during a collision</span>
  <span class="nc">HashMap</span><span class="o">&lt;</span><span class="nc">String</span><span class="o">,</span> <span class="nc">String</span><span class="o">&gt;</span> <span class="n">map</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">HashMap</span><span class="o">&lt;&gt;();</span>
        
  <span class="n">map</span><span class="o">.</span><span class="na">put</span><span class="o">(</span><span class="s">"Aa"</span><span class="o">,</span> <span class="s">"Value1"</span><span class="o">);</span>  <span class="c1">// Hash 2112 -&gt; Bucket 0</span>
  <span class="n">map</span><span class="o">.</span><span class="na">put</span><span class="o">(</span><span class="s">"BB"</span><span class="o">,</span> <span class="s">"Value2"</span><span class="o">);</span>  <span class="c1">// Hash 2112 -&gt; Same bucket 0 (collision!)</span>
        
  <span class="c1">// Internally, bucket 0 becomes a linked list:</span>
  <span class="c1">// ["Aa" -&gt; "Value1"] -&gt; ["BB" -&gt; "Value2"]</span>
</code></pre></div>        </div>
      </li>
    </ul>
  </li>
  <li>해시 충돌이 성능에 미치는 영향
    <ul>
      <li>Java 8버전 이후 부터는 Java가 linked list를 red-black tree로 변환하여 최악의 경우에 발생하는 성능을 O(n)에서 O(log n)으로 개선했다.</li>
      <li>
        <p>좋은 해시 함수 (충돌이 덜 남)</p>

        <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="nc">Bucket</span> <span class="mi">0</span><span class="o">:</span> <span class="o">[</span><span class="nc">Entry1</span><span class="o">]</span>
  <span class="nc">Bucket</span> <span class="mi">1</span><span class="o">:</span> <span class="o">[</span><span class="nc">Entry2</span><span class="o">]</span>
  <span class="nc">Bucket</span> <span class="mi">2</span><span class="o">:</span> <span class="o">[</span><span class="nc">Entry3</span><span class="o">]</span>
  <span class="o">...</span>
  <span class="c1">// O(1) operations</span>
</code></pre></div>        </div>
      </li>
      <li>
        <p>나쁜 해시 함수 (충돌이 자주 남)</p>

        <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="nc">Bucket</span> <span class="mi">0</span><span class="o">:</span> <span class="o">[</span><span class="nc">Entry1</span><span class="o">]</span> <span class="o">-&gt;</span> <span class="o">[</span><span class="nc">Entry2</span><span class="o">]</span> <span class="o">-&gt;</span> <span class="o">[</span><span class="nc">Entry3</span><span class="o">]</span> <span class="o">-&gt;</span> <span class="o">[</span><span class="nc">Entry4</span><span class="o">]</span> <span class="o">-&gt;</span> <span class="o">...</span>
  <span class="nc">Bucket</span> <span class="mi">1</span><span class="o">:</span> <span class="o">[</span><span class="nc">Entry5</span><span class="o">]</span>
  <span class="nc">Bucket</span> <span class="mi">2</span><span class="o">:</span> <span class="o">[]</span>
  <span class="o">...</span>
  <span class="c1">// Degrades to O(n) operations in worst case</span>
</code></pre></div>        </div>
      </li>
    </ul>
  </li>
  <li>핵심 요약
    <ul>
      <li>해시 기반 컬렉션에서 충돌은 일반적이고 예측 가능한 현상이다.</li>
      <li>서로 다른 객체들의 해시가 동일할 수 있고, 동일할 것이다.</li>
      <li>컬렉션은 chaining을 사용하여 충돌을 내부적으로 해소한다. (linked list, tree)</li>
      <li>동등한 객체들은 해시 코드 값이 같지만, 해시 코드 값이 같다고 해서 동등한 객체라는 의미는 아니다.</li>
      <li>해시 함수를 잘못 짜면 성능이 나빠진다. 좋은 해시 함수는 성능이 O(1)과 비슷하다.</li>
    </ul>
  </li>
</ul>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">String</span> <span class="n">a</span> <span class="o">=</span> <span class="s">"Aa"</span><span class="o">;</span>
<span class="nc">String</span> <span class="n">b</span> <span class="o">=</span> <span class="s">"BB"</span><span class="o">;</span>

<span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="n">a</span><span class="o">.</span><span class="na">hashCode</span><span class="o">());</span>  <span class="c1">// 2112</span>
<span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="n">b</span><span class="o">.</span><span class="na">hashCode</span><span class="o">());</span>  <span class="c1">// 2112 - Same hash code!</span>
<span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="n">a</span><span class="o">.</span><span class="na">equals</span><span class="o">(</span><span class="n">b</span><span class="o">));</span>   <span class="c1">// false - Different objects</span>
</code></pre></div></div>]]></content><author><name>베르</name></author><category term="theory" /><summary type="html"><![CDATA[JLS(Java Language Specification)에 따른 이유]]></summary></entry><entry><title type="html">Object 클래스의 toString()을 오버라이딩하는 이유</title><link href="https://parkjunhee9327.github.io/theory/tostring-overriding-reason/" rel="alternate" type="text/html" title="Object 클래스의 toString()을 오버라이딩하는 이유" /><published>2026-03-24T00:00:00+00:00</published><updated>2026-03-24T00:00:00+00:00</updated><id>https://parkjunhee9327.github.io/theory/tostring-overriding-reason</id><content type="html" xml:base="https://parkjunhee9327.github.io/theory/tostring-overriding-reason/"><![CDATA[<h2 id="tostring이란">toString()이란</h2>

<ul>
  <li>객체를 문자열로 표현하는 값을 반환하는 메서드이다.</li>
  <li>Object 클래스에 정의되어 있다.</li>
  <li>기본 반환값은 “객체의 타입인 클래스의 이름 + @ + 객체의 해시 코드를 표현한 값(서명되지 않은 16진수로 표현)”이다.</li>
</ul>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">Person</span><span class="err">@</span><span class="mi">15</span><span class="n">db9742</span>
</code></pre></div></div>

<h2 id="왜-오버라이딩-할까">왜 오버라이딩 할까?</h2>

<ul>
  <li>객체가 자신을 사람이 읽을 수 있는 형태로 표현하는 공식적인 방법 중 유일한 수단이다.
    <ul>
      <li>개인적인 의견으로는 이게 toString()을 오버라이딩하는 가장 중요한 이유라고 생각한다. 개발자들은 사람이니까.</li>
      <li>모든 클래스들이 상속하는 Object 클래스에서 객체가 자신을 사람이 읽을 수 있는 형태로 표현하도록 하는 메서드는 toString()이 유일하다.</li>
      <li>toString()이 없으면 커스텀 메서드를 만들어야 한다.</li>
    </ul>

    <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="c1">// 개발자: 뭐라는거야?</span>
  <span class="nc">User</span><span class="err">@</span><span class="mi">1</span><span class="n">a2b3c</span>
  <span class="c1">// 개발자: 이해 완료!</span>
  <span class="nc">User</span><span class="o">[</span><span class="n">id</span><span class="o">=</span><span class="mi">101</span><span class="o">,</span> <span class="n">name</span><span class="o">=</span><span class="nc">John</span><span class="o">,</span> <span class="n">role</span><span class="o">=</span><span class="no">ADMIN</span><span class="o">]</span>
</code></pre></div>    </div>
  </li>
  <li>객체의 상태를 나타낼 수 있는 수단이 된다.
    <ul>
      <li>객체의 상태(값이 할당된 필드)는 객체의 근본이기 때문에 매우 중요하다.
        <ul>
          <li>객체는 자신의 필드와 그 값에 의해 정의되기 때문이다.</li>
          <li>Account는 잔액, 계좌번호, 소유자로 결정된다.</li>
          <li>Car는 생산업체, 색, 속도, 연비로 결정된다.</li>
          <li>Person은 이름, 나이, 주소로 결정된다.</li>
        </ul>
      </li>
      <li>Java의 Record가 hashcode(), equals() 뿐 아니라 toString()도 자동적으로 오버라이딩 해주는 의미에 대해 생각해보자.</li>
      <li>그리고 오버라이딩해주는 문자열의 내용이 왜 필드의 이름과 값의 쌍일지 생각해보자.</li>
    </ul>

    <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="c1">// User 레코드의 toString() 값 예시</span>
  <span class="nc">User</span><span class="o">[</span><span class="n">id</span><span class="o">=</span><span class="mi">101</span><span class="o">,</span> <span class="n">name</span><span class="o">=</span><span class="nc">John</span><span class="o">,</span> <span class="n">role</span><span class="o">=</span><span class="no">ADMIN</span><span class="o">]</span>
</code></pre></div>    </div>
  </li>
  <li>유의미한 정보를 디버깅 및 로깅에 사용할 수 있다.
    <ul>
      <li>특히 프로덕션 환경에서 문제가 발생했을 때 유용하다.
        <ul>
          <li>운영중인 프로덕션 환경은 디버거(debugger)를 적용할 수 없다. 이 때 문제 상황에 대한 정보를 알려줄 수 있는 건 로깅이다.</li>
          <li>로깅에 사용되는 메서드가 toString()이다. toString()은 객체가 스스로를 문자열로 표현하는 수단이기 때문이다.</li>
        </ul>
      </li>
    </ul>

    <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="c1">// 모든 Java의 Exception들이 상속하는 Throwable도</span>
  <span class="c1">// 자신만의 toString()이 있음을 확인할 수 있다.</span>
  <span class="kd">public</span> <span class="nc">String</span> <span class="nf">toString</span><span class="o">()</span> <span class="o">{</span>
      <span class="nc">String</span> <span class="n">s</span> <span class="o">=</span> <span class="n">getClass</span><span class="o">().</span><span class="na">getName</span><span class="o">();</span>
      <span class="nc">String</span> <span class="n">message</span> <span class="o">=</span> <span class="n">getLocalizedMessage</span><span class="o">();</span>
      <span class="k">return</span> <span class="o">(</span><span class="n">message</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="o">?</span> <span class="o">(</span><span class="n">s</span> <span class="o">+</span> <span class="s">": "</span> <span class="o">+</span> <span class="n">message</span><span class="o">)</span> <span class="o">:</span> <span class="n">s</span><span class="o">;</span>
  <span class="o">}</span>
</code></pre></div>    </div>

    <ul>
      <li>toString()의 기본적 반환값인 “클래스 이름 + @ + 해시코드 표상”은 개발자에게 어떠한 정보도 제공하지 못한다.</li>
    </ul>

    <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="c1">// 테스트를 실패했는데 이런 메시지가 뜬다면</span>
  <span class="c1">// 뭐 어쩌라고? 라는 생각이 들 것이다.</span>
  <span class="c1">// 필드의 값이 달랐다던지, 예상한 값이 아니었다던지 등을 보여야지.</span>
  <span class="nl">Expected:</span> <span class="nc">User</span><span class="err">@</span><span class="mi">1</span><span class="n">a2b3c</span> <span class="n">but</span> <span class="nl">was:</span> <span class="nc">User</span><span class="err">@</span><span class="mi">4</span><span class="n">d5e6f</span>
</code></pre></div>    </div>
  </li>
  <li>외부 서비스와 상호작용할 때 객체를 전달할 수 있는 수단이 된다.
    <ul>
      <li>문자열은 모든 프로그램 및 프로그래밍 언어가 처리할 수 있는 자료이다.</li>
      <li>즉, 자바 애플리케이션에서 객체를 외부로 내보내기 위해 문자열로 바꿔야 하는 순간이 언젠가는 온다.</li>
      <li>이 때 객체에 대한 정보를 가져오기 위해 toString()을 사용할 수 있다.</li>
    </ul>
  </li>
</ul>

<h2 id="-양방향적-관계에-있는-클래스에서-tostring을-오버라이딩할-때-주의해야-하는-이유">➕ 양방향적 관계에 있는 클래스에서 toString()을 오버라이딩할 때 주의해야 하는 이유</h2>

<ul>
  <li>클래스에 있어 양방향적 관계란 서로가 서로를 참조하는 관계를 의미한다.</li>
  <li>서로를 참조하기 때문에 무한 재귀 호출의 문제가 발생하여 StackOverflowError가 발생한다.</li>
  <li>발생 과정
    <ul>
      <li>ClassA와 ClassB가 서로를 참조한다.</li>
      <li>ClassA의 toString()을 부른다.</li>
      <li>ClassA의 toString()은 ClassB의 toString()이 필요하다.</li>
      <li>ClassB의 toString() 역시 ClassA의 toString()이 필요하다.</li>
      <li>서로가 서로를 호출하다가 StackOverflowError가 발생한다.</li>
    </ul>
  </li>
  <li>toString()을 오버라이딩할 때 무한 재귀 호출을 일으키지 않는 필드만 사용하거나, id 필드만 사용하는 등의 방법으로 방지한다.</li>
  <li>알아보고 난 뒤 내가 내린 결론: 양방향적 관계에 있는 클래스에서 toString()을 오버라이딩하는 게 문제가 아니라, 클래스들이 양방향적 관계에 있는 것 자체가 문제다.</li>
</ul>]]></content><author><name>베르</name></author><category term="theory" /><summary type="html"><![CDATA[toString()이란]]></summary></entry><entry><title type="html">업캐스팅과 다운캐스팅</title><link href="https://parkjunhee9327.github.io/theory/upcasting-downcasting/" rel="alternate" type="text/html" title="업캐스팅과 다운캐스팅" /><published>2026-03-24T00:00:00+00:00</published><updated>2026-03-24T00:00:00+00:00</updated><id>https://parkjunhee9327.github.io/theory/upcasting-downcasting</id><content type="html" xml:base="https://parkjunhee9327.github.io/theory/upcasting-downcasting/"><![CDATA[<h2 id="업캐스팅">업캐스팅</h2>

<ul>
  <li>자식 클래스의 타입을 부모 클래스의 타입으로 사용하는 방식이다.</li>
  <li>암묵적이든 명시적이든 언제나 사용하기 안전하다.</li>
  <li>컴파일러가 자동적으로 허용한다.</li>
  <li>런타임 타입이 변하지 않고 유지된다. (런타임 타입 = 실제로 사용되는 자식 클래스 타입)</li>
  <li>추상화를 기반으로 다형성의 이점을 활용하기 위해 많이 쓰인다.</li>
</ul>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="nc">Animal</span> <span class="o">{}</span>
<span class="kd">class</span> <span class="nc">Dog</span> <span class="kd">extends</span> <span class="nc">Animal</span> <span class="o">{}</span>

<span class="nc">Dog</span> <span class="n">dog</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Dog</span><span class="o">();</span>
<span class="nc">Animal</span> <span class="n">animal</span> <span class="o">=</span> <span class="n">dog</span><span class="o">;</span>  <span class="c1">// Upcasting (implicit)</span>
<span class="c1">// OR</span>
<span class="nc">Animal</span> <span class="n">animal</span> <span class="o">=</span> <span class="o">(</span><span class="nc">Animal</span><span class="o">)</span> <span class="n">dog</span><span class="o">;</span>  <span class="c1">// Upcasting (explicit)</span>
</code></pre></div></div>

<h2 id="다운캐스팅">다운캐스팅</h2>

<ul>
  <li>부모 클래스의 타입을 자식 클래스의 타입으로 사용하는 방식이다.</li>
  <li>안전하는 보장이 없어서 명시적으로 캐스팅 해야 한다.
    <ul>
      <li>캐스팅이 성립되지 않으면 ClassCastException이 발생한다.</li>
      <li>instanceof으로 다운캐스팅이 되는지 확인하여 예외를 방지하는 게 좋다.</li>
    </ul>
  </li>
  <li>런타임에 타입을 확인하는 과정이 필요하다.</li>
  <li>equals() 메서드 등 일반적인 클래스를 구체화된 클래스로 변환하는 경우가 아니면 흔하게 사용되지 않는다.
    <ul>
      <li>equals()는 파라미터로 Object를 받는다.</li>
      <li>클래스 내에서 equals()를 오버라이딩할 때 반드시 다운캐스팅을 해야 한다.</li>
    </ul>

    <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="nd">@Override</span>
  <span class="kd">public</span> <span class="kt">boolean</span> <span class="nf">equals</span><span class="o">(</span><span class="nc">Object</span> <span class="n">obj</span><span class="o">)</span> <span class="o">{</span>
      <span class="k">if</span> <span class="o">(</span><span class="k">this</span> <span class="o">==</span> <span class="n">obj</span><span class="o">)</span> <span class="k">return</span> <span class="kc">true</span><span class="o">;</span>
      <span class="k">if</span> <span class="o">(!(</span><span class="n">obj</span> <span class="k">instanceof</span> <span class="nc">User</span><span class="o">))</span> <span class="k">return</span> <span class="kc">false</span><span class="o">;</span>
        
      <span class="c1">// Downcasting is required here to access .username</span>
      <span class="nc">User</span> <span class="n">other</span> <span class="o">=</span> <span class="o">(</span><span class="nc">User</span><span class="o">)</span> <span class="n">obj</span><span class="o">;</span> 
      <span class="k">return</span> <span class="k">this</span><span class="o">.</span><span class="na">username</span><span class="o">.</span><span class="na">equals</span><span class="o">(</span><span class="n">other</span><span class="o">.</span><span class="na">username</span><span class="o">);</span>
  <span class="o">}</span>
</code></pre></div>    </div>
  </li>
</ul>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">Animal</span> <span class="n">animal</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Dog</span><span class="o">();</span>
<span class="nc">Dog</span> <span class="n">dog</span> <span class="o">=</span> <span class="o">(</span><span class="nc">Dog</span><span class="o">)</span> <span class="n">animal</span><span class="o">;</span>  <span class="c1">// Downcasting (explicit, safe here)</span>

<span class="nc">Animal</span> <span class="n">animal2</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Animal</span><span class="o">();</span>
<span class="nc">Dog</span> <span class="n">dog2</span> <span class="o">=</span> <span class="o">(</span><span class="nc">Dog</span><span class="o">)</span> <span class="n">animal2</span><span class="o">;</span>  <span class="c1">// Runtime error: ClassCastException</span>
</code></pre></div></div>]]></content><author><name>베르</name></author><category term="theory" /><summary type="html"><![CDATA[업캐스팅]]></summary></entry><entry><title type="html">extends와 implements</title><link href="https://parkjunhee9327.github.io/theory/implements-and-extends/" rel="alternate" type="text/html" title="extends와 implements" /><published>2026-02-21T00:00:00+00:00</published><updated>2026-02-21T00:00:00+00:00</updated><id>https://parkjunhee9327.github.io/theory/implements-and-extends</id><content type="html" xml:base="https://parkjunhee9327.github.io/theory/implements-and-extends/"><![CDATA[<h2 id="개요">개요</h2>

<ul>
  <li>extends와 implements는 둘 다 상속에 사용된다는 공통점이 있으나, 상속하는 구조에 있어 차이가 있다.</li>
  <li>간단하게 말해 존재하는 행동을 물려주느냐(class-to-class), 새로운 행동을 만드는 데 동의하느냐(class-to-inteface)의 차이다.</li>
</ul>

<h2 id="extends">extends</h2>

<ul>
  <li>클래스를 상속하는 데 사용된다. (Implementation Inheritance)</li>
  <li>자식 클래스와 부모 클래스가 “is a” 관계를 맺는다. (예시: a Dog is an Animal)</li>
  <li>하나의 클래스만 상속받을 수 있다.</li>
  <li>일반적으로 필드, 바디가 있는 메서드를 상속받는다. (abstract 메서드는 예외)</li>
  <li>대부분 메서드 오버라이딩이 선택이다. (abstract 메서드는 예외)</li>
</ul>

<h2 id="implements">implements</h2>

<ul>
  <li>인터페이스를 구현한다. (Interface Inheritance)</li>
  <li>클래스와 인터페이스가 “can do” 관계를 맺는다. (예시: a Dog can Run)</li>
  <li>여러가지 인터페이스들을 구현할 수 있다. (구체적 로직이 없어서 다이아몬드 문제 X)</li>
  <li>일반적으로 메서드 시그니처만 상속받는다. (default 메서드는 예외)</li>
  <li>대부분 메서드 오버라이딩이 필수다. (default 메서드의 경우, 서로 관련 없는 인터페이스들이 동일한 deafult 메서드를 지닌 경우 필수)</li>
</ul>

<p>➕ extends와 implements가 물려주는 요소의 차이</p>

<ul>
  <li>질문 배경
    <ul>
      <li>extends와 implements 둘 다 클래스에게 무언가를 물려준는 점에서 동일하지 않나?</li>
      <li>왜 extends에서는 “is a” 관계를 요구하고 implements는 “can do” 관계를 요구하는가?</li>
    </ul>
  </li>
  <li>extends는 자식에게 필수적인 요소들을 물려준다.
    <ul>
      <li>그렇기에 부모 클래스의 필드(state)와 구체적인 로직(메서드)를 물려주는 것이다.</li>
      <li>자식 클래스가 코드를 재작성할 필요를 없애려는 목적이 있다.</li>
      <li>예시: Animal 클래스가 Dog, Cat 클래스에게 heartRate 변수와 eat() 메서드를 물려준다. (모든 동물들은 심박수가 있고, 먹을 수 있음)</li>
    </ul>
  </li>
  <li>implements는 선택적인 요소들을 물려준다.
    <ul>
      <li>구현하는 클래스가 수행할 수 있는 행동들을 정의하는 목적이 있다.</li>
      <li>동일한 작업을 수행할 수 있는 여러 클래스들을 갈아끼울 수 있는 구조(OOP의 다형성)를 만드는 목적이 있다.</li>
      <li>예시: Dog 클래스가 Soundable 인터페이스에서 makeSound() 메서드를 받아 구현한다. (Dog는 소리를 낼 수 있음)</li>
      <li>예시: Fish 클래스가 Swimmable 인터페이스에서 swim() 메서드를 받아 구현한다. (Fish는 수영할 수 있음)</li>
    </ul>
  </li>
  <li>코드 예시
    <ul>
      <li>
        <p>✅ 클래스가 필수적 요소를, 인터페이스가 선택적 요소를 물려주는 모습</p>

        <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="c1">// 필수적인 요소를 물려주는 클래스</span>
  <span class="kd">class</span> <span class="nc">Animal</span> <span class="o">{</span>
      <span class="kt">void</span> <span class="nf">eat</span><span class="o">()</span> <span class="o">{</span> <span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"Eating..."</span><span class="o">);</span> <span class="o">}</span>
  <span class="o">}</span>
        
  <span class="c1">// 선택적인 요소를 물려주는 인터페이스</span>
  <span class="kd">interface</span> <span class="nc">Climbable</span> <span class="o">{</span>
      <span class="kt">void</span> <span class="nf">climb</span><span class="o">();</span>
  <span class="o">}</span>
        
  <span class="c1">// Cat is an Animal이고 Cat can do Climbing임</span>
  <span class="kd">class</span> <span class="nc">Cat</span> <span class="kd">extends</span> <span class="nc">Animal</span> <span class="kd">implements</span> <span class="nc">Climbable</span> <span class="o">{</span>
      <span class="kd">public</span> <span class="kt">void</span> <span class="nf">climb</span><span class="o">()</span> <span class="o">{</span> <span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"Climbing high!"</span><span class="o">);</span> <span class="o">}</span>
  <span class="o">}</span>
        
  <span class="c1">// Dog is an Animal임. 그러나 Climbing은 못 함</span>
  <span class="kd">class</span> <span class="nc">Dog</span> <span class="kd">extends</span> <span class="nc">Animal</span> <span class="o">{</span>
      <span class="kt">void</span> <span class="nf">bark</span><span class="o">()</span> <span class="o">{</span> <span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"Woof!"</span><span class="o">);</span> <span class="o">}</span>
  <span class="o">}</span>
</code></pre></div>        </div>
      </li>
      <li>
        <p>❌ 클래스가 선택적인 요소를 물려주는 모습</p>

        <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="kd">class</span> <span class="nc">Animal</span> <span class="o">{</span>
  		<span class="c1">// 필수적 요소</span>
      <span class="kt">void</span> <span class="nf">eat</span><span class="o">()</span> <span class="o">{</span> <span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"Eating..."</span><span class="o">);</span> <span class="o">}</span>
            
      <span class="c1">// 선택적 요소</span>
      <span class="kt">void</span> <span class="nf">makeSound</span><span class="o">()</span> <span class="o">{</span> <span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"I'm making sound!"</span><span class="o">);</span> <span class="o">}</span>
  <span class="o">}</span>
        
  <span class="c1">// Cat은 eat과 makeSound 모두 할 수 있음</span>
  <span class="kd">class</span> <span class="nc">Cat</span> <span class="kd">extends</span> <span class="nc">Animal</span> <span class="o">{</span>
      <span class="kd">public</span> <span class="kt">void</span> <span class="nf">eat</span><span class="o">()</span> <span class="o">{</span> <span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"Eating meat!"</span><span class="o">);</span> <span class="o">}</span>
      <span class="kd">public</span> <span class="kt">void</span> <span class="nf">makeSound</span><span class="o">()</span> <span class="o">{</span> <span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"Meow!"</span><span class="o">);</span> <span class="o">}</span>
  <span class="o">}</span>
        
  <span class="c1">// Fish is an Animal은 맞음</span>
  <span class="c1">// 그러나 Fish는 소리를 내지 못함</span>
  <span class="kd">class</span> <span class="nc">Fish</span> <span class="kd">extends</span> <span class="nc">Animal</span> <span class="o">{</span>
      <span class="kd">public</span> <span class="kt">void</span> <span class="nf">eat</span><span class="o">()</span> <span class="o">{</span> <span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"Eating seaweed!"</span><span class="o">);</span> <span class="o">}</span>
      <span class="kd">public</span> <span class="kt">void</span> <span class="nf">makeSound</span><span class="o">()</span> <span class="o">{</span> <span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"??"</span><span class="o">);</span> <span class="o">}</span>
  <span class="o">}</span>
</code></pre></div>        </div>
      </li>
      <li>
        <p>❌ 인터페이스가 필수적인 요소를 물려주는 모습</p>
        <ul>
          <li>인터페이스는 인스턴스 필드를 생성할 수 없으므로 클래스에게 변수를 물려줄 수 없다.
            <ul>
              <li>static 필드는 상속될 수 있으나, 객체마다의 고유한 값을 설정할 수도 없고 상태가 있지도 않아서 상속인가에 대해 논란이 있다.</li>
            </ul>
          </li>
          <li>default 메서드로 바디가 있는 메서드를 클래스에 줄 수 있지만 extends로 상속받는 메서드와 목적이 다르다.
            <ul>
              <li>extends로 상속받는 메서드의 “로직과 상태를 공유한다”는 목적이 아닌 “이전 버전과의 호환성을 유지한다”는 목적이 있다.</li>
              <li>상속받아 봤자 클래스의 인스턴스 변수에 접근하지도 못한다.</li>
            </ul>
          </li>
        </ul>
      </li>
    </ul>
  </li>
</ul>

<p>➕ extends는 implements보다 덜 쓰인다?</p>

<ul>
  <li>질문 배경
    <ul>
      <li>내가 개발을 하면서 extends를 쓸 일은 사실상 없었다. 주로 implements를 썼지.</li>
      <li>근데 생각해보니 Spring Security, Java의 기본적 클래스들(JDK에 있는 클래스들)에는 extends가 많이 쓰이더라.</li>
      <li>현대에 와서 extends가 구식이 되어버린 것일까?</li>
    </ul>
  </li>
  <li>extends가 덜 쓰인다 보다는 implements와 역할이 달라졌다고 보는 게 적절하다.</li>
  <li>implements는 구현체가 무엇을 할 수 있는지를 나타내는 계약 사항이다.
    <ul>
      <li>클래스가 구현체가 아닌 추상화에 의존하도록 하여 느슨한 커플링을 형성한다.</li>
      <li>추상화에 상황에 맞는 구현체를 갈아끼울 수 있어 테스트가 수월해진다.</li>
      <li>클라이언트의 요구에 따라 코드가 유연하게 변경되어야 하는 비즈니스 로직 개발에 주로 쓰인다.</li>
    </ul>
  </li>
  <li>extends는 클래스의 신원 또는 상태를 나타낸다.
    <ul>
      <li>자식 클래스가 부모 클래스의 필드와 메서드를 물려받아 클래스들의 위계 구조를 확립한다.</li>
      <li>
        <p>Generic에 범위를 지정하는 등 타입 안전성을 유지하는 역할을 한다.</p>

        <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="c1">// This means "T must be a type that implements List"</span>
  <span class="kd">public</span> <span class="o">&lt;</span><span class="no">T</span> <span class="kd">extends</span> <span class="nc">List</span><span class="o">&gt;</span> <span class="kt">void</span> <span class="nf">processList</span><span class="o">(</span><span class="no">T</span> <span class="n">list</span><span class="o">)</span> <span class="o">{</span> <span class="o">...</span> <span class="o">}</span>
</code></pre></div>        </div>
      </li>
      <li>잠재 고객들인 개발자에게 코드의 일관되고 엄격한 구조를 보장해주어야 하는 라이브러리 또는 프레임워크 개발에 주로 쓰인다.</li>
    </ul>
  </li>
</ul>]]></content><author><name>베르</name></author><category term="theory" /><summary type="html"><![CDATA[개요]]></summary></entry><entry><title type="html">상속이란 무엇이며, 왜 사용하는가?</title><link href="https://parkjunhee9327.github.io/theory/inheritance/" rel="alternate" type="text/html" title="상속이란 무엇이며, 왜 사용하는가?" /><published>2026-02-21T00:00:00+00:00</published><updated>2026-02-21T00:00:00+00:00</updated><id>https://parkjunhee9327.github.io/theory/inheritance</id><content type="html" xml:base="https://parkjunhee9327.github.io/theory/inheritance/"><![CDATA[<h2 id="상속이란-무엇인가">상속이란 무엇인가</h2>

<ul>
  <li>하나의 클래스가 다른 클래스의 필드와 메서드를 물려받는 OOP의 개념.</li>
</ul>

<h2 id="상속의-특징">상속의 특징</h2>

<ul>
  <li>상속을 받는 클래스를 자식(서브) 클래스, 상속을 하는 클래스를 부모(수퍼) 클래스라고 한다.</li>
  <li>자식 클래스가 extends 키워드를 사용하여 부모로부터 상속을 받는다.</li>
  <li>자식 클래스가 super 키워드를 사용하여 부모 클래스를 참조할 수 있다.</li>
  <li>부모 클래스가 sealed 키워드를 사용하여 상속받을 수 있는 클래스를 한정지을 수 있다.</li>
  <li>자식 클래스가 상속받은 행동(메서드)을 수정할 수 있다. 메서드 오버라이딩이라고 한다. 자식이 부모의 메서드를 반드시 오버라이딩 해야 하는 것은 아니다.</li>
</ul>

<h2 id="자식-클래스와-부모-클래스의-관계를-형성하는-조건">자식 클래스와 부모 클래스의 관계를 형성하는 조건</h2>

<ul>
  <li>자식과 부모는 “is a kind of”의 관계를 만족해야 한다.
    <ul>
      <li>✅ Circle은 Shape의 종류 중 하나다.</li>
      <li>✅ Dog는 Animal의 종류 중 하나다.</li>
      <li>❌ Engine은 Car의 종류 중 하나가 아니다. (Engine은 Car의 부품이다)</li>
      <li>❌ Student는 Classroom의 종류 중 하나가 아니다. (Student는 Classroom을 사용한다)</li>
    </ul>
  </li>
  <li>SOLID의 리스코프 치환 원칙을 만족해야 한다.
    <ul>
      <li>자식 클래스는 코드의 기능성을 해치지 않고도 부모 클래스로 대체될 수 있어야 한다.</li>
    </ul>
  </li>
  <li>자식 클래스는 부모 클래스의 기능을 상속받을 뿐 아니라 사용해야 한다.
    <ul>
      <li>자식 클래스는 부모 클래스도 대체될 수 있어야 하기 때문이다.</li>
    </ul>
  </li>
</ul>]]></content><author><name>베르</name></author><category term="theory" /><summary type="html"><![CDATA[상속이란 무엇인가]]></summary></entry><entry><title type="html">is-a 관계와 has-a 관계</title><link href="https://parkjunhee9327.github.io/theory/isa-and-hasa/" rel="alternate" type="text/html" title="is-a 관계와 has-a 관계" /><published>2026-02-21T00:00:00+00:00</published><updated>2026-02-21T00:00:00+00:00</updated><id>https://parkjunhee9327.github.io/theory/isa-and-hasa</id><content type="html" xml:base="https://parkjunhee9327.github.io/theory/isa-and-hasa/"><![CDATA[<h2 id="is-a-관계-상속">Is-a 관계 (상속)</h2>

<ul>
  <li>클래스를 상속 받거나 인터페이스를 구현함을 나타낸다.</li>
  <li>하나의 클래스가 다른 클래스의 구체화된 버전이라는 의미다.</li>
  <li>커플링이 강하여 부모가 자식에게 영향을 준다.</li>
  <li>컴파일 타임에 위계 구조가 고정된다.
    <ul>
      <li>런타임에 상속받을 부모 클래스를 변경하거나, 조건부적으로 상속받을 수 없다.</li>
    </ul>
  </li>
  <li>다형성이 필요하거나 클래스들 간 관계가 변경될 일이 없을 때 사용한다.</li>
  <li>
    <p>코드 예시</p>

    <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="c1">// Base class</span>
  <span class="kd">class</span> <span class="nc">Vehicle</span> <span class="o">{</span>
      <span class="kt">void</span> <span class="nf">start</span><span class="o">()</span> <span class="o">{</span>
          <span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"Vehicle starting"</span><span class="o">);</span>
      <span class="o">}</span>
  <span class="o">}</span>
    
  <span class="c1">// Derived class - Car IS-A Vehicle</span>
  <span class="kd">class</span> <span class="nc">Car</span> <span class="kd">extends</span> <span class="nc">Vehicle</span> <span class="o">{</span>
      <span class="kt">void</span> <span class="nf">drive</span><span class="o">()</span> <span class="o">{</span>
          <span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"Car driving"</span><span class="o">);</span>
      <span class="o">}</span>
  <span class="o">}</span>
    
  <span class="c1">// Interface example</span>
  <span class="kd">interface</span> <span class="nc">Flyable</span> <span class="o">{</span>
      <span class="kt">void</span> <span class="nf">fly</span><span class="o">();</span>
  <span class="o">}</span>
    
  <span class="c1">// Bird IS-A Flyable</span>
  <span class="kd">class</span> <span class="nc">Bird</span> <span class="kd">implements</span> <span class="nc">Flyable</span> <span class="o">{</span>
      <span class="kd">public</span> <span class="kt">void</span> <span class="nf">fly</span><span class="o">()</span> <span class="o">{</span>
          <span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"Bird flying"</span><span class="o">);</span>
      <span class="o">}</span>
  <span class="o">}</span>
</code></pre></div>    </div>
  </li>
</ul>

<h2 id="has-a-관계-구성집합">Has-a 관계 (구성/집합)</h2>

<ul>
  <li>구성(composition) 또는 집합(aggregation) 관계를 나타낸다.
    <ul>
      <li>Composition: 강한 전체와 부품의 관계. 부품은 전체가 없이는 존재할 수 없다.</li>
      <li>Aggregation: 약한 전체와 부품의 관계. 부품은 전체가 없어도 존재할 수 있다.</li>
    </ul>
  </li>
  <li>하나의 클래스가 다른 클래스의 요소를 포함하거나 사용한다는 의미이다.</li>
  <li>커플링이 약하여 포함된 객체가 변경될 수 있다.</li>
  <li>런타임에 행동이 변경 가능하다.</li>
  <li>클래스들 간의 관계가 추후에 변경될 수 있거나 상속의 관계 없이 다른 클래스의 기능을 사용하고 싶을 때 따르는 구조이다.</li>
  <li>
    <p>코드 예시</p>

    <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="c1">// Engine class</span>
  <span class="kd">class</span> <span class="nc">Engine</span> <span class="o">{</span>
      <span class="kt">void</span> <span class="nf">ignite</span><span class="o">()</span> <span class="o">{</span>
          <span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"Engine ignited"</span><span class="o">);</span>
      <span class="o">}</span>
  <span class="o">}</span>
    
  <span class="c1">// Car HAS-A Engine (Composition)</span>
  <span class="kd">class</span> <span class="nc">Car</span> <span class="o">{</span>
      <span class="kd">private</span> <span class="nc">Engine</span> <span class="n">engine</span><span class="o">;</span>  <span class="c1">// Composition</span>
        
      <span class="kd">public</span> <span class="nf">Car</span><span class="o">()</span> <span class="o">{</span>
          <span class="k">this</span><span class="o">.</span><span class="na">engine</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Engine</span><span class="o">();</span>  <span class="c1">// Engine created with Car</span>
      <span class="o">}</span>
        
      <span class="kt">void</span> <span class="nf">start</span><span class="o">()</span> <span class="o">{</span>
          <span class="n">engine</span><span class="o">.</span><span class="na">ignite</span><span class="o">();</span>
      <span class="o">}</span>
  <span class="o">}</span>
    
  <span class="c1">// Department class</span>
  <span class="kd">class</span> <span class="nc">Department</span> <span class="o">{</span>
      <span class="kd">private</span> <span class="nc">String</span> <span class="n">name</span><span class="o">;</span>
        
      <span class="kd">public</span> <span class="nf">Department</span><span class="o">(</span><span class="nc">String</span> <span class="n">name</span><span class="o">)</span> <span class="o">{</span>
          <span class="k">this</span><span class="o">.</span><span class="na">name</span> <span class="o">=</span> <span class="n">name</span><span class="o">;</span>
      <span class="o">}</span>
  <span class="o">}</span>
    
  <span class="c1">// University HAS-A Department (Aggregation)</span>
  <span class="kd">class</span> <span class="nc">University</span> <span class="o">{</span>
      <span class="kd">private</span> <span class="nc">List</span><span class="o">&lt;</span><span class="nc">Department</span><span class="o">&gt;</span> <span class="n">departments</span><span class="o">;</span>  <span class="c1">// Aggregation</span>
        
      <span class="kd">public</span> <span class="nf">University</span><span class="o">(</span><span class="nc">List</span><span class="o">&lt;</span><span class="nc">Department</span><span class="o">&gt;</span> <span class="n">departments</span><span class="o">)</span> <span class="o">{</span>
          <span class="k">this</span><span class="o">.</span><span class="na">departments</span> <span class="o">=</span> <span class="n">departments</span><span class="o">;</span>  <span class="c1">// Departments exist independently</span>
      <span class="o">}</span>
  <span class="o">}</span>
</code></pre></div>    </div>
  </li>
</ul>

<h3 id="상속보다-구성-원칙composition-over-inheritance-principle">➕상속보다 구성 원칙(Composition Over Inheritance principle)</h3>

<ul>
  <li>객체들을 상속보다 구성의 방식으로 구축하는 방식을 제안하는 OOP 디자인 원칙 중 하나다.</li>
  <li>상속의 강한 커플링, 클래스의 경우 하나밖에 상속할 수 없는 점, 부모 클래스가 자식 클래스에게 끼치는 영향 등상속의 단점을 해소하기 위한 방식이다.</li>
  <li>
    <p>상속 대신에 인터페이스 또는 컴포지션 방식을 택한다.</p>

    <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="c1">// Instead of inheritance, use interfaces and composition</span>
  <span class="kd">interface</span> <span class="nc">FlyBehavior</span> <span class="o">{</span>
      <span class="kt">void</span> <span class="nf">fly</span><span class="o">();</span>
  <span class="o">}</span>
    
  <span class="kd">interface</span> <span class="nc">QuackBehavior</span> <span class="o">{</span>
      <span class="kt">void</span> <span class="nf">quack</span><span class="o">();</span>
  <span class="o">}</span>
    
  <span class="kd">class</span> <span class="nc">FlyWithWings</span> <span class="kd">implements</span> <span class="nc">FlyBehavior</span> <span class="o">{</span>
      <span class="kd">public</span> <span class="kt">void</span> <span class="nf">fly</span><span class="o">()</span> <span class="o">{</span>
          <span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"Flying with wings"</span><span class="o">);</span>
      <span class="o">}</span>
  <span class="o">}</span>
    
  <span class="kd">class</span> <span class="nc">FlyNoWay</span> <span class="kd">implements</span> <span class="nc">FlyBehavior</span> <span class="o">{</span>
      <span class="kd">public</span> <span class="kt">void</span> <span class="nf">fly</span><span class="o">()</span> <span class="o">{</span>
          <span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"Can't fly"</span><span class="o">);</span>
      <span class="o">}</span>
  <span class="o">}</span>
    
  <span class="kd">class</span> <span class="nc">Duck</span> <span class="o">{</span>
      <span class="kd">private</span> <span class="nc">FlyBehavior</span> <span class="n">flyBehavior</span><span class="o">;</span>
      <span class="kd">private</span> <span class="nc">QuackBehavior</span> <span class="n">quackBehavior</span><span class="o">;</span>
        
      <span class="kd">public</span> <span class="nf">Duck</span><span class="o">(</span><span class="nc">FlyBehavior</span> <span class="n">flyBehavior</span><span class="o">,</span> <span class="nc">QuackBehavior</span> <span class="n">quackBehavior</span><span class="o">)</span> <span class="o">{</span>
          <span class="k">this</span><span class="o">.</span><span class="na">flyBehavior</span> <span class="o">=</span> <span class="n">flyBehavior</span><span class="o">;</span>
          <span class="k">this</span><span class="o">.</span><span class="na">quackBehavior</span> <span class="o">=</span> <span class="n">quackBehavior</span><span class="o">;</span>
      <span class="o">}</span>
        
      <span class="kt">void</span> <span class="nf">performFly</span><span class="o">()</span> <span class="o">{</span>
          <span class="n">flyBehavior</span><span class="o">.</span><span class="na">fly</span><span class="o">();</span>
      <span class="o">}</span>
        
      <span class="kt">void</span> <span class="nf">performQuack</span><span class="o">()</span> <span class="o">{</span>
          <span class="n">quackBehavior</span><span class="o">.</span><span class="na">quack</span><span class="o">();</span>
      <span class="o">}</span>
        
      <span class="c1">// Dynamically change behavior at runtime</span>
      <span class="kt">void</span> <span class="nf">setFlyBehavior</span><span class="o">(</span><span class="nc">FlyBehavior</span> <span class="n">fb</span><span class="o">)</span> <span class="o">{</span>
          <span class="k">this</span><span class="o">.</span><span class="na">flyBehavior</span> <span class="o">=</span> <span class="n">fb</span><span class="o">;</span>
      <span class="o">}</span>
  <span class="o">}</span>
    
  <span class="c1">// Usage</span>
  <span class="nc">Duck</span> <span class="n">mallard</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Duck</span><span class="o">(</span><span class="k">new</span> <span class="nc">FlyWithWings</span><span class="o">(),</span> <span class="k">new</span> <span class="nc">LoudQuack</span><span class="o">());</span>
  <span class="nc">Duck</span> <span class="n">rubberDuck</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Duck</span><span class="o">(</span><span class="k">new</span> <span class="nc">FlyNoWay</span><span class="o">(),</span> <span class="k">new</span> <span class="nc">Squeak</span><span class="o">());</span>
</code></pre></div>    </div>
  </li>
  <li>장점
    <ul>
      <li>
        <p>유연성 및 런타임 행동의 변화 가능</p>

        <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="kd">class</span> <span class="nc">Character</span> <span class="o">{</span>
      <span class="kd">private</span> <span class="nc">WeaponBehavior</span> <span class="n">weapon</span><span class="o">;</span>  <span class="c1">// Composition</span>
            
      <span class="kt">void</span> <span class="nf">setWeapon</span><span class="o">(</span><span class="nc">WeaponBehavior</span> <span class="n">weapon</span><span class="o">)</span> <span class="o">{</span>
          <span class="k">this</span><span class="o">.</span><span class="na">weapon</span> <span class="o">=</span> <span class="n">weapon</span><span class="o">;</span>  <span class="c1">// Change behavior at runtime</span>
      <span class="o">}</span>
            
      <span class="kt">void</span> <span class="nf">fight</span><span class="o">()</span> <span class="o">{</span>
          <span class="n">weapon</span><span class="o">.</span><span class="na">useWeapon</span><span class="o">();</span>
      <span class="o">}</span>
  <span class="o">}</span>
        
  <span class="c1">// Character can switch weapons dynamically</span>
  <span class="n">character</span><span class="o">.</span><span class="na">setWeapon</span><span class="o">(</span><span class="k">new</span> <span class="nc">Sword</span><span class="o">());</span>
  <span class="n">character</span><span class="o">.</span><span class="na">fight</span><span class="o">();</span>  <span class="c1">// Uses sword</span>
        
  <span class="n">character</span><span class="o">.</span><span class="na">setWeapon</span><span class="o">(</span><span class="k">new</span> <span class="nc">Bow</span><span class="o">());</span>
  <span class="n">character</span><span class="o">.</span><span class="na">fight</span><span class="o">();</span>  <span class="c1">// Now uses bow</span>
</code></pre></div>        </div>
      </li>
      <li>
        <p>상속보다 나은 캡슐화</p>

        <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="c1">// Inheritance exposes protected members</span>
  <span class="kd">class</span> <span class="nc">Base</span> <span class="o">{</span>
      <span class="kd">protected</span> <span class="nc">String</span> <span class="n">internalData</span><span class="o">;</span>  <span class="c1">// Exposed to subclasses</span>
  <span class="o">}</span>
        
  <span class="c1">// Composition keeps implementation hidden</span>
  <span class="kd">class</span> <span class="nc">Container</span> <span class="o">{</span>
      <span class="kd">private</span> <span class="nc">Base</span> <span class="n">base</span><span class="o">;</span>  <span class="c1">// Internal implementation hidden</span>
      <span class="kd">public</span> <span class="kt">void</span> <span class="nf">doSomething</span><span class="o">()</span> <span class="o">{</span>
          <span class="c1">// Use base internally</span>
      <span class="o">}</span>
  <span class="o">}</span>
</code></pre></div>        </div>
      </li>
      <li>
        <p>클래스의 과도한 추가 방지</p>

        <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="c1">// Without composition: combinatorial explosion</span>
  <span class="c1">// class FlyingSwordWieldingElf extends Elf {}</span>
  <span class="c1">// class FlyingAxeWieldingElf extends Elf {}</span>
  <span class="c1">// class WalkingSwordWieldingElf extends Elf {}</span>
  <span class="c1">// ... and so on</span>
        
  <span class="c1">// With composition: combine behaviors</span>
  <span class="kd">class</span> <span class="nc">GameCharacter</span> <span class="o">{</span>
      <span class="kd">private</span> <span class="nc">MovementBehavior</span> <span class="n">movement</span><span class="o">;</span>
      <span class="kd">private</span> <span class="nc">WeaponBehavior</span> <span class="n">weapon</span><span class="o">;</span>
      <span class="kd">private</span> <span class="nc">Race</span> <span class="n">race</span><span class="o">;</span>
            
      <span class="c1">// Combine independent behaviors</span>
      <span class="nc">GameCharacter</span> <span class="n">elfArcher</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">GameCharacter</span><span class="o">(</span>
          <span class="k">new</span> <span class="nf">FlyingMovement</span><span class="o">(),</span>
          <span class="k">new</span> <span class="nf">BowWeapon</span><span class="o">(),</span>
          <span class="k">new</span> <span class="nf">ElfRace</span><span class="o">()</span>
      <span class="o">);</span>
  <span class="o">}</span>
</code></pre></div>        </div>
      </li>
    </ul>
  </li>
  <li>실무에서의 구현 패턴
    <ul>
      <li>
        <p>Strategy 패턴 (행동적인 구성)</p>

        <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="kd">interface</span> <span class="nc">PaymentStrategy</span> <span class="o">{</span>
      <span class="kt">void</span> <span class="nf">pay</span><span class="o">(</span><span class="kt">double</span> <span class="n">amount</span><span class="o">);</span>
  <span class="o">}</span>
        
  <span class="kd">class</span> <span class="nc">CreditCardPayment</span> <span class="kd">implements</span> <span class="nc">PaymentStrategy</span> <span class="o">{</span>
      <span class="kd">private</span> <span class="nc">String</span> <span class="n">cardNumber</span><span class="o">;</span>
            
      <span class="kd">public</span> <span class="kt">void</span> <span class="nf">pay</span><span class="o">(</span><span class="kt">double</span> <span class="n">amount</span><span class="o">)</span> <span class="o">{</span>
          <span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"Paid "</span> <span class="o">+</span> <span class="n">amount</span> <span class="o">+</span> <span class="s">" using credit card"</span><span class="o">);</span>
      <span class="o">}</span>
  <span class="o">}</span>
        
  <span class="kd">class</span> <span class="nc">PayPalPayment</span> <span class="kd">implements</span> <span class="nc">PaymentStrategy</span> <span class="o">{</span>
      <span class="kd">private</span> <span class="nc">String</span> <span class="n">email</span><span class="o">;</span>
            
      <span class="kd">public</span> <span class="kt">void</span> <span class="nf">pay</span><span class="o">(</span><span class="kt">double</span> <span class="n">amount</span><span class="o">)</span> <span class="o">{</span>
          <span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"Paid "</span> <span class="o">+</span> <span class="n">amount</span> <span class="o">+</span> <span class="s">" using PayPal"</span><span class="o">);</span>
      <span class="o">}</span>
  <span class="o">}</span>
        
  <span class="kd">class</span> <span class="nc">ShoppingCart</span> <span class="o">{</span>
      <span class="kd">private</span> <span class="nc">PaymentStrategy</span> <span class="n">paymentStrategy</span><span class="o">;</span>
            
      <span class="kd">public</span> <span class="kt">void</span> <span class="nf">setPaymentStrategy</span><span class="o">(</span><span class="nc">PaymentStrategy</span> <span class="n">strategy</span><span class="o">)</span> <span class="o">{</span>
          <span class="k">this</span><span class="o">.</span><span class="na">paymentStrategy</span> <span class="o">=</span> <span class="n">strategy</span><span class="o">;</span>
      <span class="o">}</span>
            
      <span class="kd">public</span> <span class="kt">void</span> <span class="nf">checkout</span><span class="o">(</span><span class="kt">double</span> <span class="n">amount</span><span class="o">)</span> <span class="o">{</span>
          <span class="n">paymentStrategy</span><span class="o">.</span><span class="na">pay</span><span class="o">(</span><span class="n">amount</span><span class="o">);</span>
      <span class="o">}</span>
  <span class="o">}</span>
</code></pre></div>        </div>
      </li>
      <li>
        <p>Decorator 패턴 (구조적인 구성)</p>

        <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="kd">interface</span> <span class="nc">Coffee</span> <span class="o">{</span>
      <span class="kt">double</span> <span class="nf">getCost</span><span class="o">();</span>
      <span class="nc">String</span> <span class="nf">getDescription</span><span class="o">();</span>
  <span class="o">}</span>
        
  <span class="kd">class</span> <span class="nc">BasicCoffee</span> <span class="kd">implements</span> <span class="nc">Coffee</span> <span class="o">{</span>
      <span class="kd">public</span> <span class="kt">double</span> <span class="nf">getCost</span><span class="o">()</span> <span class="o">{</span> <span class="k">return</span> <span class="mf">5.0</span><span class="o">;</span> <span class="o">}</span>
      <span class="kd">public</span> <span class="nc">String</span> <span class="nf">getDescription</span><span class="o">()</span> <span class="o">{</span> <span class="k">return</span> <span class="s">"Basic coffee"</span><span class="o">;</span> <span class="o">}</span>
  <span class="o">}</span>
        
  <span class="kd">abstract</span> <span class="kd">class</span> <span class="nc">CoffeeDecorator</span> <span class="kd">implements</span> <span class="nc">Coffee</span> <span class="o">{</span>
      <span class="kd">protected</span> <span class="nc">Coffee</span> <span class="n">decoratedCoffee</span><span class="o">;</span>
            
      <span class="kd">public</span> <span class="nf">CoffeeDecorator</span><span class="o">(</span><span class="nc">Coffee</span> <span class="n">coffee</span><span class="o">)</span> <span class="o">{</span>
          <span class="k">this</span><span class="o">.</span><span class="na">decoratedCoffee</span> <span class="o">=</span> <span class="n">coffee</span><span class="o">;</span>
      <span class="o">}</span>
  <span class="o">}</span>
        
  <span class="kd">class</span> <span class="nc">MilkDecorator</span> <span class="kd">extends</span> <span class="nc">CoffeeDecorator</span> <span class="o">{</span>
      <span class="kd">public</span> <span class="nf">MilkDecorator</span><span class="o">(</span><span class="nc">Coffee</span> <span class="n">coffee</span><span class="o">)</span> <span class="o">{</span>
          <span class="kd">super</span><span class="o">(</span><span class="n">coffee</span><span class="o">);</span>
      <span class="o">}</span>
            
      <span class="kd">public</span> <span class="kt">double</span> <span class="nf">getCost</span><span class="o">()</span> <span class="o">{</span>
          <span class="k">return</span> <span class="n">decoratedCoffee</span><span class="o">.</span><span class="na">getCost</span><span class="o">()</span> <span class="o">+</span> <span class="mf">1.5</span><span class="o">;</span>
      <span class="o">}</span>
            
      <span class="kd">public</span> <span class="nc">String</span> <span class="nf">getDescription</span><span class="o">()</span> <span class="o">{</span>
          <span class="k">return</span> <span class="n">decoratedCoffee</span><span class="o">.</span><span class="na">getDescription</span><span class="o">()</span> <span class="o">+</span> <span class="s">", Milk"</span><span class="o">;</span>
      <span class="o">}</span>
  <span class="o">}</span>
        
  <span class="c1">// Usage: Compose features dynamically</span>
  <span class="nc">Coffee</span> <span class="n">myCoffee</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">MilkDecorator</span><span class="o">(</span>
                      <span class="k">new</span> <span class="nf">SugarDecorator</span><span class="o">(</span>
                          <span class="k">new</span> <span class="nf">BasicCoffee</span><span class="o">()));</span>
</code></pre></div>        </div>
      </li>
      <li>
        <p>의존성 주입 (생성자 구성)</p>

        <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="kd">class</span> <span class="nc">DataProcessor</span> <span class="o">{</span>
      <span class="kd">private</span> <span class="kd">final</span> <span class="nc">Repository</span> <span class="n">repository</span><span class="o">;</span>
      <span class="kd">private</span> <span class="kd">final</span> <span class="nc">Validator</span> <span class="n">validator</span><span class="o">;</span>
            
      <span class="c1">// Dependencies injected via constructor</span>
      <span class="kd">public</span> <span class="nf">DataProcessor</span><span class="o">(</span><span class="nc">Repository</span> <span class="n">repo</span><span class="o">,</span> <span class="nc">Validator</span> <span class="n">validator</span><span class="o">)</span> <span class="o">{</span>
          <span class="k">this</span><span class="o">.</span><span class="na">repository</span> <span class="o">=</span> <span class="n">repo</span><span class="o">;</span>
          <span class="k">this</span><span class="o">.</span><span class="na">validator</span> <span class="o">=</span> <span class="n">validator</span><span class="o">;</span>
      <span class="o">}</span>
            
      <span class="kd">public</span> <span class="kt">void</span> <span class="nf">process</span><span class="o">(</span><span class="nc">Data</span> <span class="n">data</span><span class="o">)</span> <span class="o">{</span>
          <span class="k">if</span> <span class="o">(</span><span class="n">validator</span><span class="o">.</span><span class="na">isValid</span><span class="o">(</span><span class="n">data</span><span class="o">))</span> <span class="o">{</span>
              <span class="n">repository</span><span class="o">.</span><span class="na">save</span><span class="o">(</span><span class="n">data</span><span class="o">);</span>
          <span class="o">}</span>
      <span class="o">}</span>
  <span class="o">}</span>
</code></pre></div>        </div>
      </li>
    </ul>
  </li>
  <li>그럼에도 상속을 써야 하는 경우
    <ul>
      <li>
        <p>공유하는 정체성이 있는 실제 “is-a” 관계</p>

        <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="c1">// Good inheritance: Shape hierarchy</span>
  <span class="kd">abstract</span> <span class="kd">class</span> <span class="nc">Shape</span> <span class="o">{</span>
      <span class="kd">abstract</span> <span class="kt">double</span> <span class="nf">area</span><span class="o">();</span>
      <span class="kd">abstract</span> <span class="kt">double</span> <span class="nf">perimeter</span><span class="o">();</span>
  <span class="o">}</span>
        
  <span class="kd">class</span> <span class="nc">Circle</span> <span class="kd">extends</span> <span class="nc">Shape</span> <span class="o">{</span>  <span class="c1">// Circle IS-A Shape</span>
      <span class="kd">private</span> <span class="kt">double</span> <span class="n">radius</span><span class="o">;</span>
            
      <span class="kt">double</span> <span class="nf">area</span><span class="o">()</span> <span class="o">{</span>
          <span class="k">return</span> <span class="nc">Math</span><span class="o">.</span><span class="na">PI</span> <span class="o">*</span> <span class="n">radius</span> <span class="o">*</span> <span class="n">radius</span><span class="o">;</span>
      <span class="o">}</span>
  <span class="o">}</span>
</code></pre></div>        </div>
      </li>
      <li>
        <p>위계 구조가 필요한 프레임워크 / API 디자인</p>

        <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="c1">// Java Collections Framework</span>
  <span class="kd">public</span> <span class="kd">abstract</span> <span class="kd">class</span> <span class="nc">AbstractList</span><span class="o">&lt;</span><span class="no">E</span><span class="o">&gt;</span> <span class="kd">implements</span> <span class="nc">List</span><span class="o">&lt;</span><span class="no">E</span><span class="o">&gt;</span> <span class="o">{</span>
      <span class="c1">// Provides skeletal implementation</span>
      <span class="c1">// Subclasses fill in specifics</span>
  <span class="o">}</span>
</code></pre></div>        </div>
      </li>
      <li>
        <p>Template Method 패턴</p>

        <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="kd">abstract</span> <span class="kd">class</span> <span class="nc">DataParser</span> <span class="o">{</span>
      <span class="c1">// Template method with fixed algorithm</span>
      <span class="kd">public</span> <span class="kd">final</span> <span class="kt">void</span> <span class="nf">parse</span><span class="o">()</span> <span class="o">{</span>  <span class="c1">// final to prevent overriding</span>
          <span class="n">readData</span><span class="o">();</span>
          <span class="n">processData</span><span class="o">();</span>  <span class="c1">// Abstract - subclass implements</span>
          <span class="n">saveData</span><span class="o">();</span>
      <span class="o">}</span>
            
      <span class="kd">protected</span> <span class="kd">abstract</span> <span class="kt">void</span> <span class="nf">processData</span><span class="o">();</span>
  <span class="o">}</span>
</code></pre></div>        </div>
      </li>
    </ul>
  </li>
  <li>Composition을 지원하는 Java의 특징
    <ul>
      <li>
        <p>인터페이스의 default 메서드</p>

        <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="kd">interface</span> <span class="nc">Logger</span> <span class="o">{</span>
      <span class="kt">void</span> <span class="nf">log</span><span class="o">(</span><span class="nc">String</span> <span class="n">message</span><span class="o">);</span>
            
      <span class="c1">// Default implementation - like inheritance but composable</span>
      <span class="k">default</span> <span class="kt">void</span> <span class="nf">logError</span><span class="o">(</span><span class="nc">String</span> <span class="n">error</span><span class="o">)</span> <span class="o">{</span>
          <span class="n">log</span><span class="o">(</span><span class="s">"ERROR: "</span> <span class="o">+</span> <span class="n">error</span><span class="o">);</span>
      <span class="o">}</span>
  <span class="o">}</span>
        
  <span class="c1">// Multiple interfaces can be composed</span>
  <span class="kd">class</span> <span class="nc">FileLogger</span> <span class="kd">implements</span> <span class="nc">Logger</span><span class="o">,</span> <span class="nc">AutoCloseable</span> <span class="o">{</span>
      <span class="kd">public</span> <span class="kt">void</span> <span class="nf">log</span><span class="o">(</span><span class="nc">String</span> <span class="n">message</span><span class="o">)</span> <span class="o">{</span> <span class="cm">/* write to file */</span> <span class="o">}</span>
      <span class="kd">public</span> <span class="kt">void</span> <span class="nf">close</span><span class="o">()</span> <span class="o">{</span> <span class="cm">/* close file */</span> <span class="o">}</span>
  <span class="o">}</span>
</code></pre></div>        </div>
      </li>
      <li>
        <p>데이터 구성을 위한 레코드</p>

        <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="c1">// Records automatically compose equals(), hashCode(), toString()</span>
  <span class="n">record</span> <span class="nf">Point</span><span class="o">(</span><span class="kt">int</span> <span class="n">x</span><span class="o">,</span> <span class="kt">int</span> <span class="n">y</span><span class="o">)</span> <span class="o">{}</span>
        
  <span class="n">record</span> <span class="nf">Line</span><span class="o">(</span><span class="nc">Point</span> <span class="n">start</span><span class="o">,</span> <span class="nc">Point</span> <span class="n">end</span><span class="o">)</span> <span class="o">{</span>  <span class="c1">// Composition</span>
      <span class="kt">double</span> <span class="nf">length</span><span class="o">()</span> <span class="o">{</span>
          <span class="k">return</span> <span class="nc">Math</span><span class="o">.</span><span class="na">hypot</span><span class="o">(</span><span class="n">end</span><span class="o">.</span><span class="na">x</span><span class="o">()</span> <span class="o">-</span> <span class="n">start</span><span class="o">.</span><span class="na">x</span><span class="o">(),</span> 
                           <span class="n">end</span><span class="o">.</span><span class="na">y</span><span class="o">()</span> <span class="o">-</span> <span class="n">start</span><span class="o">.</span><span class="na">y</span><span class="o">());</span>
      <span class="o">}</span>
  <span class="o">}</span>
</code></pre></div>        </div>
      </li>
    </ul>
  </li>
</ul>]]></content><author><name>베르</name></author><category term="theory" /><summary type="html"><![CDATA[Is-a 관계 (상속)]]></summary></entry></feed>