<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>baemungs.log</title>
        <link>https://velog.io/</link>
        <description>SSAFY 6th -&gt; SEC VD SW  👨‍💻🔥</description>
        <lastBuildDate>Sat, 23 Jul 2022 09:37:20 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>baemungs.log</title>
            <url>https://images.velog.io/images/bae_mung/profile/960024f2-5a98-48a0-82bc-f4f694f2d373/social.jpeg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. baemungs.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/bae_mung" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[AWS - 01. IAM]]></title>
            <link>https://velog.io/@bae_mung/AWS-01.-IAM</link>
            <guid>https://velog.io/@bae_mung/AWS-01.-IAM</guid>
            <pubDate>Sat, 23 Jul 2022 09:37:20 GMT</pubDate>
            <description><![CDATA[<hr>
<h2 id="iamidentity-and-access-management이란">IAM(Identity and Access Management)이란?</h2>
<h3 id="iam이-제공하는-서비스">IAM이 제공하는 서비스</h3>
<h4 id="유저를-관리하고-접근-레벨-및-권한에-대한-관리">유저를 관리하고 접근 레벨 및 권한에 대한 관리</h4>
<h4 id="접근키access-key-비밀키secret-access-key-생성">접근키(Access Key) 비밀키(Secret Access Key) 생성</h4>
<ul>
<li>Root 유저가 유저 A를 생성하면 IAM은 A라는 유저에 대한 접근키와 비밀키를 생성 해줌</li>
<li>유저 A는 해당 키들을 가지고 AWS 서비스들을 사용할 수 있음</li>
</ul>
<h4 id="매우-세밀한-접근-권한-부여granular-permission">매우 세밀한 접근 권한 부여(Granular Permission)</h4>
<ul>
<li>AWS DynamoDB 테이블 생성, 삭제, 복사라는 기능 중,</li>
<li>유저 A에게 테이블 삭제나 복사기능을 제한하고 생성 기능만 허락할 수 있다.</li>
</ul>
<h4 id="비밀번호를-수시로-변경-가능">비밀번호를 수시로 변경 가능</h4>
<ul>
<li>보안적인 이유</li>
<li>한달 또는 분기별로 한번씩 모든 AWS 사용자들의 비밀번호 업데이트를 강요</li>
</ul>
<h4 id="mfa-multi-factor-authentification-다중-인증">MFA (Multi-Factor Authentification, 다중 인증)</h4>
<p><img src="https://velog.velcdn.com/images/bae_mung/post/a3dc5438-0740-4424-8260-a3de933227c7/image.png" alt=""></p>
<ul>
<li>Facebook, Google등 다양한 사용자 인증을 요구</li>
<li>특히, Root유저는 무조건 <code>MFA</code>를 해야한다고 AWS에서 권장</li>
</ul>
<h3 id="root유저로-생성할-수-있는-것들">Root유저로 생성할 수 있는 것들</h3>
<h4 id="1-그룹-group">1. 그룹 (Group)</h4>
<h4 id="2-유저-user">2. 유저 (User)</h4>
<h4 id="3-역할-role">3. 역할 (Role)</h4>
<ul>
<li>역할에 하나 혹은 다수의 정책을 지정 가능</li>
<li>그래서 유저마다 다양한 정책을 부여함으로써 다른 권한을 위임 (Full Access or Not)</li>
</ul>
<h4 id="4-정책-policy">4. 정책 (Policy)</h4>
<ul>
<li>JSON 형태로 작성되어 있는 Document를 가르킴</li>
<li>세밀한 접근 권한을 일일이 설정하여 하나의 정책 Document를 만들 수 있음</li>
<li>따라서, 다양한 정책을 만들어 다양한 접근 레벨 및 권한 부여가 가능</li>
</ul>
<blockquote>
<p>정책은 그룹, 역할에 추가시킬 수 있음
하나의 그룹 안에 다수의 유저가 존재 가능</p>
</blockquote>
<blockquote>
<p>IAM은 Universal 하다!
지역 설정이 필요 없음</p>
</blockquote>
<h2 id="iam-정책-시뮬레이터">IAM 정책 시뮬레이터</h2>
<ol>
<li><p>개발 환경(Develop or Staging)에서 실제 환경(Production)으로 빌드하기 전 IAM 정책이 잘 작동되는지 테스트하기 위함</p>
</li>
<li><p>IAM과 관련된 문제들을 디버깅하기에 최적화된 툴</p>
</li>
</ol>
<blockquote>
<p>이미 실제로 유저에 부여된 다양한 정책들도 테스트 가능</p>
</blockquote>
<h2 id="iam-실습">IAM 실습</h2>
<h3 id="사용자-생성">사용자 생성</h3>
<p><img src="https://velog.velcdn.com/images/bae_mung/post/9c078fae-a6fd-4ffe-b6f8-e5b9b37bd8d3/image.png" alt=""></p>
<ul>
<li>사용자 탭 -&gt; 사용자 추가</li>
</ul>
<p><img src="https://velog.velcdn.com/images/bae_mung/post/3c517920-07be-407d-a9aa-fc2a35a633a9/image.png" alt=""></p>
<h4 id="access-유형">Access 유형</h4>
<ol>
<li>프로그래밍 방식 Access</li>
</ol>
<ul>
<li>접근키(Access Key) 비밀키(Secret Access Key) 생성해서 API나 CLI를 통해 서비스에 접근</li>
</ul>
<ol start="2">
<li>AWS Management Console Access</li>
</ol>
<ul>
<li>비밀번호를 부여해주고 해당 비밀번호로 서비스에 접근</li>
</ul>
<p><img src="https://velog.velcdn.com/images/bae_mung/post/a0e1ba04-6007-4b64-95ed-4354c689f193/image.png" alt=""></p>
<ul>
<li>Access 유형 선택 이후로는 모두 다음을 눌러줘도 무방</li>
</ul>
<h3 id="그룹-생성">그룹 생성</h3>
<p><img src="https://velog.velcdn.com/images/bae_mung/post/e74f93a0-6474-4a3f-b2ea-4197de81242b/image.png" alt=""></p>
<ul>
<li>사용자 그룹 탭 -&gt; 그룹 생성</li>
</ul>
<p><img src="https://velog.velcdn.com/images/bae_mung/post/11e3023d-a6a3-4ede-b258-0a169f1bc0c3/image.png" alt=""></p>
<ul>
<li>그룹 이름을 지정하고, 사용자를 추가한 뒤 일단 정책은 연결하지 않고 그룹을 생성</li>
</ul>
<h3 id="역할-생성">역할 생성</h3>
<ul>
<li>역할은 각 사용자에게 다양한 Policy(정책)을 부여할 수 있다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/bae_mung/post/37846728-f19e-4014-9e3c-7d7ab28d04b2/image.png" alt=""></p>
<ul>
<li>역할 탭 -&gt; 역할 만들기</li>
</ul>
<p><img src="https://velog.velcdn.com/images/bae_mung/post/98ed85f6-d5e5-4445-ba0e-4220a0038cf3/image.png" alt=""></p>
<ul>
<li>역할을 만들게 되면 위 이미지와 같이 다양한 서비스가 뜨는데, 아직은 몰라도 됨</li>
</ul>
<blockquote>
<p>우리가 특정한 역할을 만든다면 그 역할 안에서 어떠한 서비스를 차단, 허용하는지에 대한 권한을 주는 것</p>
<p>정책과 비슷한 것 같지만, 역할은 사용자와 밀접한 연관이 있음</p>
<p>(개인적으로 역할보다는 정책이 더 중요하다 생각)</p>
</blockquote>
<h3 id="정책-생성">정책 생성</h3>
<ul>
<li>기본적으로 AWS에서 제공하는 정책이 이미 존재함</li>
</ul>
<p><img src="https://velog.velcdn.com/images/bae_mung/post/a1008731-1134-41e7-a466-4e25b28948d5/image.png" alt=""></p>
<ul>
<li>정책 탭 -&gt; 정책 생성</li>
</ul>
<p><img src="https://velog.velcdn.com/images/bae_mung/post/dad0c908-9d6f-4a9c-8437-85337077bfc2/image.png" alt=""></p>
<ul>
<li>정책 생성하는 2가지 방법.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/bae_mung/post/89dfe24d-c234-43ab-a74b-3149941f5939/image.png" alt=""></p>
<ol>
<li><strong>시각적 편집기</strong>
우리가 원하는 서비스(ex: DynamoDB)를 선택하면 해당 서비스에서 허용되는 Access Level을 선택</li>
</ol>
<p><strong>읽기, 쓰기 선택</strong></p>
<p>이 후 리소스(DynamoDB에서 제공하는 다양한 Function)들을 임의대로 추가하고 제거할 수 있음.
-&gt; 일반적으로는 모든 리소스들을 선택</p>
<p><img src="https://velog.velcdn.com/images/bae_mung/post/27174720-6f77-46f8-ace7-7dedffaa3cc8/image.png" alt=""></p>
<ol start="2">
<li><strong>JSON</strong> 
수동으로 JSON 정책 Docuement를 생성할 수 있음</li>
</ol>
<p><img src="https://velog.velcdn.com/images/bae_mung/post/211d11c9-bb6a-465f-8b76-06e352fbc94f/image.png" alt=""></p>
<p>생성하려는 정책의 이름을 부여한 뒤 정책 생성</p>
<p><img src="https://velog.velcdn.com/images/bae_mung/post/c043b3dd-62cc-41c9-839d-20fec1224d02/image.png" alt=""></p>
<p>정책 리스트에 방금 생성한 정책을 확인할 수 있음</p>
<p><img src="https://velog.velcdn.com/images/bae_mung/post/4b5cc8b7-7ffc-4130-b30c-b02a01b4d99c/image.png" alt=""></p>
<p>그리고 해당 정책을 선택하고 들어가서 정책 요약 옆 {} JSON을 선택해보면, 위와 같은 JSON 정책 Document를 확인할 수 있음</p>
<blockquote>
<p>마찬가지로 기존에 생성된 정책들도 위와 같은 방법으로 JSON Document 로 작성된 정책을 확인 가능</p>
</blockquote>
<h3 id="iam-정책-시뮬레이터-1">IAM 정책 시뮬레이터</h3>
<p><img src="https://velog.velcdn.com/images/bae_mung/post/75efc7e5-30de-43e8-a741-02469b1e0c48/image.png" alt=""></p>
<p>IAM Home 우측 하단의 도구 밑 정책 시뮬레이터를 선택</p>
<p><img src="https://velog.velcdn.com/images/bae_mung/post/def38467-b642-4c21-ba38-4fda7beeb991/image.png" alt=""></p>
<p>우리가 생성한 유저, 그룹, 역할들을 살펴볼 수 있음</p>
<p><img src="https://velog.velcdn.com/images/bae_mung/post/59f52b71-46ec-485d-bf2b-2495358353f6/image.png" alt=""></p>
<p>유저 탭에서 방금 생성한 aws_learner 유저를 선택하면, 해당 유저에 대한 정책들을 확인할 수 있음</p>
<blockquote>
<p>아직은 아무 정책을 추가하지 않았기 때문에 아무것도 뜨지 않는데
그말인 즉슨, aws_learner 유저는 어떠한 권한도 가지고 있지 않음</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/bae_mung/post/abb792c4-5de5-42e0-a7fa-986a0f8c46c9/image.png" alt=""></p>
<p>위 말이 사실인지 확인할 수 있는 것이 정책 시뮬레이터</p>
<p>우측 파티션 Policy Simulator에서 DynamoDB 서비스를 선택하고, Actions는 Select All을 한 뒤 Run Simulation을 돌려보면 아무런 권한도 없기 때문에 Permission Denied가 뜨는 것을 확인할 수 있음</p>
<h4 id="유저에-정책-추가하기">유저에 정책 추가하기</h4>
<p><img src="https://velog.velcdn.com/images/bae_mung/post/a9fee11a-ce41-4675-8024-b16c057dee88/image.png" alt=""></p>
<p>유저 탭에서 aws_learner 유저를 선택하고, 권한 시작하기 아래에 보이는 권한 추가를 선택</p>
<p><img src="https://velog.velcdn.com/images/bae_mung/post/59e0c270-3d1f-4802-a7ba-bd036163fc3c/image.png" alt=""></p>
<p>일단은 기존 정책 직접 연결을 선택하고 <code>AmazonDynamoDBReadOnlyAccess</code> 정책을 선택하고 추가</p>
<p><img src="https://velog.velcdn.com/images/bae_mung/post/92346ef6-35bd-47f4-a5e1-e8927a2ddc2a/image.png" alt=""></p>
<p>그 다음 다시 IAM 정책 시뮬레이터 돌아와서 새로고침을 하거나, 기존창을 닫고 다시 IAM 정책 시뮬레이터에 접속하여 aws_learner 유저를 선택하면 위 이미지 처럼 <code>AmazonDynamoDBReadOnlyAccess</code> 정책이 추가된 것을 확인할 수 있음</p>
<blockquote>
<p>지금은 <code>AmazonDynamoDBReadOnlyAccess</code> 정책하나 밖에 없지만, 한 유저에게 다양한 정책이 있을 때 체크 박스를 끄고 키면서 정책 시뮬레이션을 돌릴 수 있다.</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/bae_mung/post/7cb4ae37-579c-45d2-96c0-d78afbc19eca/image.png" alt=""></p>
<p>다시 우측 파티션 Policy Simulator에서 DynamoDB 서비스를 선택하고, Actions는 Select All을 한 뒤 Run Simulation을 돌려보면 아까와는 다른 결과를 확인할 수 있음</p>
<p><code>AmazonDynamoDBReadOnlyAccess</code> 정책이 지원하는 Read 관련 기능들은 allowed 됨을 확인</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[AWS - 00. Introduction]]></title>
            <link>https://velog.io/@bae_mung/AWS-00.-Introduction</link>
            <guid>https://velog.io/@bae_mung/AWS-00.-Introduction</guid>
            <pubDate>Sat, 23 Jul 2022 08:21:39 GMT</pubDate>
            <description><![CDATA[<hr>
<h2 id="hello-amazon-web-service">Hello Amazon Web Service</h2>
<h3 id="cloud-computing">Cloud Computing</h3>
<ul>
<li>원격상에 존재하는 서버가 직접 작동되고 운영되며 데이터가 Processing 되는것.</li>
<li>Local 컴퓨터는 전혀 상관 X</li>
<li>하늘에 떠다니는 구름(Cloud)처럼 우리(Local)와 동떨어져서 존재</li>
</ul>
<h3 id="serverless-기능-지원">Serverless 기능 지원</h3>
<ul>
<li>Serverless란, Cloud가 서버를 작동시키고 관리하며 메모리 할당에 대해 유연한 방식을 채택해 스스로 생존하는 것</li>
</ul>
<h4 id="awsamazon-web-service-입문자를-위한-강의는-아래와-같은-사람들에게-적합">AWS(Amazon Web Service) 입문자를 위한 강의는 아래와 같은 사람들에게 적합</h4>
<ul>
<li>AWS를 배우고 싶은 분</li>
<li>AWS 자격증(특히 Developer Associate) 준비에 관심 있으신 분</li>
<li>현재 회사 프로모션에 관심이 있으신 분</li>
<li>새로운 클라우드 지식을 쌓고 싶으신 분</li>
</ul>
<h2 id="aws-계정-만들기">AWS 계정 만들기</h2>
<h3 id="as-you-pay-go-서비스">As You Pay Go 서비스</h3>
<ul>
<li>서비스를 사용한 만큼 요금을 지불</li>
<li>아무것도 사용하지 않는다면 0$</li>
</ul>
<h3 id="free-tier-서비스">Free-tier 서비스</h3>
<ul>
<li>많은 서비스에서 Free-tier라는 기본적인 옵션(일종의 데모 버전?)을 제공</li>
<li>지금 강의처럼 학습하는 용도라면 적합</li>
</ul>
<h3 id="루트root-사용자">루트(Root) 사용자</h3>
<ul>
<li>처음 계정을 만들면 모든 권한을 가진 Root 유저가 됨</li>
<li>다른 유저 생성, 삭제, 권한 부여 가능</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[디자인 패턴 - 🧬 구조] 🌲 Composite Pattern]]></title>
            <link>https://velog.io/@bae_mung/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4-%EA%B5%AC%EC%A1%B0-Composite-Pattern</link>
            <guid>https://velog.io/@bae_mung/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4-%EA%B5%AC%EC%A1%B0-Composite-Pattern</guid>
            <pubDate>Sun, 07 Nov 2021 16:32:23 GMT</pubDate>
            <description><![CDATA[<h2 id="🧬-구조-패턴">🧬 구조 패턴</h2>
<h2 id="🌲-composite">🌲 Composite</h2>
<p><img src="https://user-images.githubusercontent.com/51703260/140633928-205dd18b-c314-49f8-83e8-baeccf12d8b5.png" alt="image"></p>
<h3 id="composite-pattern-이란">Composite Pattern 이란?</h3>
<p>Composite Pattern은 객체들을 트리 구조로 구성한 다음, 이러한 구조를 개별 객체인 것처럼 사용할 수 있는 구조 설계 디자인 패턴이다.</p>
<h3 id="problem">Problem</h3>
<blockquote>
<p>Composite Pattern을 사용하는 것은 어플리케이션의 핵심 모델을 트리로 나타낼 수 있는 경우에만 의미가 있다.</p>
</blockquote>
<p><img src="https://user-images.githubusercontent.com/51703260/140634082-16812f69-8d0a-42bd-8bde-53f71d07d38f.png" alt="image"></p>
<p>예를 들어, <code>Product</code> 및 <code>Box</code>라는 두 가지 유형의 객체가 있다고 가정해 보자. </p>
<p><code>Box</code>에는 여러 <code>Product</code>와 여러 개의 작은 <code>Box</code>가 포함될 수 있다. 이러한 작은 상자에는 일부 <code>Product</code> 또는 더 작은 <code>Box</code> 등이 포함될 수 있다.</p>
<p>그 다음 이러한 클래스를 사용하는 주문 시스템을 만들기로 결정했다고 추가적으로 가정해 보자. </p>
<p>주문에는 박스 포장이 없는 <code>Prodcut</code>와, 작은 Box와 Product들로 채워진 <code>Box</code>가 포함될 수 있다.</p>
<p>이 때, 주문의 총 가격을 어떻게 결정해야할까?</p>
<p>당장 떠오르는 러프한 결정 방법으로는 포장된 상자를 모두 풀고 모든 제품을 살펴본 다음 합계를 계산하는 방법이 있다. 이 방법은 현실세계에서 이런식으로 할 수 있다.</p>
<p>하지만, 프로그램에서는 이건 그렇게 간단한 문제가 아니다.</p>
<p>그렇다면 어떤 해결 방법이 있을까?</p>
<h3 id="solution">Solution</h3>
<p>Composite pattern을 적용한다면, 토탈 가격을 계산할 수 있는 공통 인터페이스를 선언하고 <code>Product</code>와 <code>Box</code>가 이를 구현하는 방식으로 문제를 해결할 수 있다.</p>
<p>이러한 구조는 어떻게 작동할까? </p>
<p><code>Product</code>의 경우, 단순히 Product의 가격을 리턴한다. </p>
<p><code>Box</code>의 경우 Box에 들어 있는 각 아이템들을 살펴보고 각각 아이템에 대한 가격을 모두 구한 다음 결과적으로 이 상자에 대한 토탈 가격을 리턴한다. </p>
<p><img src="https://user-images.githubusercontent.com/51703260/140634390-d3312d75-37d4-4e82-b6a9-342709211c47.png" alt="image"></p>
<p>만약 <code>Box</code>의 아이템이 <code>더 작은 Box</code>라면, 재귀적으로 접근하여 작은 Box 또한 자신이 담겨있는 큰 Box와 동일한 매커니즘으로 가격을 구할 수 있다.</p>
<br/>

<p>이러한 접근 방식의 가장 큰 장점은 트리를 구성하는 객체들의 구체적인 클래스에 대해 신경을 쓰지않아도 된다는 점이다.</p>
<p><code>Box</code>속 객체가 <code>Product</code>인지 또 <code>다른 Box</code>인지 알 필요없이 공통 인터페이스를 통해 모두 동일하게 처리할 수 있다. </p>
<h3 id="structure">Structure</h3>
<p><img src="https://user-images.githubusercontent.com/51703260/140637232-3bc42df8-2d7a-4409-a3d1-2f0e637adc8e.png" alt="image"></p>
<p>Composite Pattern의 구조는 위에서 설명했듯 트리구조이고, 크게 4가지로 구조를 구분할 수 있다.</p>
<ol>
<li><code>Component</code> : Component 인터페이스는 트리의 단일 객체(like <code>Product</code>)와 복합 객체(like <code>Box</code>) 모두에게 공통 인터페이스를 제공한다.</li>
<li><code>Leaf</code> : Leaf는 일반적인 트리구조에서 Leaf Node와 같은 의미이다. Composite Pattern에서 Leaf는 트리의 단순 요소(like <code>Product</code>)만으로 이루어져 있으므로 대부분의 실제 작업을 수행한다. </li>
<li><code>Container</code> : Container는 Composite와 동일한 의미이며, Container는 하위 요소들을 가진 요소(like <code>작은 Box</code>를 가진 <code>Box</code>)이다. <br/>
 자식들의 구체적인 클래스를 알지못하며 공통 인터페이스를 통해 모든 하위 요소와 함께 작동한다. <br/>
 요청을 받으면 본인이 처리할 수 있는 부분은 직접 처리하고, 하위 요소중 자신과 같은 Container가 있다면 자식 Container에게 작업을 위임하여 결과를 리턴받고 결과를 종합하여 응답한다.</li>
<li><code>Client</code> : Client는 Component 인터페이스를 통해 모든 구성요소와 함께 작동한다. 결과적으로 Client는 트리의 단순 요소 또는 복잡한 요소 모두에 대해 동일한 방식으로 작업할 수 있게된다.</li>
</ol>
<h3 id="implementation">Implementation</h3>
<p>지금까지의 <code>Product</code> <code>Box</code>를 예시로 Composite Pattern을 간단하게 구현해보자.</p>
<blockquote>
<p>Product.interface</p>
</blockquote>
<pre><code class="language-java">public interface Products {
    int getPrice();
}</code></pre>
<blockquote>
<p>Product.class</p>
</blockquote>
<pre><code class="language-java">public class Product implements Products{
    int price = 1000;

    @Override
    public int getPrice() {
        return this.price;
    }
}</code></pre>
<blockquote>
<p>Box.class</p>
</blockquote>
<pre><code class="language-java">import java.util.*;

public class Box implements Products{
    List&lt;Products&gt; products = new ArrayList&lt;Products&gt;();
    int price;

    public void addProduct(Products product) {
        products.add(product);
    }

    @Override
    public int getPrice() {
        for(Products product : products) this.price += product.getPrice();
        return this.price;
    }
}</code></pre>
<blockquote>
<p>Main.class</p>
</blockquote>
<pre><code class="language-java">public class Main {
    public static void main(String[] args) {
        Box box1 = new Box();
        box1.addProduct(new Product());
        box1.addProduct(new Product());
        box1.addProduct(new Product());

        Box box2 = new Box();
        box2.addProduct(new Product());
        box2.addProduct(new Product());
        box2.addProduct(box1);

        Box product = new Box();
        product.addProduct(new Product());
        product.addProduct(box2);

        System.out.println(product.getPrice());
    }
}</code></pre>
<blockquote>
<p>출력 : 6000 </p>
</blockquote>
<h3 id="composite-pattern의-장단점">Composite Pattern의 장단점</h3>
<p><strong>장점</strong></p>
<ul>
<li>객체들이 모두 같은 타입으로 취급되기 때문에 새로운 클래스 추가가 용이하다.</li>
<li>단일 객체, 복합 객체 구분하지 않고 코드 작성이 가능하다.</li>
</ul>
<p><strong>단점</strong></p>
<ul>
<li>설계를 일반화 시켜 객체간의 구분, 제약이 힘들다.</li>
</ul>
<p>정리하자면, 컴포지트 패턴의 장점은 사용자 입장에서는 이게 단일 객체인지 복합 객체인지 신경쓰지 않고 사용할 수 있다는 장점이 있지만 설계가 지나치게 범용성을 갖기 때문에 새로운 요소를 추가할 때 복합 객체에서 구성 요소에 제약을 갖기가 힘들다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL] View]]></title>
            <link>https://velog.io/@bae_mung/TIL-View</link>
            <guid>https://velog.io/@bae_mung/TIL-View</guid>
            <pubDate>Thu, 04 Nov 2021 08:59:25 GMT</pubDate>
            <description><![CDATA[<hr>
<h3 id="web-application-구성-동기통신">Web Application 구성 (동기통신)</h3>
<blockquote>
<p>서버측 프로그램, Page 요청 -&gt; 그 결과로 화면을 응답받는 방식 (화면 요청)</p>
</blockquote>
<p><img src="https://images.velog.io/images/bae_mung/post/95695f5b-c4db-4f88-afcb-6013faf5f322/WebApplication.png" alt=""></p>
<h3 id="web-application-구성-비동기통신">Web Application 구성 (비동기통신)</h3>
<blockquote>
<p>FrontEnd의 화면이동 없이 BackEnd와 통신하는 방식 (데이터 요청)
통신 결과(<code>XML</code>, <code>JSON</code>, <code>CSV</code>, <code>TEXT</code>)를 응답받는 형식
통신을 위한 API 사용 필요 (<code>XMLHttpRequest</code>, <code>JQuery</code>, <code>ajax</code>, <code>axios(vue 권장)</code>, <code>fetch</code>, ..)</p>
</blockquote>
<p><img src="https://images.velog.io/images/bae_mung/post/d7526daa-fe1e-44ef-a0ba-e5859f38fbf4/WebApplication2.png" alt=""></p>
<p><img src="https://images.velog.io/images/bae_mung/post/db2ebaad-2708-4747-bc67-c4f0ab17f09b/WebApplication3.png" alt=""></p>
<h3 id="vuejs">Vue.js</h3>
<p><code>React</code> : <strong>단방향 데이터 흐름</strong>(부모 컴포넌트 -&gt; 자식 컴포넌트간의 데이터 흐름), <strong>Virtual DOM</strong>
<code>Angular</code> : <strong>양방향 데이터 바인딩</strong></p>
<p><code>Vue.js</code>는 <code>React</code> <code>Angular</code>의 장점을 반영</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL] REST]]></title>
            <link>https://velog.io/@bae_mung/TIL-REST</link>
            <guid>https://velog.io/@bae_mung/TIL-REST</guid>
            <pubDate>Fri, 29 Oct 2021 01:22:41 GMT</pubDate>
            <description><![CDATA[<h2 id="representational-state-transfer">Representational State Transfer</h2>
<blockquote>
<p>웹에서 데이터를 전송하고 처리하는 방법을 정의한 <strong>인터페이스</strong></p>
</blockquote>
<ul>
<li><p><strong>URI(Uniform Resource Identifier)</strong>로 자원을 구분</p>
</li>
<li><p><strong>METHOD</strong>로 자원에 대한 행위(동작) 구분
  <strong>METHOD</strong> 종류</p>
<ul>
<li><code>GET</code> : 자원 <strong>조회</strong></li>
<li><code>POST</code> : 자원 <strong>생성</strong></li>
<li><code>DELETE</code> : 자원 <strong>삭제</strong></li>
<li><code>PUT</code> : 자원 <strong>전체</strong> 항목 <strong>수정</strong></li>
<li><code>PATCH</code> : 자원 <strong>일부</strong> 항목 <strong>수정</strong></li>
</ul>
</li>
<li><p><strong>Representation</strong>으로 자원을 나타냄 =&gt; <code>XML</code> <code>JSON</code> 포맷 등</p>
</li>
</ul>
<h3 id="rest-uri-설계-가이드">REST URI 설계 가이드</h3>
<ol>
<li><code>동사</code>(작업, 행위 표현 -&gt; Method 설계) 사용 X ⇒ <code>명사</code> 권장</li>
<li><code>_</code>(언더바) 사용 X ⇒ <code>-</code>(하이픈) 권장</li>
<li>마지막 <code>/</code>사용 X</li>
<li>확장자 사용 X</li>
</ol>
<p>ex) 자원은 <strong>단수자원</strong>, <strong>복수자원</strong>으로 구분할 수 있음</p>
<ul>
<li><strong><code>GET</code></strong> : <code>~/api/directors</code> = 감독 리스트 조회</li>
<li><strong><code>POST</code></strong> : <code>~/api/directors</code> = 감독 복수자원 한단계 아래 자원 생성</li>
<li><strong><code>PUT</code></strong> : <code>~/api/directors/:id</code> = id에 부합하는 감독(단수자원) 수정</li>
<li><strong><code>DELETE</code></strong> : <code>~/api/directors/:id</code> = id에 부합하는 감독(단수자원) 삭제</li>
<li><strong><code>GET</code></strong> : <code>~/api/directors/:id</code> = id에 부합하는 감독(단수자원) 조회
  <code>~/api/directors/:age</code> ⇒ <code>~/api/directors?age=52</code></li>
</ul>
<h3 id="rest-장단점">REST 장/단점</h3>
<h4 id="장점">장점</h4>
<ul>
<li><code>HTTP</code> 프로토콜 사용 ⇒ 추가적인 인프라 구축 필요 X</li>
<li><code>Server</code>/<code>Client</code> 환경</li>
<li><code>Stateless</code><ul>
<li><code>Server</code> <code>Client</code> 분리된 개발 가능<h4 id="단점">단점</h4>
</li>
</ul>
</li>
<li>표준화 X</li>
</ul>
<h3 id="rest-api">REST API</h3>
<p>REST 서비스를 구현한 것</p>
<h3 id="restful">Restful</h3>
<p>REST 아키텍처를 잘 준수(따른)한 것</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL] Spring 초기 설정하기]]></title>
            <link>https://velog.io/@bae_mung/TIL-Spring-%EC%B4%88%EA%B8%B0-%EC%84%A4%EC%A0%95%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@bae_mung/TIL-Spring-%EC%B4%88%EA%B8%B0-%EC%84%A4%EC%A0%95%ED%95%98%EA%B8%B0</guid>
            <pubDate>Thu, 28 Oct 2021 03:40:25 GMT</pubDate>
            <description><![CDATA[<ol>
<li><p>데이터베이스 설계를 먼저 해서 테이블들 구축해놓기.</p>
</li>
<li><p><code>Spring Legacy Project</code>에서 <code>Spring MCV Project</code> 생성하기.</p>
</li>
<li><p><code>context path</code> 설정하기</p>
<blockquote>
<p>[<a href="https://sports.news.naver.com/wfootball/index%5D">https://sports.news.naver.com/wfootball/index]</a> (<a href="https://sports.news.naver.com/wfootball/index)%EC%97%90%EC%84%9C">https://sports.news.naver.com/wfootball/index)에서</a> 
 sports.news.naver는 <code>domain name</code>, wfootball이 <code>context path</code></p>
</blockquote>
</li>
<li><p><code>pom.xml</code> 설정하기</p>
<ul>
<li><code>pom(Project Object Mode).xml</code>이라는 빌드 파일의 빌드 정보를 <code>Maven</code>이 읽어서 프로젝트를 빌드하고 라이브러리를 관리한다.<blockquote>
<p><code>Maven</code> : <strong>장점</strong> = 빠름 (이전 실행내용 재사용), <strong>단점</strong> = 버그 많음
<code>Gradle</code> : <strong>장점</strong> = 버그 별로 없음, <strong>단점</strong> = 느림</p>
</blockquote>
</li>
</ul>
<ol>
<li>line 10. <code>&lt;properties&gt;</code> 태그부터 끝까지 쭉 긁어서 지우고 셋팅된 내용으로 다시 밀어넣기.</li>
<li><code>프로젝트 우클릭 &gt; Maven &gt; Update Project &gt; force 체크</code>해서 업데이트.</li>
</ol>
</li>
<li><p>프로젝트를 서버에 올려서 제대로 작동하는지 확인.</p>
</li>
<li><p>필요한 자바 파일들을 넣기 위한 패키지들 전체적으로 작성하기. (샘플 자바도 만들어놓으면 좋음)</p>
<ul>
<li><code>controller</code> <code>model.dto</code> <code>model.mapper</code> <code>model.service</code></li>
</ul>
</li>
<li><p><code>servlet-context.xml</code> 파일에서 <strong>controller</strong> 스캔 &amp; <code>root-context.xml</code> 파일에서 <strong>model</strong> 스캔시키기.</p>
<ul>
<li><code>&lt;context:component-scan base-package=&quot;com.ssafy.after.controller&quot; /&gt;</code></li>
<li><code>&lt;context:component-scan base-package=&quot;com.ssafy.after.model&quot;/&gt;</code>
(<code>root-context.xml</code>은 namespace에서 context 체크)</li>
</ul>
</li>
<li><p><code>root-context.xml</code> 파일에 MyBatis 관련 객체 3개 등록하기 (namespace에서 p 체크)</p>
<pre><code class="language-xml"> &lt;!-- 데이터베이스 관련 라이브러리 객체 3개는 항상 무조건 필요함! --&gt;
 &lt;!-- 1. 커넥션 관리 객체 (타이어)--&gt;
 &lt;context:property-placeholder location=&quot;classpath:db.properties &quot;/&gt;
 &lt;bean id=&quot;dataSource&quot; class=&quot;org.apache.commons.dbcp.BasicDataSource&quot;
     p:driverClassName=&quot;${db_driver}&quot;
     p:url=&quot;${db_url}&quot;
     p:username=&quot;${db_username}&quot;
     p:password=&quot;${db_password}&quot; /&gt;

 &lt;!-- 2. MyBatis 설정 객체 (휠)--&gt;
 &lt;bean id=&quot;sqlSessionFactory&quot; class=&quot;org.mybatis.spring.SqlSessionFactoryBean&quot;
     p:dataSource-ref=&quot;dataSource&quot;
     p:typeAliasesPackage=&quot;com.ssafy.baemung.model.dto&quot;
     p:mapperLocations=&quot;classpath:/**/maapper/*.xml&quot; /&gt;

 &lt;!-- 3. 마이바티스 설정 + 예전 DAO에서 &#39;?&#39; 처리해주는 기능 구현되어 있는 객체(바퀴)--&gt;
 &lt;bean id=&quot;sqlSession&quot; class=&quot;org.mybatis.spring.SqlSessionTemplate&quot;&gt;
     &lt;constructor-arg ref=&quot;sqlSessionFactory&quot; /&gt;
 &lt;/bean&gt;</code></pre>
</li>
<li><p><code>web.xml</code> 파일에 한글 파라미터 인코딩 관련 <code>filter</code> 등록하기</p>
<pre><code class="language-xml"> &lt;!-- 모든 Character에 대한 Encoding을 UTF-8로 하는 Filter &amp; Filter Mapping 추가! --&gt;
 &lt;filter&gt;
     &lt;filter-name&gt;encodingFilter&lt;/filter-name&gt;
     &lt;filter-class&gt;org.springframework.web.filter.CharacterEncodingFilter
     &lt;/filter-class&gt;
     &lt;init-param&gt;
         &lt;param-name&gt;encoding&lt;/param-name&gt;
         &lt;param-value&gt;UTF-8&lt;/param-value&gt;
     &lt;/init-param&gt;
 &lt;/filter&gt;

 &lt;filter-mapping&gt;
     &lt;filter-name&gt;encodingFilter&lt;/filter-name&gt;
     &lt;url-pattern&gt;/*&lt;/url-pattern&gt;
 &lt;/filter-mapping&gt;</code></pre>
</li>
<li><p>DTO, SQL 관련 <code>Mapper(xml+interface)</code>  <code>Service</code> <code>Controller</code> 클래스 자바 파일들 작성하고 미리 애노테이션들 다 붙여놓기</p>
<ul>
<li><code>@Controller</code> <code>@Service</code> <code>@Autowired</code> 같은 애들 빠진거 없나 미리 확인해두기.</li>
</ul>
</li>
<li><p>DTO <code>클래스 변수</code> <code>Getter</code> <code>Setter</code> <code>toString</code> 채우기</p>
<ul>
<li><strong>lombok</strong>으로 채우거나 그냥 코드로 채우거나 선택 </li>
</ul>
</li>
<li><p><code>Mapper(xml+interface)</code>에 사용할 SQL 관련 설정들 다 작성하기 (interface 메소드 작성 후 xml에 mybatis SQL 작성)</p>
</li>
<li><p><code>Service</code> <code>Controller</code> <code>jsp</code>를 작성해서 한가지 기능씩 실행시키면서 작업하기</p>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL] AOP ( Aspect Oriented Programming)]]></title>
            <link>https://velog.io/@bae_mung/TIL-AOP-Aspect-Oriented-Programming</link>
            <guid>https://velog.io/@bae_mung/TIL-AOP-Aspect-Oriented-Programming</guid>
            <pubDate>Thu, 21 Oct 2021 07:40:00 GMT</pubDate>
            <description><![CDATA[<p><img src="https://images.velog.io/images/bae_mung/post/c9983c36-46d6-45ca-9f59-5cf4ab0e1323/image.png" alt=""></p>
<h4 id="관심사의-분리">관심사의 분리!</h4>
<blockquote>
<p><strong>OOP</strong>를 더 <strong>OOP</strong>스럽게 만들어 주는 기술 </p>
</blockquote>
<h4 id="장점">장점</h4>
<ol>
<li><code>공통 로직</code>과의 의존성 x</li>
<li><code>단위테스트</code> 용이</li>
<li><code>핵심 로직</code>에 집중 -&gt; 코드관리, 가독성 용이</li>
</ol>
<h3 id="aop-도입-전">AOP 도입 전</h3>
<pre><code class="language-java">XXXService{
    login() {
        1. 로그를 남김
            2. login 처리 로직
    }

        register() {
            1. 로그를 남김
            2. register 처리 로직
       }

        XXX() {
            login, register 로그를 복붙 (코드 중복 -&gt; 유지보수 어려움)
        }

}</code></pre>
<h4 id="리팩토링1">리팩토링1</h4>
<pre><code class="language-java">XXXService{
    login() {
        1. log();
            2. login 처리 로직
    }

        register() {
            1. log();
            2. register 처리 로직
       }

        log(){
            로그를 남김
        }

}

YYYService{
        write(){
            XXXService.log(); // 의존성 생김(결합도 ↑)
        }

}</code></pre>
<h4 id="리팩토링2">리팩토링2</h4>
<pre><code class="language-java">XXXService{
    login() {
        1. LogService.log();
            2. login 처리 로직
    }

        register() {
            1. LogService.log();
            2. register 처리 로직
       }
}

YYYService{
        write(){
            LogService.log();
        }

}

LogService{
        log(){
            로그를 남김
        }
}</code></pre>
<blockquote>
<p><code>log()</code> 메소드 호출 코드까지 관심사로 봄 =&gt; 호출코드까지 분리해야 완벽한 관심사의 분리</p>
</blockquote>
<h2 id="aop-aspect-oriented-programming-용어">AOP (Aspect Oriented Programming) 용어</h2>
<ul>
<li><p><strong><code>핵심 로직 (Core Concern)</code></strong> : 우리가 직접 구현하는 주요 로직들, 공통 로직을 활용(사용) 대상</p>
</li>
<li><p><strong><code>횡단(공통) 로직 (Cross-Cutting Concern)</code></strong> : 여러 핵심 로직에서 재사용되는 공통(공용) 로직
<img src="https://images.velog.io/images/bae_mung/post/e61360bd-9fce-4bba-9968-2db742e7eeff/image.png" alt=""></p>
</li>
<li><p><strong><code>Advice</code></strong> : <code>공통 로직</code> Class
<img src="https://images.velog.io/images/bae_mung/post/964ad7a1-c4b1-4754-a892-71adacd01a4d/image.png" alt=""></p>
</li>
<li><p><strong><code>Target</code></strong> : <code>핵심 로직</code> Class, <code>Advice</code>가 적용될 대상</p>
</li>
<li><p><strong><code>Weaving</code></strong> : <code>Advice</code>를 <code>Target</code>에 적용, 처리해주는 작업
  <code>Weaving</code> 의 작업 방식 3가지</p>
<ol>
<li><strong>Compile-Time <code>Weaving</code></strong>
<code>XXX.class(공통 로직 호출코드 X) - Weaving -&gt; XXX.class(공통 로직 호출코드 O)</code></li>
<li><strong>Run-Time <code>Weaving</code></strong>
<code>XXX.class - 메모리 로드 (바이트코드 조작) -&gt; XXX.class(메소드안에 공통 로직 호출코드 포함)</code></li>
<li><strong>Proxy <code>Weaving</code> (Spring 방식)</strong>
<code>XXX.class - 실행 시 Proxy 생성 -&gt; XXX_Proxy.class(공통 로직 호출코드 O)</code>
<img src="https://images.velog.io/images/bae_mung/post/d7f528bf-c9c5-4d1c-9164-0c1460df9177/image.png" alt=""></li>
</ol>
</li>
<li><p><strong><code>JoinPoint</code></strong> : 어떤 부분, 어디에 <code>Advice</code> 적용, 코드 삽입할지 위치</p>
</li>
<li><p><strong><code>PointCut</code></strong> : <code>target</code> 필터링 + <code>method</code> 필터링 역할 
  <strong>표현식 사용</strong>(주로 <strong>AspectJ</strong> 표현식 사용)
  =&gt; 메소드 호출 관련 =&gt; <strong>execution(메소드 선언부 : public * *(..) throws XXXException)</strong> (..은 0개 이상)</p>
<p>  <strong>Spring은 Proxy기반 위빙 사용.</strong>
  <code>PointCut</code>에 관련된 <code>JoinPoint</code>는 <strong>메소드 호출 관련된 것만 가능!</strong></p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL] Connection Pool]]></title>
            <link>https://velog.io/@bae_mung/TIL-Connection-Pool</link>
            <guid>https://velog.io/@bae_mung/TIL-Connection-Pool</guid>
            <pubDate>Thu, 14 Oct 2021 05:06:02 GMT</pubDate>
            <description><![CDATA[<h4 id="connection-대여점">&quot;Connection 대여점&quot;</h4>
<p>JDBC 처리단계 중 Connection 생성 처리시간 가장 많이 소요
-&gt; Connection을 save하면 응답시간 시간단축 가능</p>
<p><img src="https://images.velog.io/images/bae_mung/post/0c0c848f-ed0d-4a24-bfc2-c9d7ebafd36a/%ED%99%94%EB%A9%B4%20%EC%BA%A1%EC%B2%98%202021-10-14%20124256.png" alt=""></p>
<p>1~9 처리 소요시간 : 요청에 대한 응답시간</p>
<p>Pool 생성 -&gt; App 시작</p>
<h4 id="장점">장점</h4>
<ol>
<li><strong>응답시간 단축</strong></li>
<li><strong>리소스 부하 일정</strong></li>
</ol>
<h4 id="사용">사용</h4>
<ol>
<li><strong>직접 구현 사용</strong></li>
<li><strong>오픈소스 라이브러리 사용</strong></li>
<li><strong>WAS 제공 사용</strong><ul>
<li>JDBC Driver class</li>
<li>DB URL</li>
<li>DB user</li>
<li>DB userpass</li>
</ul>
</li>
</ol>
<h3 id="javaxdqldatasource"><code>javax.dql.DataSource</code></h3>
<p>Connection Pool 인터페이스 표준</p>
<p>getConnection() : connect 대여 메소드</p>
<p>DataSource ds = WAS 구현체, 오픈소스 구현체... 다 올 수 있음</p>
<h3 id="naming-service--jndi">Naming Service &amp; JNDI</h3>
<p><img src="https://images.velog.io/images/bae_mung/post/41f054ec-ecc7-42bb-af2a-acec889eaaf6/image.png" alt=""></p>
<p><code>Naming Service</code></p>
<ul>
<li>Name &lt;- 매핑 -&gt; Resource -&gt; 찾기</li>
<li>ex) 전화번호부, DNS</li>
</ul>
<p><code>JNDI (Java Naming and Directory Interface)</code></p>
<ul>
<li>가상 경로를 추가하여 name의 unique를 높임.</li>
<li>/db/XXX 와</li>
<li>/db/YYY 같은 리소스가 있을 때,</li>
<li>XXX 와 YYY를 찾을 때 바로 db로 접근해서 XXX, YYY를 찾아서 효율성을 높임</li>
</ul>
<p><a href="https://tomcat.apache.org/tomcat-9.0-doc/jndi-datasource-examples-howto.html#MySQL_DBCP_2_Example">JNDI Datasource How-To
</a></p>
<pre><code class="language-java">ctx = new InitialContext(); // Root 설정
실제 리소스 or 디렉토리 = ctx.lookup(&quot; &quot;);</code></pre>
<pre><code class="language-java">//Connection Interface

conn = DriverManager.getConnection();
conn = ds.getConnection();
conn.close();</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL] JSTL & EL]]></title>
            <link>https://velog.io/@bae_mung/TIL-JSTL-EL</link>
            <guid>https://velog.io/@bae_mung/TIL-JSTL-EL</guid>
            <pubDate>Wed, 13 Oct 2021 03:04:14 GMT</pubDate>
            <description><![CDATA[<h2 id="jstl--jsp-standard-tag-library"><code>JSTL</code> : <code>JSP Standard Tag Library</code></h2>
<pre><code>&lt;%@ taglib prefix=&quot;별칭&quot; uri=&quot;tld경로&quot;%&gt;</code></pre><h4 id="표준화된-custom-tag">표준화된 Custom Tag</h4>
<ul>
<li><strong><code>core</code></strong> : <code>if</code>(단독) <code>choose ~ (when + otherwise)</code>(분기) <code>forEach</code>(횟수기반, 반복객체) <code>set</code>(var 생성)</li>
<li><strong><code>formatting</code></strong> </li>
<li><code>sql</code> : mvc 패턴에서 쓸 일 없음</li>
<li><code>xml</code> </li>
</ul>
<h2 id="el--expression-language"><code>EL</code> : <code>Expression Language</code></h2>
<pre><code>&lt;c:forEach items=&quot;반복 대상 객체&quot; var=&quot;꺼내어진 대상 객체 이름&quot; scope=&quot;저장해 줄 스코프(생략 시 페이지 스코프(page))&quot;&gt;&lt;/c:forEach&gt;</code></pre><p>여기서 items에는 객체 참조값이 와야하고, var에는 문자열이 와야하는데 <code>JSTL</code>에는 둘 다 문자열로 인식하기 때문에 <code>EL</code>이 필요하다</p>
<pre><code>&lt;c:if test=&quot;age&gt;10&quot;&gt;&lt;/c:if&gt;</code></pre><p>마찬가지로 test에 오는 논리식 연산같은 경우에도 마찬가지로 <code>JSTL</code>에서 문자열로 인식하기 때문에 <code>EL</code>이 필요한 것이다.</p>
<ol>
<li><strong>출력 담당 (output 처리 위치)</strong><ul>
<li>ex ) HTML태그 위치</li>
</ul>
</li>
<li><strong>JSTL 속성 처리 담당 (JSTL 속성값 위치)</strong><ul>
<li>ex ) <code>&lt;c:if test=&quot;조건식&quot;&gt;</code> : true / false</li>
<li>ex ) <code>&lt;c:forEach items=&quot;반복객체&quot;&gt;</code> : 객체참조</li>
</ul>
</li>
</ol>
<h4 id="el-내장객체-11개">EL 내장객체 (11개)</h4>
<blockquote>
<p>EL 내장객체는 JSTL 내장객체와 다름!!</p>
</blockquote>
<pre><code>${firstThing.secondThing....}</code></pre><h4 id="firstthing에-올-수-있는-것-2가지">firstThing에 올 수 있는 것 2가지</h4>
<ol>
<li><strong>EL 내장객체 O</strong></li>
<li><strong>EL 내장객체 X</strong> : 4개 보관함에 저장되어 있는 attribute <code>key</code> 로 본다!
 오타나도 오류가 나는게 아니라 해당 이름의 속성을 찾아감. 
 탐색 순서 : pageContext -&gt; request -&gt; session -&gt; servletContext</li>
</ol>
<ol>
<li><code>pageScope</code> : pageContext attribute만 모아놓은 Map</li>
<li><code>requestScope</code> : request attribute만 모아놓은 Map (K, V : attr명, object)</li>
<li><code>sessionScope</code> : session attribute만 모아놓은 Map</li>
<li><code>applicationScope</code> : servletContext attribute만 모아놓은 Map</li>
<li><code>params</code> : request(단일) parameter만 모아놓은 Map (K, V : param명, value)</li>
<li><code>paramValues</code> : request(배열) parameter만 모아놓은 Map</li>
<li><code>header</code> </li>
<li><code>headerValue</code> </li>
<li><code>cookie</code></li>
<li><code>initParam</code> 
Map유형 (10개) </li>
<li><code>pageContext(Getter, Setter, Beans)</code> : 유일하게 Map이 아님</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL] Session Tracking]]></title>
            <link>https://velog.io/@bae_mung/TIL-Session-Tracking</link>
            <guid>https://velog.io/@bae_mung/TIL-Session-Tracking</guid>
            <pubDate>Tue, 12 Oct 2021 09:45:06 GMT</pubDate>
            <description><![CDATA[<p><code>HTTP</code> : connectless, stateless  (연결 비유지, 상태 비유지)
-&gt; 그래서 상태 유지 가능하도록 보완하는 기술과 함께 사용</p>
<p>일정 시간 동안 동일한 사용자로부터 들어오는 일련의 요청들을 하나의 연속된 상태로 보고 유지할 수 있도록 해주는 기술에는 2가지가 있다.</p>
<h2 id="cookie--client-side"><code>Cookie</code> : <code>Client Side</code></h2>
<ul>
<li>과자 부스러기처럼 흔적이 남는 것에서 이름을 따왔음.</li>
<li><code>이름, 값</code> : String, Unique  관리 <code>도메인</code> : 자동부여 <code>경로</code></li>
<li><code>유효시간</code> : <strong>생략 or 음수</strong> = 세션 쿠키, <strong>자연수</strong> = 해당 시간만큼 유지하는 쿠키, <strong>0</strong> = 쿠키 삭제</li>
<li><code>Cookie</code>는 Defualt 생성자가 존재하지 않음 <code>이름, 값</code>이 유니크해야 하므로 </li>
<li><strong>Client Side</strong>는 <code>도메인</code>별로 쿠키를 유지한다.</li>
<li><code>Cookie</code>를 <code>DTO</code> 비슷하게 생각하면 좋다.</li>
<li><strong>단점</strong> : String만 저장, 크키 제한, 사용자가 차단 가능, 보안에 취약</li>
</ul>
<blockquote>
<p><strong>Cookie 생성</strong></p>
</blockquote>
<pre><code>cookie = new Cookie(이름, 값);
response.addCookie(cookie);</code></pre><blockquote>
<p><strong>Cookie 조회 (상태 조회)</strong></p>
</blockquote>
<pre><code>Cookie[] cookies = response.getCookies();
배열 반복돌며 원하는 쿠키 찾기! getName(), getValues()</code></pre><blockquote>
<p><strong>Cookie 삭제</strong></p>
</blockquote>
<pre><code>cookie.setMaxAge(0);
response.addCookie(cookie);</code></pre><h2 id="session--server-side"><code>Session</code> : <code>Server Side</code></h2>
<ul>
<li>동작 원리상 <code>Session</code>도 <code>Cookie</code> 베이스라고 할 수있다.</li>
<li><code>Session</code> 은 상태 정보를 유지할 수 있는 보관함이다.</li>
</ul>
<blockquote>
<p><strong>Client 최초 접속시 <code>Session</code> 객체 생성 (일정 시간 유지)</strong></p>
</blockquote>
<pre><code>HttpSession session = request.getSession(true) or getSession(false) : 없을 때 생성 여부 (false 쓸 일 거의 없음)</code></pre><blockquote>
<p><strong>상태 정보 조회</strong></p>
</blockquote>
<pre><code>session.getAttribute(key)</code></pre><blockquote>
<p><strong>상태 정보 삭제</strong></p>
</blockquote>
<pre><code>session.removeAttribute(key)</code></pre><blockquote>
<p><strong><code>Session</code> 삭제</strong></p>
</blockquote>
<pre><code>session.invaliddate()</code></pre><h3 id="include-지시자">include 지시자</h3>
<pre><code>&lt;%@ include file=&quot;/&quot; %&gt; : 정적 리소스 (html) include -&gt; 소스코드 복붙 그 이상 그 이하도 아님

복붙이기 때문에, 변수 중복이 허용되지 않는다.
호출된 파일의 이름의 .java, .class가 생성되지 않는다.</code></pre><h3 id="include-액션-tag">include 액션 tag</h3>
<pre><code>&lt;jsp:include page=&quot;/&quot;&gt;&lt;/jsp:include&gt; : 동적 리소스(jsp) include -&gt; 해당 page 실행시킴

출력 결과가 include 시키는 page response 출력으로 포함된다.
복붙시키는 것이 아니기 때문에, 변수 중복이 허용된다.
호출된 파일의 이름의 .java, .class가 생성된다.</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[Become a Java-Masta👨‍🏫 7주차] 애노테이션, I/O, 제네릭, 람다식]]></title>
            <link>https://velog.io/@bae_mung/Become-a-Java-Masta-7%EC%A3%BC%EC%B0%A8-%EC%95%A0%EB%85%B8%ED%85%8C%EC%9D%B4%EC%85%98-IO-%EC%A0%9C%EB%84%A4%EB%A6%AD-%EB%9E%8C%EB%8B%A4%EC%8B%9D</link>
            <guid>https://velog.io/@bae_mung/Become-a-Java-Masta-7%EC%A3%BC%EC%B0%A8-%EC%95%A0%EB%85%B8%ED%85%8C%EC%9D%B4%EC%85%98-IO-%EC%A0%9C%EB%84%A4%EB%A6%AD-%EB%9E%8C%EB%8B%A4%EC%8B%9D</guid>
            <pubDate>Tue, 28 Sep 2021 11:53:58 GMT</pubDate>
            <description><![CDATA[<h2 id="🎯-목표">🎯 목표</h2>
<h3 id="자바의-annotation-io-generic-lambda에-대해-학습하기">자바의 Annotation, I/O, Generic, Lambda에 대해 학습하기.</h3>
<h2 id="📌-학습할-것">📌 학습할 것</h2>
<h3 id="annotation"><a href="#annotation-1">Annotation</a></h3>
<ul>
<li><a href="#%EC%A0%95%EC%9D%98%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95">정의하는 방법</a></li>
<li><a href="#%EC%95%A0%EB%85%B8%ED%85%8C%EC%9D%B4%EC%85%98%EC%9D%98-%EC%9A%A9%EB%8F%84">애노테이션의 용도</a></li>
<li><a href="#retention">@Retention</a></li>
<li><a href="#target">@Target</a></li>
<li><a href="#documented">@Documented</a></li>
<li><a href="#annotation-processor">Annotation Processor</a></li>
</ul>
<h3 id="io"><a href="#io-1">I/O</a></h3>
<ul>
<li><a href="#stream">Stream</a></li>
<li><a href="#%ED%91%9C%EC%A4%80-stream">표준 Stream</a></li>
<li><a href="#channel">Channel</a></li>
<li><a href="#buffer">Buffer</a></li>
<li><a href="#inputstream">InputStream</a></li>
<li><a href="#outputstream">OutputStream</a></li>
<li><a href="#%ED%8C%8C%EC%9D%BC-%EC%9D%BD%EA%B3%A0-%EC%93%B0%EA%B8%B0">파일 읽고 쓰기</a></li>
</ul>
<h3 id="generic"><a href="#generic-1">Generic</a></h3>
<ul>
<li><a href="#boundedtype">BoundedType</a></li>
<li><a href="#wildcard">WildCard</a></li>
<li><a href="#erasure">Erasure</a></li>
</ul>
<h3 id="lambda"><a href="#lambda-1">Lambda</a></h3>
<ul>
<li><a href="#lambda-%EC%82%AC%EC%9A%A9%EB%B2%95">Lambda 사용법</a></li>
<li><a href="#%ED%95%A8%EC%88%98%ED%98%95-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4">함수형 인터페이스</a></li>
<li><a href="#variable-capture">Variable Capture</a></li>
<li><a href="#%EB%A9%94%EC%86%8C%EB%93%9C-%EC%83%9D%EC%84%B1%EC%9E%90-%EB%A0%88%ED%8D%BC%EB%9F%B0%EC%8A%A4">메소드, 생성자 레퍼런스</a></li>
</ul>
<hr>
<h2 id="annotation-1">Annotation</h2>
<p><strong><code>애노테이션(Annotation)</code></strong> : 사전적 의미로 주석을 의미하며, 프로그램에 대한 데이터를 제공하는 메타데이터의 한 형태</p>
<hr>
<h3 id="정의하는-방법">정의하는 방법</h3>
<p>애노테이션 타입은 java.lang or java.lang.annotation에서 제공해주는 것이 있고 필요에따라 자신이 직접 정의해서 사용할 .</p>
<p>애노테이션을 직접 정의하는 방법은 <code>@interface</code> 키워드를 사용하여 정의한다.</p>
<pre><code class="language-java">public @interface CustomAnnotation {
        // Element
    int value();
}

@CustomAnnotation(value = 29)
@CustomAnnotation(29)</code></pre>
<p><code>@interface</code>는 애노테이션 타입(annotation type)을 선언하는 키워드이고, 애노테이션 타입 선언을 일반적인 인터페이스 선언과 구분하기 위해 interface 앞에 기호 @를 붙인다.</p>
<p>애노테이션은 Element라는 것을 멤버로 가질 수 있으며, Element는 타입과 이름으로 구성되며 default 값을 가질 수 있다. </p>
<p>Element의 이름 뒤에는 메소드를 작성하는 것 처럼 뒤에 ()를 붙여야 한다.</p>
<p>정의된 애노테이션을 사용하는 방법은 <code>@애노테이션</code> 명으로 선언할 수 있고, 특정 클래스나 메소드, 변수에 붙여 사용한다.</p>
<p>그리고 한 선언부에 여러 애노테이션을 사용하는 것도 가능하다.</p>
<p>기본 Element는 value이며, 해당하는 값은 생략하고 바로 사용이 가능하다.</p>
<hr>
<h3 id="애노테이션의-용도">애노테이션의 용도</h3>
<ol>
<li><strong><code>컴파일 타임</code>에 제공하는 정보</strong> <ul>
<li><code>@Override</code> : 상위 클래스의 메서드를 재정의하였음을 나타내는 Annotation. 상위 클래스에 해당 메서드가 존재하지 않는 경우 Compiler가 경고하는 기능을 제공함.</li>
<li><code>@SuppressWarnings</code> : 컴파일러가 경고하는 내용을 Ignore 할 때 사용하는 Annotation</li>
<li><code>@Generated</code> : 소스 코드를 생성하는 도구에 의해서 해당 코드가 자동적으로 생성되었음을 나타내는 Annotation</li>
</ul>
</li>
<li><strong>컴파일 시간 및 배포 시간 처리</strong> -&gt; 소프트웨어 개발툴이 애노테이션 정보를 처리하여 코드, XML 파일등을 생성 가능 (애노테이션을 사용한 곳에 특정 코드를 추가 ex) Lombok의 <code>@Getter</code>, <code>@Setter</code>)</li>
<li><strong>런타임 처리</strong> -&gt; 일부애 노테이션은 런타임에 특정 기능을 실행하도록 정보를 제공 (Java Reflection)<ul>
<li><code>자바 리플렉션(Java Reflection)</code> : 구체적인 클래스 타입을 알지 못해도 런타임 시에 클래스 이름만 알고있다면 그 클래스의 메소드, 타입, 변수들에 접근할 수 있도록 해주는 자바 API, </li>
<li><code>@FunctionalInterface</code> : 해당 Interface가 하나의 메서드만을 제공하는 함수형 인터페이스임을 나타내는 Annotation</li>
<li><code>@Deprecated</code> : 더 이상 지원하지 않는 기능임을 알려주는 Annotation</li>
<li><code>@SafeVarargs</code> : Generic과 같은 가변 인자 Parameter를 사용할 때 발생하는 경고를 ignore 하는 Annotation</li>
<li><code>@Repeatable</code> : 해당 Annotation을 반복적으로 사용할 수 있게 지원하는 Annotation</li>
<li><code>@Inherited</code> : Meta Annotation 중 하나로 써 적용된 대상 Annotation을 하위 Class, Interface에게 상속시키는 Annotation</li>
</ul>
</li>
</ol>
<hr>
<h3 id="retention">@Retention</h3>
<p><code>@Retention</code> 에노테이션은 애노테이션 선언에 사용되는 메타 애노테이션으로, 마크된 에노테이션을 언제까지 유지할 건지 결정해주는 애노테이션이다.</p>
<p>즉, Java 컴파일러가 애노테이션을 다루는 방법을 기술하며, 어느 시점까지 영향을 미치는지 결정한다. </p>
<p>보존할 기간을 특정하게 명시하지 않으면 기본값은 클래스 파일까지 보존한다.</p>
<p>해당 정책들은 <code>java.lang.annotation.RetentionPolicy</code>에 <code>enum</code>으로 정의되어 있으며 아래와 같다.</p>
<ul>
<li><code>SOURCE</code> : 컴파일러가 컴파일할 때 해당 애노테이션 제외</li>
<li><code>CLASS</code> : 컴파일러가 컴파일에서는 해당 애노테이션을 가져가지만 런타임 시에는 사라짐</li>
<li><code>RUNTIME</code> : 런타임에도 해당 애노테이션 유지</li>
</ul>
<pre><code class="language-java">@Retention(RetentionPolicy.RUNTIME) //런타임에도 해당 애노테이션 유지
public @interface CustomAnnotation {
        // Element
    int value();
}</code></pre>
<hr>
<h3 id="target">@Target</h3>
<p><code>@Target</code> 애노테이션은 애노테이션 선언에 사용되는 메타 애노테이션으로, 애노테이션을 적용할 수 있는 범위를 정의한다.</p>
<p>해당 범위들은 <code>java.lang.annotation.ElementType</code>에 다양한 범위가 정의되어 있으며 아래와 같다.</p>
<ul>
<li><code>TYPE</code> : Class, Interface 등의 Level에 선언 가능</li>
<li><code>METHOD</code> : 메서드에 선언 가능</li>
<li><code>FIELD</code> : Enum, 상수, Field 변수에 대해 선언 가능</li>
<li><code>PARAMETER</code> : 매개변수에 선언 가능</li>
<li><code>CONTRUCTOR</code> : 생성자 Type에 선언 가능</li>
<li><code>LOCAL_VARIABLE</code> : 지역 변수에 대해 선언 가능</li>
<li><code>ANNOTATION_TYPE</code> : Annotation에 선언 가능</li>
<li><code>PACKAGE</code> : 패키지에 선언 가능</li>
</ul>
<pre><code class="language-java">@Target(ElementType.FIELD) //  Enum, 상수, Field 변수에 대해 선언 가능
@Retention(RetentionPolicy.RUNTIME) // 런타임에도 해당 애노테이션 유지
public @interface CustomAnnotation {
        // Element
    int value();
}</code></pre>
<hr>
<h3 id="documented">@Documented</h3>
<p><code>@Documented</code> 애노테이션은 애노테이션 선언에 사용되는 메타 애노테이션으로, 해당 애노테이션에 대한 정보를 Javadoc문서에 포함한다는 것을 선언한다.</p>
<pre><code class="language-java">@Documented // 이 애노테이션에 대한 정보를 Javadoc문서에 
@Target(ElementType.FIELD) //  Enum, 상수, Field 변수에 대해 선언 가능
@Retention(RetentionPolicy.RUNTIME) // 런타임에도 해당 애노테이션 유지
public @interface CustomAnnotation {
        // Element
    int value();
}</code></pre>
<hr>
<h3 id="annotation-processor">Annotation Processor</h3>
<p><code>Annotation Processor</code>는 애노테이션을 이용하여 프로세스를 처리하는 것을 의미하며, 컴파일러가 컴파일 중에 새로운 소스코드를 생성하거나 기존의 코드 변경을 가능하게 한다.</p>
<p>특히 컴파일 단계에서 애노테이션에 정의된 액션을 처리하는데, 이것은 애플리케이션이 실행되기 전 컴파일 타임에 미리 체크를 해주기 때문에 애노테이션이 의도한대로 이루어지지 않으면 눈으로 확인할 수 있는 에러나 경고를 보여준다.</p>
<p>애노테이션 프로세서의 가장 대표적인 예로는 <code>Lombok</code> 라이브러리가 있다. </p>
<p>Getter, Setter와 같이 반복적이고 중복되는 많은 코드를 양산하는 코드(boilerplate code)를 최소화하고 핵심적인 기능을 명확하게 확인할 수 있도록 한다.</p>
<p>애노테이션 프로세서를 작성하고 등록하기 위해서는 <code>AbstractProcessror</code> 클래스를 상속받아야 하는데, <code>Lombok</code> 또한 <code>AbstractProcessor</code>를 상속받아 애노테이션 프로세서를 정의한 것이다. </p>
<ol>
<li><code>Lombok</code><ul>
<li><strong>@Getter</strong> <strong>@Setter</strong> <strong>@Builder</strong></li>
</ul>
</li>
<li><code>AutoService</code> : <ul>
<li><strong>java.util.ServiceLoader</strong> 용 파일 생성 유틸리티<ul>
<li>리소스 파일을 만들어 줌.</li>
<li>META-INF 밑의 service 밑에 ServiceLoader용 레지스트리 파일을 만들어 줌.</li>
</ul>
</li>
</ul>
</li>
<li><code>@Override</code><ul>
<li>컴파일러가 오버라이딩하는 메서드가 잘못된 대상임을 체크해주는 것도 애노테이션 프로세서임</li>
</ul>
</li>
<li><code>Dagger2</code><ul>
<li>컴파일 타임 DI 제공 -&gt; 런타임 비용이 없어짐.</li>
</ul>
</li>
<li><code>안드로이드 라이브러리</code> <ul>
<li><strong>ButterKnife</strong> : @BindView (뷰 아이디와 애노테이션 붙인 필드 바인딩)</li>
<li><strong>DeepLinkDispatcher</strong> : 특정 URI 링크를 Activity로 연결할 때 사용</li>
</ul>
</li>
</ol>
<hr>
<h2 id="io-1">I/O</h2>
<p><code>I/O</code>는 Input(입력) and Output(출력)의 약자이다.</p>
<p>I/O의 간단한 예시는, 키보드로 텍스트를 입력하고 모니터로 입력한 텍스트를 출력하는 것이다.</p>
<p>기존의 <code>IO(I/O)</code>방식은 스트림 방식의 입출력인데, 이 방식으로는 네트워크상에서 이루어지는 입출력의 속도가 하드웨어에서 이루어지는 입출력 속도에 비해 현저히 느리기 때문에 문제점이 생겼다.</p>
<p>또한 스트림 방식은 병목현상에 매우 취약하다는 단점이 있고 네트워크의 발전보다 하드웨어의 발전속도가 앞서나가면서 새로운 I/O 방식이 필요해졌다.</p>
<p>그래서 이러한 네트워크 환경에서의 문제점을 해결하기 위해서 <code>NIO(NEW I/O)</code>방식이 나타났다.</p>
<table>
<thead>
<tr>
<th align="center">구분</th>
<th align="center">IO</th>
<th align="center">NIO</th>
</tr>
</thead>
<tbody><tr>
<td align="center">입출력</td>
<td align="center">스트림</td>
<td align="center">채널</td>
</tr>
<tr>
<td align="center">버퍼</td>
<td align="center">non-버퍼</td>
<td align="center">버퍼</td>
</tr>
<tr>
<td align="center">비동기</td>
<td align="center">지원 안함</td>
<td align="center">지원</td>
</tr>
<tr>
<td align="center">블로킹</td>
<td align="center">블로킹만 지원</td>
<td align="center">블로킹 / non-블로킹 모두 지원</td>
</tr>
</tbody></table>
<hr>
<h3 id="stream">Stream</h3>
<p>Stream이란, 한 방향으로 연속적으로 흘러가는 것을 의미한다.</p>
<p><img src="https://user-images.githubusercontent.com/51703260/134504606-d51eed4a-a9bd-41f8-9d45-4050e46ea012.png" alt="Untitled"></p>
<p>이 Stream이 프로그래밍에서는 데이터가 한 방향으로 흘러갈 수 있도록 도와주는 관, 통로라는 의미로 사용된다.</p>
<p>입출력 노드에 직접 연결되는 Stream을 <code>노드스트림</code>이라고 하고, 이는 <strong>필수</strong> 다.</p>
<p>그리고 다른 스트림을 보조하는 기능적인 Stream을 <code>필터스트림</code>이라고 하며, 이는 <strong>옵션</strong> 이다.</p>
<p><code>데코레이터 패턴</code>으로 <code>노드스트림</code>에 <code>필터스트림</code>이 추가되는 방식이다. </p>
<br>

<p>Stream이 데이터를 어떤 방식으로 전달하느냐에 따라 2가지로 구분할 수 있다.</p>
<ol>
<li><strong><code>Byte Stream</code> (바이트 스트림)</strong><ul>
<li>데이터를 Byte 단위로 주고 받음</li>
<li>Binary 데이터를 입출력하는 스트림</li>
<li><strong>모든 종류의 데이터</strong> 를 주고받을 수 있음</li>
<li><code>InputStream</code>과 <code>OutputStream</code> 클래스를 상속받아 사용</li>
</ul>
<hr>
<ul>
<li><code>FileInputStream</code> / <code>FileOutputStream</code> : 파일 입출력 스트림</li>
<li><code>ByteArrayInputStream</code> / <code>ByteArrayOutputStream</code> : 메모리 입출력 스트림</li>
<li><code>PipedInputStream</code> / <code>PipedOutputStream</code> : 프로세스 입출력 스트림</li>
<li><code>AudioInputStream</code> / <code>AudioOutputStream</code> : 오디오 장치 입출력 스트림</li>
</ul>
</li>
</ol>
<p>자바에서 가장 작은 타입인 char 형이 2바이트이므로, 1바이트씩 전송되는 바이트 기반 스트림으로는 원활한 처리가 힘든 경우가 있다. 이러한 경우를 해결하기 위해 자바는 <code>Character Stream</code>을 지원함</p>
<ol start="2">
<li><strong><code>Character Stream</code> (문자 스트림)</strong><ul>
<li>데이터를 Character 단위로 주고 받음</li>
<li>문자 데이터를 인코딩 처리하여 입출력하는 스트림</li>
<li>오직 <strong>문자 데이터</strong> 만 주고받을 수 있음</li>
<li><code>Reader</code>와 <code>Writer</code> 클래스를 상속받아 사용</li>
</ul>
<hr>
<ul>
<li><code>FileReader</code> / <code>FileWriter</code> : 파일 입출력 스트림</li>
<li><code>CharArrayReader</code> / <code>CharArrayWriter</code> : 메모리 입출력 스트림</li>
<li><code>PipedReader</code> / <code>PipedWriter</code> : 프로세스 입출력 스트림</li>
<li><code>StringReader</code> / <code>StringWriter</code> : 문자열 입출력 스트림</li>
</ul>
</li>
</ol>
<p>두 Stream은 모두 처음에는 byte로 받아들이고, 그 다음은 각 Stream이 알아서 처리를 해준다.</p>
<hr>
<h3 id="표준-stream">표준 Stream</h3>
<p><code>System</code> Class는 자바에서 미리 정의해둔 표준 입출력 클래스이며, <code>java.lang</code> 패키지에 포함되어 있다.</p>
<ul>
<li><code>System.in</code> : 표준 입력 스트림</li>
<li><code>System.out</code> : 표준 출력 스트림</li>
<li><code>System.err</code> : 표준 에러 출력 스트림</li>
</ul>
<hr>
<h3 id="channel">Channel</h3>
<p><code>서버와 클라이언트간의 통신수단</code>을 의미한다. </p>
<p>일반적으로 NIO(new I/O)의 모든 I/O는 채널로 시작한다. </p>
<p>채널은 스트림과 유사하지만 몇 가지 차이점이 존재한다.</p>
<ul>
<li><strong>비동기적</strong> 입출력</li>
<li><code>스트림</code>은 단방향 <strong>입출력(읽기 또는 쓰기)</strong> 만 가능하지만 <code>채널</code>을 통해서는 <strong>양방향 입출력(읽고 쓰기)</strong> 이 가능하다 있다.</li>
<li>항상 <code>버퍼</code>를 이용하여 입출력을 한다.</li>
</ul>
<hr>
<h3 id="buffer">Buffer</h3>
<p><strong>데이터를 임시 저장하는 공간</strong>을 의미한다.</p>
<p><code>IO</code>에서는 출력 스트림이 1바이트를 쓰면 입력 스트림이 1바이트를 읽는다.</p>
<p><code>NIO</code>에서 버퍼는 채널과 상호작용할 때 사용된다. 커널에 의해 관리되는 시스템 메모리를 직접 사용할 수 있는 채널에 의 해 직접 read 되거나 write 될 수 있는 배열과 같은 객체이다.</p>
<p>입출력을 담당하는 장치, 프로세스에서 고속 장치(프로세스)가 저속 장치(프로세스)가 작업을 하는 동안 기다리는 시간을 줄여 개별 작업들 간의 협동을 원활하게 지원하기 위해 존재한다.</p>
<p>따라서, 1바이트씩 전달이 아니라 기다리는 동안 버퍼에 데이터를 축척하여 한번에 전달하여 빠른 속도를 보인다.</p>
<hr>
<h3 id="inputstream">InputStream</h3>
<p><code>Byte Stream</code>기반의 입력 스트림의 최상위 클래스(추상클래스)로써 모든 Byte기반 입력 스트림은 이 클래스를 상속받고 데코레이터 패턴으로 기능을 추가하는 방식으로 스트림이 만들어진다.</p>
<p><code>InputStream</code> 클래스에는 입력을 위해 필요한 기본적인 메소드들이 정의되어 있다.</p>
<ul>
<li><code>int available()</code> : 현재 읽을 수 있는 byte수를 리턴</li>
<li><code>abstract int read()</code> : InputStream으로부터 1byte를 읽고 리턴.</li>
<li><code>int read(byte[] b)</code> : InputStream으로부터 읽은 바이트들을 byte[] b에 저장하고 읽은 바이트 수를 리턴.</li>
<li><code>int read(byte[] b, int off, int len)</code> : InputStream으로부터 <strong>len</strong> byte만큼 읽어 byte[] b의 b[ <strong>off</strong> ] 부터 <strong>len</strong> 개까지 저장한 후 읽은 byte 수인 <strong>len</strong> 개를 리턴. 만약 <strong>len</strong> 개보다 적은 byte를 읽는 경우 실제 읽은 byte수를 리턴</li>
<li><code>void close()</code> : 사용한 시스템 리소스를 반납 후 입력 스트림을 닫는 메소드.close() : 사용한 시스템 리소스를 반납 후 InputStream을 닫음.</li>
</ul>
<hr>
<h3 id="outputstream">OutputStream</h3>
<p>OutputStream 또한 <code>Byte Stream</code>기반의 출력 스트림의 최상위 클래스(추상클래스)로써 모든 Byte기반 출력 스트림은 이 클래스를 상속받고 데코레이터 패턴으로 기능을 추가하는 방식으로 스트림이 만들어진다.</p>
<p><code>OutputStream</code> 클래스에도 출력을 위해 필요한 기본적인 메소드들이 정의되어 있다.</p>
<ul>
<li><code>void flush()</code> : 버퍼에 남아있는 OutputStream을을 출력</li>
<li><code>abstract void write(int b)</code> : 정수 b의 하위 1byte를 출력</li>
<li><code>void write(byte[] b)</code> : 버퍼의 내용을 출력</li>
<li><code>void write(byte[] b, int off, int len)</code> : b 배열 안의 시작점 <strong>off</strong> 부터 <strong>len</strong> 만큼 출력</li>
<li><code>void close()</code> : 사용한 시스템 리소스를 반납 후 OutputStream을 닫음.</li>
</ul>
<hr>
<h3 id="파일-읽고-쓰기">파일 읽고 쓰기</h3>
<p>자바의 내장 클래스인 <code>FileReader</code>, <code>FileWriter</code>, <code>BufferedReader</code>, <code>BufferedWriter</code>를 사용하여 파일을 읽고 쓸 수 있다.</p>
<pre><code class="language-java">File file = new File(PATH);

FileWriter fw = new FileWriter(file);
FileReader fr = new FileReader(file);
BufferedWriter bw = new BufferedWriter(fw);
BufferedReader br = new BufferedReader(fr);</code></pre>
<p><code>FileReader</code>, <code>FileWriter</code>와 <code>BufferedReader</code>, <code>BufferedWriter</code>는 데코레이터 패턴이 적용됨을 알 수 있다.</p>
<hr>
<h2 id="generic-1">Generic</h2>
<p><code>Java 5</code>부터 추가되어 클래스와 인터페이스, 메소드를 정의할 때 <code>타입 변수</code>를 사용할 수 있게 하는 방법이다.</p>
<ul>
<li><strong><code>타입 변수</code></strong> : 일반적으로 대문자 알파벳 한 글자로 표현한다.<ul>
<li><code>&lt;T&gt;</code> :    Type</li>
<li><code>&lt;E&gt;</code> :    Element</li>
<li><code>&lt;K&gt;</code> :    Key</li>
<li><code>&lt;N&gt;</code> :    Number</li>
<li><code>&lt;V&gt;</code> :    Value</li>
<li><code>&lt;R&gt;</code> :    Return</li>
</ul>
</li>
</ul>
<p>컴파일 시의 객체의 타입을 체크를 해주는 기능을 제공함으로써 안정성을 높이고 형변환의 번거로움을 줄여준다.</p>
<p><code>Collection</code> 라이브러리에서 흔히 <code>Generic</code>이 활용된다.</p>
<pre><code class="language-java">//List&lt;T&gt;
List&lt;Integer&gt; listG = new ArrayList&lt;&gt;(); // 제네릭
listG.add(1);
int temp = listG.get(0);

List listNG = new ArrayList(); // 제네릭 사용 X
listNG.add(1);
temp = (int)listNG.get(0); // 형변환 필요</code></pre>
<p>Generic은 <code>Generic 타입</code>과 <code>Generic 메소드</code>로 구분할 수 있다.</p>
<h4 id="generic-타입"><code>Generic 타입</code></h4>
<p>타입 변수가 있는 클래스 또는 인터페이스</p>
<pre><code class="language-java">class GenericClass&lt;T&gt; {
     ...
}

interface  GenericInterface&lt;T&gt; {
     ...
}</code></pre>
<h4 id="generic-메소드"><code>Generic 메소드</code></h4>
<p>매개 타입과 리턴 타입으로 타입 변수를 갖는 메소드</p>
<pre><code class="language-java">public &lt;T, R&gt; R genericMethod(T t) { }</code></pre>
<h4 id="제네릭을-사용할-수-없는-경우">제네릭을 사용할 수 없는 경우</h4>
<ol>
<li><p><strong>제네릭 타입의 배열을 생성할 경우</strong> : new T[N]은 컴파일 타임에 배열의 타입을 알 수 없기 때문에 사용할 수 없다.</p>
</li>
<li><p><strong>static 변수에 사용할 경우</strong> : static 변수는 인스턴스에 종속되지 않으므로 인스턴스별 타입이 변경될 수 없기 때문에 사용할 수 없다. (단, static 메소드에는 제네릭 사용 가능)</p>
</li>
</ol>
<br>

<p>Generic의 주요 개념으로는 <code>Bounded-Type</code>과 <code>Wild-Card</code>가 있다.</p>
<hr>
<h3 id="boundedtype">BoundedType</h3>
<p><code>Bounded-Type</code>은 제네릭으로 사용될 타입 변수의 범위를 제한하는 것이다.</p>
<p>Generic 타입에 <code>extends</code>를 사용하여 타입 변수의 범위를 제한한다. (인터페이스, 클래스 모두 상관없이 <code>extends</code>를 사용)</p>
<pre><code class="language-java">public class CustomGeneric&lt;T extends Number&gt; {
     ...
}

CustomGeneric&lt;Integer&gt; listI = new CustomGeneric&lt;();
CustomGeneric&lt;String&gt; listS = new CustomGeneric&lt;&gt;(); // Bounded-Type으로 타입 변수를 Number로 제한했기 때문에 컴파일 에러 발생!</code></pre>
<pre><code class="language-java">public class CustomGeneric&lt;T extends ClassName &amp; InterfaceName&gt; { // &amp; 기호를 사용하여 타입 변수를 클래스와 인터페이스 2개로 제한 가능 
     ...
}</code></pre>
<hr>
<h3 id="wildcard">WildCard</h3>
<p>제네릭 타입을 메소드의 매개값으로 전달할 때 구체적인 타입으로만 타입 제한이 생긴다 그러한 문제를 해결하기 위해 와일드 카드를 사용한다.</p>
<p><code>?</code> 키워드를 사용하여 와일드 카드를 사용할 수 있다.</p>
<ul>
<li><code>제네릭 타입 &lt;?&gt;</code> : 제한 없음. 모든 클래스나 인터페이스 가능</li>
<li><code>제네릭 타입 &lt;? extends 상위 타입&gt;</code> : 타입의 상한선 지정(해당 타입 및 하위타입만, 최상이 제시한 타입), 최대 제시된 상위 타입보다 더 상위 타입을 사용할 수 없음</li>
<li><code>제네릭 타입 &lt;? super 하위 타입&gt;</code> : 타입의 하한선 지정(해당 타입 및 상위타입만, 최하가 제시한 타입), 최소 제시된 하위 타입보다 더 하위 타입을 사용할 수 없음</li>
</ul>
<hr>
<h3 id="erasure">Erasure</h3>
<ul>
<li><code>제네릭의 타입 소거(Generics Type Erasure)</code> : 컴파일러는 제네릭 타입을 이용해 소스파일을 검사하고 런타임에는 해당 타입의 정보를 알 수 없다는 개념이다. 즉, 컴파일된 파일<code>*.class</code>에는 제네릭 타입에 대한 정보가 없다는 뜻.</li>
</ul>
<h4 id="erasure-규칙">Erasure 규칙</h4>
<ul>
<li><code>UnBounded-Type</code>은 Object<ul>
<li>ex) <code>(&lt;?&gt;, &lt;T&gt;)</code> =&gt; Object</li>
</ul>
</li>
<li><code>Bounded-Type</code>은 extends 뒤에 작성한 객체<ul>
<li>ex) <code>&lt;T extends Number&gt;</code> =&gt; Number</li>
</ul>
</li>
</ul>
<hr>
<h2 id="lambda-1">Lambda</h2>
<p>람다식(Lambda expression)은 메소드를 간단하면서 명확한 <code>식(expression)</code>으로 표현한 것이다.</p>
<p>람다식은 인해 이름과 리턴타입이 필요없어, <code>익명 함수(anonymous function)</code>라고도 한다.</p>
<p>람다식은 메소드와 동등한 것처럼 보이지만, 사실 람다식은 익명 클래스의 객체와 동등하여 런타임 시에 인터페이스의 익명 구현 객체로 생성되고 대입되는 인터페이스에 따라 구현 인터페이스가 결정된다.</p>
<p>Lambda의 도입으로 인해 자바는 객체 지향 언어인 동시에 함수형 언어가 되었다.</p>
<hr>
<h3 id="lambda-사용법">Lambda 사용법</h3>
<p>메소드에서 메소드이름과 리턴타입을 제거하고 <code>매개변수</code> <code>{실행코드}</code> 사이에 <code>-&gt;</code> 화살표를 추가하여</p>
<p><code>매개변수</code> -&gt; <code>{실행코드}</code> 로 람다식을 사용할 수 있다.</p>
<p>메소드를 선언 할 때도 끝에 <code>세미콜론 ;</code>을 붙이지 않듯이, 람다식 또한 마찬가지로 <code>세미콜론 ;</code>을 붙이지 않는다 </p>
<pre><code class="language-java">// 메소드
리턴타입 메소드이름 (매개변수타입 매개변수) {
    실행코드
}
// 람다식
((매개변수) -&gt; {실행코드})
// 매개변수 :
// 매개변수가 하나일 때는 ()를 생략할 수 있다.   
// 단, 매개변수 타입이 있으면(대부분의 매개변수 타입은 추론이 가능해서 생략 가능) ()를 생략할 수 없다.  
// 코드 : 
// 실행코드가 하나일 때는 {}를 생략할 수 있다.   
// 단, {} 안의 실행코드에 return 키워드가 사용되는 경우 {}를 생략할 수 없다. 


// 메소드
int max(int a, int b) {
    return a &gt; b ? a : b;
}
// 람다식
((a, b) -&gt; a &gt; b ? a : b) // 매개변수가 a와 b 2개이므로 () 생략 불가. 그리고 return 키워드가 사용되지 않으므로 {} 생략 가능</code></pre>
<p>List를 람다식으로 조작하는 간단한 예시를 살펴보자.</p>
<pre><code class="language-java">ArrayList&lt;Integer&gt; list = new ArrayList&lt;Integer&gt;();
for(int i=1; i&lt;=10; ++i) list.add(i);

list.replaceAll(e -&gt; e+10); // 모든 요소에 10씩 더하기
list.removeIf(e -&gt; e%2==1); // 홀수값 요소 없애기
list.forEach(e -&gt; System.out.println(e)); // 모든 요소 출력    </code></pre>
<p>그리고 PS를 하다보면 자주 접하게 되는 Comparator 인터페이스의 compare메소드 또한 익명 구현 객체로 사용할 수도 있지만, 람다식으로 간단하게 표현할 수 있다. </p>
<pre><code class="language-java">// Comparator 인터페이스의 compare메소드 익명 구현 객체
Arrays.sort(time, new Comparator&lt;int[]&gt;() {
            @Override
            public int compare(int[] t1, int[] t2) {
                if(t1[0] == t2[0]) return t1[1] - t2[1];
                else return t1[0] - t2[0];
            }
        });</code></pre>
<pre><code class="language-java">// 람다식
Arrays.sort(time, (t1, t2)-&gt;{
            if(t1[0] == t2[0]) return t1[1] - t2[1];
            else return t1[0] - t2[0];
        });</code></pre>
<hr>
<h3 id="함수형-인터페이스">함수형 인터페이스</h3>
<p>람다 표현식으로 구현이 가능한 인터페이스는 추상 메서드를 1개만 가지고 있는 인터페이스만 가능하다.</p>
<p>그래서 추상 메서드가 1개인 인터페이스를 함수형 인터페이스라고 한다.</p>
<pre><code class="language-java">// 약식 사용 예제
@FunctionalInterface
interface CustomFunction{
    void customMethod();
}

// 사용 1. 람다식을 참조하는 참조변수로 함수형 인터페이스를 지정하고, 참조변수에서 메소드를 호출
CustomFunction cf = () -&gt; System.out.println(&quot;This is FunctionalInterface&quot;);
customMethod(cf); // This is FunctionalInterface

// 사용 2. 참조변수 없이 바로 람다식을 메소드로 사용 
customMethod() -&gt; System.out.println(&quot;This is FunctionalInterface&quot;);</code></pre>
<pre><code class="language-java">// 매개변수를 받고 리턴해주는 예제
@FunctionalInterface
interface CustomFunction{
    int customMethod(int a, int b);
}

CustomFunction cf = (a, b) -&gt; a &gt; b ? a : b;
int bigNum = cf.customMethod(1, 2); 
</code></pre>
<p><code>@FunctionalInterface</code> : 해당 인터페이스가 함수형 인터페이스라는걸 알려주는 애노테이션, 인터페이스 선언시 해당 애노테이션을 붙이면 2개 이상의 추상 메소드가 선언되지 않았는지 컴파일러가 체크하여 2개 이상의 추상 메소드가 선언되어 있다면 컴파일 에러가 발생한다.</p>
<p>모든 애노테이션들의 기능이 그렇듯, <code>@FunctionalInterface</code>은 컴파일러에게 확인을 부탁하는 것일 뿐 안붙어있다고 해서 함수형 인터페이스로 동작하지 않는 것은 아니다. </p>
<p>자바에서 함수형 인터페이스를 제공하는 <a href="https://docs.oracle.com/javase/8/docs/api/java/util/function/package-summary.html">표준 API</a> <code>java.util.function</code>를 제공해준다.</p>
<hr>
<h3 id="variable-capture">Variable Capture</h3>
<p><code>Variable Capture</code>는 람다식에서 파라미터로 넘겨진 변수가 아닌 외부에서 정의된 변수를 참조하는 것을 의미한다.</p>
<p>람다식에서 접근 가능한 변수들은 아래와 같다.</p>
<ol>
<li><code>로컬 변수</code>   </li>
<li><code>static 변수</code> </li>
<li><code>인스턴스 변수</code> </li>
</ol>
<p><code>Variable Capture</code>에는 위 변수들 중 1. <code>로컬 변수</code>에 대한 제약 조건이 존재한다.</p>
<ol>
<li>로컬 변수는 <code>final</code>으로 선언되어야 한다,</li>
<li><code>final</code>로 선언되어 있지 않은 로컬 변수는 <code>Effectively Final</code>(유사 final; final 처럼 동작)이어야 한다. 즉, 값의 재할당이 일어나면 안된다.</li>
</ol>
<p>따라서, 람다식에서 로컬 변수만 변경이 불가능하고, 나머지 변수들은 읽기 및 쓰기가 가능하다.</p>
<p>이러한 제약이 존재하는 이유는 아래와 같다.</p>
<blockquote>
<p>1주차에서 정리하였듯이, JVM에서 로컬 변수는 스택 영역에 생성된다.</p>
<p>실제 메모리와는 달리 JVM에서 스택 영역은 쓰레드마다 별도의 스택이 또 생성되어 쓰레드끼리는 로컬 변수 공유가 불가능 하다.</p>
<p>그리고 JVM에서 인스턴스 변수는 힙 영역에 생성되기 때문에 인스턴스 변수는 쓰레드끼리 공유가 가능하다.</p>
<p>람다식은 로컬 변수가 존재하는 스택에 직접 접근하지 않고, 로컬 변수를 자신(람다가 동작하는 별도의 쓰레드)의 스택에 복사한다. </p>
<p>그래서 만약 원래 지역 변수가 있는 쓰레드는 사라져서 로컬 변수가 사라져도 에러가 발생하지 않는다.</p>
<p>그래서 진짜 문제는 멀티 쓰레드 환경에서, 여러 개의 쓰레드에서 람다식을 사용하면서 람다 캡쳐링이 계속 발생하는데 이 때 외부 변수 값의 불변성을 보장하지 못한다면 동기(sync)화 문제가 발생할 수 있다.</p>
<p>이러한 문제 때문에 지역변수에 대한 제약사항이 존재하게 되는 것이다.</p>
<p>static 변수나 인스턴스 변수는 스택 영역이 아닌 힙 영역에 위치하고, 힙 영역은 모든 쓰레드가 공유하고 있는 메모리 영역이기 때문에 값을 직접 접근하기 때문에 문제가 없는 것이다.</p>
</blockquote>
<hr>
<h3 id="메소드-생성자-레퍼런스">메소드, 생성자 레퍼런스</h3>
<h4 id="method-reference"><code>Method Reference</code></h4>
<p>람다식이 하나의 메소드만 호출하는 경우에는 &#39;메소드 참조(Method References)&#39;를 통해 람다식을 더 간략하게 표현할 수 있다.</p>
<p>메소드를 참조해서 매개 변수의 정보 및 리턴 타입을 알아낸다. 람다식에서 불필요한 매개 변수를 제거하는 것이 목적이다.</p>
<blockquote>
<p>ClassName::MethodName</p>
<p>or</p>
<p>ReferenceVariable::MethodName</p>
</blockquote>
<pre><code class="language-java">Integer parseInt(String s) {                 // 메소드
    return Integer.parseInt(s);
}
Function&lt;String, Integer&gt; f = s -&gt; Integer.parseInt(s); // 람다식
Function&lt;String, Integer&gt; f = Integer::parseInt;     // 메소드 참조</code></pre>
<pre><code class="language-java">Function&lt;String, String, Boolean&gt; f = (s1, s2) -&gt; s1.equlas(s2);     // 람다식
Function&lt;String, String, Boolean&gt; f = String::equals;             // 메소드 참조</code></pre>
<h4 id="constructor-references"><code>Constructor References</code></h4>
<p><code>생성자 참조(Constructor References)</code>는 Constructor를 생성해주는 코드로써 객체 생성을 의미한다.</p>
<blockquote>
<p>ClassName::new</p>
</blockquote>
<pre><code class="language-java">Function&lt;Integer, int[]&gt; f = x -&gt; new int[x];   // 람다식
Function&lt;Integer, int[]&gt; f = int[]::new;      // 생성자 참조</code></pre>
<pre><code class="language-java">Supplier&lt;CustomClass&gt; s = () -&gt; new CustomClass();     // 람다식
Supplier&lt;CustomClass&gt; s = CustomClass:new;         // 생성자 참조</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL] 네트워크 유량(포드-풀커슨 + 에드먼드-카프 알고리즘 + 이분 매칭)]]></title>
            <link>https://velog.io/@bae_mung/TIL-%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-%EC%9C%A0%EB%9F%89%ED%8F%AC%EB%93%9C-%ED%92%80%EC%BB%A4%EC%8A%A8-%EC%97%90%EB%93%9C%EB%A8%BC%EB%93%9C-%EC%B9%B4%ED%94%84-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98</link>
            <guid>https://velog.io/@bae_mung/TIL-%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-%EC%9C%A0%EB%9F%89%ED%8F%AC%EB%93%9C-%ED%92%80%EC%BB%A4%EC%8A%A8-%EC%97%90%EB%93%9C%EB%A8%BC%EB%93%9C-%EC%B9%B4%ED%94%84-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98</guid>
            <pubDate>Sun, 26 Sep 2021 09:41:04 GMT</pubDate>
            <description><![CDATA[<h1 id="네트워크-유량">네트워크 유량</h1>
<p><img src="https://user-images.githubusercontent.com/51703260/134789412-d2455d13-e1e7-4b73-8b19-cab576011eba.png" alt="9921CE375BB450461A"></p>
<p>네트워크 유량이란 유방향 그래프에 용량이 존재하는 것이다. 유량의 시작 정점을 Source, 끝 정점을 Sink라고 한다.<br>
이 때, Source에서 Sink로 흘려보낼 수 있는 최대 유량(flow)을 구하는 문제를 네트워크 유량 문제라고 한다.</p>
<ul>
<li><code>유량(flow)</code> : 두 정점 사이에서 현재 흐르는 양</li>
<li><code>용량(capacity)</code> : 두 정점 사이에 최대로 흐를수 있는 양</li>
<li><code>잔여 용량(residual capacity)</code> : 두 정점 사이에서 현재 더 흐를 수 있는 유량. (용량 - 유량)</li>
<li><code>소스(source)</code> : 유량이 시작되는 정점. 보통 S로 표현</li>
<li><code>싱크(sink)</code> : 유량이 도착하는 정점. 보통 T로 표현</li>
<li><code>증가 경로(augmenting path)</code> : S에서 T로 유량이 흐르는 경로 </li>
</ul>
<p align="center"><img src="https://user-images.githubusercontent.com/51703260/133916224-1b022950-880b-436a-b105-885ed3c305ed.png"></p>

<p>위 이미지와 같은 네트워크 유량이 있다고 하자.</p>
<p>S에서 1로 갈 수 있는 유량은 2, 2로 갈 수 있는 유량은 3이다.<br>
S에서 1로 2만큼 유량이 흘러갔다면, 1에서 T로 용량은 3이지만 S에서 1로 흘러 들어온 2만큼만 유량을 보낼 수 있다.<br>
마찬가지로, S에서 2로 갈 수있는 유량은 3이라 3을 흘려 보냈더라도 2에서 T로 흐를 수 있는 용량이 2라서 2만큼만 유량을 보낼 수 있다.<br>
결과적으로 위 그래프는 S에서 T로 4를 흘러보내주게 되고, 최대 유량이 4라고 한다.</p>
<p>네트워크 유량 문제가 성립하기 위해서는 3가지 약속이 있다.<br>
일단 네트워크 유량에서는 위에서&quot; S에서 1로 갈 수 있는 유량은 2, 2로 갈 수 있는 유량은 3이다&quot;<br>
라는 표현을 <code>c(S,1)</code> = 2, <code>c(S,2)</code> = 3 이라고 간단하게 표현할 수 있다.</p>
<ul>
<li><code>c(u,v)</code> : <code>capacity</code> 정점 u에서 v로 가는 간선의 용량</li>
<li><code>f(u,v)</code> : <code>flow</code> 정점 u에서 v로 실제 흐르는 유량</li>
<li><code>r(u,v)</code> : <code>residual</code> 정점 u에서 v로 가는 잔여 용량 <code>r(u,v)</code> =  <code>c(u,v)</code> - <code>f(u,v)</code></li>
</ul>
<p><strong>1) 용량 제한 속성 <code>f(u,v)</code> &lt;= <code>c(u,v)</code> :</strong></p>
<p>두 간선 사이에서 흐르는 유량은 용량을 넘을 수 없다.</p>
<p><strong>2) 유량의 대칭성 <code>f(u,v)</code> = <code>-f(v,u)</code> :</strong></p>
<p>u-&gt;v로 2만큼 흐른다면, v-&gt;u엔 -2만큼 흐른다.
쉽게 생각하면, &#39;u-&gt;v로 2만큼 나가고 v-&gt;u로 2만큼 들어온다.&#39; 라고 이해하면 된다.</p>
<p><strong>3) 유량 보존의 법칙 <code>∑f(u,v)</code> = 0 :</strong>
S 와 T를 제외하고는 각 정점에서 들어오는 유량과 나가는 유량이 일치해야 한다.
그래서 유량의 대칭성 때문에 S와 T를 제외하고 유량을 모두 합하면 0이 되어야 한다.</p>
<h1 id="포드-풀커슨-알고리즘">포드-풀커슨 알고리즘</h1>
<p>최초의 네트워크 유량 알고리즘<br>
개념과 구현이 간단하다.</p>
<h3 id="개념">개념</h3>
<ol>
<li>각 간선의 용량을 입력받는다.</li>
<li>DFS(포드-풀커슨)를 이용하여 <code>r(u,v)</code> &gt; 0인 증가 경로를 찾는다. (DFS 기 때문에 최단경로 아님 )</li>
<li>찾은 증가 경로 상에서 <code>r(u,v)</code>이 가장 낮은 엣지를 찾는다.</li>
<li>찾은 엣지의 <code>r(u,v)</code>만큼만 S에서 T까지 유량을 흘려보낸다(경로의 모든 엣지에 유량 추가).</li>
<li>더 이상 증가 경로가 발견이 되지 않을 때까지 반복한다.</li>
</ol>
<p>아래 그래프를 가지고 포드-풀커슨 알고리즘의 과정을 살펴 보면,</p>
<p align="center"><img src="https://user-images.githubusercontent.com/51703260/133918099-b2b92772-fdf9-401b-a51e-dcf4be73666a.png"></p>

<p>S-&gt;a-&gt;T 라는 증가 경로를 먼저 찾고, 그 다음 S-&gt;b-&gt;T라는 증가 경로를 찾아서 최대 유량을 찾을 수도 있다.</p>
<p align="center"><img src="https://user-images.githubusercontent.com/51703260/133918097-a56dd01d-465e-49d5-9bc4-ee35c1496d38.png"></p>

<p>하지만, 만약 S-&gt;a-&gt;b-&gt;T라는 증가 경로를 가장 먼저 찾았는데, 이때 흘려 보낼수 있는 플로우는 1을 보내고 나니 그 다음 유량을 흘려 보낼 수 있는 루트를 찾아보니 없다.</p>
<p>여기서 위에서 살펴 보았던 <strong>2) 유량의 대칭성</strong> <code>f(u,v)</code> = <code>-f(v,u)</code>의 개념이 이용된다.<br>
현재 <code>c(a,b)</code>는 1이다. 그리고 <code>c(b,a)</code>는 경로가 존재하지 않으니 0이다.<br>
그리고 <code>f(a,b)</code>도 방금 <strong>S-&gt;a-&gt;b-&gt;T</strong> 라는 증가 경로로 유량이 흘렀기 때문에 1이 되고, 유량의 대칭성에 의해서 <code>f(b,a)</code>은 -1이 된다.</p>
<p align="center"><img src="https://user-images.githubusercontent.com/51703260/133918095-0f78c106-146f-400a-bb93-5f778eff21c2.png"></p>

<p>그러면 놀랍게도 잔여 용량 <code>r(b,a)</code>(<code>c(b,a)</code> - <code>f(b,a)</code>)은 0 - (-1)로, b에서 a로 흐르는 잔여 용량이 1이 된다.<br>
즉, 유량의 하나 보내는 것은 반대로 유량을 하나 보낼 수 있는 작업이 동반된다고 생각하면 된다.<br>
이렇게 Back-Edge라고 불리는 역간선 덕분에 포드-풀커슨 알고리즘이 성립 가능하게 된다.</p>
<p>그러면 결과적으로는 어떤 경로를 선택하든 최대 유량을 구할 수 있다.</p>
<h3 id="시간복잡도">시간복잡도</h3>
<p>증가경로 한개당 플로우 1밖에 보낼 수 없다.<br>
그래서 DFS를 플로우 수만큼 사용해야 하는데 플로우 수가 크다면 스택오버플로우가 발생할 수 있다.<br>
시간복잡도는 O((V+E)F) 인데, E가 V를 도미넌트 하므로 보통 O(EF)라고 표현한다.</p>
<h3 id="코드">코드</h3>
<p><a href="https://www.acmicpc.net/problem/6086">최대 유량 : 백준 6086</a>문제의 포드-풀커슨 알고리즘 풀이이다.</p>
<pre><code class="language-java">import java.io.*;
import java.util.*;

/*
 *  메모리        시간
 *  14388      140
 */
public class BaekOJ6086_배문규_DFS {
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static StringBuilder sb = new StringBuilder();
    static StringTokenizer st = null;

    static final int MAX_SIZE = 52;
    static int N, maxFlow, S, T = 25, capacity[][], flow[][];
    static boolean check[];

    public static void main(String[] args) throws NumberFormatException, IOException {
        capacity = new int[MAX_SIZE][MAX_SIZE];
        flow = new int[MAX_SIZE][MAX_SIZE];
        check = new boolean[MAX_SIZE];

        N = Integer.parseInt(br.readLine());
        for(int i = 0; i &lt; N; i++) {
            st = new StringTokenizer(br.readLine());
            int start = charToInt(st.nextToken().charAt(0));
            int end = charToInt(st.nextToken().charAt(0));
            int weight = Integer.parseInt(st.nextToken());
            // 여기서는 그냥 연결이기 때문에 무향 그래프라서 양방향으로 웨이트를 둘 다 더해줌
            capacity[start][end] += weight; 
            capacity[end][start] += weight;
        }

        // 더 이상 증가경로가 없을 때 까지 반복
        while(true) {
            // 방문 체크 초기화
            Arrays.fill(check, false);
            // DFS로 최대 유량 찾기
            int flowAmount = dfs(S, Integer.MAX_VALUE);
            if(flowAmount == 0) break;
            maxFlow += flowAmount;
        }

        System.out.println(maxFlow);
    }

    public static int dfs(int from, int amount) {
        // 증가경로가 완성되면 해당 증가경로의 최소 잔여용량 리턴
        if(from == T) return amount;

        // 방문한 곳이면 리턴
        if(check[from]) return 0;
        check[from] = true;

        for(int to = 0; to &lt; MAX_SIZE; to++) {
            // 유량이 흐를 수 있으면
            if(capacity[from][to] &gt; flow[from][to]) {
                // 현재 도달한 경로까지의 최소 잔여용량 저장
                int flowAmount = dfs(to, Math.min(amount, capacity[from][to]-flow[from][to]));
                if(flowAmount &gt; 0) {
                    // 잔여용량 갱신하고 리턴
                    flow[from][to] += flowAmount;
                    flow[to][from] -= flowAmount;
                    return flowAmount;
                }
            }
        }

        return 0;
    }

    // 문자를 인덱스로 매핑하기 위해 변환
    public static int charToInt(char c) {
        if(&#39;a&#39; &lt;= c &amp;&amp; c &lt;= &#39;z&#39;) c -= 6;
        return c - 65;
    }
}</code></pre>
<h1 id="에드몬드-카프-알고리즘">에드몬드-카프 알고리즘</h1>
<p>앞서 살펴본 <code>포드-풀커슨</code> 알고리즘은 임의의 유량 그래프가 주어졌을 때, 원래 경로가 이미 사용되어 막혀있어도 <code>Back-Edge</code> 덕분에 최대 유량은 확실하게 구할 수 있다는 것을 알게되었다.</p>
<p>하지만 최대 유량만 알 수 있지, 우리가 생각하는 유량이 흐르는 실제 경로를 제시하지는 않는다.</p>
<p>아래 유량 그래프를 다시 한 번 예시로 보자.</p>
<p align="center"><img src="https://user-images.githubusercontent.com/51703260/133916224-1b022950-880b-436a-b105-885ed3c305ed.png"></p>

<p><code>포드-풀커슨</code> 알고리즘에서는 S-&gt;1-&gt;2-&gt;T 가 먼저 증가경로로 잡히면, 유량의 대칭성으로 잔여 유량이 1이 생겨 2-&gt;1로 갈 수 있는 경로가 생겨서 S-&gt;2-&gt;1-&gt;T라는 증가경로가 생기게 되어서 </p>
<ul>
<li>S-&gt;1-&gt;2-&gt;T (유량 1 보냄)</li>
<li>S-&gt;2-&gt;1-&gt;T (유량 1 보냄)</li>
<li>S-&gt;1-&gt;2-&gt;T (유량 1 보냄)</li>
<li>S-&gt;2-&gt;1-&gt;T (유량 1 보냄)</li>
<li><strong>최대 유량 : 4</strong></li>
</ul>
<p>이런 방식으로 결국 최대 유량을 알게되었다. 그래서 총 4번의 증가경로 탐색이 필요하다.</p>
<p>이렇기 때문에 위 그래프와 같이 중간에 용량이 1인 엣지가 끼어있는 병목상태에서는 <code>포드-풀커슨</code> 알고리즘은 굉장히 비효율적으로 동작할 수 있다.</p>
<p>하지만 실제 유량이 흐르는 증가경로는 아래와 같다.</p>
<ul>
<li>S-&gt;1-&gt;T (유량 2 보냄)</li>
<li>S-&gt;2-&gt;T (유량 2 보냄)</li>
<li><strong>최대 유량 : 4</strong></li>
</ul>
<p>위 방식처럼 동작하는 알고리즘이 바로 <code>에드먼드-카프</code> 알고리즘이다.</p>
<p><code>포드-풀커슨</code> 알고리즘이 DFS 방식으로 증가경로를 탐색했다면, <code>에드먼드-카프</code> 알고리즘은 BFS 방식으로 증가경로를 탐색한다. </p>
<p>가장 짧은 경로의 증가 경로를 탐색하여 해당 증가경로로 보낼 수 있는 최대의 유량을 한번에 보내면 된다.</p>
<p>즉, 최단거리로 최대의 유량을 보내기 때문에 중간에 용량이 1인 엣지가 끼어있어도 <strong>돌아가는 길이라면</strong> 무시할 수 있는 것이다.</p>
<p>잔여용량이 남은 간선들만을 이용해서 BFS를 반복적으로 수행하고, 찾은 경로들에게 유량을 보내고, 더이상 할 수 없을때까지 보낸 총 유량을 반환하기만 하면 된다.</p>
<h3 id="개념-1">개념</h3>
<ol>
<li>각 간선의 용량을 입력받는다.</li>
<li>BFS(에드몬드-카프)를 이용하여 <code>r(u,v)</code> &gt; 0인 증가 경로 중 최단 거리를 찾는다.</li>
<li>찾은 증가 경로 중에서 <code>r(u,v)</code>이 가장 낮은 엣지를 찾는다.</li>
<li>찾은 엣지의 <code>r(u,v)</code>만큼만 S에서 T까지 유량을 흘려보낸다(경로의 모든 엣지에 유량 추가).</li>
<li>더 이상 증가 경로가 발견이 되지 않을 때까지 반복한다.</li>
</ol>
<h3 id="시간복잡도-1">시간복잡도</h3>
<p>BFS 한번이 O(E)이고, 증가 경로를 최대 VE번 찾기 때문에 <code>에드먼드-카프</code> 알고리즘의 일반적으로 알려진 시간복잡도는 <code>O(VE^2)</code>라고 한다.</p>
<p>증가 경로를 최대 VE번 찾는 이유(복잡함)에 대한 더 이상의 자세한 설명은 생략한다.</p>
<p>정확하게는 <code>min(O(|E|f), O(VE^2))</code>라고 하는데 만약 간선은 많고, 흘러야 하는 유량이 적을 때는 <code>O(|E|f)</code> &lt; <code>O(VE^2)</code>이 될 수 있다고 한다.</p>
<h3 id="코드-1">코드</h3>
<p><a href="https://www.acmicpc.net/problem/6086">최대 유량 : 백준 6086</a>문제의 에드몬드-카프 알고리즘 풀이이다.</p>
<pre><code class="language-java">import java.io.*;
import java.util.*;

/*
 *  메모리     시간
 *  14208    136
 */

public class BaekOJ6086_배문규_BFS {
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static StringBuilder sb = new StringBuilder();
    static StringTokenizer st = null;

    static final int MAX_SIZE = 52;
    static int N, maxFlow, S, T = 25, aPath[], capacity[][], flow[][];
    static Queue&lt;Integer&gt; queue;

    public static void main(String[] args) throws NumberFormatException, IOException {
        capacity = new int[MAX_SIZE][MAX_SIZE];
        flow = new int[MAX_SIZE][MAX_SIZE];

        N = Integer.parseInt(br.readLine());
        for(int i = 0; i &lt; N; i++) {
            st = new StringTokenizer(br.readLine());
            int start = charToInt(st.nextToken().charAt(0));
            int end = charToInt(st.nextToken().charAt(0));
            int weight = Integer.parseInt(st.nextToken());
            // 여기서는 그냥 연결이기 때문에 무향 그래프라서 양방향으로 웨이트를 둘 다 더해줌
            capacity[start][end] += weight; 
            capacity[end][start] += weight;
        }

        queue = new ArrayDeque&lt;Integer&gt;();
        aPath = new int[MAX_SIZE];
        // 더 이상 증가경로가 없을 때 까지 반복
        while(true) {
            // 큐, 증가경로 초기화
            queue.clear();
            Arrays.fill(aPath, -1);
            aPath[S] = S;
            queue.add(S);

            // BFS로 최단거리 증가경로 찾기
            while(!queue.isEmpty() &amp;&amp; aPath[T] == -1) {
                int from = queue.poll();
                for(int to = 0; to &lt; MAX_SIZE; to++) {
                    // 유량이 흐를 수 있으면서, 아직 방문하지 않았다면
                    if(capacity[from][to] &gt; flow[from][to] &amp;&amp; aPath[to] == -1) {
                        queue.offer(to);
                        aPath[to] = from;
                    }
                }
            }

            // 경로가 없으면 종료
            if(aPath[T] == -1) break;

            // 찾은 증가 경로의 r(u,v)의 최솟값 (최소 잔여 용량)을 찾음 
            int flowAmount = Integer.MAX_VALUE;
            for(int i = T; i != S; i = aPath[i]) 
                flowAmount = Math.min(capacity[aPath[i]][i] - flow[aPath[i]][i], flowAmount);

            for(int i = T; i != S; i = aPath[i]) {
                flow[aPath[i]][i] += flowAmount; // 경로들에 유량 흘러줌
                flow[i][aPath[i]] -= flowAmount; // 유량의 대칭성으로 반대 경로에 - 유량 흘림
            }

            maxFlow += flowAmount;
        }

        System.out.println(maxFlow);
    }

    // 문자를 인덱스로 매핑하기 위해 변환
    public static int charToInt(char c) {
        if(&#39;a&#39; &lt;= c &amp;&amp; c &lt;= &#39;z&#39;) c -= 6;
        return c - 65;
    }
}
</code></pre>
<h1 id="이분-매칭">이분 매칭</h1>
<p><code>이분 매칭(Bipartite Matching)</code> 알고리즘은 <code>네트워크 유량</code> 알고리즘과 연계되는 개념으로, <code>이분 그래프</code>에서 두 그룹간의 최대 매칭을 의미한다.</p>
<blockquote>
<p>즉, <code>집단 A</code>가 <code>집단 B</code>를 선택하는 방법에 대한 알고리즘이다.</p>
</blockquote>
<p>먼저 <code>이분 그래프</code>란, 전체 그래프에서 점 들을 두 그룹으로 나누었을 때, 같은 그룹내에는 간선이 존재하지 않게 나눌 수 있는 그래프를 의미한다.</p>
<p>그래프를 나눌 수 있는 경우가 여러가지 있을 수 있지만, 보통 문제에서는 명확히 두 그룹을 분류해주는 경우가 많다.</p>
<h3 id="개념-2">개념</h3>
<p>아래 예시를 통해 이분 매칭의 개념을 대해 알아보도록 하자.</p>
<p>네이버 클라우드, 카카오, 삼성전자에 각각 1자리씩 TO가 났고, 위 세 기업에 모두 최종 합격한 3명의 스터디원들이 있다.</p>
<img width="866" alt="스크린샷 2021-10-03 오전 2 59 03" src="https://user-images.githubusercontent.com/51703260/135727444-b9ba4b0a-9d3a-4211-948b-e3c79beceebc.png">

<p>위 예시에서는 <code>집단 A</code>가 <strong>스터디원</strong> 들이고, <code>집단 B</code>는 <strong>기업</strong> 이라고 할 수 있다. </p>
<p>이와 같이 각 스터디원들이 희망하는 기업들이 미리 정해져 있을 때, 스터디원들이 희망 기업으로 입사하는 경우를 이분 매칭으로 알아보자.</p>
<p>먼저, 위 경우를 아래와 같은 그래프로 표현할 수 있다.</p>
<img width="698" alt="스크린샷 2021-10-03 오전 2 59 50" src="https://user-images.githubusercontent.com/51703260/135727445-5e7d280d-5572-4b7c-b51d-f45f5356a7c0.png">

<p><strong>이분 매칭은, 두개의 그래프를 최대한으로 연결시켜주는 최대 연결(매칭)을 의미한다.</strong></p>
<p>즉,  최대한 많은 스터디원들이 희망 기업으로 입사하는 경우를 찾는 문제로 볼 수 있다. 뭔가 느낌이 오지 않는가?</p>
<p>우리가 그전까지 살펴본 <code>네트워크 유량</code> 문제 또한 Source에서 Sink로 흘려보낼 수 있는 최대 유량(flow)을 구하는 문제이고,</p>
<p><code>이분 매칭</code> 문제 또한 A에서 B로 갈 수 있는 최다 경우를 구하는 문제이기 때문에, 아래와 같이 <strong>이분 매칭을 네트워크 유량으로 표현할 수 있다.</strong></p>
<img width="978" alt="스크린샷 2021-10-03 오전 2 59 35" src="https://user-images.githubusercontent.com/51703260/135727447-8d345188-4fc4-42e1-83e8-8cad92173a16.png">

<p>위와 같이 선택을 1가지만 할 수 있는 이분 매칭은 모든 엣지의 용량이 1로 설정된 네트워크 유량 문제로 이해할 수 있다.</p>
<p>우리가 직전에 보았던 에드몬드-카프 알고리즘은 보통 시간 복잡도가 O(V*E^2)라고 알려져 있는데, 이분 매칭의 경우에는 이보다 더 빠르고 효율적으로 알고리즘을 설계할 수 있다.</p>
<p>그게 바로 단순히 <strong>DFS</strong>로 푸는 방법이다. (포드-풀커슨의 DFS가 아닌 그냥 DFS)</p>
<img width="698" alt="스크린샷 2021-10-03 오전 2 59 55" src="https://user-images.githubusercontent.com/51703260/135727449-e6a5ffb5-b5ed-4bae-9551-47341c6d0729.png">

<p>먼저 첫 출발로 문규가 네이버 클라우드를 선택한다. 현재까지는 네이버 클라우드가 아무에게도 선택되지 않았으므로 바로 선택할 수 있다.</p>
<img width="698" alt="스크린샷 2021-10-03 오전 2 59 57" src="https://user-images.githubusercontent.com/51703260/135727452-9ca7f518-c802-4a34-86f4-4e0042b85995.png">

<p>문규의 선택이 끝났다면, 그 다음 경준님이 선택할 차례인데 경준님께서 희망하는 네이버 클라우드는 이미 문규가 선택하고 있는 상황이다.</p>
<img width="698" alt="스크린샷 2021-10-03 오전 2 59 59" src="https://user-images.githubusercontent.com/51703260/135727453-de4ee412-0704-41b1-9956-656e49111f69.png">

<p>이 때, 네이버 클라우드를 선택한 문규가 네이버 클라우드를 제외하고 다른 희망 기업을 선택할 수 있는지 살펴본다. 살펴보니 아직 카카오가 아무에게도 선택되지 않았으므로 카카오를 선택하였다.</p>
<p>그래서 경준님이 네이버 클라우드를, 문규가 카카오를 선택하게 되었다.</p>
<img width="698" alt="스크린샷 2021-10-03 오전 3 00 01" src="https://user-images.githubusercontent.com/51703260/135727454-3ed9986c-9e89-442d-a696-dffe0a07f45d.png">

<p>그 다음 윤주님이 기업을 선택할 차례가 왔다. 윤주님께서 희망하는 카카오는 또 문규가 선택하고 있는 상황이다.</p>
<img width="698" alt="스크린샷 2021-10-03 오전 3 00 03" src="https://user-images.githubusercontent.com/51703260/135727455-e18ebd7f-6934-4847-af89-99bc38bf7135.png">

<p>이 때, 또 카카오를 선택한 문규가 카카오를 제외하고 다른 기업을 선택할 수 없는지 살펴본다. 네이버 클라우드를 혹시나 다시 한번 살펴 봤더니 경준님께서 계속 선택하고 계신 상황이라 선택할 수가 없었다. </p>
<img width="698" alt="스크린샷 2021-10-03 오전 3 00 05" src="https://user-images.githubusercontent.com/51703260/135727457-2ace68ec-fa73-4eb5-909b-d59d39d80e13.png">

<p>그래서 카카오와 네이버 클라우드를 제외하고 남은 희망 기업중 남아있는 삼성전자를 선택하였다.</p>
<img width="698" alt="스크린샷 2021-10-03 오전 3 00 07" src="https://user-images.githubusercontent.com/51703260/135727458-a596952e-622d-463c-a064-f331657009a8.png">

<p><strong>이렇게 문규는 삼성전자, 경준님은 네이버 클라우드, 윤주님은 카카오로 매칭되어 입사를 하게 되었다.</strong> 😊</p>
<h3 id="시간복잡도-2">시간복잡도</h3>
<p>위와 같은 예시처럼 DFS를 이용해 이분 매칭을 간단히 풀 때 시간 복잡도는 <code>O(V * E)</code> 이다. </p>
<p>이 방법은 가장 빠른 속도의 알고리즘은 아니지만 구현이 가장 간단하고 쉽다는 점에서 많이 사용된다.</p>
<h3 id="코드-2">코드</h3>
<p>이분 매칭에 대한 코드는 이분 매칭의 기본 문제라고 할 수 있는 <a href="https://www.acmicpc.net/problem/11375">열혈강호 : 백준 11375</a>문제를 대표로 하여 작성하였다.</p>
<p>더 효과적인 이분 매칭 코드가 있지만, 일단 가장 간단하게 구현할 수 있는 DFS 풀이부터 숙지하도록 하자.</p>
<pre><code class="language-java">import java.io.*;
import java.util.*;

/*
 * 회사에 N명의 직원과, M가지 작업이 있을 때,
 * 해당 회사가 할 수 있는 최대 일의 개수를 구하시오.
 * 
 * 1. 각 직원은 1개의 일을 할 수 있다.
 * 2. 각 작업을 담당하는 사람은 1명이다. 즉, 1 : 1 매칭
 * 3. 각 직원이 할 수 있는 일의 목록이 주어진다.
 * 
 * 직원(집단 A)과 작업(집단 B)을 최대한 매칭시키는 베이직한 이분 매칭 문제.
 * 
 * 메모리     시간
 * 78212    964
 */

public class BaekOJ11375_배문규 {
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static StringBuilder sb = new StringBuilder();
    static StringTokenizer st = null;

    static final int MAX_SIZE = 1001;
    static int N, M, worker[][], b[];
    static boolean check[];

    public static void main(String[] args) throws NumberFormatException, IOException {
        st = new StringTokenizer(br.readLine());
        N = Integer.parseInt(st.nextToken());
        M = Integer.parseInt(st.nextToken());

        worker = new int[N+1][];
        for(int i = 1; i &lt;= N; i++) {
            st = new StringTokenizer(br.readLine());
            int cnt = Integer.parseInt(st.nextToken());

            worker[i] = new int[cnt];
            for(int j = 0; j &lt; cnt; j++) worker[i][j] = Integer.parseInt(st.nextToken());
        }

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

    public static int bMatch() {
        b = new int[MAX_SIZE]; // b배열의 인덱스 : 작업 인덱스, b배열의 값 : 직원 인덱스 
        check = new boolean[MAX_SIZE]; // 이미 확인한 직원인지 체크 배열
        int result = 0; // 매칭된 작업 수

        for(int i = 1; i &lt;= N; i++) {
            Arrays.fill(check, false); // 매번 매칭을 시도할 때마다 이미 매칭된 사람도 
                          // 다른 작업으로 매칭이 바뀔 수 있으므로 방문 체크를 초기화 해야함 
            if(dfs(i)) result++; // i번 째 직원이 일과 매칭이 되면 카운트
        }

        return result;
    }

    public static boolean dfs(int workerIdx) {
        if(check[workerIdx]) return false;  // 이미 확인한 사람은 다시 확인할 필요 없음
        check[workerIdx] = true;

        // 해당 직원이 수행할 수 있는 작업들 
        for(int job : worker[workerIdx]) {

            // 매칭이 가능한 경우는 2가지가 있다.
            // 1. 아직 해당 작업이 아무런 직원과 매칭이 되어 있지 않았을 때 
            // 2. 이미 해당 작업에 매칭된 직원이 다른 작업도 매칭할 수 있을 때
            if(b[job] == 0 || dfs(b[job])) {
                b[job] = workerIdx; // 직원 &lt;--&gt; 작업 매칭하고 true 리턴
                return true;
            }
        }

        return false;
    }
}
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Become a Java-Masta👨‍🏫 6주차] 멀티쓰레드 프로그래밍, Enum]]></title>
            <link>https://velog.io/@bae_mung/Become-a-Java-Masta-6%EC%A3%BC%EC%B0%A8-%EB%A9%80%ED%8B%B0%EC%93%B0%EB%A0%88%EB%93%9C-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-Enum</link>
            <guid>https://velog.io/@bae_mung/Become-a-Java-Masta-6%EC%A3%BC%EC%B0%A8-%EB%A9%80%ED%8B%B0%EC%93%B0%EB%A0%88%EB%93%9C-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-Enum</guid>
            <pubDate>Thu, 23 Sep 2021 11:13:50 GMT</pubDate>
            <description><![CDATA[<h2 id="🎯-목표">🎯 목표</h2>
<h3 id="자바의-멀티쓰레드-프로그래밍-enum에-대해-학습하기">자바의 멀티쓰레드 프로그래밍, Enum에 대해 학습하기.</h3>
<h2 id="📌-학습할-것">📌 학습할 것</h2>
<h3 id="멀티쓰레드-프로그래밍"><a href="#%EB%A9%80%ED%8B%B0%EC%93%B0%EB%A0%88%EB%93%9C-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D">멀티쓰레드 프로그래밍</a></h3>
<ul>
<li><a href="#thread-%ED%81%B4%EB%9E%98%EC%8A%A4">Thread 클래스</a></li>
<li><a href="#runnable-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4">Runnable 인터페이스</a></li>
<li><a href="#%EC%93%B0%EB%A0%88%EB%93%9C-%EC%83%81%ED%83%9C">쓰레드 상태</a></li>
<li><a href="#%EC%93%B0%EB%A0%88%EB%93%9C-%EC%9A%B0%EC%84%A0%EC%88%9C%EC%9C%84">쓰레드 우선순위</a></li>
<li><a href="#main-%EC%93%B0%EB%A0%88%EB%93%9C">Main 쓰레드</a></li>
<li><a href="#%EB%8F%99%EA%B8%B0%ED%99%94">동기화</a></li>
<li><a href="#%EB%8D%B0%EB%93%9C%EB%9D%BD">데드락</a></li>
</ul>
<h3 id="enum"><a href="#enum">Enum</a></h3>
<ul>
<li><a href="#enum-%EC%A0%95%EC%9D%98%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95">enum 정의하는 방법</a></li>
<li><a href="#enum%EC%9D%B4-%EC%A0%9C%EA%B3%B5%ED%95%98%EB%8A%94-%EB%A9%94%EC%86%8C%EB%93%9C">enum이 제공하는 메소드</a></li>
<li><a href="#enumset">EnumSet</a></li>
</ul>
<hr>
<h2 id="멀티쓰레드-프로그래밍-1">멀티쓰레드 프로그래밍</h2>
<p>먼저 <code>Process</code> 와 <code>Thread</code>의 차이점을 이해하고 넘어가야 할 필요가 있다. </p>
<ul>
<li><p><code>프로세스(Process)</code> : OS 내에서 실행중인 프로그램</p>
</li>
<li><p><code>쓰레드(Thread)</code> : 프로세스 내에서 실제 작업이 실행되는 흐름의 단위</p>
</li>
</ul>
<p>따라서 프로세스는 하나 이상의 쓰레드를 가지고 있다.</p>
<br> 

<p>일반적으로 한 프로그램(Process)은 하나의 쓰레드를 가지고 있지만, 프로그램 환경에 따라 둘 이상의 스레드를 동시에 실행할 수 있다. 이러한 실행 방식을 멀티쓰레드(multithread)라고 한다.</p>
<p>근데 왜 멀티프로세스 프로그래밍이 아니라 멀티쓰레드 프로그래밍을 할까?</p>
<p>멀티프로세스와 멀티쓰레드는 양쪽 모두 여러 흐름이 동시에 진행된다는 공통점을 가지고 있다. </p>
<p>하지만 멀티프로세스에서 각 프로세스는 독립적으로 실행되며 각각 별개의 메모리를 차지하고 있는 것과 달리 멀티쓰레드는 프로세스 내의 메모리를 공유해 사용할 수 있다. 또한 프로세스 간의 전환에는 많은 비용이 소모되기 때문에 속도와 비용 측면에서 쓰레드가 유리하기 때문이다.</p>
<p>java에서는 쓰레드를 2가지 방식으로 구현할 수 있다. </p>
<ol>
<li><code>Thread 클래스</code>를 상속</li>
<li><code>Runnable 인터페이스</code>를 구현</li>
</ol>
<hr>
<h3 id="thread-클래스">Thread 클래스</h3>
<p>Thread 클래스를 상속받아 쓰레드를 구현하면, Thread 클래스 내의 run 메소드를 재정의(Override) 하면 된다.</p>
<pre><code class="language-java">public class ThreadByThread extends Thread {
    @Override
    public void run() {
        System.out.println(&quot;Run Thread By Thread&quot;);
    }
}</code></pre>
<pre><code class="language-java">public class Main {
    public static void main(String[] args) {
        ThreadByThread thread =new ThreadByThread();
        thread.start();
    }
}</code></pre>
<p>Thread 클래스를 상속받은 객체를 생성하여 start 메소드를 호출함으로써 쓰레드를 생성할 수 있다.</p>
<hr>
<h3 id="runnable-인터페이스">Runnable 인터페이스</h3>
<p>Runnable 인터페이스를 구현하여 쓰레드를 구현하면, run 메서드 안에 쓰레드가 할 코드를 작성해주면 된다.</p>
<pre><code class="language-java">public class ThreadByRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println(&quot;Run Thread By Runnable&quot;);
    }
}</code></pre>
<pre><code class="language-java">public class Main {
    public static void main(String[] args) {
        Thread thread = new Thread(new ThreadByRunnable());
        thread.start();
    }
}</code></pre>
<p>여기서 Runnable 객체는 Thread객체를 생성하여 Thread 생성자에 파라미터로 넘기어 Thread 타입으로 생성 후 start 메소드를 호출함으로써 쓰레드를 생성할 수 있다.</p>
<hr>
<h3 id="쓰레드-상태">쓰레드 상태</h3>
<p><code>쓰레드 스케줄링</code>: 쓰레드의 개수가 코어(CPU)의 수보다 많을 경우, 쓰레드를 어떤 순서에 의해 concurrent하게 실행할 것인가를 정하는 작업</p>
<p><img src="https://user-images.githubusercontent.com/51703260/134359608-dc4c8f7b-7daf-428c-be60-b4f2e10d5972.png" alt="20170126_214028"></p>
<p><code>실행 상태</code>: 실행 대기 상태에 있는 쓰레드 중에서 쓰레드 스케줄링으로 선택된 쓰레드가 CPU를 점유하고 <code>run()</code>메소드를 실행한 상태</p>
<p>쓰레드 상태를 확인할 수 있도록 해주는 <code>getState()</code> 메소드는 쓰레드 상태에 따른 <code>Thread.State</code> 열거 상수를 리턴한다.</p>
<table>
<thead>
<tr>
<th align="center">상태</th>
<th align="center">열거 상수</th>
<th align="center">설명</th>
</tr>
</thead>
<tbody><tr>
<td align="center">생성</td>
<td align="center"><code>NEW</code></td>
<td align="center">스레드 객체가 생성된 상태. 아직 <code>start()</code> 호출 전</td>
</tr>
<tr>
<td align="center">대기</td>
<td align="center"><code>RUNNABLE</code></td>
<td align="center">실행될 준비(스케줄러에 의해 선택 받기 전)를 마친 상태. <code>start()</code> 호출 됨</td>
</tr>
<tr>
<td align="center">정지</td>
<td align="center"><code>WAITING</code></td>
<td align="center">다른 스레드로부터 오는 이벤트를 대기하는 상태</td>
</tr>
<tr>
<td align="center"></td>
<td align="center"><code>TIMED_WAITING</code></td>
<td align="center">주어진 시간 동안 대기하는 상태</td>
</tr>
<tr>
<td align="center"></td>
<td align="center"><code>BLOCKED</code></td>
<td align="center">사용하고자 하는 객체의 lock이 풀릴 때까지 대기하는 상태</td>
</tr>
<tr>
<td align="center">종료</td>
<td align="center"><code>TERNINATED</code></td>
<td align="center">실행이 다 끝난 상태</td>
</tr>
</tbody></table>
<p><code>NEW</code>로 쓰레드 객체를 생성하고, <code>start()</code> 메소드를 호출하면 곧바로 쓰레드가 실행되는 것처럼 보이지만 사실은 준비가 완료된 대기 상태이다. </p>
<p>실행 대기 상태에 있는 쓰레드 중에서 쓰레드 스케줄링으로 선택된 쓰레드만이 실행 상태가 되고, 실행 상태의 쓰레드는 <code>run()</code> 메소드를 모두 실행하기 전에 쓰레드 스케줄링에 의해 다시 실행 대기 상태로 돌아갈 수 있다(interrupt). </p>
<p>그리고 실행 대기 상태에 있는 다른 쓰레드가 선택(scheduler dispatch)되는 방식으로 쓰레드 스케줄링이 이루어 진다.</p>
<p>아래 표는 쓰레드의 상태를 조작할 수 있는 메소드이다. </p>
<table>
<thead>
<tr>
<th align="center">메소드</th>
<th align="center">설명</th>
</tr>
</thead>
<tbody><tr>
<td align="center"><code>static void yield()</code></td>
<td align="center">현재 쓰레드가 프로세서의 현재 사용을 양보(yield) 할 의사가 있다는 스케줄러에 대한 힌트이다.</td>
</tr>
<tr>
<td align="center"><code>static void sleep(long millis)</code></td>
<td align="center">현재 실행중인 쓰레드가 지정된 밀리 초 동안 일시적으로 실행 중지 되도록 한다. 즉, <code>TIMED_WAITING</code> 상태로 만든다.</td>
</tr>
<tr>
<td align="center"><code>void join(long millis)</code></td>
<td align="center">이 쓰레드가 작업이 완료 될 때까지 기다린다.</td>
</tr>
<tr>
<td align="center"><code>void interrupt()</code></td>
<td align="center">이 쓰레드의 interrupted 상태를 true로 변경한다.</td>
</tr>
</tbody></table>
<hr>
<h3 id="쓰레드-우선순위">쓰레드 우선순위</h3>
<p>쓰레드에 우선순위를 부여함으로써 해당 쓰레드가 먼저 끝 날 확률을 높여준다.</p>
<p>하지만, 우선순위가 높다고 해서 무조건 먼저 끝나는 것은 아니다.</p>
<br>

<p>java에서 쓰레드의 우선순위를 설정하는 방법은 <code>setPriority(int weight)</code> 메소드를 통해 설정 할 수 있다.</p>
<p><code>weight</code> 파라미터는 숫자가 클수록 우선순위가 높은것이며, 설정 범위는 1부터 10까지 우선순위를 설정할 수 있다.</p>
<p>디폴트 <code>weight</code>는 중간값인 5가 설정된다.</p>
<hr>
<h3 id="main-쓰레드">Main 쓰레드</h3>
<p>Main 쓰레드는 모든 자바 애플리케이션의 시작점이다.</p>
<p>Main 쓰레드로 프로그램이 시작되어 실행을 되고, 멀티 쓰레드는 싱글 쓰레드인 Main 쓰레드에서부터 파생되어 생성된 쓰레드라고 할 수 있다.</p>
<p>참고로, 멀티 쓰레드 어플리케이션에서는 Main 스레드가 종료되더라도 자식 스레드가 종료되지 않으면 어플리케이션이 종료되지 않는다.</p>
<pre><code class="language-java">public static void main(String[] args) { // 메인 쓰레드 
      Thread thread = new Thread(new ThreadByRunnable());  // 멀티 쓰레드 생성
      thread.start();
}</code></pre>
<hr>
<h3 id="동기화">동기화</h3>
<p>멀티쓰레드 프로그래밍에서 여러 쓰레드가 한 프로세스내 자원을 공유하므로 한 쓰레드가 진행중인 작업을 다른 쓰레드 쪽에서 사용, 변경하는 일이 발생할 수 있다.</p>
<p>이러한 문제점을 해결 하기위해 하나의 쓰레드만 영역 내의 코드를 수행하도록 하는 쓰레드 동기화를한다.</p>
<p>java에서 2가지 방식으로 멀티쓰레드 프로그래밍 동기화 할 수 있다. </p>
<ol>
<li><code>synchronized</code> 키워드 사용</li>
<li><code>java.lang.Object</code> 클래스의 <code>wait()</code>, <code>notify()</code>, <code>notifyAll()</code> 메소드 사용</li>
</ol>
<h4 id="1-synchronized-키워드-사용">1. <code>synchronized</code> 키워드 사용</h4>
<p><code>synchronized</code> 키워드로 실행 블록이나, 메소드를 임계 구역으로 만들어 동기화 시킬 수 있다.</p>
<blockquote>
<p>동기화 블록</p>
</blockquote>
<pre><code class="language-java">synchronized(쓰레드 객체){
     // 동기화 시킬 코드
}</code></pre>
<blockquote>
<p>동기화 메소드</p>
</blockquote>
<pre><code class="language-java">public static synchronized void syncMethod(){
           // 동기화 시킬 코드
}</code></pre>
<p>해당 동기화 블록이나, 메소드는 하나의 쓰레드만이 진입될 수 있다.</p>
<h4 id="javalangobject-클래스의--wait-notify-notifyall-메소드-사용">java.lang.Object 클래스의  wait(), notify(), notifyAll() 메소드 사용</h4>
<p>아래 표의 메소드들은 임계 구역에서만 사용 가능하다.</p>
<table>
<thead>
<tr>
<th align="center">메소드</th>
<th align="center">설명</th>
</tr>
</thead>
<tbody><tr>
<td align="center"><code>wait()</code></td>
<td align="center">다른 스레드가 <code>notify()</code>로 불러줄 때까지 대기한다.</td>
</tr>
<tr>
<td align="center"><code>notify()</code></td>
<td align="center">무작위로 대기 중인 스레드를 깨워 <code>RUNNABLE</code> 상태로 변경, 2개 이상의 스레드가 대기 중이라도 오직 한 개의 스레드만 깨워 <code>RUNNABLE</code> 상태로 변경한다.</td>
</tr>
<tr>
<td align="center"><code>notifyAll()</code></td>
<td align="center">대기 중인 모든 스레드를 깨우고 모두 <code>RUNNABLE</code> 상태로 변경한다.</td>
</tr>
</tbody></table>
<hr>
<h3 id="데드락">데드락</h3>
<p>데드락은, 두 개 이상의 쓰레드들이 각자 자원을 점유한 상태에서 서로 다른 쓰레드의 자원을 요구하며 모두 무한정 대기중인 상태를 말한다.</p>
<p>즉, 쓰레드1이 자원1을 점유하였고, 쓰레드2가 자원2를 점유한 상태에서 쓰레드1이 자원2를 요청하는데 쓰레드2도 자원 1을 요청하여 서로 자원을 점유한 채 요청만 하며 양보하지 않고 버티는 상황이다.</p>
<p>그렇기 때문에 <code>yield()</code>를 사용하여 양보를 하기도 한다. </p>
<hr>
<h2 id="enum-1">Enum</h2>
<p>enum 이란 관련이 있는 &quot;상수&quot;의 집합을 정의하는 타입으로 클래스의 특수한 형식이다.</p>
<p>자바5부터 enum 타입이 도입되었고, 변수, 메소드, 생성자를 추가하여 사용할 수 있다.</p>
<p>enum 타입은 여러 특성들이 존재한다.</p>
<ol>
<li><code>java.lang.Enum</code> 클래스(추상 클래스)를 상속한 완전한 클래스이므로 필드와 메소드를 가질 수 있으며, 그러므로 다른 클래스를 상속받을 수 없다.</li>
<li><code>public static final</code> 타입으로 공개되며 상수와 동일하게 명칭을 전부 대문자로 정의한다.</li>
<li>고정된 상수들의 집합이기 때문에 런타임이 아닌 컴파일타임에 모든 값을 알고있어야 하므로 생성자의 접근지정자가 <code>private</code>로 동적으로 값을 변경하여 생성하면 안된다.</li>
<li>singleton 패턴이 적용되어 필드에 존재하는 상수 하나당 하나의 인스턴스가 된다.</li>
<li>싱글톤으로 존재하므로 객체를 <code>equals()</code> 메소드가 아닌 <code>==</code> 로 비교가 가능하다.</li>
</ol>
<hr>
<h3 id="enum-정의하는-방법">enum 정의하는 방법</h3>
<pre><code class="language-java">public enum CHICEKN {
    [public static final] BBQ(&quot;BBQ치킨&quot;),  //CHICEKN.BBQ로 접근
    [public static final] PURADAK(&quot;푸다락치킨&quot;), // ;가 아닌 ,
    [public static final] GOOBNE(&quot;굽네치킨&quot;); // 내부적으로 new로 생성한 것과 같다.

    private final String name; // 필드를 가질 수 있음

    [private] CHICEKN(String name) { // private 생략
        this.name = name;
    }

    public String getName() { // 메소드를 가질 수 있음
        return name;
    }
}</code></pre>
<hr>
<h3 id="enum이-제공하는-메소드">enum이 제공하는 메소드</h3>
<p>enum 타입은 java.lang.Enum 클래스를 상속하므로 해당 클래스의 메소드를 사용할 수 있는데,</p>
<p>대표적인 메소드로는 <code>values()</code>, <code>valueOf()</code>, <code>ordinal()</code>이 있다.</p>
<table>
<thead>
<tr>
<th align="center">메소드</th>
<th align="center">설명</th>
</tr>
</thead>
<tbody><tr>
<td align="center"><code>values()</code></td>
<td align="center">모든 enum 요소들을 enum 타입 배열로 반환</td>
</tr>
<tr>
<td align="center"><code>valueOf()</code></td>
<td align="center">특정 문자열이 enum 타입으로 존재하면 반환(존재하지 않으면 exception 발생)</td>
</tr>
<tr>
<td align="center"><code>ordinal()</code></td>
<td align="center">해당 enum 요소의 index를 반환</td>
</tr>
</tbody></table>
<hr>
<h3 id="enumset">EnumSet</h3>
<p>이름 그대로 Set을 기반으로 쉽고 빠르게 enum 타입 요소들을 다룰수 있는 기능을 제공한다.</p>
<p>enum은 싱글턴 패턴의 단일 객체임을 보장 함으로 해싱작업을 필요로 하지 않기 때문에 EnumSet은 enum의 요소 갯수가 64개를 넘지 않는다면, 내부적으로 long 데이터형의 64비트 필드를 이용하여 좋은 성능을 보여준다.</p>
<p>대표적인 EnumSet의 메소드로는 <code>.allOf(enum.class)</code>, <code>EnumSet.of(enum1, enum2...)</code>, <code>EnumSet.complementOf(enum of EnumSet)</code>, <code>EnumSet.range(enum1, enum4)</code> 가 있다.</p>
<table>
<thead>
<tr>
<th align="center">메소드</th>
<th align="center">설명</th>
</tr>
</thead>
<tbody><tr>
<td align="center"><code>.allOf(enum.class)</code></td>
<td align="center">enum 타입의 모든 요소들을 가져오기</td>
</tr>
<tr>
<td align="center"><code>EnumSet.of(enum1, enum2...)</code></td>
<td align="center">특정 enum요소들을 가져오기</td>
</tr>
<tr>
<td align="center"><code>EnumSet.complementOf(enum of EnumSet)</code></td>
<td align="center">특정한 enum요소를 제외하고 가져오기</td>
</tr>
<tr>
<td align="center"><code>EnumSet.range(enum1, enum4)</code></td>
<td align="center">범위로 요소들 가져오기</td>
</tr>
</tbody></table>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Become a Java-Masta👨‍🏫 5주차] 상속, 예외처리, 패키지]]></title>
            <link>https://velog.io/@bae_mung/Become-a-Java-Masta-5%EC%A3%BC%EC%B0%A8-%EC%83%81%EC%86%8D-%EC%98%88%EC%99%B8%EC%B2%98%EB%A6%AC-%ED%8C%A8%ED%82%A4%EC%A7%80</link>
            <guid>https://velog.io/@bae_mung/Become-a-Java-Masta-5%EC%A3%BC%EC%B0%A8-%EC%83%81%EC%86%8D-%EC%98%88%EC%99%B8%EC%B2%98%EB%A6%AC-%ED%8C%A8%ED%82%A4%EC%A7%80</guid>
            <pubDate>Wed, 15 Sep 2021 00:39:31 GMT</pubDate>
            <description><![CDATA[<h2 id="🎯-목표">🎯 목표</h2>
<h3 id="자바의-상속-예외처리-패키지에-대해-학습하기">자바의 상속, 예외처리, 패키지에 대해 학습하기.</h3>
<h2 id="📌-학습할-것">📌 학습할 것</h2>
<h3 id="상속"><a href="#%EC%83%81%EC%86%8D">상속</a></h3>
<ul>
<li><a href="#%EA%B4%80%EA%B3%84%EC%84%B1">관계성</a></li>
<li><a href="#%EB%8B%A4%ED%98%95%EC%84%B1">다형성</a></li>
<li><a href="#%EB%A9%94%EC%86%8C%EB%93%9C-%EC%9E%AC%EC%A0%95%EC%9D%98">메소드 재정의</a></li>
<li><a href="#%EB%8F%99%EC%A0%81-%EB%B0%94%EC%9D%B8%EB%94%A9">동적 바인딩</a></li>
</ul>
<h3 id="예외-처리"><a href="#%EC%98%88%EC%99%B8-%EC%B2%98%EB%A6%AC">예외 처리</a></h3>
<ul>
<li><a href="#%EC%B2%98%EB%A6%AC-%EB%B0%A9%EB%B2%95">처리 방법</a></li>
<li><a href="#%EC%B2%98%EB%A6%AC-%EA%B7%9C%EC%B9%99">처리 규칙</a></li>
</ul>
<h3 id="패키지"><a href="#%ED%8C%A8%ED%82%A4%EC%A7%80">패키지</a></h3>
<ul>
<li><a href="#%EB%AA%85%EB%AA%85-%EA%B7%9C%EC%B9%99">명명 규칙</a></li>
<li><a href="#%ED%8C%A8%ED%82%A4%EC%A7%80-%EC%82%AC%EC%9A%A9">패키지 사용</a></li>
<li><a href="#%EC%A0%91%EA%B7%BC-%EC%A0%9C%EC%96%B4%EC%9E%90">접근 제어자</a></li>
<li><a href="#%EC%82%AC%EC%9A%A9-%EC%98%88%EC%8B%9C">사용 예시</a></li>
</ul>
<hr>
<h2 id="상속-1">상속</h2>
<p>기존 클래스를 <strong>확장</strong>하여 새로운 내용을 덧붙이거나 내용의 일부를 바꿔 <strong>재정의</strong>하여 사용하는 것.</p>
<p><code>extends</code> 키워드로 상속받을 수 있다.</p>
<ul>
<li><strong>클래스</strong> &lt;- <strong>클래스</strong> : <code>extends</code> 키워드로 <strong>단일</strong> 상속</li>
<li><strong>인터페이스</strong> &lt;- <strong>인터페이스</strong> : <code>extends</code> 키워드로 <strong>다중</strong> 상속</li>
<li><strong>클래스</strong> &lt;- <strong>인터페이스</strong> : <code>implements</code> 키워드로 <strong>다중</strong> 상속 &amp; 구현</li>
</ul>
<p><strong>장점 :</strong> 코드의 재사용 (有 -&gt; 또 다른 有 창조), 확장용이
<strong>단점 :</strong> 높은 결합도</p>
<ul>
<li><p><strong>클래스상속 (구현상속)</strong></p>
<ul>
<li><p><code>Concrete클래스</code> 상속 : 온전한 클래스 -&gt; <strong>재정의 옵션</strong></p>
</li>
<li><p><code>Abstract클래스</code> 상속 : 미완성 클래스</p>
<ul>
<li><p>추상메소드 구현부 없이 선언으로만 이루어진 메소드
설계상 의도적으로 추상클래스로 만드는 경우</p>
</li>
<li><p>추상메소드 <strong>有</strong> : XXX(); -&gt; <strong>재정의 필수</strong></p>
</li>
<li><p>추상메소드 <strong>無</strong> : XXX(){}; -&gt; <strong>재정의 옵션</strong></p>
</li>
</ul>
<p>1) 추상클래스는 직접 new로 객체 생성을 못한다.</p>
<p>2) 반드시 하위 클래스 요구!</p>
</li>
</ul>
<p>extends XXX (단일상속)</p>
<p>&quot;일반화&quot;</p>
</li>
<li><p><strong>인터페이스상속 (표준, 약속, spe, 방법)</strong></p>
<ul>
<li><p><code>사용자 관점</code> : 사용방법, 약속</p>
</li>
<li><p><code>제공자 관점</code> : 구현의 책임</p>
</li>
</ul>
<p>implements XXX,YYY (다중상속)
&quot;실현&quot;
추상메소드와 상수로 이루어진 특별한 타입 -&gt; <strong>재정의 필수</strong></p>
</li>
</ul>
<hr>
<h3 id="관계성">관계성</h3>
<p><strong>1. <code>is a</code></strong> : 상속관계 (일반화)</p>
<p><strong>2. <code>has a</code></strong> : 소유 (연관관계 - 영구적)</p>
<p><strong>3. <code>use a</code></strong> : 사용 (의존관계 - 일시적)</p>
<hr>
<h3 id="메소드-재정의">메소드 재정의</h3>
<p><code>논리적 재정의</code></p>
<p><strong>전제조건 :</strong> 상속</p>
<ul>
<li>전부다 뒤갈아 엎는 재정의</li>
<li>살짝 덧붙이는 구형의 재정의</li>
</ul>
<p><strong>1.</strong> 메소드 이름<br>
<strong>2.</strong> 매개변수 목록<br>
<strong>3.</strong> 리턴타입</p>
<p>1 ~ 3까지는 같아야 함</p>
<p><strong>4.</strong> 접근지정자 같거나 넓게 <strong>(넓어짐)</strong><br>
<strong>5.</strong> throws 구문 예외 같거나 하위타입으로 or 안던지거나 <strong>(좁아짐)</strong></p>
<hr>
<h3 id="다형성">다형성</h3>
<h4 id="상속이-전제조건">상속이 전제조건!</h4>
<p>형태가 다양한 성질 =&gt; 다양한 형태를 가질 수 있다.</p>
<ul>
<li><p><code>객체 다형성</code> : <strong>Type다형성</strong></p>
</li>
<li><p><code>메소드 다형성</code> : 다중정의(<strong>오버로딩</strong>), 재정의(<strong>오버라이딩</strong>)</p>
</li>
</ul>
<h4 id="type-다형성">Type 다형성</h4>
<pre><code class="language-java"> Object &lt;- Employee &lt;- Engineer
 big ----------------- small

 Engineer e1 = new Engineer();
 Employee e2 = new Engineer();
 Object e3 = new Engineer();

 big &gt;= small
 잔 = 내용물
 커피잔 = 커피
 텀블러(with빨대) = 커피

 잔의 형태에 따라 커피마시는 방식이 결정된다.
 즉, 객체를 어디에 담느냐에 따라 객체의 사용방법이 달라진다.

 만약 Object에 a, Employee에 b, Engineer에 c가 선언되어 있다고 할 때,
 e3.a
 e2.a, e2.b
 e1.a, e1.b, e1.c 사용가능.</code></pre>
