<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>presentLee</title>
    <link>https://nownow.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Mon, 13 Jul 2026 00:33:15 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>nownow</managingEditor>
    <item>
      <title>effective java item 17 - 변경 가능성을 최소화하라.</title>
      <link>https://nownow.tistory.com/261</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;불변클래스&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인스턴스 내부 값을 수정할 수 없는 클래스.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가변클래스보다 설계와 구현, 사용이 쉽고 오류가 생길 여지가 적어 안전하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ex) String, BigDecimal,BigInteger&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;불변클래스의 규칙.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1.객체의 상태를 변경할 수 있는 set 메서드를 제공하지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2.클래스를 확장할 수 없도록 한다. 하위 클래스에서 의도적으로 객체의 상태를 변하는 것을 막아야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;final로 클래스를 선언하거나 생성자를 private으로 두고 복사 생성자를 구현한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3.모든 필드를 private로 유지한다. 필드가 참조하고 있는 가변 객체를 클라이언트가&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;의도적으로 접근해 수정하는 일을 막아야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;접근자를 통해 참조를 반환해서도 안된다. private필드이므로 참조를 변경할 수는 없지만&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참조중인 인스턴스 내부 정보가 변경될 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1742266437117&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public final class Complex {
    private final double re;
    private final double im;

    public Complex(double re, double im) {
        this.re = re;
        this.im = im;
    }

    public Complex plus(Complex c) {
        return new Complex(re + c.re, im + c.im);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와같이 연산 메서드가 인스턴스 자신을 수정하는 것이 아닌 새로운 인스턴스를 반환하는&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;형태를 함수형 프로그래밍 패턴이라 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같은 형태를 사용할 때는 add 와 같은 동사 대신 plus와 같은 전치사형 함수명을&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;관례적으로 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같은 방식이 적용되어 있기에 불변클래스는 failure Atomicity를 보장하며&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;thread safe 하게 구현할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인스턴스의 상태가 절대 변하지 않고, 메서드 호출 중 실패하더라도&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그것이 보장되므로 failure Atomicity를 보장하고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 스레드가 동시에 접근해도 기존 객체의 값이 바뀌지 않으므로 thread safe 하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;불변클래스의 특징을 활용해 자주 쓰일 값들을 미리 상수로 등록해둘 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드의 경우에는&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1742273536953&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public static final Complex ZERO = new Complex(0, 0);
 public static final Complex ONE = new Complex(1, 0);
 public static final Complex I = new Complex(0, 1);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와같이 자주 활용될 단순한 복소수를 미리 상수로 만들어둘 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;667&quot; data-origin-height=&quot;121&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bPMcsG/btsMOCK1qJU/b3HEydq4Nqoc9Hj8pV29P1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bPMcsG/btsMOCK1qJU/b3HEydq4Nqoc9Hj8pV29P1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bPMcsG/btsMOCK1qJU/b3HEydq4Nqoc9Hj8pV29P1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbPMcsG%2FbtsMOCK1qJU%2Fb3HEydq4Nqoc9Hj8pV29P1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;667&quot; height=&quot;121&quot; data-origin-width=&quot;667&quot; data-origin-height=&quot;121&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;불변객체간에는 값을 공유하는것도 가능하다. 불변객체인 BigInteger 클래스 에서는&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정수를 비트단위로 나누어 배열에 저장한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;부호가 반전된 값을 반환하는 negate의 경우에는 새로운 배열을 참조하는 인스턴스를 반환할 수도 있겠지만&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어차피 기존 객체의 값을 담당하는 배열 부분이 바뀌지 않을 것이기 때문에&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 배열의 데이터의 참조를 공유하면서 부호만 바꾼 형태의 인스턴스를 반환하는 형태로 이루어져 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;불변클래스의 단점&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단점으로는 값이 다르면 항상 새로운 인스턴스를 반환해야 한다는 점에 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;791&quot; data-origin-height=&quot;419&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TcDJ9/btsMPjdgb4r/ua9taT0qo35jbPLYmGqon1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TcDJ9/btsMPjdgb4r/ua9taT0qo35jbPLYmGqon1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TcDJ9/btsMPjdgb4r/ua9taT0qo35jbPLYmGqon1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTcDJ9%2FbtsMPjdgb4r%2Fua9taT0qo35jbPLYmGqon1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;583&quot; height=&quot;309&quot; data-origin-width=&quot;791&quot; data-origin-height=&quot;419&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BigInteger의 flipBit 메서드를 보면 비트 하나를 토글하는 연산일 뿐인데 정적 팩터리 메서드 valueOf를 사용해&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;새로운 BigInteger 인스턴스를 반환하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;백만비트짜리의 BigInteger의 비트를 하나만 전환하려고 해도 거의 같은 클래스를 하나 더 만들어야 한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;701&quot; data-origin-height=&quot;223&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zFHJ2/btsMPnNqKr7/fzzK6Cddi2QR8sg75emg6k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zFHJ2/btsMPnNqKr7/fzzK6Cddi2QR8sg75emg6k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zFHJ2/btsMPnNqKr7/fzzK6Cddi2QR8sg75emg6k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzFHJ2%2FbtsMPnNqKr7%2FfzzK6Cddi2QR8sg75emg6k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;701&quot; height=&quot;223&quot; data-origin-width=&quot;701&quot; data-origin-height=&quot;223&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;485&quot; data-origin-height=&quot;135&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JICCP/btsMOYUJo6A/Z6IhR77he6U26YtERp8Uq1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JICCP/btsMOYUJo6A/Z6IhR77he6U26YtERp8Uq1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JICCP/btsMOYUJo6A/Z6IhR77he6U26YtERp8Uq1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJICCP%2FbtsMOYUJo6A%2FZ6IhR77he6U26YtERp8Uq1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;485&quot; height=&quot;135&quot; data-origin-width=&quot;485&quot; data-origin-height=&quot;135&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러한 비효율성을 개선하기 위해서, 불변 객체들에는 package-private으로 선언되어 내부에서 활용할 수 있는&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가변 동반 클래스들을 지원하곤 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;String과 StringBuilder도 비슷한 예지만, StringBuilder는 독립적으로도 사용할 수 있기에 public으로 설계됐다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;효율&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;불변객체는 항상 같은 값을 갖고 있기 때문에 계산 비용이 큰 값을 lazy하게 계산하며 캐시해두기도 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1742277612840&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;private int hashCode; // 자동으로 0으로 초기화된다.
    @Override
    public int hashCode(){
        int result=hashCode;
        if(result=0){
            result=Short.hashCode(a reaCode);
            result=31*result+Short.hashCode(prefix);
            result=31*result+Short.hashCode(lineNum);
            hashCode=result;
        }
        return result;
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BigInteger&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BigInteger클래스가 설계될 때는, 아직 개념이 일반적으로 확정되지 않아 불변객체의 역할임에도&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;public으로 설계되어있다. 그렇기에 메서드를 재정의하여 불변을 해치는 상황이 발생할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 불변객체를 사용할 때에는 신뢰할 수 있는 객체인지 확인하기위해&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BigInteger.getclass() == 인스턴스.getclass() 와 같이 검증 결과가 따로 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>java</category>
      <author>nownow</author>
      <guid isPermaLink="true">https://nownow.tistory.com/261</guid>
      <comments>https://nownow.tistory.com/261#entry261comment</comments>
      <pubDate>Thu, 13 Mar 2025 20:50:34 +0900</pubDate>
    </item>
    <item>
      <title>Comparable</title>
      <link>https://nownow.tistory.com/260</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Arrays.sort()와 Collections.sort()로 정렬이 가능한 이유는, 해당 자료구조에 Comparable이 구현되어 있기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Comparable도 equals와 같이 반사성, 대칭성, 추이성을 충족해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반사성: x.compareTo(y) == -y.compareTo(x) 여야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추이성: x.compareTo(y) &amp;gt;0 이며 y.compareTo(z) &amp;gt;0 라면 x.compareTo(z) &amp;gt;0 여야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대칭성: 크기가 같은 객체간에는 어떤 객체와 비교하더라도 같아야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;equals를 오버라이드 할 때와 마찬가지로, Comparable을 구현할 때도&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상속받아 구체화 한 클래스에서 Comparable을 유지할 방법이 없기에&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상속 대신 컴포지션을 사용하여, 생성자에서 기본 클래스를 주입받아 equals를 재정의 하는 식으로 구현한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 compareTo로 시행한 동치성 검사의 결과가 equals와 동일한 결과를 내도록 구현해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자료구조에 따라 동일 여부를 compareTo로 하는 것과 equals로 하는 것이 있기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시로 정확성을 위한 자료구조 BigDecimal은&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;new BigDecimal(&quot;1.0&quot;) 과 new BigDecimal(&quot;1.00&quot;) 을 equals로 비교할 때 서로 다르다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 자료구조는 수의 크기, 소수점 이하 자릿수 scale필드를 모두 관리하기에 equals로는 둘중 하나가 다르면 다르다.&lt;/p&gt;
&lt;pre id=&quot;code_1741714730683&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.math.BigDecimal;
import java.util.HashMap;
import java.util.TreeMap;

public class Sort {
    public static void main(String[] args) {
        BigDecimal bigDecimal1 = new BigDecimal(&quot;1.0&quot;);
        BigDecimal bigDecimal2 = new BigDecimal(&quot;1.00&quot;);

        System.out.println(bigDecimal1.compareTo(bigDecimal2));  // 0
        System.out.println(bigDecimal1.equals(bigDecimal2));  // false

        TreeMap&amp;lt;BigDecimal, Integer&amp;gt; treeMap = new TreeMap&amp;lt;&amp;gt;();
        treeMap.put(bigDecimal1,1);
        treeMap.put(bigDecimal2,2);

        HashMap&amp;lt;BigDecimal, Integer&amp;gt; hashMap = new HashMap&amp;lt;&amp;gt;();
        hashMap.put(bigDecimal1,1);
        hashMap.put(bigDecimal2,2);

        System.out.println(treeMap.size());  // 1
        System.out.println(hashMap.size());  // 2

    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;treeMap에서는 compareTo를 기반으로, hashMap에서는 equals를 기반으로 동치성을 검사하기에&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같은 결과를 얻는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 상황에서의 차이를 방지하기 위해 equals와 compareTo간 동치성 검사를 일치시킬 필요가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1741715191069&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package Compare;

public class Score implements Comparable&amp;lt;Score&amp;gt; {
    public int Eng;
    public int Math;
    public int total;
    public Score(int Eng,int Math){
        this.Eng=Eng;this.Math=Math;this.total=Eng+Math;
    }
    @Override
    public int compareTo(Score o) {
        int result=Integer.compare(total,o.total);
        if(result==0){
            result=Integer.compare(Eng,o.Eng);
            if(result==0){
                result=Integer.compare(Math,o.Math);
            }
        }
        return result;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Comparable를 구현하며 오버라이드하는 compareTo는 위와 같이 구현할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 중요한 항목을 기준으로 비교를 실시하고 그가 동일하면 우선순위가 높은 순서로 비교해나간다.&lt;/p&gt;
&lt;pre id=&quot;code_1741715413237&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;private static final Comparator&amp;lt;Score&amp;gt; COMPARATOR=
        comparingInt((Score o) -&amp;gt; o.total)
                .thenComparingInt(o -&amp;gt; o.Eng)
                .thenComparingInt(o -&amp;gt; o.Math);
    @Override
    public int compareTo(Score o){
        return COMPARATOR.compare(this, o);
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메서드체이닝이 가능하며 primitive type을 직접 비교해서 박싱, 언박싱이 일어나지 않아 성능도 준수한 방식으로&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와같이 Comparator의 메서드를 사용하여 구현도 가능하다.&lt;/p&gt;</description>
      <category>java</category>
      <author>nownow</author>
      <guid isPermaLink="true">https://nownow.tistory.com/260</guid>
      <comments>https://nownow.tistory.com/260#entry260comment</comments>
      <pubDate>Wed, 12 Mar 2025 02:56:07 +0900</pubDate>
    </item>
    <item>
      <title>객체 참조 해제, Java 참조 유형</title>
      <link>https://nownow.tistory.com/259</link>
      <description>&lt;pre id=&quot;code_1741241480846&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Stack {
    private Object[] elements;
    private int size = 0;
    private static final int DEFAULT_INITIAL_CAPACITY = 16;
    public StackO {
        elements = new Object[DEFAULT_INITIAL_CAPACITY];
    }
    public void push(Object e) {
        ensureCapacity();
        elements[size++] = e;
    }
    public Object pop() {
        if (size = 0)
            throw new EmptyStackException();
        return elements[&amp;mdash;size];
    }

    /**
     * 원소를 위한 공간을 적어도 하나 이상 확보한다.
     *  배열 크기를 늘려야 할 때마다 대략 두 배씩 늘린다.
    */
    private void ensureCapacity() {
    if (elements.length = size)
        elements = Arrays.copyOf(elementsf 2 * size + 1);
    }
 }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GC를 통해 메모리 관리가 이루어지는 Java에서는 참조되지 않는 객체의 메모리 할당을 JVM에서 해제해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적인 경우에는 최소한의 참조가 되도록 구현하고 참조하고 있는 변수가 scope에서 벗어나며 자동으로 해제된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 위와 같이 객체 배열을 가지고 있는 클래스 즉 자기 메모리를 직접 관리하는 클래스에서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;pop() 메서드를 수행할 때 객체 배열에 처리를 해주지 않고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;size 필드 연산만 해준다면, Object 참조 배열에서 삭제되어야 할 객체를 그대로 참조하고 있어 메모리 누수가 발생한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 상황을 방지하기 위해 elements[size] = null 과 같은 처리가 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특정상황을 위해 참조 유형을 고려할 수도 잇다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Java의 참조 유형에는 4가지가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1.Strong Reference&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2.Soft Reference&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3.Weak Reference&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4.Phantom Reference&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래로 갈 수록 GC의 대상이 될 시점이 빠르다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Strong Reference&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적으로 사용하는 new 키워드 인스턴스 생성의 경우가 Strong Reference다.&lt;/p&gt;
&lt;pre id=&quot;code_1741243844850&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;TestClass strongRef = new TestClass();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Soft Reference&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;강한 참조를 하고 있는 변수가 사라지더라도 Soft Reference를 유지하고 있는 상태 일때는&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JVM의 메모리가 부족해지는 시점에 GC의 대상이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Weak Reference&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;강한 참조를 하고 있는 변수가 사라지면 Weak Reference가 참조를 유지하고 있더라도&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GC의 대상이 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1741244782484&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;

public class Stack {
    public static void main(String[] args) {
        TestClass strongRef = new TestClass();
        TestClass strongRef2 = new TestClass();
        SoftReference&amp;lt;TestClass&amp;gt; softRef = new SoftReference&amp;lt;&amp;gt;(strongRef);
        WeakReference&amp;lt;TestClass&amp;gt; weakRef = new WeakReference&amp;lt;&amp;gt;(strongRef2);
        strongRef2=null;
        strongRef=null;
        System.out.println(softRef.get());
        System.out.println(weakRef.get());
        System.gc();
        System.out.println(softRef.get());
        System.out.println(weakRef.get());
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;180&quot; data-origin-height=&quot;96&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FXHBe/btsMDJDssft/kRREKSWVxVigK3HgXrCptK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FXHBe/btsMDJDssft/kRREKSWVxVigK3HgXrCptK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FXHBe/btsMDJDssft/kRREKSWVxVigK3HgXrCptK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFXHBe%2FbtsMDJDssft%2FkRREKSWVxVigK3HgXrCptK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;180&quot; height=&quot;96&quot; data-origin-width=&quot;180&quot; data-origin-height=&quot;96&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Weak Reference 방식의 HashMap이 존재한다.&lt;/p&gt;
&lt;pre id=&quot;code_1741245149898&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public static void main(String[] args) {
        Object test1 = new Object();
        Object test2 = new Object();
        WeakHashMap&amp;lt;Object, String&amp;gt; weakHashMap = new WeakHashMap&amp;lt;&amp;gt;();
        weakHashMap.put(test1,&quot;Test1&quot;);
        weakHashMap.put(test2,&quot;Test2&quot;);
        for(String str : weakHashMap.values()){
            System.out.println(str);
        }
        test1=null;
        test2=null;
        System.gc();
        for(String str : weakHashMap.values()){
            System.out.println(str);
        }
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;374&quot; data-origin-height=&quot;161&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nzbfM/btsMCZtvbI6/bJNLOeRYkk25cc0WiZNUAk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nzbfM/btsMCZtvbI6/bJNLOeRYkk25cc0WiZNUAk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nzbfM/btsMCZtvbI6/bJNLOeRYkk25cc0WiZNUAk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnzbfM%2FbtsMCZtvbI6%2FbJNLOeRYkk25cc0WiZNUAk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;374&quot; height=&quot;161&quot; data-origin-width=&quot;374&quot; data-origin-height=&quot;161&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;필요한 값을 캐싱하는 용도로 HashMap을 사용할 때 외부에서 키 객체를 참조하는 동안만 캐싱을 유지하도록&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구현할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;세번째로 콜백 구현 시에도 메모리 누수가 발생할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1741248080515&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Caller {
    public static void main(String[] args) {
        Callee callee = new Callee();
        Callback callback = () -&amp;gt; {
            System.out.println(&quot;콜백&quot;);
        };
        callee.setCallback(callback);
        callee.task();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1741248087025&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@FunctionalInterface
public interface Callback {
    public void callbackMethod();
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1741248094501&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Callee {
    Callback callback;
    public void setCallback(Callback callback){
        this.callback=callback;
    }
    public void task(){
        System.out.println(&quot;작업 완료&quot;);
        callback.callbackMethod();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와같이 일반적인 콜백 구현에서는 Callee가 callback을 강한 참조로 갖고 있기 때문에&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Caller 객체가 사라지더라도 callback 객체가 사라지지 않는다.&lt;/p&gt;
&lt;pre id=&quot;code_1741248718535&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.lang.ref.WeakReference;

public class Callee {
    WeakReference&amp;lt;Callback&amp;gt; callback;

    public void setCallback(Callback callback){
         this.callback = new WeakReference&amp;lt;&amp;gt;(callback);
    }
    public void task(){
        System.out.println(&quot;작업 완료&quot;);
        Callback callbackGet = callback.get();
        callbackGet.callbackMethod();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;콜백을 약한참조로 지정함으로서 보완할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;WeakReference&amp;lt;&amp;gt;() 에서 실제 내부 객체를 꺼내서 사용해야 메서드를 호출할 수 있기에 .get()을 사용한다.&lt;/p&gt;</description>
      <category>java</category>
      <author>nownow</author>
      <guid isPermaLink="true">https://nownow.tistory.com/259</guid>
      <comments>https://nownow.tistory.com/259#entry259comment</comments>
      <pubDate>Thu, 6 Mar 2025 17:12:57 +0900</pubDate>
    </item>
    <item>
      <title>클래스 빌더 패턴</title>
      <link>https://nownow.tistory.com/257</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;클래스의 생성자, 정적 팩터리 패턴에서는 선택적 매개변수가 많을 때 적용하기 불리한 점이 있다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;영양성분을 클래스를 표현한다고 가정하면. 여러 성분 중 해당 식품에 필요한 정보만 선택적으로 입력해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1741052301359&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class 영양성분{
	영양성분(탄수화물,단백질,지방){};
	영양성분(탄수화물,단백질,지방,칼로리){};
	영양성분(탄수화물,단백질,지방,칼로리,비타민A,비타민B){};
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 방식으로 모든 상황을 가정하여 생성자를 지정할 수도 있지만(점층적 생성자 패턴)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;매개변수가 너무 많아진다면 활용하기 어려워진다.&lt;/p&gt;
&lt;pre id=&quot;code_1741052465909&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class 영양성분{
	int vitamina;
	int vitaminb;
	영양성분(탄수화물,단백질,지방){};
	public setvitaminA(int num){
	vitamina=num;
	}
	public setvitaminB(int num){
	vitaminb=num;
	}
}

main(){
	영양성분 snack = new 영양성분(1,2,3);
	snack.setvitaminA(4);
	// 여기서 문제
	snack.setvitaminB(5);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런 상황에 대응하기 위해 set메서드를 통해 필드 데이터를 설정해주면(자바빈즈 패턴)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 필드를 설정하는 도중에 일관성이 깨지게 되고 스레드 안정성을 위해 부가 처리가 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 문제를 클래스 내부에 정적 빌더 객체를 추가함으로서 해결할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 계층적 빌더 패턴의 예시다.&lt;/p&gt;
&lt;pre id=&quot;code_1741052882489&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public abstract class Coffee {
    public enum topping {SUGAR,SYRUP,CREAM,CINNAMON};
    final Set&amp;lt;topping&amp;gt; toppings;
    static public abstract class Builder&amp;lt;T extends Builder&amp;lt;T&amp;gt;&amp;gt;{
        EnumSet&amp;lt;topping&amp;gt; toppingEnumSet = EnumSet.noneOf(topping.class);
        public T addTopping(topping topping){
            toppingEnumSet.add(topping);
            return self();
        }
        abstract Coffee build();
        abstract T self();
    }
    Coffee(Builder&amp;lt;?&amp;gt; build){
        toppings=build.toppingEnumSet.clone();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Coffee는 추상 클래스로 구현될 하위 클래스가 존재한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메서드체이닝을 활용할 수 있도록 재귀적 제네릭을 사용한다. (Builder&amp;lt;T extends Builder&amp;lt;T&amp;gt;&amp;gt;)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하위 클래스의 공통 기능이기에 상위 클래스에 구현해둔 addTopping 메서드에서 Builder 클래스를 반환한다면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하위클래스를 생성할 때 메서드체이닝 활용이 불가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇기에 타입 매개변수 제한으로 Builder&amp;lt;T&amp;gt; 클래스를 상한으로 두고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하위클래스를 반환할 수 있도록 구현한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생성자에서 참조형 객체인 EnumSet을 .clone() 하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Coffee.Builder은 가변형 자료구조인 EnumSet을 사용하고 있기에 그를 = 연산자로 참조하게 되면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;static class인 Builder를 사용하는 다른 객체에 의해서 EnumSet이 사용되면 불변성을 유지할 수 없기에&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;.clone() 메서드를 통해 새로운 EnumSet을 복사 생성하여 관리한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;.clone() 메서드는 참조형 자료구조의 내부 요소를 얕은복사 하기에 다른 Set 자료구조라면 문제가 생길 수 있지만&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;enum은 하나의 인스턴스만 존재하기에 얕은 복사로도 불변을 유지할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1741053223364&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Latte extends Coffee{
    public enum milkEnum {NORMAL, VEGAN};
    final milkEnum milk;
    static public class Builder extends Coffee.Builder&amp;lt;Builder&amp;gt;{
        private final milkEnum milk;
        public Builder(milkEnum milk){
            this.milk=milk;
        }
        @Override
        Latte build(){
            return new Latte(this);
        }
        @Override
        Builder self() {
            return this;
        }
    }
    Latte(Builder builder){
        super(builder);
        milk=builder.milk;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Coffee를 상속한 클래스에서의 Builder는 extends 부분에 상위 클래스의 타입 매개변수를 지정해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추상 메서드였던 self()를 구현하고 있는데, 이도 메서드체이닝을 위한 구현으로&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상위 클래스에서 addToppings 후 self()를 반환하고 있는데, 하위클래스의 self() 구현에서 자신을 return 하게 함으로서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공통 상위 메서드에서 구체화 된 클래스를 return 하며 메서드 체이닝이 작동할 수 있도록 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 작업을 끝낸 뒤 build() 메서드를 통해 필요한 필드 값을 지정한 인스턴스를 반환할 수 있다.&lt;/p&gt;</description>
      <category>java</category>
      <author>nownow</author>
      <guid isPermaLink="true">https://nownow.tistory.com/257</guid>
      <comments>https://nownow.tistory.com/257#entry257comment</comments>
      <pubDate>Tue, 4 Mar 2025 11:35:14 +0900</pubDate>
    </item>
    <item>
      <title>enum 매핑</title>
      <link>https://nownow.tistory.com/256</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;enum에 한글을 지정하거나 데이터 타입 호환성을 위해 다른 상수를 추가로 지정할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1740902117621&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public enum EnumDay {
    SPRING(&quot;봄&quot;),
    SUMMER(&quot;여름&quot;),
    WINTER(&quot;겨울&quot;);
    private String season;
    private EnumDay(String season){
        this.season=season;
    }
    public String KOSeason(){
        return season;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1740902137962&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Main {
    public static void main(String[] args) {
        EnumDay day =EnumDay.SUMMER;
        System.out.println(day); //SUMMER
        System.out.println(day.KOSeason()); //여름
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;enum은 내부적으로는 private static final 객체 = new 객체(); 와 같은 식으로 구성되어 있기에&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클래스 로딩시 정적 불변 클래스로 생성된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 enum의 생성자는 암묵적으로 private 이기에 각 상수가 단일 인스턴스로 유지되고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생성자에서 필드 값을 초기화해주면 추가 메서드를 통해 맵핑해둔 다른 값을 불러올 수 있다.&lt;/p&gt;</description>
      <category>java</category>
      <author>nownow</author>
      <guid isPermaLink="true">https://nownow.tistory.com/256</guid>
      <comments>https://nownow.tistory.com/256#entry256comment</comments>
      <pubDate>Fri, 28 Feb 2025 20:28:02 +0900</pubDate>
    </item>
    <item>
      <title>백준 14426, 5052 (Trie)</title>
      <link>https://nownow.tistory.com/255</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;문자열의 순서를 고려해서 접두사인지 판별할때 활용할 수 있는 Trie&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/14426&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/14426&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;루트 노드를 기준으로 전개해나가고 각 노드에서 여러개의 갈래가 생길 수 있으므로&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ArrayList로 노드를 연결시켜준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ArrayList대신 HashMap을 사용해도 가능.&lt;/p&gt;
&lt;pre id=&quot;code_1740642657142&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.*;
import java.util.*;

class Main {
    static class node {
        char ch;
        ArrayList&amp;lt;node&amp;gt; nodes = new ArrayList&amp;lt;&amp;gt;();
    }

    static node root = new node();
    static int n, m;
    static int result=0;

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String str = br.readLine();
        StringTokenizer token = new StringTokenizer(str);
        n = Integer.parseInt(token.nextToken());
        m = Integer.parseInt(token.nextToken());
        for (int i = 0; i &amp;lt; n; i++) {
            str = br.readLine();
            add(str);
        }
        //test();
        for(int i=0;i&amp;lt;m;i++){
            str=br.readLine();
            result+=count(str);
        }
        System.out.println(result);
    }
    static int count(String str){
        int len = str.length();
        node temp = root;
        for (int i = 0; i &amp;lt; len; i++) {
            char alphabet = str.charAt(i);
            boolean newWay = true;
            for (node node : temp.nodes) {
                if (node.ch == alphabet) { //갈길이 있을경우
                    temp = node;
                    newWay = false;
                    break;
                }
            }
            if(newWay) {
                return 0;
            }
        }
        return 1;
    }
    static void test(){
        for(node node : root.nodes){
            System.out.println(node.ch);
        }
    }

    static void add(String str) {
        int len = str.length();
        node temp = root;
        for (int i = 0; i &amp;lt; len; i++) {
            char alphabet = str.charAt(i);
            boolean newWay = true;
            for (node node : temp.nodes) {
                if (node.ch == alphabet) { //갈길이 있을경우
                    temp = node;
                    newWay = false;
                    break;
                }
            }
            if(newWay) {
                node addedNode = new node();
                addedNode.ch=alphabet;
                temp.nodes.add(addedNode);
                temp=addedNode;
            }
        }
    }
}

/*
트라이
루트에서부터 26개의 갈 길을 두고 전개해나감
n개를 그렇게 세팅해두고
m개에서는 갈길이 없으면 멈추고 끝까지 나아가면 결과에 +1
 */&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/5052&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/5052&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예제 입력에서&lt;/p&gt;
&lt;pre id=&quot;sample-input-1&quot; class=&quot;angelscript&quot; style=&quot;background-color: #f7f7f9; color: #333333; text-align: start;&quot;&gt;&lt;code&gt;3
911
97625999
91125426&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미 입력된 전화번호의 종료 지점까지 동일한 케이스가 입력될 경우 접미사로 취급된다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 케이스만 고려해서 하면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;911과 91125426의 순서가 바뀐 케이스를 잡을 수 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 케이스를 검증할 때, 그 케이스의 마지막 숫자를 확인하는데 이미 입력된 케이스의 Trie를 따라왔다면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 케이스가 이미 있는 케이스의 접미사라고 취급하여 이 경우도 판별해주어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대안&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정렬을 통해 길이가 짧은 케이스 먼저 검증을 시도할 수도 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1740643434555&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.*;
import java.util.*;

class Main {

    static class node{
        char num;
        ArrayList&amp;lt;node&amp;gt; arr = new ArrayList&amp;lt;&amp;gt;();
        boolean finishLine;

    }
    static node root = new node();

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int testCase = Integer.parseInt(br.readLine());
        for(int i=0;i&amp;lt;testCase;i++){
            int numCount = Integer.parseInt(br.readLine());
            boolean flag=false;
            for(int j=0;j&amp;lt;numCount;j++){
                String str = br.readLine();
                if(!add(str)){
                    flag=true;
                }
            }
            if(flag){
                System.out.println(&quot;NO&quot;);
            }
            else{
                System.out.println(&quot;YES&quot;);
            }

            root=new node();
        }
    }
    static boolean add(String str){
        node temp = root;
        int len = str.length();
        for(int i=0;i&amp;lt;len;i++){
            boolean lastFlag = false;
            boolean moveFlag = false;
            if(i==len-1) lastFlag=true;
            char idxNum = str.charAt(i);
            for(node node : temp.arr){
                if(node.num==idxNum){ // 같은게 있다면
                    moveFlag=true;
                    temp=node;
                    if(temp.finishLine){
                        return false;
                    }
                    if(i==len-1){
                        return false;
                    }
                }
            }
            if(!moveFlag){
                node addedNode = new node();
                if(lastFlag){
                    addedNode.finishLine = true;
                }
                addedNode.num=idxNum;
                temp.arr.add(addedNode);
                temp=addedNode;
            }

        }
        return true;
    }
}

/*
트라이
이미 있는 트라이의 종료지점을 통과해선 안된다. 그럼 아예 STOP
or
내가 마지막인데 이미 있는곳을 왔다

1
3
91125426
911
97625999
 */&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1740644790338&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;//HashMap을 사용하고 정렬처리한 코드


import java.io.*;
import java.util.*;

class Main {

    static class node {
        char num;
        //ArrayList&amp;lt;node&amp;gt; arr = new ArrayList&amp;lt;&amp;gt;();
        HashMap&amp;lt;Character, node&amp;gt; arr = new HashMap&amp;lt;&amp;gt;();
        boolean finishLine;

    }

    static node root = new node();
    static ArrayList&amp;lt;String&amp;gt; stringArr = new ArrayList&amp;lt;&amp;gt;();

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int testCase = Integer.parseInt(br.readLine());
        for (int i = 0; i &amp;lt; testCase; i++) {
            int numCount = Integer.parseInt(br.readLine());
            boolean flag = false;
            for (int j = 0; j &amp;lt; numCount; j++) {
                String str = br.readLine();
                stringArr.add(str);
            }
            Collections.sort(stringArr);
            for(String tempstr : stringArr){
                if (!add(tempstr)) {
                    flag = true;
                }
            }


            if (flag) {
                System.out.println(&quot;NO&quot;);
            } else {
                System.out.println(&quot;YES&quot;);
            }

            root = new node();
            stringArr = new ArrayList&amp;lt;&amp;gt;();
        }
    }

    static boolean add(String str) {
        node temp = root;
        int len = str.length();
        for (int i = 0; i &amp;lt; len; i++) {
            boolean lastFlag = false;
            boolean moveFlag = false;
            if (i == len - 1) lastFlag = true;
            char idxNum = str.charAt(i);
            //for(node node : temp.arr){
            node node = temp.arr.getOrDefault(idxNum,null);
            if (node!=null) { // 같은게 있다면
                moveFlag = true;
                temp = node;
                if (temp.finishLine) {
                    return false;
                }
//                if (i == len - 1) {
//                    return false;
//                }
            }
            //}
            if (!moveFlag) {
                node addedNode = new node();
                if (lastFlag) {
                    addedNode.finishLine = true;
                }
                addedNode.num = idxNum;
                temp.arr.put(idxNum,addedNode);
                temp = addedNode;
            }

        }
        return true;
    }
}

/*
트라이
이미 있는 트라이의 종료지점을 통과해선 안된다. 그럼 아예 STOP
or
내가 마지막인데 이미 있는곳을 왔다

1
3
91125426
911
97625999
 */&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;847&quot; data-origin-height=&quot;264&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b4mS4v/btsMzsOV3Gt/td0rl5ISHrohYhK8HgGOkK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b4mS4v/btsMzsOV3Gt/td0rl5ISHrohYhK8HgGOkK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b4mS4v/btsMzsOV3Gt/td0rl5ISHrohYhK8HgGOkK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb4mS4v%2FbtsMzsOV3Gt%2Ftd0rl5ISHrohYhK8HgGOkK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;847&quot; height=&quot;264&quot; data-origin-width=&quot;847&quot; data-origin-height=&quot;264&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최하단 먼저 작성된 코드&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중간 HashMap을 사용하되 정렬하지 않고 if문으로 검사한 코&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최상단 아래쪽에 작성되어있는 코드&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <author>nownow</author>
      <guid isPermaLink="true">https://nownow.tistory.com/255</guid>
      <comments>https://nownow.tistory.com/255#entry255comment</comments>
      <pubDate>Thu, 27 Feb 2025 17:28:50 +0900</pubDate>
    </item>
    <item>
      <title>혼공컴운 6주차 (가상메모리)</title>
      <link>https://nownow.tistory.com/254</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;페이징&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로그램을 실행할 때 메모리에 적재할 필요가 있음. 메모리에 연속적으로 배치할 경우&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로세스가 종료될 때 중간중간 프로세스가 종료되며 외부단편화가 발생하고 메모리 공간을&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;효율적으로 사용하지 못하게 될 수 있다. 또한 메모리 남은공간을 초과하는 프로그램 실행 불가&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 해결하기 위해, 메모리의 물리적 공간을 프레임 단위로 나누어서 각 칸에 프로세스의 일부를&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비연속적으로 배치한다. 당장 필요한 부분만을 메모리에 적재하고 나머지는 디스크에 저장하는&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스와핑 방식을 적용하여 메모리를 효율적으로 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로세스가 메모리에 불연속적으로 배치되므로 cpu의 논리주소를 물리주소로 변환하기 위한&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;페이지 테이블이 존재한다. 메모리에 저장하면 2중 참조가 되어 비효율적이므로&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가상주소를 물리주소로 변환하는 mmu 내부의 tlb 캐시를 참조하도록 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 주소를 사용할 때, 페이지 번호와 페이지 내부에서의 변위를 함께 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;페이지가 너무 많아지면 페이지 테이블이 너무 커지고 메모리의 공간을 차지하므로&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;페이지를 계층적으로 설계하는 계층적 페이지 시스템을 적용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;copy on write&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로세스를 fork 할 시 프로세스를 복사해야 하기에 메모리 사용량이 늘어난다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 fork한 프로세스를 수정하지 않는다면 굳이 복사할 필요가 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러므로&amp;nbsp; fork 할 당시에는 복사된 프로세스도 동일한 프레임을 가리키도록 설정하고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특정 프레임에 해당하는 부분을 수정할 경우에 페이지 폴트를 발생시키고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 프레임 부분만을 복사한뒤 테이블을 수정한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본숙제&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;P400. 확인문제 1&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최초로 발견한 적재 가능한 빈 공간에 프로세스를 배치 -&amp;gt; 최초적합&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로세스가 적재될 수 있는 가장 큰 공간에 프로세스를 배치 -&amp;gt; 최악적합&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로세스가 적재될 수 있는 가장 작은 공간에 프로세스를 배치 -&amp;gt;최적적합.&lt;/p&gt;</description>
      <category>혼공단/컴구운체</category>
      <author>nownow</author>
      <guid isPermaLink="true">https://nownow.tistory.com/254</guid>
      <comments>https://nownow.tistory.com/254#entry254comment</comments>
      <pubDate>Mon, 24 Feb 2025 16:25:01 +0900</pubDate>
    </item>
    <item>
      <title>혼공컴운 5주차 (동기화, deadlock)</title>
      <link>https://nownow.tistory.com/253</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=SJ_AqcH1OUQ&amp;amp;t=1489s&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.youtube.com/watch?v=SJ_AqcH1OUQ&lt;/a&gt;&lt;/p&gt;
&lt;figure data-ke-type=&quot;video&quot; data-ke-style=&quot;alignCenter&quot; data-video-host=&quot;youtube&quot; data-video-url=&quot;https://www.youtube.com/watch?v=SJ_AqcH1OUQ&quot; data-video-thumbnail=&quot;https://scrap.kakaocdn.net/dn/cb4oBU/hyYfEY0dyY/QyQhnmfYfPazLxPCMJaUek/img.jpg?width=1280&amp;amp;height=720&amp;amp;face=0_0_1280_720,https://scrap.kakaocdn.net/dn/xpnry/hyYfAbcKZc/ZrI2L3MkHZv5OeEgpDm2V1/img.jpg?width=1280&amp;amp;height=720&amp;amp;face=0_0_1280_720&quot; data-video-width=&quot;860&quot; data-video-height=&quot;484&quot; data-video-origin-width=&quot;860&quot; data-video-origin-height=&quot;484&quot; data-ke-mobilestyle=&quot;widthContent&quot; data-video-title=&quot;‭ ‭ ‭ ‭ ‭ ‭ ‭ ‭ ‭ ‭ ‭ ‭ ‭ ‭ ‭ ‭ ‭ ‭&quot; data-original-url=&quot;&quot;&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/SJ_AqcH1OUQ&quot; width=&quot;860&quot; height=&quot;484&quot; frameborder=&quot;&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;figcaption style=&quot;display: none;&quot;&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동기화&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따로 정리한 포스트와 참고해서 보기 좋은 영상.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://nownow.tistory.com/247&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://nownow.tistory.com/247&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1739873237973&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;동기화 (mutex, Semaphore, monitor)&quot; data-og-description=&quot;동기화의 필요성&amp;nbsp;멀티스레딩으로 갯수를 세는 상황을 가정해보자.int target=0;을 2개의 스레드에서 50번씩 target++; 즉 값을 1씩 100번 늘리려고 한다.target++;라는 연산을 어셈블리로 생각해보면&amp;nbsp;1. LO&quot; data-og-host=&quot;nownow.tistory.com&quot; data-og-source-url=&quot;https://nownow.tistory.com/247&quot; data-og-url=&quot;https://nownow.tistory.com/247&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/qXCvR/hyYfSQwXfx/8Kv6K4gudmLJXL0EFHsmmK/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/bEmR5h/hyYfGbntJ1/devFAGO9P7w1KdoqXXKMX0/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800&quot;&gt;&lt;a href=&quot;https://nownow.tistory.com/247&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://nownow.tistory.com/247&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/qXCvR/hyYfSQwXfx/8Kv6K4gudmLJXL0EFHsmmK/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/bEmR5h/hyYfGbntJ1/devFAGO9P7w1KdoqXXKMX0/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;동기화 (mutex, Semaphore, monitor)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;동기화의 필요성&amp;nbsp;멀티스레딩으로 갯수를 세는 상황을 가정해보자.int target=0;을 2개의 스레드에서 50번씩 target++; 즉 값을 1씩 100번 늘리려고 한다.target++;라는 연산을 어셈블리로 생각해보면&amp;nbsp;1. LO&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;nownow.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=gTkvX2Awj6g&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.youtube.com/watch?v=gTkvX2Awj6g&lt;/a&gt;&lt;/p&gt;
&lt;figure data-ke-type=&quot;video&quot; data-ke-style=&quot;alignCenter&quot; data-video-host=&quot;youtube&quot; data-video-url=&quot;https://www.youtube.com/watch?v=gTkvX2Awj6g&quot; data-video-thumbnail=&quot;https://scrap.kakaocdn.net/dn/j1qVW/hyYfNO9tiu/PyE57vo1wKh9iMEjsXZKpk/img.jpg?width=1280&amp;amp;height=720&amp;amp;face=0_0_1280_720,https://scrap.kakaocdn.net/dn/cEzOQn/hyYjwZh1zW/L0Di3Vq9u4XXpRXs7BPQ5k/img.jpg?width=1280&amp;amp;height=720&amp;amp;face=0_0_1280_720&quot; data-video-width=&quot;860&quot; data-video-height=&quot;484&quot; data-video-origin-width=&quot;860&quot; data-video-origin-height=&quot;484&quot; data-ke-mobilestyle=&quot;widthContent&quot; data-video-title=&quot;스핀락(spinlock) 뮤텍스(mutex) 세마포(semaphore) 각각의 특징과 차이 완벽 &quot; data-original-url=&quot;&quot;&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/gTkvX2Awj6g&quot; width=&quot;860&quot; height=&quot;484&quot; frameborder=&quot;&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;figcaption style=&quot;display: none;&quot;&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;deadlock&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;교착상태에 도달할 수 있는 조건&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(1)비선점&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; 선점형 스케줄링과 같이 타 프로세스가 사용중인 자원을 뺏어오기가 불가능&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(2)순환참조&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;자원과 자원을 요구하는프로세스, 자원을 사용중인 프로세스가 cycle을 이룰 때&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(3)상호배제&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;여러 프로세스가 자원을 공유해서 사용할 수 없음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(4)hold and wait&amp;nbsp; &amp;nbsp; &amp;nbsp; 한 자원의 lock을 얻고 다른 lock을 얻기 위해 대기한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;교착 상태 예방&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4가지 조건 중 하나 이상을 만족할 수 없도록 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;교착 상태 회피&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;안전순서열에 의해 프로세스간 자원 할당 순서를 지정한대로 처리하고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;안전순서열이 지정되어 시스템이 안전상태로 움직일 때만 자원을 할당한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;교착상태 회복&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;교착상태 감지시 선점을 통해 자원을 몰아주거나 교착상태가 발생한 프로세스들을 종료.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;교착상태를 무시하는 타조알고리즘.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본숙제&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;p.363 확인문제 1&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;뮤텍스 락과 세마포에 대한 설명으로 옳지 않은 것&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(4)세마포를 이용하면 반드시 바쁜 대기를 해야 합니다 (X)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;세마포 방식에서는 wait 호출로 대기큐에 있는 프로세스를 signal로 깨우는 형태로 관리된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>혼공단/컴구운체</category>
      <author>nownow</author>
      <guid isPermaLink="true">https://nownow.tistory.com/253</guid>
      <comments>https://nownow.tistory.com/253#entry253comment</comments>
      <pubDate>Tue, 18 Feb 2025 21:07:07 +0900</pubDate>
    </item>
    <item>
      <title>혼공컴운 4주차 (프로세스와 스레드)</title>
      <link>https://nownow.tistory.com/252</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=6SfLag6ktJc&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.youtube.com/watch?v=6SfLag6ktJc&lt;/a&gt;&lt;/p&gt;
&lt;figure data-ke-type=&quot;video&quot; data-ke-style=&quot;alignCenter&quot; data-video-host=&quot;youtube&quot; data-video-url=&quot;https://www.youtube.com/watch?v=6SfLag6ktJc&quot; data-video-thumbnail=&quot;https://scrap.kakaocdn.net/dn/AhR1j/hyYjkEzFRp/QkBsCd1K3SbvKBL9s7EzgK/img.jpg?width=1280&amp;amp;height=720&amp;amp;face=106_68_1124_278,https://scrap.kakaocdn.net/dn/dwczQc/hyYfJMK686/cqoyau8Kdw0iybaerAlkX1/img.jpg?width=1280&amp;amp;height=720&amp;amp;face=106_68_1124_278&quot; data-video-width=&quot;860&quot; data-video-height=&quot;484&quot; data-video-origin-width=&quot;860&quot; data-video-origin-height=&quot;484&quot; data-ke-mobilestyle=&quot;widthContent&quot; data-video-title=&quot;Anime Jazz Cover アニソン | Hajimete No Chuu (from Kiteretsu Daihyakka) | Platina Jazz プラチナジャズ&quot; data-original-url=&quot;&quot;&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/6SfLag6ktJc&quot; width=&quot;860&quot; height=&quot;484&quot; frameborder=&quot;&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;figcaption style=&quot;display: none;&quot;&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로세스&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로그램이 실행되면 프로세스가 되며 커널영역에 PCB가 저장된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PCB에는 각 프로세스의 PC 레지스터 정보 등 주요 context가 저장되어 있고, 인터럽트 등으로&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;cpu를 점유중인 프로세스가 바뀌며 context switching이 일어날 때 PCB에 정보를 저장하고 불러온다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로세스들은 fork되며 복사되고 부모의 ppid를 저장하며 exec()되어 수정된다 (Windows에서는 다른방식)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생성된 프로세스는 ready 상태에서 cpu를 할당받는 dispatch되며 running 상태가 되고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;타이머 인터럽트에 의해 ready상태로 돌아가거나, 입출력 요청 후 wait 상태로 머문다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;입출력 완료 후 인터럽트 요청을 보내고 ready상태로 복귀한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;종료상태는 terminate&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스레드&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;fork()시에 데이터, 코드 힙, 스택 영역이 모두 복사되어 개별 저장공간을 갖는 프로세스와 달리&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스레드간에서는 프로세스 내 자원을 공유한다 각자 PC와 레지스터, 스택영역을 가질 뿐&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드, 데이터,힙 영역과 열린 파일과 같은 자원을 공유한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로세스 간에도 공유메모리를 두어 자원을 공유하거나 소켓등을 통해 통신하기도 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본숙제&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;p.304 1번&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; ㅣㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㄱ&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; ㅣ&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;(타이머 인터럽트)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; ㅣ&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;ㅣ&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(1) 생성 -&amp;gt; (2) 준비 -&amp;gt; (디스패치) -&amp;gt; (3) 실행 -&amp;gt; (4)종료&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; ㅣ&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;ㅣ&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; ㅣ&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;ㅣ&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; ㅣ&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;(입출력 요청)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; ㅣㅡㅡㅡㅡㅡㅡㅡㅡㅡ (5)대기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추가숙제&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Ch.11-2 1번&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;FCFS 알고리즘에 ABCD 순으로 삽입된다면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그대로 먼저들어간순으로 A-B-C-D 순으로 처리됨.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최근 시스템에 일반적으로 채택되는 CPU 스케줄링 기법인 다단계 피드백 큐를 사용할 경우&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모두 우선순위가 가장 높은 큐에 대기시키고 RR 방식과같이 일정 타임 슬라이스동안 실행 후&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;완료하지 못하면 그보다 낮은 우선순위 큐로 이동시키고 오래된 프로세스는 에이징 보정을 통해&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선순위를 높이는 방식으로 설계할 수 있다.&lt;/p&gt;</description>
      <category>혼공단/컴구운체</category>
      <author>nownow</author>
      <guid isPermaLink="true">https://nownow.tistory.com/252</guid>
      <comments>https://nownow.tistory.com/252#entry252comment</comments>
      <pubDate>Mon, 17 Feb 2025 21:32:57 +0900</pubDate>
    </item>
    <item>
      <title>아두이노 esp-01 http 통신(WiFiEsp.h)</title>
      <link>https://nownow.tistory.com/250</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/present0917/arduinoFingerPrint&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/present0917/arduinoFingerPrint&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 프로젝트를 진행하며 esp-01을 활용한 http 클라이언트 구현 중 내용정리 포스팅 입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹서버에 http request를 보내고 response를 처리하기 위해 esp-01 모듈을 구매하고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;WiFiEsp.h 라이브러리를 사용했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/bportaluri/WiFiEsp&quot;&gt;https://github.com/bportaluri/WiFiEsp&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;라이브러리 git repo의 examples와 포럼 글을 참고해 작성했습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1736748055135&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void httpRequest() {
  client.stop();
  client.flush();
  client.setTimeout(10000);
  if (client.connect(서버ip, 포트번호)) {
    client.println(&quot;GET /api/bus/1 HTTP/1.1&quot;);
    //client.println(&quot;Host: &quot;);
    client.println(&quot;Connection: close&quot;);
    client.println();
    lastConnectionTime = millis();
  } else {
    Serial.println(&quot;Connection failed&quot;);
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;get 요청입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1736748267658&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void postmethod() {
  String postData;
  postData = &quot;{\&quot;busId\&quot;: \&quot;&quot; + padNum + &quot;\&quot;, \&quot;Id\&quot;: \&quot;&quot; + postId + &quot;\&quot;, \&quot;message\&quot;: \&quot;&quot; + &quot;test&quot; + &quot;\&quot;}&quot;;
  int contentLength = postData.length();
  
  if (client.connect(SERVER, HTTPPORT)) {
    // Send HTTP POST request
    client.print(&quot;POST &quot;);
    client.print(PATH);
    client.print(&quot; HTTP/1.1\r\n&quot;);
    client.print(&quot;Host: &quot;);
    client.print(SERVER);
    client.print(&quot;\r\n&quot;);
    client.print(&quot;Content-Type: application/json\r\n&quot;);
    client.print(&quot;Content-Length: &quot;);
    client.print(contentLength);
    client.print(&quot;\r\n\r\n&quot;);
    client.print(postData);
    //client.print(&quot;\r\n&quot;);
    // Close connection
  } else {
    Serial.println(&quot;Failed to connect to server&quot;);
  }
  delay(1000);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;post 요청입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 메서드의 양식에 따라 \r\n도 신경써서 작성해주셔야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1736748887172&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void getbody() {
  bool isBody = false;
  String line;
  while (client.available()) {
    line = client.readStringUntil('\n');
    if (line == &quot;\r&quot;) {
      isBody = true;  // 헤더가 끝나고 본문이 시작됨
      continue;       // 본문의 첫 줄을 읽기 위해 계속
    }
    if (isBody) {
      DynamicJsonDocument doc(1024);
      //Serial.println(line);  // 본문 출력
      DeserializationError error = deserializeJson(doc, line);
      String response = doc[&quot;type&quot;];
      if (response!=&quot;null&quot;){
        Serial.println(response);
      }
      }
    } 
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;response를 파싱해서 저장하는 부분입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>아두이노</category>
      <author>nownow</author>
      <guid isPermaLink="true">https://nownow.tistory.com/250</guid>
      <comments>https://nownow.tistory.com/250#entry250comment</comments>
      <pubDate>Mon, 13 Jan 2025 15:16:06 +0900</pubDate>
    </item>
  </channel>
</rss>