<h4 id="다형성을-사용활용하는-경우">다형성을 사용(활용)하는 경우</h4>
<ol>
<li><strong>이형 집합 배열</strong></li>
</ol>
<p>만약 Engineer와 Manager등 다른 직무의 직원 총 100명의 샐러리를 관리할 리스트를 생성할 때 사용</p>
<pre><code class="language-java">Employee[] list = new Employee[100];</code></pre>
<ol start="2">
<li><strong>매개변수 다형성</strong></li>
</ol>
<p>Engineer와 Manager등 다양한 직무의 직원들을 매개변수로 받아야 할 때 사용</p>
<pre><code class="language-java">
XXX(Employee e)</code></pre>
<blockquote>
<p>&quot;직원들 모이세요&quot; -&gt; &quot;거기서 직원들 공통적인 이야기를 해야지, 엔지니어 or 매니저 이야기 하면 안됨&quot;</p>
</blockquote>
<ol start="3">
<li><strong>리턴타입 다형성</strong></li>
</ol>
<p>경우에 따라 리턴타입을 다르게 전달해야 할 때 사용</p>
<pre><code class="language-java">Employee XXX(){
   if(...) return new Engineer();
   else return new Manager();
}</code></pre>
<hr>
<h3 id="동적-바인딩">동적 바인딩</h3>
<p><code>동적 바인딩 (Run-time)</code> &lt;-&gt; <code>정적 바인딩 (Compile-time)</code></p>
<p>컴파일시에 컴파일러가 인지한 객체와 런타임시 실제 객체를 다르게 인지</p>
<pre><code class="language-java">// Employee에 정의된 getInfo()를 
// Engineer에서 getInfo()를 오버라이딩 했을 때,

Employee e = new Engineer();
e.getInfo();
ㄴ Compile-time : Employee
ㄴ Run-time : Engineer

Employee e = new Engineer();에서 
e는 Engineer에 없는 메소드는 사용하지 못하지만
유일하게 Engineer가 영향을 주는것은 오버라이딩된 메소드이다.</code></pre>
<hr>
<h2 id="예외-처리-1">예외 처리</h2>
<p>예외 처리 키워드 5가지 : <code>try</code> <code>catch</code> <code>throw</code> <code>throws</code> <code>finally</code></p>
<p>예외 처리란, 프로그램 실행 중 발생할 수 있는 예기치 못한 예외 발생에 대비한 코드를 작성하는 것이며,<br>
예외처리의 목적은 예외의 발생으로 인한 실행중인 프로그램의 갑작스런 비정상 종료를 막고 실행상태를 유지할 수 있도록 함</p>
<h3 id="처리-방법">처리 방법</h3>
<p>예외를 처리하는 방법은 크게 3가지로 나눌 수 있다.</p>
<h4 id="1-예외가-발생한-메소드-내에서-직접-처리">1. 예외가 발생한 메소드 내에서 직접 처리</h4>
<pre><code>try - catch - finally</code></pre><p>try 구문은 예외가 발생 할 가능성이 있는 범위를 지정한다.<br>
try 구문에는 최소 하나 이상의 catch 구문이 따라와 위치해야 한다.<br>
finally 구문은 선택적으로 사용 가능하며, 예외 발생, catch 유무와 상관없이 반드시 수행된다.</p>
<pre><code class="language-java">try{
    // 예외가 발생할 만한 코드
}catch (Exception e) {
    System.out.println(e.getMessage()); 
}finally{
    System.out.println(&quot;종료&quot;);
}</code></pre>
<h4 id="2-예외가-발생한-메소드를-호출한-곳으로-예외-객체를-넘겨줌">2. 예외가 발생한 메소드를 호출한 곳으로 예외 객체를 넘겨줌</h4>
<pre><code>throws</code></pre><p>throws는 어떠한 메소드의 내부 소스코드에서 에러가 발생했을시 1번 방법처럼 예외를 직접 처리하는 것이 아니라,<br>
이 메소드를 호출하는 곳에서 처리를 하도록 예외 객체를 전달함.</p>
<pre><code class="language-java">public void throwMethod() throws Exception{
    // 예외가 발생할 만한 코드
}

public static void main(String[] args) {
    try{ 
        throwMethod();
    }catch (Exception e) {
        System.out.println(e.getMessage()); 
    }finally{
        System.out.println(&quot;종료&quot;);
    }
}</code></pre>
<h4 id="3-사용자-정의-예외를-생성하여-처리">3. 사용자 정의 예외를 생성하여 처리</h4>
<pre><code>throw</code></pre><p>Exception 클래스를 상속받는 사용자 정의 예외 클래스를 생성하여 해당 예외 객체를 throw할 수 있다.</p>
<p>3번 방법은 앞선 1번 방법, 2번 방법을 모두 적용가능하다.</p>
<pre><code class="language-java">public class CustomException extends Exception{
    public CustomException(){
        super(&quot;사용자 정의 예외 발생!&quot;);
    }
}</code></pre>
<p>1번 방법처럼 try - catch문으로 예외가 발생한 메소드 내에서 직접 처리</p>
<pre><code class="language-java">try{
    throw new CustomException();
}catch (CustomException e) {
    System.out.println(e.getMessage()); 
}finally{
    System.out.println(&quot;종료&quot;);
}</code></pre>
<p>2번 방법처럼 해당 메소드를 호출한 곳으로 예외 객체를 넘겨줌</p>
<pre><code class="language-java">public void thorwMethod() throws CustomException{
    if(예외 발생 조건) throw new CustomException();   
}</code></pre>
<h3 id="처리-규칙">처리 규칙</h3>
<h4 id="1-try-catch">1. try-catch</h4>
<pre><code class="language-java">// 적절한 예외처리
try{
    // 예외가 발생할 만한 코드
} catch (XXException e){
    // 처리코드
} catch (YYException e){
    // 처리코드
} catch (Exception e){
    // 처리코드
}</code></pre>
<pre><code class="language-java">// 적절하지 않은 예외처리
try{
    // 예외가 발생할 만한 코드
} catch (Exception e){
    // 처리코드
} catch (YYException e){
    // 처리코드
} catch (XXException e){
    // 처리코드
}</code></pre>
<p>JVM이 던진 예외는 catch문장을 찾을 때 다형성이 적용됨. <br>
상위 타입의 예외가 먼저 선언되는 경우 뒤에 등장하는 catch는 절대 실행되지 않음.</p>
<blockquote>
<p>Unreachable catch block for Exception.</p>
</blockquote>
<p>상속 관계가 없는 경우는 무관하다.</p>
<p>작은 범위(자식)에서 큰 범위(부모)순으로 catch문을 정의하는것이 적절하게 예외처리하는 방법임.</p>
<h4 id="2-throws">2. throws</h4>
<pre><code class="language-java">class Parent {

    void methodA() throws IOExeption{}

    void methodB() throws ClassNotFoundException{}

}

class Child extends Parent {

    @override
    void methodA() throws FileNotFoundException{}

    @override
    void methodB() throws Exception{} // 문제 발생!

}</code></pre>
<p>자식이 부모의 메서드를 오버라이딩 할 때, 부모 클래스가 던지는 예외보다 더 부모의 예외를 던질 수 없다!<br>
(같거나 하위타입으로 or 안던지거나 <strong>(좁아짐)</strong>)</p>
<p>즉, 부모A가 던지는 어느 자식b가 있는데, A의 자식인 a가 이 b의 부모인 B를 던질 수는 없다.<br>
a는 b 또는 b보다 더 작은 자식부터 던질 수 있음.</p>
<hr>
<h2 id="패키지-1">패키지</h2>
<ul>
<li>클래스를 구분짓는 폴더 개념</li>
<li>패키지이름을 java 로 시작하면 안된다.</li>
<li>패키지 이름과 위치한 폴더의 이름이 같아야한다.</li>
<li>모든 클래스에는 정의가 되어있는 클래스 이름과 패키지 이름이 존재한다 (패키지를 따로 지정하지 않으면 디폴트 패키지).</li>
<li>패키지 이름 + 클래스 이름이 합쳐져야 클래스를 온전히 표현할 수 있으며 이를 <code>FQCN(Fully Qualified Class Name)</code>라고 한다. </li>
</ul>
<blockquote>
<p>ex) com.ssafy 패키지의 JavaTest 클래스를 FQCN로 표현하면 com.ssafy.JavaTest가 됨</p>
</blockquote>
<h4 id="명명-규칙">명명 규칙</h4>
<ul>
<li>자바 예약어 사용금지</li>
<li>소문자만 사용</li>
</ul>
<h4 id="패키지-사용">패키지 사용</h4>
<ul>
<li><code>import</code>키워드로 패키지명을 지정</li>
<li>해당 패키지의 모든 클래스를 사용하려면 <code>import com.ssafy.*;</code> 라고 선언하면 됨</li>
<li>특정 클래스만 사용하려면, * 대신 클래스명을 지정하면 됨</li>
</ul>
<h4 id="접근-제어자">접근 제어자</h4>
<p><img src="https://user-images.githubusercontent.com/51703260/132984874-d731c312-7304-4e17-8505-d9c0ab1cce0b.png" alt="99F2454B5B45C99728"></p>
<h4 id="사용-예시">사용 예시</h4>
<ul>
<li>패키지 선언문 (0 or 1)</li>
</ul>
<pre><code class="language-java">package top.sub....;

// 물리적 : 폴더
// 보통 domain name(Unique!) 역순사용</code></pre>
<ul>
<li>import문 (0 ~ 多) </li>
</ul>
<pre><code class="language-java">import top.sub...클래스이름;// 소스 클래스명 바로사용
import top.sub...*;// all classes, interfaces

// (not package) : import단위는 패키지가 아님, 클래스 단위!</code></pre>
<p>현 클래스안에서 참조, 사용하는 클래스가 자신과 같은 패키지가 아닌 경우 명시
단, <code>java.lang</code>은 자동으로 불러옴</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL] MySQL Hint]]></title>
            <link>https://velog.io/@bae_mung/TIL-MySQL-Hint</link>
            <guid>https://velog.io/@bae_mung/TIL-MySQL-Hint</guid>
            <pubDate>Wed, 15 Sep 2021 00:33:21 GMT</pubDate>
            <description><![CDATA[<h1 id="hint">Hint</h1>
<p>아래 Hint에 대한 모든 내용들은 <code>MySQL</code>을 기준으로 작성되었음.</p>
<p>힌트는 옵티마이저의 실행 계획을 원하는대로 바꿀 수 있게 해준다. <br>
옵티마이저라고 반드시 최선의 실행계획을 수립할 수는 없기 때문에, 조인이나 인덱스의 잘못된 실행 계획을 개발자가 직접 바꿀 수 있도록 도와주는 것이 힌트이다. </p>
<p>힌트의 문법이 올바르더라도 힌트가 반드시 받아 들여지는 것은 아니며, 옵티마이저에 의해 선택되지 않을 수도 있고 선택될 수도 있다.</p>
<p>Hint는 크게 2가지로 구분할 수 있다.</p>
<ol>
<li><code>옵티마이저 힌트</code></li>
<li><code>인덱스 힌트</code></li>
</ol>
<p><code>옵티마이저 힌트</code>와 <code>인덱스 힌트</code>는 서로 다르며, 함께 사용할 수도 있고 별도로 사용할 수도 있다.</p>
<h2 id="옵티마이저-힌트">옵티마이저 힌트</h2>
<p>옵티마이저를 제어하는 방법 중 하나는, optimizer_switch 시스템 변수를 설정하는 것 이다. 이는 모든 후속 쿼리 실행에 영향을 주기 때문에, 일반적인 사용자들에게는 권장되지 않은 방법이다.</p>
<p>그래서 옵티마이저를 더 세밀하게 선택적으로 제어해야 할 땐, 옵티마이저 제어를 원하는 부분을 지정할 수 있는 옵티마이저 힌트를 사용하는 것이다.<br>
즉, 명령문의 한 테이블에 대한 최적화를 활성화하고 다른 테이블에 대한 최적화를 비활성화할 수 있다.<br>
명령문 내의 옵티마이저 힌트는 optimizer_switch 보다 우선시 되어 적용된다.</p>
<p>옵티마이저 힌트는 다양한 범위 수준에서 적용된다.</p>
<ul>
<li><code>전역</code>: 힌트가 전체 문에 영향을 줌</li>
<li><code>쿼리 블록</code>: 힌트가 명령문 내의 특정 쿼리 블록에만 영향을 줌</li>
<li><code>테이블</code>: 힌트가 쿼리 블록 내의 특정 테이블에민 영향을 줌</li>
<li><code>인덱스</code>: 힌트가 테이블 내의 특정 인덱스에만 영향을 줌</li>
</ul>
<h3 id="사용-방법">사용 방법</h3>
<p>옵티마이저 힌트는 /*+ .... */주석 내에 지정해야 한다.</p>
<table>
<thead>
<tr>
<th align="center">힌트 명</th>
<th align="center">힌트 설명</th>
<th align="center">적용 범위 수준</th>
</tr>
</thead>
<tbody><tr>
<td align="center"><a href="https://dev.mysql.com/doc/refman/8.0/en/optimizer-hints.html#optimizer-hints-table-level">BKA</a><strong>,</strong> <a href="https://dev.mysql.com/doc/refman/8.0/en/optimizer-hints.html#optimizer-hints-table-level">NO_BKA</a></td>
<td align="center">일괄 처리된 키 액세스 조인 처리에 영향</td>
<td align="center">쿼리 블록, 테이블</td>
</tr>
<tr>
<td align="center"><a href="https://dev.mysql.com/doc/refman/8.0/en/optimizer-hints.html#optimizer-hints-table-level">BNL</a><strong>,</strong> <a href="https://dev.mysql.com/doc/refman/8.0/en/optimizer-hints.html#optimizer-hints-table-level">NO_BNL</a></td>
<td align="center">MySQL 8.0.20 이전: 블록 중첩-루프 조인 처리,  MySQL 8.0.18 이상: 해시 조인 최적화,  MySQL 8.0.20 이상: 해시 조인 최적화에만 영향</td>
<td align="center">쿼리 블록, 테이블</td>
</tr>
<tr>
<td align="center"><a href="https://dev.mysql.com/doc/refman/8.0/en/optimizer-hints.html#optimizer-hints-table-level">DERIVED_CONDITION_PUSHDOWN</a><strong>,</strong> <a href="https://dev.mysql.com/doc/refman/8.0/en/optimizer-hints.html#optimizer-hints-table-level">NO_DERIVED_CONDITION_PUSHDOWN</a></td>
<td align="center">구체화된 파생 테이블에 대한 파생 조건 푸시다운 최적화 사용 또는 무시(MySQL 8.0.22에 추가)</td>
<td align="center">쿼리 블록, 테이블</td>
</tr>
<tr>
<td align="center"><a href="https://dev.mysql.com/doc/refman/8.0/en/optimizer-hints.html#optimizer-hints-index-level">GROUP_INDEX</a><strong>,</strong> <a href="https://dev.mysql.com/doc/refman/8.0/en/optimizer-hints.html#optimizer-hints-index-level">NO_GROUP_INDEX</a></td>
<td align="center">GROUP BY 작업(MySQL 8.0.20에 추가)에서 인덱스 검색에 대해 지정된 인덱스를 사용하거나 무시</td>
<td align="center">인덱스</td>
</tr>
<tr>
<td align="center"><a href="https://dev.mysql.com/doc/refman/8.0/en/optimizer-hints.html#optimizer-hints-table-level">HASH_JOIN</a><strong>,</strong> <a href="https://dev.mysql.com/doc/refman/8.0/en/optimizer-hints.html#optimizer-hints-table-level">NO_HASH_JOIN</a></td>
<td align="center">해시 조인 최적화에 영향 (MySQL8.0.18만 해당)</td>
<td align="center">쿼리 블록, 테이블</td>
</tr>
<tr>
<td align="center"><a href="https://dev.mysql.com/doc/refman/8.0/en/optimizer-hints.html#optimizer-hints-index-level">INDEX</a><strong>,</strong> <a href="https://dev.mysql.com/doc/refman/8.0/en/optimizer-hints.html#optimizer-hints-index-level">NO_INDEX</a></td>
<td align="center">JOIN_INDEX,  GROUP_INDEX 및 ORDER_INDEX의 조합으로  작동하거나 NO_JOIN_INDEX, NO_GROUP_INDEX 및 NO_ORDER_INDEX(MySQL 8.0.20에 추가)의 조합으로 작동</td>
<td align="center">인덱스</td>
</tr>
<tr>
<td align="center"><a href="https://dev.mysql.com/doc/refman/8.0/en/optimizer-hints.html#optimizer-hints-index-level">INDEX_MERGE</a><strong>,</strong> <a href="https://dev.mysql.com/doc/refman/8.0/en/optimizer-hints.html#optimizer-hints-index-level">NO_INDEX_MERGE</a></td>
<td align="center">인덱스 병합 최적화에 영향</td>
<td align="center">테이블,  인덱스</td>
</tr>
<tr>
<td align="center"><a href="https://dev.mysql.com/doc/refman/8.0/en/optimizer-hints.html#optimizer-hints-index-level">JOIN_INDEX</a><strong>,</strong> <a href="https://dev.mysql.com/doc/refman/8.0/en/optimizer-hints.html#optimizer-hints-index-level">NO_JOIN_INDEX</a></td>
<td align="center">모든 액세스 방법에 대해 지정된 인덱스 또는 인덱스를 사용하거나 무시(MySQL 8.0.20에 추가)</td>
<td align="center">인덱스</td>
</tr>
<tr>
<td align="center"><a href="https://dev.mysql.com/doc/refman/8.0/en/optimizer-hints.html#optimizer-hints-join-order">JOIN_FIXED_ORDER</a></td>
<td align="center">FROM절에 지정된 순서대로(FIXED) 테이블을 조인하도록 지시</td>
<td align="center">쿼리 블록</td>
</tr>
<tr>
<td align="center"><a href="https://dev.mysql.com/doc/refman/8.0/en/optimizer-hints.html#optimizer-hints-join-order">JOIN_ORDER</a></td>
<td align="center">가능하다면 힌트에 지정된 순서대로 조인하도록 지시</td>
<td align="center">쿼리 블록</td>
</tr>
<tr>
<td align="center"><a href="https://dev.mysql.com/doc/refman/8.0/en/optimizer-hints.html#optimizer-hints-join-order">JOIN_PREFIX</a></td>
<td align="center">가장 먼저 조인을 시작 할 테이블 지정</td>
<td align="center">쿼리 블록</td>
</tr>
<tr>
<td align="center"><a href="https://dev.mysql.com/doc/refman/8.0/en/optimizer-hints.html#optimizer-hints-join-order">JOIN_SUFFIX</a></td>
<td align="center">가장 마지막으로 조인 할 테이블 지정</td>
<td align="center">쿼리 블록</td>
</tr>
<tr>
<td align="center"><a href="https://dev.mysql.com/doc/refman/8.0/en/optimizer-hints.html#optimizer-hints-execution-time">MAX_EXECUTION_TIME</a></td>
<td align="center">구문 실행 시간 제한</td>
<td align="center">전역 범위</td>
</tr>
<tr>
<td align="center"><a href="https://dev.mysql.com/doc/refman/8.0/en/optimizer-hints.html#optimizer-hints-table-level">MERGE</a><strong>,</strong> <a href="https://dev.mysql.com/doc/refman/8.0/en/optimizer-hints.html#optimizer-hints-table-level">NO_MERGE</a></td>
<td align="center">외부 쿼리 블록으로 병합되는 파생 테이블/뷰에  영향</td>
<td align="center">테이블</td>
</tr>
<tr>
<td align="center"><a href="https://dev.mysql.com/doc/refman/8.0/en/optimizer-hints.html#optimizer-hints-index-level">MRR</a><strong>,</strong> <a href="https://dev.mysql.com/doc/refman/8.0/en/optimizer-hints.html#optimizer-hints-index-level">NO_MRR</a></td>
<td align="center">다중 범위 읽기 최적화에 영향</td>
<td align="center">테이블,  인덱스</td>
</tr>
<tr>
<td align="center"><a href="https://dev.mysql.com/doc/refman/8.0/en/optimizer-hints.html#optimizer-hints-index-level">NO_ICP</a></td>
<td align="center">인덱스 조건 푸시다운 최적화에 영향</td>
<td align="center">테이블,  인덱스</td>
</tr>
<tr>
<td align="center"><a href="https://dev.mysql.com/doc/refman/8.0/en/optimizer-hints.html#optimizer-hints-index-level">NO_RANGE_OPTIMIZATION</a></td>
<td align="center">범위 최적화에 영향</td>
<td align="center">테이블,  인덱스</td>
</tr>
<tr>
<td align="center"><a href="https://dev.mysql.com/doc/refman/8.0/en/optimizer-hints.html#optimizer-hints-index-level">ORDER_INDEX</a><strong>,</strong> <a href="https://dev.mysql.com/doc/refman/8.0/en/optimizer-hints.html#optimizer-hints-index-level">NO_ORDER_INDEX</a></td>
<td align="center">행을 정렬하기 위해 지정된 인덱스 또는 인덱스 사용하거나 또는 무시(MySQL 8.0.20에 추가)</td>
<td align="center">인덱스</td>
</tr>
<tr>
<td align="center"><a href="https://dev.mysql.com/doc/refman/8.0/en/optimizer-hints.html#optimizer-hints-query-block-naming">QB_NAME</a></td>
<td align="center">쿼리 블록에 이름 할당</td>
<td align="center">쿼리 블록</td>
</tr>
<tr>
<td align="center"><a href="https://dev.mysql.com/doc/refman/8.0/en/optimizer-hints.html#optimizer-hints-resource-group">RESOURCE_GROUP</a></td>
<td align="center">구문을 실행하는 동안 리소스 그룹 설정</td>
<td align="center">전역 범위</td>
</tr>
<tr>
<td align="center"><a href="https://dev.mysql.com/doc/refman/8.0/en/optimizer-hints.html#optimizer-hints-subquery">SEMIJOIN</a><strong>,</strong> <a href="https://dev.mysql.com/doc/refman/8.0/en/optimizer-hints.html#optimizer-hints-subquery">NO_SEMIJOIN</a></td>
<td align="center">Semijoin 전략에 영향, MySQL 8.0.17부터는 anti조인에도 적용</td>
<td align="center">쿼리 블록</td>
</tr>
<tr>
<td align="center"><a href="https://dev.mysql.com/doc/refman/8.0/en/optimizer-hints.html#optimizer-hints-index-level">SKIP_SCAN</a><strong>,</strong> <a href="https://dev.mysql.com/doc/refman/8.0/en/optimizer-hints.html#optimizer-hints-index-level">NO_SKIP_SCAN</a></td>
<td align="center">스킵 검색 최적화에 영향</td>
<td align="center">테이블,  인덱스</td>
</tr>
<tr>
<td align="center"><a href="https://dev.mysql.com/doc/refman/8.0/en/optimizer-hints.html#optimizer-hints-set-var">SET_VAR</a></td>
<td align="center">구문을 실행하는 동안 변수 설정</td>
<td align="center">전역 범위</td>
</tr>
<tr>
<td align="center"><a href="https://dev.mysql.com/doc/refman/8.0/en/optimizer-hints.html#optimizer-hints-subquery">SUBQUERY</a></td>
<td align="center">구체화에 영향,  IN-to-EXISTS 하위 쿼리 전략</td>
<td align="center">쿼리 블록</td>
</tr>
</tbody></table>
<pre><code class="language-sql">/*+ BKA(table1) */ 

/*+ BNL(table1, table2) */

/*+ NO_RANGE_OPTIMIZATION(table3 PRIMARY) */

/*+ QB_NAME(queryblock1) */

SELECT /*+ BNL(t1) BKA(t2) */ ...
// 하나의 쿼리 블록에서 여러 힌트를 사용할 땐, 하나의 힌트 주석안에 여러개의 힌트를 선언하여 사용해야 한다.
// 즉, SELECT /*+ BNL(t1) */ /* BKA(t2) */ ... 는 안됨.</code></pre>
<p>옵티마이저 힌트는 SELECT, UPDATE, INSERT, REPLACE, DELETE문에서 아래와 같이 사용할 수 있다.</p>
<pre><code class="language-sql">SELECT /*+ HINT */ ...
INSERT /*+ HINT */ ...
REPLACE /*+ HINT */ ...
UPDATE /*+ HINT */ ...
DELETE /*+ HINT */ ...</code></pre>
<p>그리고 아래와 같이 쿼리 블록으로 구분하여 사용이 가능하다.</p>
<pre><code class="language-sql">(SELECT /*+ ... */ ... )
(SELECT ... ) UNION (SELECT /*+ ... */ ... )
(SELECT /*+ ... */ ... ) UNION (SELECT /*+ ... */ ... )
UPDATE ... WHERE x IN (SELECT /*+ ... */ ...)
INSERT ... SELECT /*+ ... */ ...</code></pre>
<h2 id="조인-순서-최적화-힌트">조인 순서 최적화 힌트</h2>
<p>MySQL 8.0은 이전 버전보다 훨씬 강력하고 편의성이 강한 Optimizer hint를 제공한다.<br>
그 중 하나가 조인 순서 최적화 힌트이다.</p>
<p>조인 순서 최적화 힌트는 옵티마이저가 테이블을 조인하는 순서에 영향을 준다.<br>
기존의 join 순서를 제어하던 STRAIGHT_JOIN 구문등은 사용상의 여러 문제를 만들어 냈지만, 조인 순서 최적화 힌트를통해 그러한 문제를 해결하게 되었다.</p>
<h3 id="사용-방법-1">사용 방법</h3>
<pre><code class="language-sql">HINT_NAME([@query_block_name])
HINT_NAME([@query_block_name] TABLE_NAME [, tbl_name] ...)
HINT_NAME(TABLE_NAME[@query_block_name] [, TABLE_NAME[@query_block_name]] ...)</code></pre>
<p>HINT_NAME에 올 수 있는 조인 순서 최적화 힌트는 4가지가 있다.</p>
<ul>
<li><code>JOIN_FIXED_ORDER</code>: FROM절에 지정된 순서대로(FIXED) 테이블을 조인하도록 지시 (STRAIGHT_JOIN의 힌트화)</li>
<li><code>JOIN_ORDER</code>: 가능하다면 힌트에 지정된 순서대로 조인하도록 지시</li>
<li><code>JOIN_PREFIX</code>: 가장 먼저 조인을 시작 할 테이블 지정</li>
<li><code>JOIN_SUFFIX</code>: 가장 마지막으로 조인 할 테이블 지정<br>

</li>
</ul>
<p>지정한 TABLE_NAME의 모든 테이블에 힌트가 적용되며, TABLE_NAME은 스키마 이름으로 한정할 수 없다.<br>
TABLE_NAME에 별칭이 있는 경우 힌트는 테이블 이름이 아니라 별칭을 참조해야 한다.</p>
<pre><code class="language-sql">SELECT
/*+ JOIN_PREFIX(t2, t5@subq2, t4@subq1)
    JOIN_ORDER(t4@subq1, t3)
    JOIN_SUFFIX(t1) */
COUNT(*) 
FROM t1 JOIN t2 JOIN t3
WHERE t1.f1 IN (SELECT /*+ QB_NAME(subq1) */ f1 FROM t4)
  AND t2.f1 IN (SELECT /*+ QB_NAME(subq2) */ f1 FROM t5);</code></pre>
<p><code>(SELECT /*+ QB_NAME(subq1) */ f1 FROM t4)</code> : 쿼리 블록의 이름을 subq1로 지정
<code>t4@subq1</code> : 쿼리 블록 subq1의 테이블 t4를 지정</p>
<pre><code class="language-sql">/*+ JOIN_PREFIX(t2, t5@subq2, t4@subq1)
JOIN_ORDER(t4@subq1, t3)
 JOIN_SUFFIX(t1) */</code></pre>
<p><code>t2</code>, <code>t5@subq2</code>, <code>t4@subq1</code>, <code>t3</code>, <code>t1</code> 순서대로 조인</p>
<h2 id="인덱스-힌트">인덱스 힌트</h2>
<p>Mysql를 사용을 하다보면 복잡한 쿼리의 경우 서로의 인덱스가 물리고 물려서 필요한 인덱스를 안타고 엉뚱한 인덱스를 사용하는 경우가 있다.<br>
예를 들어서 A, B, C의 인덱스가 순서대로 사용되어야 하는데 옵티마이저가 B, C, A 순으로 처리를 하여서 속도가 느려지는 경우에 이런 순서를 잡기 위해서 인덱스 힌트를 사용한다.<br>
즉, Mysql에서 제공하는 인덱스 힌트를 쓰면 강제적으로 할당한 Index를 이용하여 쿼리가 실행이 된다. <br>
하지만 JPA(hibernate)에서 사용이 불가능하기 때문에 JdbcTemplate 등을 이용하여 Native Query로 활용해야 된다.</p>
<h3 id="사용-방법-2">사용 방법</h3>
<pre><code class="language-sql">TABLE_NAME [[AS] ALIAS] INDEX_HINT INDEX_LIST

INDEX_LIST:
    USE {INDEX|KEY}
      [FOR {JOIN|ORDER BY|GROUP BY}] (INDEX_LIST)
  | IGNORE {INDEX|KEY}
      [FOR {JOIN|ORDER BY|GROUP BY}] (INDEX_LIST)
  | FORCE {INDEX|KEY}
      [FOR {JOIN|ORDER BY|GROUP BY}] (INDEX_LIST)

INDEX_LIST:
    INDEX_NAME , INDEX_NAME ...</code></pre>
<ul>
<li><code>USE 키워드</code> : 특정 인덱스를 사용하도록 권장</li>
<li><code>IGNORE 키워드</code> : 특정 인덱스를 사용하지 않도록 지정</li>
<li><code>FORCE 키워드</code> : USE 키워드와 동일한 기능을 하지만, 옵티마이저에게 보다 강하게 해당 인덱스를 사용하도록 권장</li>
</ul>
<ul>
<li><code>USE INDEX FOR JOIN</code> : JOIN 키워드는 테이블간 조인뿐 아니라 레코드 검색하는 용도까지 포함</li>
<li><code>USE INDEX FOR ORDER BY</code> : 명시된 인덱스를 ORDER BY 용도로만 사용하도록 제한</li>
<li><code>USE INDEX FOR GROUP BY</code> : 명시된 인덱스를 GROUP BY 용도로만 사용하도록 제한</li>
</ul>
<pre><code class="language-sql">SELECT * 
FROM TABLE1 
  USE INDEX (COL1_INDEX, COL2_INDEX)
WHERE COL1=1 AND COL2=2 AND COL3=3;

SELECT * 
FROM TABLE2 
  IGNORE INDEX (COL1_INDEX)
WHERE COL1=1 AND COL2=2 AND COL3=3;

SELECT * 
FROM TABLE3
  USE INDEX (COL1_INDEX)
  IGNORE INDEX (COL2_INDEX) FOR ORDER BY
  IGNORE INDEX (COL3_INDEX) FOR GROUP BY
WHERE COL1=1 AND COL2=2 AND COL3=3;</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL] 셸 정렬]]></title>
            <link>https://velog.io/@bae_mung/TIL-%EC%85%B8-%EC%A0%95%EB%A0%AC</link>
            <guid>https://velog.io/@bae_mung/TIL-%EC%85%B8-%EC%A0%95%EB%A0%AC</guid>
            <pubDate>Wed, 08 Sep 2021 00:05:28 GMT</pubDate>
            <description><![CDATA[<h1 id="셸-정렬">셸 정렬</h1>
<p>셸 정렬은 우선적으로 버블 정렬과 삽입 정렬에 대한 이야기가 필요하다.</p>
<p>버블 정렬이나 삽입 정렬이 수행되는 과정은 이웃하는 원소끼리의 자리 이동으로 원소들이 정렬된다.</p>
<p>버블 정렬이 오름차순으로 정렬하는 과정에서 작은 숫자가 배열의 앞부분으로 매우 느리게 이동한다.</p>
<p>그리고 삽입 정렬의 경우는 만일 배열의 마지막 원소가 가장 작은 숫자일 경우 그 숫자가 배열의 맨 앞으로 이동해야 하므로, 모든 다른 숫자들이 1칸씩 뒤로 이동해야한다.</p>
<p>셸 정렬은 이러한 단점을 보완하기 위해서 삽입 정렬을 이용하여 배열 뒷부분의 작은 숫자들을 앞부분으로 빠르게 이동시키고,</p>
<p>동시에 앞부분의 큰 숫자들은 뒷부분으로 이동시키고, 그리고 가장 마지막에는 삽입 정렬을 수행하는 알고리즘이다.</p>
<p align="center"><img src="https://user-images.githubusercontent.com/51703260/132044503-092612ca-9df9-4f4f-a6a5-4601f5b0d136.gif"></p>
<br>

<h4 id="셸-정렬-아이디어">셸 정렬 아이디어</h4>
<p>만약 아래와 같이 값이 저장된 배열이 존재한다고 하자.</p>
<blockquote>
<p><strong>30 60 90 10 40 80 40 20 10 60 50 30 40 90 80</strong></p>
</blockquote>
<p>먼저 간격 (gap)이 5가 되는 숫자끼리 그룹을 만든다.</p>
<p align="center"><img src="https://user-images.githubusercontent.com/51703260/132047715-211c4c09-f14b-499c-a7da-44c29b24af48.png"></p>

<p>각 그룹 별로 삽입 정렬을 수행한 결과를 1줄에 나열해 보면 다음과 같다.</p>
<blockquote>
<p><strong>30 30 20 10 40   /   50 40 40 10 60   /   80 60 90 90 80</strong></p>
</blockquote>
<p>간격이 5인 그룹 별로 정렬한 결과</p>
<ul>
<li>80과 90같은 큰 숫자가 뒷부분으로 이동하였고,</li>
<li>20과 30같은 작은 숫자가 앞부분으로 이동하였다.</li>
</ul>
<p>그 다음엔 간격을 5보다 작게 하여, 예를 들어, 3으로 하여, 3개의 그룹으로 나누어 각 그룹별로 삽입 정렬을 수행한다.</p>
<ul>
<li>이때에는 각 그룹에 5개의 숫자가 있다.</li>
</ul>
<p>최종적으로 마지막에는 반드시 간격을 1로 놓고 수행해야 한다.</p>
<ul>
<li>그 이유는, 다른 그룹에 속해 서로 비교되지 않은 숫자가 있을 수 있기 때문이다.</li>
<li>즉, 모든 원소를 1개의 그룹으로 여기는 것이고, 이는 삽입 정렬 그 자체이다.</li>
<li>삽입 정렬은 대강 정렬이 되어있는 상태에서 좋은 성능을 발휘한다.</li>
</ul>
<pre><code>// 수도코드
A[N]; // 크기가 N인 정렬되지 않은 배열
shell_Sort(A);

shell_Sort(A){
    gap = [ g0 &gt; g1 &gt; ... &gt; gk = 1 ]; // 큰 gap부터 차례로 저장된 gap배열, 마지막 gap은 반드시 1
    for(g : gap){
        for(i = 0; i &lt; g; i++) { // gap 만큼 반복한다
            insertion_Sort(i, gap); // 삽입 정렬
        }
    }
}

insertion_Sort(i, gap){
    for(j = i + gap; j &lt; N; j += gap){ // gap만큼 점프하며 삽입 정렬 수행
        for(x = i; x &lt; j; x += gap){
            if(A[x] &gt; A[j]){
                swap(A, x, j);
            }
        }
    }
}

swap(A, i, j){
    temp = A[i];
    A[i] = A[j];
    A[j] = temp;
}
</code></pre><p align="center"><img src="https://user-images.githubusercontent.com/51703260/132052008-19038dcc-629b-4d3d-b023-d4802fd4f4f0.png"></p>

<p>만약 gap의 5라서 5개의 그룹이 구분되면, 각 그룹별로 삽입 정렬을 수행한다.</p>
<p>이 과정으로 인해 앞에 있는 큰 수가 빠르게 뒤로 가고, 뒤에 있는 작은 수가 빠르게 앞으로 올 수 있게 된다.</p>
<p>gap을 차차 줄여가며, 최종적으로 gap을 1을 둔 삽입 정렬을 시행한다.</p>
<p>삽입 정렬은 이미 어느정도 정렬이 된 상태일수록 효율이 <strong>O(n)</strong> 에 가까워 진다.
<br></p>
<h4 id="시간복잡도">시간복잡도</h4>
<p>셸 정렬의 최악 경우의 시간복잡도는 <strong>O(n^2)</strong> 이며, 셸 정렬의 수행 속도는 간격 선정에 따라 좌우된다.</p>
<p>셸 정렬은 1959년에 발표될 정도로 역사가 오래된 정렬 알고리즘인 만큼, 이 알고리즘에 대한 많은 실험들이 진행되어왔다.</p>
<p>그 중 가장 유명한 gap 설정 방법인 히바드(Hibbard) 간격을 사용하면 <strong>O(n^(1.5))</strong> 라고 한다.</p>
<p>히바드 간격은 시작 간격을 2^k - 1로 두고 k를 1씩 줄여서 2^k -1, ... , 15, 7, 3, 1로 간격을 설정하는 방법이다.</p>
<p>이 후 많은 실험을 통한 현재까지의 셸 정렬의 최적의 시간복잡도는 <strong>O(n^(1.25))</strong> 으로 알려지고 있다.</p>
<p>아직까지는 가장 좋은 간격이 무엇인지 밝혀지지 않기 때문에, 셸 정렬의 시간 복잡도는 아직 풀리지 않은 문제 이다.</p>
<p>지금까지 알려진 가장 좋은 성능을 보인 간격은 Marcin Ciura이 밝혀낸 1750, 701, 301, 132, 57, 23, 10, 4, 1 이라고 한다.</p>
<p>마지막으로 정리하자면, 셸 정렬은 입력 크기가 매우 크지 않은 경우에 매우 좋은 성능을 보인다.</p>
<p>셸 정렬은 임베디드(Embedded) 시스템에서 주로 사용되는데, 셸 정렬의 특징인 간격에 따른 그룹 별 정렬 방식이 H/W로 정렬 알고리즘을 구현하는데 매우 적합하기 때문이라고 한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL] 이항계수]]></title>
            <link>https://velog.io/@bae_mung/TIL-%EC%9D%B4%ED%95%AD%EA%B3%84%EC%88%98</link>
            <guid>https://velog.io/@bae_mung/TIL-%EC%9D%B4%ED%95%AD%EA%B3%84%EC%88%98</guid>
            <pubDate>Tue, 07 Sep 2021 23:55:05 GMT</pubDate>
            <description><![CDATA[<h1 id="이항-계수">이항 계수</h1>
<p>우선 이항 계수를 다루기전에 근본적으로 이항 정리에 대해 알아야 한다.</p>
<p>이항 정리는 (A + B)^n (여기서 n은 음이 아닌 정수)라는 다항식을 전개할 때 쓰는 정리이며, 여기서 &#39;이항&#39;이라는 단어는 &#39;두 개의 항&#39;이라는 뜻이다. </p>
<p>이항 계수는 (A + B)^n 라는 다항식을 전개했을 때, A^r*B^(n-r) (0 &lt;= r &lt;= n인 정수)의 계수를 의미한다.</p>
<p>A^r*B^(n-r)의 계수는 총  n개의 문자를 순서없이 배열하는 경우의 수와 같으며, 이는 조합과 같다.</p>
<p>그래서 A^r*B^(n-r)의 계수는 nCr과 같다.</p>
<p>우리는 이항 계수의 수학적인 증명이나 성질을 자세하게 다루기보다는 PS에 이항 계수 관련 문제가 나오면</p>
<p>어떻게 이 이항 계수를 빠르고 효율적으로 구할 수 있느냐를 중점적으로 알아보려고 한다.</p>
<p>2가지 문제를 통해서 이항 계수 PS을 알아보도록 하자. 먼저 가장 기초적인 이항 계수를 구하는 문제이다.</p>
<blockquote>
<p>자연수 N과 정수 K가 주어졌을 때, 이항 계수를 10,007으로 모듈라 연산한 값을 구하시오. (1 &lt;= N &lt;= 1,000 / 0 &lt;= K &lt;= N)</p>
</blockquote>
<pre><code>binomial_coefficient(N, K){
    K = Max(K, N-K); // K와 N-K 중 큰 수를 고른다. return으로  K를 나눈 값을 return하는데 K가 0일 수 있기 때문에
    A = N;

    for(i = K-1; i &gt; 0; i--){
        A = A * (N - i); // nPk
        K = K * i;    // k!
    }

    return A/K; //nPk/k! == nCk
}</code></pre><p>보통 위 같은 문제는 겉으로 보기에는 return 값이 엄청나게 커져 오버플로우가 발생할 수 있기 때문에 보기 편하게 10,007을 나눈 나머지 값을 구하라는 문제라고 생각할 수 있다.</p>
<p>그리고 실제로 N의 범위가 1,000까지기 때문에 정석적인 방식으로 이항계수를 구하고 모듈라 연산을 그냥 리턴할 때 하면 된다.</p>
<p>만약 N의 범위가 4,000,000이라면 위처럼 구할 수 있을까? 동일하게 자연수 N과 정수 K가 주어졌을 때, 이항 계수를 구하는 문제인데,</p>
<p>N의 범위를 4,000,000까지 확장하여 이항 계수를 1,000,000,007으로 모듈라 연산한 값을 구하여라.</p>
<p>이 땐 처음 문제와 다르게 모듈라 연산의 존재 유무가 중요해졌다.</p>
<p>이 문제를 풀기 위해서는 우리가 앞서 배운 모듈라 연산의 분배법칙 속성을 활용해야 한다.</p>
<p>N과 K의 이항계수는 nCk = N!/(K!*(N-K)!) 로 구할 수 있다.</p>
<p>그렇다면 이 이항계수를 모듈라 연산으로 분할정복해서 구할 순 없을까?</p>
<p>하지만 위에서 봤을 때, 덧셈, 뺄셈, 곱셈에 대해서는 분배법칙이 존재했지만, 나눗셈은 존재하지 않았다.</p>
<p>즉, (A / B) mod M != ((A mod M) / (B mod M)) mod M 이라는 것이다.</p>
<p>여기서 A를 N!, B를 K!*(N-K)! 이라고 대입해보자.</p>
<p>(N! / K!<em>(N-K)!) mod M != ((N! mod M) / (K!</em>(N-K)! mod M)) mod M 으로 바꿀 수 있다.</p>
<p>왜 성립하지도 않는데 귀찮게 대입을 해서 식을 직접 눈으로 확인해 본 이유가 있다.</p>
<p>우리가 이항 계수의 분수가 나눗셈이기 때문에 분배법칙이 적용되지 않았는데, 이 분수를 비틀어서 곱셈으로 만들어 버린다면 이항계수의 분배법칙을 가능하게 할 수 있다.</p>
<p>그렇다면 곱셈꼴로는 어떻게 만들까? 분수를 곱셈꼴로 만드는 방법은 역원을 이용하면 쉽게 만들 수 있다.</p>
<p>만약 A / B = C 라면, 이는 A * B^(-1) = C라는 의미이다. 즉 A 나누기 B는 A 곱하기 B의 역원과 같다.</p>
<p>그렇기 때문에, (N! / K!<em>(N-K)!) mod M는 (N! * (K!</em>(N-K)!)^(-1)) mod M 로 표현 가능하다.</p>
<p>역원을 이용해 나눗셈을 곱셈까지는 표현하는데는 성공하였다. 그런데 나눗셈이 존재했던 이유는 분수때문이고, 분수의 역원은 어쨌든 분수가 아닌가? </p>
<p>이 문제를 해결하기 위해서 필요한 공식이 &#39;페르마의 소정리&#39;이다.</p>
<p>페르마의 소정리는 다음과 같다.</p>
<blockquote>
<p>A는 정수, P는 소수이며 A가 P로 나눠지지 않을 때, (A는 P의 배수가 아니라는 뜻)</p>
<p>A^P ≡ A (mod P)이다. (P에 대해 모듈라 합동이다 : P를 나눈 나머지가 같다.)</p>
</blockquote>
<p>이는 이렇게 표현이 가능하다 -&gt; A^P mod M ≡ A mod M</p>
<p>다시 말하지만 우리는 위 공식이 어떻게 증명되는지에 대해서는 관심없고 증명된 공식들을 잘 써먹는데에 관심이 있는 공학자들이다.</p>
<p>위 표현식을 다시 응용하면, A^(P-1) ≡ 1 (mod P) =&gt; A * A^(P-2) ≡ 1 (mod P)로 변형이 가능하다.</p>
<p>놀랍게도, A (mod P)에 대한 역원은 A^(P-2) (mod P)라는 것이다.</p>
<p>그렇다면 다시 문제로 돌아와서 해당 분수의 역원을 페르마의 소정리로 구해보면,</p>
<p>A는 (K! * (N-K)!) , P는 1,000,000,007 로 대입할 수 있다.</p>
<p>A^(-1) = A^(P-2) = (K! * (N-K)!)^(-1) = (K! * (N-K)!)^1,000,000,005 가 된다.</p>
<p>이제는 더 이상 역원이 분수가 아닌 정수로 표현되니, 모듈라 곱셈 분배 법칙 적용할 수 있게 되었다.</p>
<p>최종적으로 도출되는 식은 아래와 같다.</p>
<p>  N! / (K!<em>(N-K)!) mod M
= (N! * (K!</em>(N-K)!)^(-1)) mod M 
= (N! * (K!*(N-K)!)^(M-2)) mod M 
= ((N! mod M) * (K! * (N-K)!)^(M-2) mod M) mod M</p>
<p>이렇게 정리가 된다.</p>
<p>이제 곱셈 분배법칙이 적용되니 분할 정복을 하여야 한다.</p>
<p>분할 정복은 (K! * (N-K)!)^(M-2)에서 지수 M-2를 계속 절반씩 나눠서 지수가 짝수일 때와 홀수일 때를 구분하여 리턴해주면 된다.</p>
<p>아래는 위 문제의 수도코드이다.</p>
<pre><code>// 수도코드
M = 1,000,000,007
A = factorial(N); // N!
B = factorial(K) * factorial(N-K) % M; // K!*(N-K)!

print(A * divide_conquer(B, M-2) % M); // (N! * (K!*(N-K)!)^(M-2)) mod M  

// 팩토리얼 구하면서 mod M을 계속 해줌
factorial(num){
    result = 1;
    while(num &gt; 1){
        result = (result * num--) % M
    }

    return result;
}

// num : 밑수, exp : 지수
divide_conquer(num, exp){
        if(exp == 1) return num % M; // 지수가 1일 경우 num^1 이므로 num % M 리턴

    temp = divide_conquer(num, exp/2); // 모듈라 연산 곱셈 분배법칙을 이용한 분할 정복

    if(exp % 2 == 1) return (temp * temp) * num % M; // 분할 정복이 끝나고 지수가 홀수가 남으면 ex)A^5 = A^2 * A^2 * A
    else return temp * temp % M; // 지수가 짝수면 A^4 = A^2 * A^2
}</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[Become a Java-Masta👨‍🏫 4주차] 클래스, 인터페이스]]></title>
            <link>https://velog.io/@bae_mung/Become-a-Java-Masta-4%EC%A3%BC%EC%B0%A8-%ED%81%B4%EB%9E%98%EC%8A%A4-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4</link>
            <guid>https://velog.io/@bae_mung/Become-a-Java-Masta-4%EC%A3%BC%EC%B0%A8-%ED%81%B4%EB%9E%98%EC%8A%A4-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4</guid>
            <pubDate>Sun, 05 Sep 2021 06:42:47 GMT</pubDate>
            <description><![CDATA[<h2 id="🎯-목표">🎯 목표</h2>
<h3 id="자바의-class-와-interface에-대해-학습하기">자바의 Class 와 Interface에 대해 학습하기.</h3>
<h3 id="📌-학습할-것">📌 학습할 것</h3>
<h3 id="클래스"><a href="#-%ED%81%B4%EB%9E%98%EC%8A%A4">클래스</a></h3>
<ul>
<li><a href="#-%ED%81%B4%EB%9E%98%EC%8A%A4-%EC%A0%95%EC%9D%98">클래스 정의</a></li>
<li><a href="#-%ED%81%B4%EB%9E%98%EC%8A%A4-%EA%B5%AC%EC%84%B1">클래스 구성</a></li>
<li><a href="#-%ED%81%B4%EB%9E%98%EC%8A%A4-%EC%9E%91%EC%84%B1">클래스 작성</a></li>
<li><a href="#-new-%ED%82%A4%EC%9B%8C%EB%93%9C">new 키워드</a></li>
<li><a href="#-this-%ED%82%A4%EC%9B%8C%EB%93%9C">this 키워드</a></li>
<li><a href="#-super-%ED%82%A4%EC%9B%8C%EB%93%9C">super 키워드</a></li>
</ul>
<h3 id="추상-클래스"><a href="#%EC%B6%94%EC%83%81-%ED%81%B4%EB%9E%98%EC%8A%A4">추상 클래스</a></h3>
<h3 id="인터페이스"><a href="#-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4">인터페이스</a></h3>
<ul>
<li><a href="#-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4-%EC%A0%95%EC%9D%98">인터페이스 정의</a></li>
<li><a href="#-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4-%EA%B5%AC%ED%98%84">인터페이스 구현</a></li>
</ul>
<hr>
<h2 id="🇨🇱-클래스">🇨🇱 클래스</h2>
<h3 id="💡-클래스-정의">💡 클래스 정의</h3>
<p>자바에서 클래스란 유사한 특징들의 지닌 객체들의 속성과 행위들을 정의해놓은 설계도와 같은 것이다.<br>
이 설계도를 이용해서 동일한 특징을 객체를 찍어내는 틀과 같은 역할을 한다.</p>
<p><strong>객체</strong> : 실세계(Real World)에 존재하는 유/무형의 <strong>모든 것</strong></p>
<p>속성(명사형)과 행위(동사형)를 갖는다.</p>
<p>ex) <strong>자동차</strong> (유형)</p>
<ul>
<li>속성 : 주행거리, 차종, 색상, 마력,,, </li>
<li>행위 : 시동켜기, 시동끄기, 주행하기,,, </li>
</ul>
<p>ex) <strong>계좌</strong> (무형)</p>
<ul>
<li>속성 : 계좌번호, 예금주, 잔액, 이체한도,,,</li>
<li>행위 : 잔액조회, 입금, 출금, 송금,,, </li>
</ul>
<table>
<thead>
<tr>
<th align="center">클래스</th>
<th align="center">객체</th>
</tr>
</thead>
<tbody><tr>
<td align="center">붕어빵틀</td>
<td align="center">붕어빵</td>
</tr>
<tr>
<td align="center">공장 생산라인</td>
<td align="center">제품</td>
</tr>
<tr>
<td align="center">건물설계도</td>
<td align="center">건물</td>
</tr>
</tbody></table>
<p>같은 클래스로부터 생성된 객체는 모두 같은 속성과 행위를 가지는데, 객체마다 고유한 속성값을 가질 수 있다.</p>
<p><strong>즉, 같은 클래스에서 생성된 객체라도 모두 다르다!</strong></p>
<hr>
<p>클래스는 접근제어자와 함께 class키워드를 사용해서 정의할 수 있다.</p>
<pre><code class="language-java">[접근 제어자] class XXX{
    필드
    생성자
    메소드
}</code></pre>
<p>만약 public class로 클래스를 정의하면 해당 소스코드(.java)의 이름은 반드시 해당 클래스의 이름으로 작성되어야 한다.</p>
<blockquote>
<p>ex) public class Baemung ==&gt; Baemung.java</p>
</blockquote>
<p>그리고 클래스를 정의할 땐, 클래스 이름 첫글자는 보통 대문자로 시작하는 파스칼 표기법(PascalCase) 를 사용한다.</p>
<p>클래스안에 다른 클래스를 정의하는 것도 가능하다. <br>
이렇게 하나의 클래스 파일에 여러 클래스를 정의했을 때 <a href="../../../tree/main/Week_01/#-%EC%BB%B4%ED%8C%8C%EC%9D%BC-%EB%B0%8F-%EC%8B%A4%ED%96%89%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95">소스코드를 컴파일하면 각 클래스마다 .class 파일이 생성되는 것을 확인할 수 있다.</a></p>
<p>클래스를 정의할 때 객체들의 속성과 행위를 필드와 메소드로 정의할 수 있다.</p>
<table>
<thead>
<tr>
<th align="center">객체</th>
<th align="center">클래스</th>
</tr>
</thead>
<tbody><tr>
<td align="center">속성</td>
<td align="center">필드 (클래스변수(static), 인스턴스변수(non-static))</td>
</tr>
<tr>
<td align="center">행위</td>
<td align="center">메소드</td>
</tr>
</tbody></table>
<ul>
<li>사람 (객체)<ul>
<li>속성 : 이름, 나이</li>
<li>행위 : 나이먹기, 잠자기,,,</li>
</ul>
</li>
</ul>
<ul>
<li>Person (클래스)</li>
</ul>
<blockquote>
<p>Person.java</p>
</blockquote>
<pre><code class="language-java">public class Person{
    //field
    String name;
    int age;

    //constructor
    Person(String name, int age){
        this.name = name;
        this.age = age;
    }

    //method
    increaseAge(){}
    Sleep(){}
}</code></pre>
<h3 id="💡-클래스-구성">💡 클래스 구성</h3>
<h4 id="1-필드field">1. <a href="../../../tree/main/Week_02/#-%EB%B3%80%EC%88%98%EC%9D%98-%EC%8A%A4%EC%BD%94%ED%94%84%EC%99%80-%EB%9D%BC%EC%9D%B4%ED%94%84%ED%83%80%EC%9E%84"><strong>필드(field)</strong></a></h4>
<p>클래스의 필드(field)란 클래스에 포함된 멤버 변수(variable)</p>
<ul>
<li><p><strong>클래스 변수(static variable)</strong></p>
<ul>
<li>클래스의 상태</li>
<li>클래스 메모리 로드시 1번만 할당</li>
</ul>
</li>
<li><p><strong>인스턴스 변수(instance variable)</strong></p>
<ul>
<li>객체의 상태</li>
<li>객체 생성시마다 할당</li>
</ul>
</li>
</ul>
<h4 id="2-메소드method">2. <strong>메소드(method)</strong></h4>
<p>클래스에서 메소드(method)란 어떠한 특정 작업을 수행하기 위한 명령문의 집합</p>
<ul>
<li><p><strong>클래스 메소드(static method)</strong></p>
<ul>
<li>클래스 관점에서의 행위</li>
<li>객체 식별을 해야만하는 작업X</li>
<li>객체를 생성하지 않고도 실행할 수 있는 작업</li>
</ul>
</li>
<li><p><strong>인스턴스 메소드(instance method)</strong></p>
<ul>
<li>객체 관점에서의 행위</li>
<li>객체 식별을 해야만 하는 작업 O</li>
<li>객체 관련 작업</li>
</ul>
</li>
</ul>
<h4 id="3-생성자constructor">3. <strong>생성자(constructor)</strong></h4>
<p>클래스를 생성할 때, 필드(인스턴스 변수) 값들을 초기화 시키기 위한 특별한 메소드<br>
객체 초기화의 다양성 제공</p>
<h4 id="4-중첩-클래스nested-class-inner-class">4. <strong>중첩 클래스(Nested Class, Inner Class)</strong></h4>
<ul>
<li>클래스 속 클래스</li>
</ul>
<h4 id="5-initializer">5. <strong>Initializer</strong></h4>
<ul>
<li><strong>Static Initializer</strong><blockquote>
<p>static{ 실행문장 } : 클래스 메모리 로드시 자동실행 </p>
</blockquote>
</li>
<li><strong>Instance Initializer</strong><blockquote>
<p>{ 실행문장 } : 객체 생성시 마다 자동실행 --&gt; 생성자 때문에 잘 사용 안함</p>
</blockquote>
</li>
</ul>
<hr>
<h3 id="💡-클래스-작성">💡 클래스 작성</h3>
<ul>
<li><p>패키지 선언문 (0 or 1)</p>
<pre><code class="language-java">package top.sub....; 
// 물리적 : 폴더
// 보통 domain name(Unique!) 역순사용</code></pre>
</li>
<li><p>import문 (0 ~ 多) </p>
<pre><code class="language-java">import top.sub...클래스이름; // 소스 클래스명 바로사용
import top.sub...*; // all classes, interfaces
(not package) : import단위는 패키지 아님!
</code></pre>
</li>
</ul>
<p>현 클래스안에서 참조, 사용하는 클래스가 자신과 같은 패키지가 아닌 경우 명시
단, java.lang은 자동으로 불러옴</p>
<pre><code>
- class 정의 (1 ~ 多)
``` java
** []는 상황에 따라 생략가능함

* 클래스정의
[접근지정자] [활용지정자] class 클래스명 [extends 부모클래스명] [implements 부모인터페이스명,,,] { } 

// 접근지정자
(default),public

// 활용지정자
final : 상속금지
abstract : 추상클래스 (미완성클래스)

// 클래스명
명사형, 첫글자 대문자, 카멜표기법

// extends 
클래스 단일상속

// implements
인터페이스 다중상속



* 멤버정의
[접근지정자] [활용지정자] DataType 변수명 [=초기값];

// 접근지정자
public,protected,(default),private

// 활용지정자
static : 클래스멤버
final : 상수화, 생성자에서 초기화 필수
static final : 어차피 상수이기 때문에 static으로 사용
transient : 객체직렬화 대상제외

// 변수명
명사형, 첫글자 소문자, 카멜표기법

// 초기값
생략시 default값으로 초기화 (0, null, false)



* 메소드정의
[접근지정자] [활용지정자] returnType 메소드명 ([매개변수선언,,,]) [throws Exception명,,,] 
{
    실행문장 
    [return 리턴값]
}

// 접근지정자
public,protected,(default),private

// 활용지정자
static : 객체 생성없이 &#39;클래스이름.메소드이름()&#39;으로 호출 가능, 메소드 내에서 인스턴스 변수 사용 불가
final : 메소드 재정의 X
synchronized : 객체 동기화를 위한 잠금
abstract : 메소드 추상화

// return 리턴값
void : 없음 -&gt; return문 생략가능
not void : return값 명시



* 생성자
[접근지정자] 클래스명 ([매개변수선언,,,]) [throws Exception명,,,] {}

// 접근지정자
public,protected,(default),private
</code></pre><h3 id="💡-new-키워드">💡 new 키워드</h3>
<p><strong>객체를 생성할 때는 new 라는 키워드를 사용한다.</strong></p>
<p>new 키워드는 메모리상에 공간을 할당하고, 할당받은 공간의 주소값을 반환한다.</p>
<p>자바에서 Primitive Type을 제외한 타입 즉, Reference Type의 변수를 초기화 시키면 객체를 Heap 영역에 저장하고 레퍼런스 타입의 변수에는 new 키워드가 주소값을 가지고 Stack 영역에 저장된다.</p>
<p>new라는 키워드는 메모리상에 공간을 할당하고, 할당받은 공간을 주소를 리턴한다.</p>
<pre><code class="language-java">// 클래스이름 참조변수 = new 생성자호출; -&gt; 객체생성시 초기화를 담당하는 특별한 메소드
Person p1 = new Person(&quot;배문규&quot;, 29);
Person p2 = new Person(&quot;정다운&quot;, 29);</code></pre>
<p>위 소스코드를 실행하면</p>
<ol>
<li><p>Class Area에 Person 바이트코드가 올라감</p>
</li>
<li><p>new 키워드가 메모리상에 공간을 할당하여 Heap에 인스턴스 변수가 올림</p>
</li>
<li><p>new 키워드가 인스턴스변수의 메모리 주소를 리턴하여 Stack에 p1, p2 레퍼런스 변수를 저장해서 올림</p>
</li>
</ol>
<p><img src="https://user-images.githubusercontent.com/51703260/132106339-c2ffcdf1-54fc-46d7-982b-e44bece8a755.png" alt=""></p>
<hr>
<h3 id="💡-this-키워드">💡 this 키워드</h3>
<ul>
<li>non-static 영역(instance 메소드, 생성자, instance initializer)에서 사용함.</li>
<li>현재 생성중인, 실행중인 그 객체 자기자신을 일컫음.</li>
</ul>
<p><strong>사용법</strong></p>
<h4 id="1-지역변수와-인스턴스변수를-구분하기-위해서">1. 지역변수와 인스턴스변수를 구분하기 위해서</h4>
<pre><code class="language-java">void setName(String name){
   this.name=name;
}</code></pre>
<h4 id="2-생성자가-오버로딩된-경우-자신의-또-다른-생성자를-호출-시-this를-부를-수-있다">2. 생성자가 오버로딩된 경우, 자신의 또 다른 생성자를 호출 시 this를 부를 수 있다.</h4>
<pre><code class="language-java">this();</code></pre>
<h4 id="3-자기-자신의-객체를-메소드의-매개변수로-전달하거나-리턴하기-위해서">3. 자기 자신의 객체를 메소드의 매개변수로 전달하거나 리턴하기 위해서</h4>
<pre><code class="language-java">XXX(){
   return this; // 자기 자신을 리턴
}

YYY(){
   obj.zzz(this); // 자기 자신을 매개변수로 전달
}</code></pre>
<hr>
<h3 id="💡-super-키워드">💡 super 키워드</h3>
<ul>
<li>this와 마찬가지로 non-static 영역(instance 메소드, 생성자, instance initializer)에서 사용함.</li>
<li>현재 생성중인, 실행중인 객체의 부모를 의미하도록 사용하는 논리적인 개념</li>
</ul>
<p><strong>사용법</strong></p>
<h4 id="1-자신의-메소드와-부모의-메소드를-구분하기-위해-사용메소드-재정의-상황">1. 자신의 메소드와 부모의 메소드를 구분하기 위해 사용(메소드 재정의 상황)</h4>
<pre><code class="language-java">this.XXX()
super.XXX()

// 참고로, 메소드 말고 멤버는 개념적으로 구분하지 않음
// 부모의 멤버는 자식에게도 있기 때문임</code></pre>
<h4 id="2-자식의-생성자에서-부모-생성자를-명시적으로-호출하기-위해-사용">2. 자식의 생성자에서 부모 생성자를 명시적으로 호출하기 위해 사용</h4>
<pre><code class="language-java">super();</code></pre>
<p>this의 3번 개념은 super에 없다. (있을 필요가 없다.) </p>
<hr>
<h2 id="추상-클래스-1">추상 클래스</h2>
<p>추상 클래스를 선언하는 방법은 class키워드 앞에 <strong>abstract</strong> 를 붙혀서 선언할 수 있다.</p>
<p>추상 클래스는 미완성 클래스로 new키워드로 다이렉트 객체 생성이 불가능하고 반드시 하위 클래스를 필요로한다. <br>대신 자식 객체의 참조변수로 사용가능하다.</p>
<p>인터페이스에서 선언할 수 없는 변수나 구현된 메소드를 포함시킬 때 사용한다.<br>
추상클래스는 결국 클래스이기 때문에 단일상속만 가능하다.<br></p>
<p>추상 클래스는 2가지로 구분할 수 있다.</p>
<ol>
<li><p><strong>추상 메소드가 없는 추상 클래스</strong></p>
<ul>
<li>해당 클래스의 객체생성을 막을 때 사용</li>
<li>상속 받는 자식 클래스에서 개별적인 특성을 추가적으로 부여한 후 객체 생성</li>
</ul>
</li>
<li><p><strong>추상 메소드가 있는 추상 클래스</strong></p>
<ul>
<li>해당 추상 클래스를 상속받는 자식 클래스에서 추상 메소드 오버라이딩 필수</li>
<li>자식 클래스에게 추상 메서드의 오버라이딩 강제성을 부여하여 프로그램의 안정성을 향상</li>
<li>추상 메소드가 존재하면 반드시 해당 클래스는 추상 클래스</li>
</ul>
</li>
</ol>
<p>참고로, 최상위 클래스를 상속받는 중간 클래스에서 최상위 클래스의 메소드를 추상메소드로 오버라이딩을 할 수 있다.<br>
최상위클래스에서 없던 의무성을 중간 클래스에서 아래로 부여할 수도 있다.</p>
<h2 id="🇮🇳-인터페이스">🇮🇳 인터페이스</h2>
<h3 id="💡-인터페이스-정의">💡 인터페이스 정의</h3>
<p>인터페이스란, 어떠한 기능을 사용하기 위한 일종의 <strong>표준(약속, 방법)</strong> 이다. <br>인터페이스는 기능을 사용하는 <strong>사용자 관점</strong> 과 기능을 제공하는 <strong>제공자 관점</strong> 으로 구분할 수 있다.</p>
<p><strong>기능 사용자</strong> 는 인터페이스를 통해 사용방법을 알 수 있으며, 인터페이스에 적혀 있는대로만 기능을 사용할 수 있다. <br>또한, 제공자가 어떻게 구현했는지에 대해 상세히 알 필요가 없어 결합도가 낮아지며 모듈화가 가능해진다. </p>
<p><strong>기능 제공자</strong> 는 이 기능들을 꼭 구현해야만 책임이 부여되지만 자신의 코드를 노출하지 않아도 된다는 장점을 가지고 있다.</p>
<ul>
<li><strong>사용자 관점 :</strong> 사용방법, 약속    </li>
<li><strong>제공자 관점 :</strong> 구현의 책임</li>
</ul>
<p>구현의 강제화로 서로 다른 모듈이 같은 인터페이스를 상속한다면 사용자들은 손쉽게 모듈 교체가 가능</p>
<p>서로 상속 관계가 없는 간접적인 클래스들에게 인터페이스를 통한 관계 부여로 다형성 확장 가능</p>
<hr>
<h3 id="💡-인터페이스-구현">💡 인터페이스 구현</h3>
<p>클래스를 구현할 땐 class키워드를 사용했지만, 인터페이스는 interface라는 키워드를 사용한다.</p>
<pre><code class="language-java">** []는 상황에 따라 생략가능함

* 인터페이스 정의
[접근지정자] interface 인터페이스명 [extends 부모 인터페이스명]{ } 

// 접근지정자
(default),public
// 클래스는 인터페이스를 상속받을 때 implements키워드를 사용하지만,
// 인터페이스가 인터페이스를 상속받을 때는 extends키워드를 사용한다.

interface 인터페이스명{
    // 1. 상수
    [public static final]타입 상수명 = 상수값;

    // 2. 추상 메소드
    [public abstract]타입 메소드명(매개변수);

    // 3. 디폴트 메소드
    default 타입 메소드명(매개변수){
        // 구현
    }

    // 4. 스태틱 메소드
    static 타입 메소드명(매개변수){
        // 구현
    }
}</code></pre>
<p><strong>Java 8 이전까지</strong>는 상수와 추상 메소드만 선언 가능하였지만, <br>
<strong>Java 8 이후부터는</strong> 디폴트 메소드와 스태틱 메소드가 추가되었다.</p>
<ol>
<li>상수 <strong>(절대)</strong> : 인터페이스에서 고정된 값만 제공.</li>
<li>추상 메소드 <strong>(강제)</strong> : 인터페이스에서 <strong>가이드</strong>를 제공하고 상속받아 오버라이딩해서 구현.</li>
<li>디폴트 메소드 <strong>(선택)</strong> : 인터페이스에서 구현 메소드 제공, <strong>오버라이딩 가능</strong></li>
<li>스태틱 메소드 <strong>(절대)</strong> : 인터페이스에서 구현 메소드 제공, <strong>오버라이딩 불가</strong></li>
</ol>
<p>근본적으로 추상 클래스는 클래스이므로 <strong>&quot;is-a : ~는 ~이다.&quot; 관계</strong> 이기 때문에 단일 상속만 가능한 것이고,<br>
인터페이스는 클래스가 아니므로 <strong>&quot;has-a : ~는 ~를 할 수 있다.&quot; 관계</strong> 이기 때문에 다중 상속이 가능한 것이다.</p>
<pre><code class="language-java">// Baemung은 사람이며 움직일 수 있고, 들을 수 있고, 개발할 수 있다.
class Baemung extends Person implements Movable, Hearable, Developable </code></pre>
<h4 id="다형성은-조상클래스와-조상인터페이스-모두-적용-가능">다형성은 조상클래스와 조상인터페이스 모두 적용 가능</h4>
<pre><code class="language-java">class IronMan implements Heroble, Fightable, Transformable {}

IronMan tony = new IronMan();
Object obj = tony;
Heroable hero = tony;
Fightable fighter = tony;
Transformable trans = tony;</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Become a Java-Masta👨‍🏫 3주차] 연산자, 제어문]]></title>
            <link>https://velog.io/@bae_mung/Become-a-Java-Masta-2%EC%A3%BC%EC%B0%A8-%EC%97%B0%EC%82%B0%EC%9E%90-%EC%A0%9C%EC%96%B4%EB%AC%B8</link>
            <guid>https://velog.io/@bae_mung/Become-a-Java-Masta-2%EC%A3%BC%EC%B0%A8-%EC%97%B0%EC%82%B0%EC%9E%90-%EC%A0%9C%EC%96%B4%EB%AC%B8</guid>
            <pubDate>Sat, 04 Sep 2021 18:47:03 GMT</pubDate>
            <description><![CDATA[<h2 id="🎯-목표">🎯 목표</h2>
<h3 id="자바가-제공하는-다양한-연산자와-제어문을-익히기">자바가 제공하는 다양한 연산자와 제어문을 익히기.</h3>
<h3 id="📌-학습할-것">📌 학습할 것</h3>
<ul>
<li><a href="#-%EC%82%B0%EC%88%A0-%EC%97%B0%EC%82%B0%EC%9E%90">산술 연산자</a></li>
<li><a href="#-%EB%B9%84%ED%8A%B8-%EC%97%B0%EC%82%B0%EC%9E%90">비트 연산자</a></li>
<li><a href="#-%EA%B4%80%EA%B3%84-%EC%97%B0%EC%82%B0%EC%9E%90">관계 연산자</a></li>
<li><a href="#-%EB%85%BC%EB%A6%AC-%EC%97%B0%EC%82%B0%EC%9E%90">논리 연산자</a></li>
<li><a href="#-instanceof">instanceof</a></li>
<li><a href="#-assignment-operator">Assignment Operator</a></li>
<li><a href="#-%ED%99%94%EC%82%B4%ED%91%9C-%EC%97%B0%EC%82%B0%EC%9E%90">화살표 연산자</a></li>
<li><a href="#-3%ED%95%AD-%EC%97%B0%EC%82%B0%EC%9E%90">3항 연산자</a></li>
<li><a href="#-%EC%84%A0%ED%83%9D%EB%AC%B8">선택문</a></li>
<li><a href="#-%EB%B0%98%EB%B3%B5%EB%AC%B8">반복문</a></li>
</ul>
<hr>
<h3 id="💡-산술-연산자">💡 산술 연산자</h3>
<p>산술 연산자는 +, -, *, / 이렇게 사칙연산와 모듈라 연산 %로 이루어져 있다.</p>
<pre><code class="language-java">int A = 10;
int B = 3;

System.out.println(A + B); // 13
System.out.println(A - B); // 7
System.out.println(A * B); // 30
System.out.println(A / B); // 3
System.out.println(A % B); // 1
</code></pre>
<hr>
<h3 id="💡-비트-연산자">💡 비트 연산자</h3>
<p>비트 연산자는 &#39;비트 논리 연산자&#39;와 &#39;비트 시프트 연산자&#39;로 구분할 수 있다.</p>
<p><strong>비트 논리 연산자</strong></p>
<p>비트 논리 연산자는 피연산자를 비트단위로 논리 연산을한다.</p>
<p>피연산자로 실수는 허용하지 않고, 정수(문자 포함)만 허용한다.</p>
<p align="center"><img src="https://user-images.githubusercontent.com/51703260/131247156-ddfe684b-2abd-4000-ba45-b978d22d99cd.png"></p>

<p><strong>비트 시프트 연산자</strong></p>
<p>피연산자의 각 비트 자리를 &#39;오른쪽(&gt;&gt;)&#39; 또는 &#39;왼쪽(&lt;&lt;)&#39;으로 이동(shift) 한다고 해서 &#39;비트 시프트 연산자&#39;라고 한다.</p>
<p align="center"><img src="https://user-images.githubusercontent.com/51703260/131247160-73eedc06-8955-4f10-8d2c-9fee78ed7ef0.png"></p>

<hr>
<h3 id="💡-관계-연산자">💡 관계 연산자</h3>
<p>관계 연산자는 조건식에 자주 쓰이는 연산자로 </p>
<p>두 비교 가능한 값이나 객체의 관계를 비교하는 연산자이다.</p>
<p>관계 연산자는 &lt;, &gt;, &lt;=, &gt;=, ==, != 으로 구성되어 있고 boolean type을 리턴한다.</p>
<pre><code class="language-java">a &lt; b // a가 b보다 작은가?
a &gt; b // a가 b보다 큰가?
a &lt;= b // a가 b보다 작거나 같은가?
a &gt;= b // a가 b보다 크거나 같은가?
a == b // a와 b가 같은가?
a != b // a와 b가 다른가?</code></pre>
<p>==, != 는 객체를 비교할 땐 레퍼런스를 비교하기 때문에 겉으로 보이는 값은 같더라도 참조하는 레퍼런스가 다르면 의도하지 않은 결과를 얻을 수도 있다.</p>
<hr>
<h3 id="💡-논리-연산자">💡 논리 연산자</h3>
<p>논리 연산자는 논리의 결합이나, 논리를 뒤집을때 사용하는 연산자로 boolean type을 리턴한다.</p>
<pre><code class="language-java">A &amp;&amp; B // A와 B 모두 true이면 연산결과는 true (and)
A || B // A와 B 둘 중 하나라도 true이면 연산결과는 true (or)
!A // 연산결과는 A가 true이면 false, A가 false이면 true (not)</code></pre>
<p>여기서 and 연산은 첫번째 논리가 false면, 뒤의 논리를 체크하지 않고 false를 리턴한다.
그리고 or 연산은 첫번째 논리가 true면, 뒤의 논리를 체크하지 않고 true를 리턴한다.</p>
<p>그렇기 때문에 논리 연산자를 사용할 때 시간, 메모리의 낭비도 있을 수 있고, 경우에 따라 런타임에러가 발생할 수도 있기 때문에 논리의 순서가 상당히 중요하다.</p>
<hr>
<h3 id="💡-instanceof">💡 instanceof</h3>
<p>참조변수가 참조하고 있는 인스턴스의 실제 타입을 알아볼 때 instanceof 연산자를 사용하는데 이 연산자는 boolean type을 리턴한다.</p>
<p>&quot;객체 instanceof 클래스&quot; 형식으로 사용하며, 주로 상속관계를 확인할 때 사용한다.</p>
<pre><code class="language-java">class A { }

class B extends A { }

public class main {
    public static void main(String[] args){
        A a = new A();
        A ab = new B();
        B b = new B();

        System.out.println(a instanceof A);   //true
        System.out.println(ab instanceof A);  //true
        System.out.println(b instanceof A);   //true

        System.out.println(a instanceof B);   //false
        System.out.println(ab instanceof B);  //true
        System.out.println(b instanceof B);   //true
    }
}</code></pre>
<p>자식 객체는 부모 클래스의 instance지만, 부모 객체는 자식 클래스의 instance가 아니다.</p>
<hr>
<h3 id="💡-assignment-operator">💡 Assignment Operator</h3>
<p>우변의 값을 좌변의 변수에 대입하는 연산자이다.</p>
<pre><code class="language-java">A = B</code></pre>
<p>대입 연산자는 다양한 연산자와 결합하여 아래와 같은 복합 대입 연산자로 활용가능하다.</p>
<pre><code class="language-java">A += B
A -= B
A *= B
A /= B
A %= B
A &amp;= B
A |= B
A ^= B
A &gt;&gt;= B
A &lt;&lt;&lt;= B</code></pre>
<hr>
<h3 id="💡-화살표-연산자">💡 화살표 연산자</h3>
<p>(매개변수) -&gt; {실행코드}와 같은 람다식에서 화살표 연산자를 사용한다.</p>
<p>여기서 람다식이란 &quot;식별자없이 실행가능한 함수&quot;로, 함수를 따로 선언하지 않고 코드한줄에 함수를 써서 그것을 호출하는 방식이다.</p>
<p>보통 특정 기준으로 정렬할 때 자주 사용하게 된다.</p>
<pre><code class="language-java">Arrays.sort(list, (l1, l2) -&gt; l1[0]) - l2[0]));</code></pre>
<p>위 코드는 2차원 배열을 정렬할 때, 배열의 첫번째 값을 기준으로 정렬하라는 람다식이다. </p>
<p>내부적으로는 Comparator 인터페이스의 compare(T o1, T o2)메소드를 오버라이딩한 것이다. </p>
<hr>
<h3 id="💡-3항-연산자">💡 3항 연산자</h3>
<pre><code class="language-java">// 변수 = 조건문 ? 참 : 거짓;
min = A &lt; B ? A : B;

// return 조건문? 참 : 거짓;
return A &lt; B ? A : B;</code></pre>
<p>변수에 값을 할당할 때만 삼항연산자를 쓸 수 있는것이 아니라, 값을 넘겨주거나 출력하는 등 값을 받아 처리를 해줄 수 있으면 사용 가능하다. </p>
<hr>
<h3 id="💡-연산자-우선-순위">💡 연산자 우선 순위</h3>
<p align="center"><img src="https://user-images.githubusercontent.com/51703260/131240291-29ad255c-2e62-4df1-b962-c4e8ae1b27de.png"></p>

<p>만약 동일한 우선순위인 경우는 해당 연산자의 연산방향에서 먼저 등장하는 연산자가 우선적으로 연산된다.</p>
<hr>
<h3 id="💡-선택문">💡 선택문</h3>
<ul>
<li><strong>if - else if - else</strong></li>
</ul>
<pre><code class="language-java">if(조건식){ }
else if( 위 조건이 거짓일 경우 조건){ }
else if( 위 조건이 거짓일 경우 조건){ }
else { // 모든 조건들이 거짓일 경우 }</code></pre>
<p>if만 단독으로 올 수 있고, else if와 else는 if문이 선행되어야지 뒤 따라 나올 수 있다.</p>
<p>else if는 if{} - else{ if{} } 의 약식 개념이다.</p>
<ul>
<li><strong>switch - case - default</strong></li>
</ul>
<pre><code class="language-java">switch(변수) {
    case A : // 변수의 값이 A일 때
        // 진입
        break;
    case B : // 변수의 값이 B일 때
        // 진입
        break;
    default :
        // A와 B가 아닌 경우
}</code></pre>
<p>switch의 변수는 Primitive 타입, Enum, String, Wrapper 클래스가 가능하다.</p>
<p>여기서 주의할 점은 case A에 진입해서 처리를 하고 break가 되지 않으면 아래 case B에도 자동으로 진입하게 프로그램이 설계되어 있기 때문에</p>
<p>A에 진입했을 때 처리하고 싶은 내용만 처리하고 싶다면 break를 해줘서 switch문을 빠져나와야 한다.</p>
<hr>
<h3 id="💡-반복문">💡 반복문</h3>
<ul>
<li><strong>while</strong><pre><code class="language-java">while(조건식){
  // 조건식이 처음 부터 성립되지 않으면 애초에 반복문에 진입을 안할 수도 있음
  // 반복내용
}</code></pre>
</li>
</ul>
<pre><code class="language-java"> do{
    // 무조건 최소 1번은 반복문 실행
    // 반복내용
 } while(조건식); // 세미콜론 &#39;;&#39; 필수</code></pre>
<ul>
<li><strong>for &amp; for-each</strong></li>
</ul>
<pre><code class="language-java">for(초기화; 조건식; 증감식){
    // 반복내용
}</code></pre>
<pre><code class="language-java">for(데이터타입 집합원소 : 반복집합객체){
    //반복 가능한 집합들의 원소들을 꺼내어 처리
}</code></pre>
<p>반복집합객체에는 array, iterable 타입이 올 수 있으며 enum의 경우 enum.values()를 반복집합객체로 사용한다.</p>
<p>for-each문을 사용하는 목적</p>
<ol>
<li>자료구조사용에 대한 추상화</li>
<li>반복 가능한 집합의 원소)값의 수정이 불가능(조회 목적)</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Become a Java-Masta👨‍🏫 2주차] 데이터 타입, 변수, 배열
]]></title>
            <link>https://velog.io/@bae_mung/Become-a-Java-Masta-2%EC%A3%BC%EC%B0%A8-%EB%8D%B0%EC%9D%B4%ED%84%B0-%ED%83%80%EC%9E%85-%EB%B3%80%EC%88%98-%EB%B0%B0%EC%97%B4</link>
            <guid>https://velog.io/@bae_mung/Become-a-Java-Masta-2%EC%A3%BC%EC%B0%A8-%EB%8D%B0%EC%9D%B4%ED%84%B0-%ED%83%80%EC%9E%85-%EB%B3%80%EC%88%98-%EB%B0%B0%EC%97%B4</guid>
            <pubDate>Mon, 23 Aug 2021 14:49:29 GMT</pubDate>
            <description><![CDATA[<h2 id="🎯-목표">🎯 목표</h2>
<h3 id="자바의-primitive-타입-변수-그리고-배열을-사용하는-방법을-익히기">자바의 Primitive 타입, 변수 그리고 배열을 사용하는 방법을 익히기.</h3>
<h3 id="📌-학습할-것">📌 학습할 것</h3>
<ul>
<li><a href="#-primitive-%ED%83%80%EC%9E%85-%EC%A2%85%EB%A5%98%EC%99%80-%EA%B0%92%EC%9D%98-%EB%B2%94%EC%9C%84-%EA%B7%B8%EB%A6%AC%EA%B3%A0-%EA%B8%B0%EB%B3%B8-%EA%B0%92">Primitive 타입 종류와 값의 범위 그리고 기본 값</a></li>
<li><a href="#-reference-%ED%83%80%EC%9E%85">Reference 타입</a></li>
<li><a href="#-literal">Literal</a></li>
<li><a href="#-%EB%B3%80%EC%88%98-%EC%84%A0%EC%96%B8-%EB%B0%8F-%EC%B4%88%EA%B8%B0%ED%99%94%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95">변수 선언 및 초기화하는 방법</a></li>
<li><a href="#-%EB%B3%80%EC%88%98%EC%9D%98-%EC%8A%A4%EC%BD%94%ED%94%84%EC%99%80-%EB%9D%BC%EC%9D%B4%ED%94%84%ED%83%80%EC%9E%84">변수의 스코프와 라이프타임</a></li>
<li><a href="#-%ED%83%80%EC%9E%85-%EB%B3%80%ED%99%98-%EC%BA%90%EC%8A%A4%ED%8C%85-%EA%B7%B8%EB%A6%AC%EA%B3%A0-%ED%83%80%EC%9E%85-%ED%94%84%EB%A1%9C%EB%AA%A8%EC%85%98">타입 변환, 캐스팅 그리고 타입 프로모션</a></li>
<li><a href="#-%EB%B0%B0%EC%97%B4">배열</a></li>
<li><a href="#-%ED%83%80%EC%9E%85-%EC%B6%94%EB%A1%A0-var">타입 추론, var</a></li>
</ul>
<hr>
<h3 id="💡-primitive-타입-종류와-값의-범위-그리고-기본-값">💡 Primitive 타입 종류와 값의 범위 그리고 기본 값</h3>
<p align="center"><img src="https://images.velog.io/images/bae_mung/post/570041f9-ed44-4f91-8673-f49c880c9d4a/chap2_3.png"></p>

<p><strong>Primitive type 종류</strong></p>
<ul>
<li>원자성의 Data</li>
<li>수의 표현 범위 : byte &lt; short &lt; int &lt; long &lt; float &lt; double     </li>
</ul>
<pre><code>                  타입 종류           용량          기본 값
-----------------------------------------------------------------------------------------------
                  boolean           1 bit        false     (숫자 호환 X)
                  char              2 bytes         &#39;\u0000&#39;  (&#39;a&#39;(문자) != &quot;a&quot;(문자열 ; 객체))

              |   byte              1 byte          0       ▲ 명시적 형변환 (Casting)
              |   short             2 bytes         0       |
              |   int(default)      4 bytes         0       |
              |   long              8 bytes         0L      |
              |   float             4 bytes         0.0f    |
묵시적 형변환  ▼   double(default)   8 bytes         0.0d    |
(Promotion)</code></pre><hr>
<h3 id="💡-reference-타입">💡 Reference 타입</h3>
<p><strong>Reference type</strong> = All type - Primitive type</p>
<p><strong>non-Primitive type</strong></p>
<ul>
<li>Reference type; 참조타입</li>
<li>Class type</li>
<li>Interface type</li>
<li>Array type</li>
</ul>
<p>java는 2Bytes체제의 유니코드를 지원한다. 
유니코드는 u0000 ~ uffff까지 표현됨
u00[<strong>]에서 [</strong>]의 1바이트는 ASCII코드</p>
<pre><code class="language-java">char ch = &#39;A&#39;;
char ch = 65;
char ch = &#39;\u0041&#39;; //A의 유니코드표기 (4*16^1+1*16^0 = 65)</code></pre>
<p align="center"><img src="https://images.velog.io/images/bae_mung/post/48c43e58-4548-4698-98ed-c1c57439cbd3/chap2_1.png"></p>

<blockquote>
<p><strong>Wrapper Class ?</strong> Primitive Type을 Boxing하여 객체화하는 클래스!</p>
<p>8개의 Primitive Type에 각각 대응되게 다 존재함.</p>
<p>java 5.0 부터 사용자들이 int와 Integer가 서로 호환되는 것 처럼 느껴지게 Auto Boxing, Auto UnBoxing을 지원함.</p>
<p>따라서 java의 모든 데이터타입은 객체로 표현이 가능해진다. 그래서 최상위 타입인 Object Type은 다형성 때문에 존재.</p>
</blockquote>
<pre><code class="language-java">Integer i = new Integer(10);</code></pre>
<blockquote>
<p>하지만 
String 도 객체인 것처럼, 엄연히 Wrapper Class도 객체임을 잊으면 안된다.</p>
<p>경우에 따라, 아래 이미지와 같은 상황도 발생할 수 있다.
equals로 값은 동일하지만 == 가 서로 다르다는 결과를 보일 때도 있다.</p>
</blockquote>
<p align="center"><img src="https://images.velog.io/images/bae_mung/post/49498a9d-095d-4209-8813-5fd4b93fd389/chap2_2.png"></p>

<hr>
<h3 id="💡-literal">💡 Literal</h3>
<p><strong>Literal</strong> : 자바 코드에 직접 &#39;값&#39;을 명시하면 리터럴로 분류함
소스 코드의 고정된 값을 대표하는 용어</p>
<p><strong>Literal 종류</strong></p>
<p>Primitive 타입과 같이 정수, 실수, 문자, 논리, 문자열 리터럴이 있다.</p>
<p><strong>1. 정수 리터럴</strong></p>
<p>10진수, 8진수, 16진수, 2진수 형태로 표현한 값이다.</p>
<pre><code class="language-java">int a = 15;
int b = 015;
int c = 0x15;
int d = 0b0101;</code></pre>
<p>정수 리터럴은 int 형이 default이다.</p>
<p>long 타입 리터럴은 숫자 뒤에 L 또는 l을 붙여 표시하여야 한다. ( long a = 26L; )</p>
<p><strong>2. 실수 리터럴</strong></p>
<p>소수점 형태나 지수 형태로 표현한 값이다.</p>
<p>실수 리터럴도 마찬가지로 double 형이 default이다.</p>
<pre><code class="language-java">double a = 0.1234;
double b = 1234E-4; </code></pre>
<p>a = 0.1234 와 b = (1234<em>10</em>(-4)는 동일한 값</p>
<p>long 타입 리터럴은 숫자 뒤에 L 또는 l을 붙여 표시하여야 하듯이, float 타입 리터럴도 f를 꼭 붙여줘야한다. ( float h = 0.1234f; )</p>
<p><strong>3. 문자 리터럴</strong></p>
<p>단일 인용부호(&#39; &#39;)로 문자를 표현한다.</p>
<pre><code class="language-java">char a = &#39;H&#39;;
char b = &#39;한&#39;;
char c = \uae00;(유니코드값) // \u다음에 4자리 16진수로, 2바이트의 유니코드(Unicode))</code></pre>
<p>아래와 같이 각각의 기능을 가지는 특수문자 리터럴도 존재한다.</p>
<p align="center"><img src="https://images.velog.io/images/bae_mung/post/b39f27bc-0656-4fa8-b607-6203ed713e56/chap2_4.png"></p>

<p><strong>4. 논리 리터럴</strong></p>
<p>boolean 타입 변수에 치환하거나 조건문에 이용한다.</p>
<pre><code class="language-java">boolean flag1 = true;

//Java에서는 다른 언어와 달리 0 과 1이상 수가 논리 리터럴이 될 수 없다.
boolean flag2 = 1; // 컴파일 에러!</code></pre>
<p>반드시 true, false만이 논리 리터럴이 된다.</p>
<p><strong>5. 문자열 리터럴</strong></p>
<p>문자열은 Primitive type이 아니고 엄연히 Reference type 객체이다. </p>
<p>이중 인용부호 (&quot; &quot;)로 문자열을 표현한다. </p>
<pre><code class="language-java">String str1 = new String(&quot;a&quot;);  // identityHashCode : 1908981452
String str2 = new String(&quot;a&quot;);  // identityHashCode : 234231844
String str3 = &quot;a&quot;;              // identityHashCode : 4332211222
String str4 = &quot;a&quot;;              // identityHashCode : 4332211222</code></pre>
<ul>
<li>str1과 str2는 새롭게 Heap 공간에 만듦, 즉 서로 참조값이 다른 다른 객체이다.</li>
<li>str3에서 문자열 &quot;a&quot;를 선언하면 이 &quot;a&quot;는 heap에 올라가는 것이 아닌 재사용하기 위해 리터럴풀에 넣고 그 &quot;a&quot;를 참조한다.</li>
<li>문자열은 변경이 되지않고 변경을 하려면 새롭게 선언을 해야하기 때문에 리터럴로 활용이 가능하다.</li>
<li>그리고 str4에서 문자열 &quot;a&quot;를 다시 선언하면, str4는 리터럴풀을 둘러보고 &quot;a&quot;가 있는 것을 발견하고 그 &quot;a&quot;를 참조한다.</li>
<li>따라서 str3과 str4는 리터럴풀에 있는 같은 &quot;a&quot;를 참조한다. </li>
<li>str1은 Heap에 새롭게 만든 String 메모리를, str3는 리터럴풀의 &quot;a&quot;를 참조하므로 다른 참조값을 가진다.</li>
</ul>
<hr>
<h3 id="💡-변수-선언-및-초기화하는-방법">💡 변수 선언 및 초기화하는 방법</h3>
<pre><code class="language-java">public class Person{
  // 멤버 변수 선언
  // 인스턴스 변수 선언
  int n, m, k;
  // 클래스 변수 선언
  int static s;

  // 생성자로 인스턴스 변수 초기화
  Person(int n, int m, int k){
      this.n = n;
      this.m = m;
      thos.k = k;
  }

  // 인스턴스 변수 블럭 초기화 
  { 
      n = 10;
      m = 20;
      k = 30;
  }

  // 클래스 변수 스태틱 블럭 초기화
  static {
      s = 40;
  }

  // 메소드 내 로컬 변수 선언 및 초기화
  void declare(){
      int a; // 선언
      a = 10; // 초기화
      int b = 10; // 선언과 동시에 초기화
  }
}
</code></pre>
<p>변수를 선언할 때 final 키워드를 붙혀서 final 변수로 선언할 수 있다.</p>
<p>final 변수는 바로 값을 초기화 하거나 생성자 또는 초기화 블럭에서 초기화 되어야한다.</p>
<p>final 변수는 4가지로 구분할 수 있다.</p>
<p><strong>1. 로컬 primitive type 변수</strong> : final로 선언하면 한번 초기화된 변수는 변경할 수 없는 상수값이 된다.</p>
<p><strong>2. 로컬 reference type 변수</strong> : final로 선언하면 그 변수에 다른 참조 값을 지정할 수 없게 되어, primitive type과 동일하게 한번 쓰여진 변수의 재변경이 불가해진다. </p>
<p>단, 해당 인스턴스 자체가 변경 불가하다는 의미는 아니라 해당 참조 변수가 다른 인스턴스로 참조 변경이 불가능 한 것이지, 인스턴스의 속성은 변경 가능하다.</p>
<p><strong>3. 메소드 인자 변수</strong> : 메소드 인자로 final 키워드를 붙인 변수는 , 메소드 안에서 변수값을 변경할 수 없다.</p>
<pre><code class="language-java">public void changeVar(final int var) {
        //var = 1; //final 인자는 메서드안에서 변경할 수 없음
}</code></pre>
<p><strong>4. 클래스 멤버 변수</strong> :  final로 선언하면 상수값이 되거나 write-once 필드로 한 번만 쓰이게 된다. final로 선언하면 초기화되는 시점은 생성자 메서드가 끝나기 전에 초기화가 되지만, fianl static이냐  그냥 final이냐에 따라서 초기화 시점이 달라진다.</p>
<pre><code class="language-java">public class InitVar{
    //static final 멤버 변수 
    static final inx a = 1; // 값과 함께 선언시
    static final int b;
    static {
        b = 2; // static 초기화 블럭에서
    }

    //instance final 멤버 변수 
    final int c = 3; // 값과 함께 선언시
    final int d;
    final int e;
    {
        d = 4; // 인스턴스 초기화 블럭에서 
    }

    InitVar(int e){
        this.e = e; // 생성자에서
    }
}</code></pre>
<hr>
<h3 id="💡-변수의-스코프와-라이프타임">💡 변수의 스코프와 라이프타임</h3>
<h4 id="변수의-scope--변수에-접근할-수-있는-유효-범위">변수의 Scope : 변수에 접근할 수 있는 유효 범위</h4>
<h4 id="변수의-lifetime--변수가-메모리에-살아있는-기간">변수의 Lifetime : 변수가 메모리에 살아있는 기간</h4>
<p><strong>인스턴스 변수</strong></p>
<ul>
<li>Scope: static 메소드를 제외한 클래스 전체</li>
<li>Lifetime : 객체가 메모리에 남아있을 때까지</li>
</ul>
<p><strong>클래스 변수</strong></p>
<ul>
<li>Scope: 클래스 전체</li>
<li>Lifetime : 클래스가 메모리에 로딩 되어 있는 동안</li>
</ul>
<p><strong>로컬 변수</strong></p>
<ul>
<li>Scope: 선언된 블록 내</li>
<li>Lifetime : 선언 된 블록이 끝날 때까지</li>
</ul>
<hr>
<h3 id="💡-타입-변환-캐스팅-그리고-타입-프로모션">💡 타입 변환, 캐스팅 그리고 타입 프로모션</h3>
<h4 id="캐스팅--명시적-형변환">캐스팅 : 명시적 형변환</h4>
<h4 id="프로모션--묵시적-형변환">프로모션 : 묵시적 형변환</h4>
<p><strong>Primitive Type</strong></p>
<p><strong>- 캐스팅 :</strong> 큰 데이터 타입에서 작은 데이터 타입으로 형 변환 (강제적으로 앞에서 명시적 형변환을 해주지 않으면 에러 발생)</p>
<p><strong>- 프로모션 :</strong> 작은 데이터 타입에서 큰 데이터 타입으로 형 변환 (자동 형변환)</p>
<pre><code class="language-java">int a = 10;
short b = (short) a; // Casting
double c = a; // Promition</code></pre>
<p><strong>Reference Type</strong></p>
<p>상속 관계인 경우 캐스팅 가능.</p>
<p><strong>- Up Casting :</strong> 부모 클래스는 명시적인 타입캐스팅 없이 자식과 연결 할 수 있다.</p>
<p><strong>- Down Casting :</strong> 자식 클래스는 명시적인 타입캐스팅이 있다면 부모와 연결할 수 있다.</p>
<pre><code class="language-java">// Person &lt;- Student로 클래스 상속 관계가 있다고 가정
Person p = new Student(); // Up Casting
Student s = (Student)p;   // Down Castinh

/* 
 * 참고로 조상 참조변수로 자식 객체를 생성하고 난 다음
 * 자식 객체로 캐스팅해주는것은 문제없으나,
 * 조상 객체를 생성하면서 자식 객체로 캐스팅하는것은 에러가 발생한다.
*/

Person p = new Person();
Student s = (Student)p;   // 컴파일 에러</code></pre>
<hr>
<h3 id="💡-배열">💡 배열</h3>
<p align="center"><img src="https://images.velog.io/images/bae_mung/post/225e8f6b-8ee1-4a45-9ee7-55162e1e7bb0/chap2_5.png"></p>

<p><strong>Reference Type (즉, 배열도 객체)</strong></p>
<p><strong>장점</strong></p>
<ul>
<li><p>데이터 관리 용이함</p>
<ul>
<li>반복문과 결합하여 일괄처리 가능</li>
<li>리턴값, 매개변수 전달시 활용 가능</li>
</ul>
</li>
<li><p>처리성능 효율적</p>
</li>
</ul>
<p><strong>단점</strong></p>
<ul>
<li>크기가 고정적 (하지만 고정이기 때문에 처리성능이 효율적이게 됨)<ul>
<li>크기를 변경하고 싶으면 배열 새로 생성</li>
</ul>
</li>
</ul>
<p><strong>배열 생성</strong></p>
<pre><code class="language-java">// 1차원 배열 생성
데이터타입[] 참조변수 = new 데이터타입[size];

// 2차원 배열 생성
데이터타입[][] 참조변수 = new 데이터타입[size][]; // 새로 선언하는 배열의 사이즈만 명시해줘도 된다. </code></pre>
<p><strong>배열 사용</strong></p>
<pre><code class="language-java">// 1차원 배열 사용
데이터타입 변수 = 참조변수[index];

// 2차원 배열 사용
데이터타입 변수 = 참조변수[index1][index2];</code></pre>
<p>index는 첫번째 원소 기준 offset 개념</p>
<p>그렇기 때문에, 0 ~ 길이-1 까지가 유효인덱스가 됨</p>
<p><strong>배열 초기화</strong></p>
<pre><code class="language-java">// 1차원 배열 초기화
데이터타입[] 참조변수 = new 데이터타입[]{값1,값2,,,,};
데이터타입[] 참조변수 = {값1,값2,,,,};

//초기화를 할 때는 들어간 초기값의 개수에 따라 자동으로 size가 결정되기 때문에 직접 size를 명시하지 않는다. 
데이터타입[] 참조변수 = new 데이터타입[size]{값1,값2,,,,}; // 컴파일 에러

// 2차원 배열 초기화
데이터타입[][] 참조변수 = new 데이터타입[][]{{값1, 값2,,,,}, {값1, 값2,,,,}, {값1, 값2,,,,}};
데이터타입[][] 참조변수 = {{값1, 값2,,,,}, {값1, 값2,,,,}, {값1, 값2,,,,}};</code></pre>
<hr>
<h3 id="💡-타입-추론-var">💡 타입 추론, var</h3>
<h4 id="타입-추론--변수의-타입을-명시하지-않고-컴파일러가-타입을-추측해서-컴파일-하는것">타입 추론 : 변수의 타입을 명시하지 않고 컴파일러가 타입을 추측해서 컴파일 하는것.</h4>
<h4 id="var--타입-추론을-위한-람다-타입">var : 타입 추론을 위한 람다 타입.</h4>
<p>Java 10부터 var 키워드를 통해 변수를 선언할 수 있게 됐다.</p>
<p>지역 변수로만 사용 가능하고 반드시 선언과 동시에 초기화를 해야 하며, null을 대입 할 수 없다.</p>
<p>동적바인딩처럼 런타임에 var를 실제 타입으로 치환할 것 같지만, 실제 타입으로 치환하는 것은 컴파일 타임이다.</p>
<pre><code class="language-java">public static void main(String[] args){
    var intNum = 10; // int
    var longNum = 10L; // long
    var floatNum = 0.1f; // float
    var doubleNum = 0.1; // double
    var bool = true; // boolean
    var str = &quot;String&quot;; // String
}</code></pre>
]]></description>
        </item>
    </channel>
</rss>