<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>디벨로피아의 개발 블로그</title>
    <link>https://developia.tistory.com/</link>
    <description>What I cannot create,
 I do not understand</description>
    <language>ko</language>
    <pubDate>Thu, 9 Apr 2026 17:07:38 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>developia</managingEditor>
    <image>
      <title>디벨로피아의 개발 블로그</title>
      <url>https://tistory1.daumcdn.net/tistory/3378480/attach/98589e2916984ad48783e8bc0765b188</url>
      <link>https://developia.tistory.com</link>
    </image>
    <item>
      <title>[Spring] Java 8 LocalDateTime 직렬화/역직렬화 오류 해결</title>
      <link>https://developia.tistory.com/entry/Spring-Java-8-LocalDateTime-%EC%A7%81%EB%A0%AC%ED%99%94%EC%97%AD%EC%A7%81%EB%A0%AC%ED%99%94-%EC%98%A4%EB%A5%98-%ED%95%B4%EA%B2%B0</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;상황&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링 부트를 사용하다가 ObjectMapper objectMapper = new ObjectMapper(); 방식으로 사용하려고 하였는데 다음과 같은 에러가 발생하였다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;Java&amp;nbsp;8&amp;nbsp;date/time&amp;nbsp;type&amp;nbsp;`java.time.LocalDateTime`&amp;nbsp;not&amp;nbsp;supported&amp;nbsp;by&amp;nbsp;default:&amp;nbsp;add&amp;nbsp;Module&amp;nbsp;&quot;com.fasterxml.jackson.datatype:jackson-datatype-jsr310&quot;&amp;nbsp;to&amp;nbsp;enable&amp;nbsp;handling&lt;/span&gt;&lt;/blockquote&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;span style=&quot;font-family: 'Noto Serif KR'; color: #333333; text-align: center;&quot;&gt;jackson-datatype-jsr310 모듈을 사용하면 된다는 거 같은데 &lt;/span&gt;스프링 부트를 기본적으로 사용하는 경우 ObjectMapper가 자동 빈 주입되는 것으로 아는데 굳이 이걸 해줘야 하나? 라는 생각이 들었다.&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;그래서 직접 생성이 아닌(new ObjectMapper()) 다음과 같이 lombok을 사용하여 자동 빈 주입 받았더니 손쉽게 해결되었다.&lt;/p&gt;
&lt;pre id=&quot;code_1685456827029&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@RequiredArgsConstructor
public class CustomAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
    private final ObjectMapper objectMapper;
    ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링 부트에는 내장으로 포함되어 있으니 build.gradle에 implementation하는 방식보다는&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;507&quot; data-origin-height=&quot;59&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dHtlFo/btshWtZR7Kk/EK7e7PkxYkPv4I5B05DtP1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dHtlFo/btshWtZR7Kk/EK7e7PkxYkPv4I5B05DtP1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dHtlFo/btshWtZR7Kk/EK7e7PkxYkPv4I5B05DtP1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdHtlFo%2FbtshWtZR7Kk%2FEK7e7PkxYkPv4I5B05DtP1%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;507&quot; height=&quot;59&quot; data-origin-width=&quot;507&quot; data-origin-height=&quot;59&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Framework/Spring</category>
      <category>jsr310</category>
      <category>LocalDateTime</category>
      <author>developia</author>
      <guid isPermaLink="true">https://developia.tistory.com/42</guid>
      <comments>https://developia.tistory.com/entry/Spring-Java-8-LocalDateTime-%EC%A7%81%EB%A0%AC%ED%99%94%EC%97%AD%EC%A7%81%EB%A0%AC%ED%99%94-%EC%98%A4%EB%A5%98-%ED%95%B4%EA%B2%B0#entry42comment</comments>
      <pubDate>Tue, 30 May 2023 23:30:09 +0900</pubDate>
    </item>
    <item>
      <title>[Spring] Querydsl select null 처리</title>
      <link>https://developia.tistory.com/entry/Spring-Querydsl-select-null-%EC%B2%98%EB%A6%AC</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;스프링에서 querydsl(5.0.0 기준)을 사용하다보면 테이블에 있는 값이 아닌 테이블의 특정 값으로 projection해야 될 때가 있다.&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;select절만 예시로 보면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;select(new QDto(user, info)).from(user).leftJoin(info)...&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;이렇게 되어 있다고 할 때 공통의 querydsl을 사용해야 할 때 info 부분만 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;아래의 예시처럼 한 개의 쿼리로 동일한 dto로 사용할 때이다.&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;1. select(new QDto(user, &lt;span style=&quot;color: #ee2323;&quot;&gt;info&lt;/span&gt;)).from(user).leftJoin(info)...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. select(new QDto(user, &lt;span style=&quot;color: #ee2323;&quot;&gt;null&lt;/span&gt;)).from(user).leftJoin(info)...&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;리턴값에 null을 명시할 경우 컴파일 에러를 발생하지 않고 런타임으로 뜬다..&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;399&quot; data-origin-height=&quot;181&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/r8pG2/btr4kQMCd1G/gab7XylbBDPiGgANy7QVu1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/r8pG2/btr4kQMCd1G/gab7XylbBDPiGgANy7QVu1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/r8pG2/btr4kQMCd1G/gab7XylbBDPiGgANy7QVu1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fr8pG2%2Fbtr4kQMCd1G%2Fgab7XylbBDPiGgANy7QVu1%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;399&quot; height=&quot;181&quot; data-origin-width=&quot;399&quot; data-origin-height=&quot;181&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;div style=&quot;background-color: #222436; color: #c8d3f5;&quot;&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;select(new QDto(user, Expressions.constant(null))).from(user).leftJoin(info)...

select(new QDto(user, Expressions.nullExpression())).from(user).leftJoin(info)...&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;누가봐도 null처리 할 수 있는 것처럼 보이기 때문에 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;이렇게 하면 될 줄 알았다.&lt;span&gt; 하지만 &lt;span style=&quot;color: #ee2323;&quot;&gt;안된다!!&lt;/span&gt;&lt;/span&gt;&lt;/span&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;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;결과적으로 해결방법은 QDto부분에 매개변수가 다른 @QueryProjection을 넣으면 된다.&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1679032679046&quot; class=&quot;java&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Dto{
	...

    @QueryProjection
    public Dto(User user, Info info){
    	...
    }
    
    @QueryProjection
    public Dto(User user){
    	...
    }
}&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;이 경우에는 공통의 querydsl에서 dto도 같이 사용하기 때문에 발생하였는데 이런 경우는 특수한 경우이다. 결과적으로 볼 때 querydsl에서 select 절에 null은 넣을 수 없다.&amp;nbsp;&lt;/p&gt;</description>
      <category>Framework/Spring</category>
      <category>queryDSL</category>
      <category>select</category>
      <author>developia</author>
      <guid isPermaLink="true">https://developia.tistory.com/41</guid>
      <comments>https://developia.tistory.com/entry/Spring-Querydsl-select-null-%EC%B2%98%EB%A6%AC#entry41comment</comments>
      <pubDate>Fri, 17 Mar 2023 21:00:03 +0900</pubDate>
    </item>
    <item>
      <title>Java Collection - Queue</title>
      <link>https://developia.tistory.com/entry/Java-Collection-Queue</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;자바 컬렉션 중 하나인 Queue(큐)에 대해서 정리를 하기 위한 포스팅이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상세한 정보는 java.util 패키지에 Queue 클래스에 나와 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;예외 발생&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;값 반환&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;Insert(추가)&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;add(e)&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;offer(e)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;remove(삭제)&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;remove()&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;poll()&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;examine(검사)&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;element()&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;peek()&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;queue에 값을 추가하는 함수는 표와 같이 add(e), offer(e) 2가지이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;둘다 boolean을 반환하지만 add()의 경우 queue에 더 이상 추가할 수 없는 경우(queue의 용량이 꽉찬 경우) IllegalStateException 에러를 발생시키게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;offer의 경우 추가하지 못하는 경우 false를 반환한다. 그렇기 때문에 좀 더 안정적으로 사용할 수 있다.&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;remove와 poll의 경우에도 마찬가지로 더 이상 지울 수 없는 경우 remove함수는 NoSuchElementException 에러를 발생시킨다. poll 함수는 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;element와 peek도 마찬가지로 queue에 마지막 원소를 확인하는데 값이 없으면 element 함수는 NoSuchElementException 에러를, peek함수는 null을 반환한다.&lt;/p&gt;</description>
      <category>Language/Java</category>
      <category>Collection</category>
      <category>java</category>
      <category>Queue</category>
      <category>큐</category>
      <author>developia</author>
      <guid isPermaLink="true">https://developia.tistory.com/40</guid>
      <comments>https://developia.tistory.com/entry/Java-Collection-Queue#entry40comment</comments>
      <pubDate>Sun, 19 Feb 2023 14:45:27 +0900</pubDate>
    </item>
    <item>
      <title>JAVA JVM(자바 가상머신)에 관하여</title>
      <link>https://developia.tistory.com/entry/JAVA-JVM%EC%9E%90%EB%B0%94-%EA%B0%80%EC%83%81%EB%A8%B8%EC%8B%A0%EC%97%90-%EA%B4%80%ED%95%98%EC%97%AC</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;자바는 JVM(JAVA Virtual Machine) 위에서 동작한다. 이번 시간에는 JVM에 대한 정보를 공부해보도록 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;JVM은 다음과 같은 &lt;b&gt;특징&lt;/b&gt;을 가지고 있다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;JAVA와 OS 사이에서 중개자 역할&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;메모리관리, Gabage Collection의 역할을 수행&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;ARM 아키텍쳐 같은 하드웨어는 레지스터 기반으로 동작하지만 JVM은 스택기반으로 동작&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;jvm은 이러한 역할을 하고 있는데 애플리케이션 개발자가 사용할 때 몰라도 된다고 생각할 수 있다. 하지만 다음과 같은 이유로, 최소한의 동작원리는 이해하고 아는 것이 중요하다고 본다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;JVM을 알아야 하는 이유&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;한정된 메모리를 효율적으로 사용하여 최고의 성능을 내기 위하여&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;메모리를 효율적으로 사용하기 위해서(메모리 구조를 알아야 한다)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;JVM을 이해하기 위해서 우선 자바 프로그램의 실행과정에 대해서 알아보도록 하자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;자바 프로그램 실행과정&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;프로그램이 실행될 때 JVM은 OS로부터 이 프로그램이 필요로 하는 메모리를 할당 받는다. 이렇게 할당 받은 메모리를 용도에 따라 영역별로 관리한다.&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;자바 컴파일러(javac)가 자바 소스코드(.java)를 읽어들여 자바 바이트코드(.class)로 변환시킨다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Class Loader를 통해 이렇게 변환된 class파일들을 JVM으로 로딩한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;해석된 바이트코드는(class파일) Runtime Data Area(JVM 메모리 영역)에 배치되어 실질적인 수행이 이루어진게 된&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;이러한 실행과정에서 JVM은 필요에 따라 Thread Synchronization과 Gabage Collection같은 관리작업을 수행한다.&lt;/span&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;자바 프로그램 실행과정에서 Class Loaderd와 Runtime Data Area영역이라는 새로운 용어가 나왔다. 이 역시 JVM을 이해하기 위해서는 반드시 알아야하는 부분이다. 다음으로 본격적으로 JVM 구조에 대해서 알아보도록 하자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;JVM 구조&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;우선 설명하기 전에 전체 그림을 보면 이해하기 좋다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1346&quot; data-origin-height=&quot;1072&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Sav7l/btrZIsRJUCh/TmkSKqnKGWtCS4TnVqQOhk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Sav7l/btrZIsRJUCh/TmkSKqnKGWtCS4TnVqQOhk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Sav7l/btrZIsRJUCh/TmkSKqnKGWtCS4TnVqQOhk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSav7l%2FbtrZIsRJUCh%2FTmkSKqnKGWtCS4TnVqQOhk%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;1346&quot; height=&quot;1072&quot; data-origin-width=&quot;1346&quot; data-origin-height=&quot;1072&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;Class Loader&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;자바 컴파일러에 의해서 클래스파일로 변환된 파일들을 Runtime Data Area로 적재하는 역할&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;Execution Engine&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Class Loader에 의해 메모리에 적재된 바이트코드들을 기계어로 변경해 명령어 단위로 실행&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;명령어를 하나 하나 실행하는 인터프리터(Interpreter)방식과 JIT(Just In Time)방식이 있다.다시 말하자면 인터프리터 방식은 한줄 한줄 해석하기 때문에 속도가 느리다는 단점을 가지고 있다. 그래서 JIT이라는 방식이 나온것인데 처음엔 인터프리터 방식으로 구동되다가 일정 기준이 넘어가면 JIT 컴파일 방식으로 명령어를 실행한다. 실행할 때 컴파일을 하면서 해당 코드를 캐싱하여 속도를 빠르게 한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;JIT 컴파일러는 적절한 시간에 전체 바이트 코드를 네이티브 코드로 변경해서 Execution Engine이 네이티브로 컴파일된 코드를 실행하는 것으로 성능을 높이는 방식이다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;Garbage Collector(줄여서 GC)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;GC는 힙(heap) 메모리 영역에서 생성된 객체들 중에 참조되지 않은 객체들을 탐색 후 제거하는 역할을 한다. 정확히 어느 시점에서 역할을 하는 지는 알 수 없다.(참조가 없어지자마자 해제되는 것을 보장하지 않음)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;가장 중요한 특징은 GC가 수행되는 동안 GC를 수행하는 스레드가 아닌 다른 모든 스레드가 일시정지 된다는 것이다. 그렇기 때문에 Full GC가 일어나서 수 초간 모든 스레드가 정지된다면 아주 큰 장애로 이어질 수 있다. (Stop The World, STW라고도 한다)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;GC에 대해서도 굉장히 긴 글이 되기 때문에 더 상세한 내용은 다음 포스팅에서 진행한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&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;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;Method Area&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;클래스 정보를 처음 메모리 공간에 올릴 때 초기화되는 대상을 저장하기 위한 메모리 공간이다. &lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;클래스 멤버 변수의 이름, 데이터 타입, 접근 제어자 정보 같은 필드 정보와 메소드의 이름, 리턴타입, 파라미터, 접근 제어자 정보 같은 메소드 정보, type정보(인터페이스인지 클래스인지), Contant pool(문자 상수, 타입, 필드, 객체 참조가 저장), static 변수, final class 변수등이 생성되는 영역&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;Heap Area&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;new 키워드로 생성된 객체와 배열이 생성되는 영역, GC가 일어나는 영역&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Stack Area&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;지역 변수, 파라미터, 리턴 값 등이 생성되는 지역&lt;/span&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;PC 레지스터&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;스레드가 생성될 때마다 생성되는 지역이다. 현재 스레드가 실행되는 부분의 주소와 명령을 저장하고 있는 영역이다(CPU 레지스터와 다름) 이것을 이용하여 스레드를 돌아가면서 수행할 수 있게 한다.&lt;/span&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Native Method Stack&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;자바 외 언어로 작성된 네이티브 코드를 위한 영역이다.&lt;/span&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;스레드가 생성되었을 때를 기준으로 Method Aread, Heap Area는 공유되고 나머지는 각 스레드마다 생성되어 공유되지 않는다. 다음 시간에는 GC가 진행이 되는 JVM의 Heap area에 대해서 상세히 알아보도록 하자.&lt;/span&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;참고 및 출처&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;a href=&quot;https://asfirstalways.tistory.com/158&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://asfirstalways.tistory.com/158&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://jeong-pro.tistory.com/148&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://jeong-pro.tistory.com/148&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://s2choco.tistory.com/13&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://s2choco.tistory.com/13&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;a href=&quot;https://www.guru99.com/java-virtual-machine-jvm.html&quot;&gt;https://www.guru99.com/java-virtual-machine-jvm.html&lt;/a&gt;&lt;/p&gt;</description>
      <category>Language/Java</category>
      <category>java</category>
      <category>jvm</category>
      <category>자바 가상머신</category>
      <author>developia</author>
      <guid isPermaLink="true">https://developia.tistory.com/39</guid>
      <comments>https://developia.tistory.com/entry/JAVA-JVM%EC%9E%90%EB%B0%94-%EA%B0%80%EC%83%81%EB%A8%B8%EC%8B%A0%EC%97%90-%EA%B4%80%ED%95%98%EC%97%AC#entry39comment</comments>
      <pubDate>Sat, 18 Feb 2023 16:39:30 +0900</pubDate>
    </item>
    <item>
      <title>자바 진법 변환(2진법 10진법 등)</title>
      <link>https://developia.tistory.com/entry/%EC%9E%90%EB%B0%94-%EC%A7%84%EB%B2%95-%EB%B3%80%ED%99%982%EC%A7%84%EB%B2%95-10%EC%A7%84%EB%B2%95-%EB%93%B1</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;자바에서 진수(진법) 변환하는 방식은 래퍼클래스의 함수를 통해서 이용하면 쉽게 변환이 가능하다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특이사항은 다른 10진법에서 다른 진법으로 변환할 때 리턴값은 String이라는 점이다.&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;먼저 가장 흔한 2진법과 10진법 변환을 살펴보자.&lt;/p&gt;
&lt;pre id=&quot;code_1676555954196&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int i = 123;
// 10진수 &amp;gt; 2진수
String binaryString = Integer.toBinaryString(i);
// 출력 1111011

// 2진수 &amp;gt; 10진수
int binaryToDecimal = Integer.parseInt(binaryString, 2);
// 출력 123&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;다른 진법은 많이 쓸 일은 없긴한데 간단하므로 쉽게 알아보도록 하자.&lt;/p&gt;
&lt;pre id=&quot;code_1676556084777&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 10진수 &amp;gt; 8진수
String octalString = Integer.toOctalString(i);
// 173

// 8진수 &amp;gt; 10진수
int octalToDecimal = Integer.parseInt(octalString, 8);
// 123

// 10진수 &amp;gt; 16진수
String hexString = Integer.toHexString(i);
// 7b&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;</description>
      <category>Language/Java</category>
      <category>java</category>
      <category>자바</category>
      <category>진법</category>
      <author>developia</author>
      <guid isPermaLink="true">https://developia.tistory.com/38</guid>
      <comments>https://developia.tistory.com/entry/%EC%9E%90%EB%B0%94-%EC%A7%84%EB%B2%95-%EB%B3%80%ED%99%982%EC%A7%84%EB%B2%95-10%EC%A7%84%EB%B2%95-%EB%93%B1#entry38comment</comments>
      <pubDate>Thu, 16 Feb 2023 23:05:34 +0900</pubDate>
    </item>
    <item>
      <title>[Mysql] docker compose로 mysql 설치 (+m1 맥북)</title>
      <link>https://developia.tistory.com/entry/Mysql-docker-compose%EB%A1%9C-mysql-%EC%84%A4%EC%B9%98-m1-%EB%A7%A5%EB%B6%81</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;맥북에서 docker를 설치하려면 &lt;a href=&quot;https://www.docker.com/products/docker-desktop/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;공식 사이트&lt;/a&gt;에서&amp;nbsp; docker desktop을 설치하고 실행하면 됩니다.&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;공식 사이트를 들어가보면 다음과 같이 인텔 기반의 맥북과 실리콘(m1, m2) 기반의 맥북 설치버전이 나뉘어진 것을 알 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1342&quot; data-origin-height=&quot;644&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dwPG5J/btrFFOUsONh/TmWK6esmzKFBSrERlSvNk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dwPG5J/btrFFOUsONh/TmWK6esmzKFBSrERlSvNk0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dwPG5J/btrFFOUsONh/TmWK6esmzKFBSrERlSvNk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdwPG5J%2FbtrFFOUsONh%2FTmWK6esmzKFBSrERlSvNk0%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;579&quot; height=&quot;278&quot; data-origin-width=&quot;1342&quot; data-origin-height=&quot;644&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;docker 까지는 설치가 무난하지만 이번에는 m1 기반의 맥북에서 docker로 mysql를 설치해보는 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(다운 받을 버전은 &lt;a href=&quot;https://hub.docker.com/_/mysql?tab=tags&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;docker hub 공식 사이트&lt;/a&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;pre id=&quot;code_1656135071169&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;- db
    - conf.d
    - data
        - ...
    - initdb.d - sql 문을 넣어두는 부분 생략가능
        - create_table.sql
        - load_data.sql
- docker-compose.yml
- .env
- my.cnf&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각각 간단히 설명해보면, conf.d는 내부 mysql 설정정보이다. 해당 사항은 사용해보지 않아서 정확한 정보는 모르겠..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;data는 mysql docker 내부 데이터 정보가 들어가는 곳이고 initdb.d 부분은 이미 써둔것처럼 sql를 미리 작성하여 생성시 호출하는 부분입니다. (예제에서는 생략)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음으로 .env파일은 계정정보를 담은 부분이고 my.cnf는 mysql character set 정보를 담는 부분입니다. (이 부분이 사실 mysql에 전반적인 설정을 변경할 수 있는 부분이지만 이번 예제 실습에서는 인코딩 부분만을 담았습니다.)&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_1656135050777&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;mkdir -p db/conf.d db/data&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;다음 정보는 docker mysql로 실행할 수 있는 docker compose 정보입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1656134746136&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;version: &quot;3&quot;

services:
  db:
    container_name: mysql_docker
    image: mysql
    ports:
      - 3306:3306
    volumes:
      - ./db/conf.d:/etc/mysql/conf.d
      - ./db/data:/var/lib/mysql
      - ./my.cnf:/etc/mysql/my.cnf
    env_file: .env
    environment:
      TZ: Asia/Seoul
    networks:
      - backend
    restart: always
    command: # 명령어 실행
      - --character-set-server=utf8mb4
      - --collation-server=utf8mb4_unicode_ci

networks:
  backend:&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;다음은 환경변수 설정을 담은 .env파일입니다. 계정 정보는 관리에 주의할 것!&lt;/p&gt;
&lt;pre id=&quot;code_1656134902390&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;MYSQL_HOST=localhost
MYSQL_PORT=3306
MYSQL_ROOT_PASSWORD=password

MYSQL_USER=user
MYSQL_PASSWORD=password&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;character set 정보를 담은 my.cnf파일 정보입니다. 해당 정보를 입력하지 않아서 예전에 latin1 인코딩이 기본설정이라 엄청 헤맨 적이 있습니다. 인코딩에 문제가 있다면 꼭 입력하시길.&lt;/p&gt;
&lt;pre id=&quot;code_1656135371266&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[client]
default-character-set = utf8mb4

[mysql]
default-character-set = utf8mb4

[mysqld]
character-set-client-handshake = FALSE
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci&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;이렇게 구성을 하고 docker-compose.yml 경로에서 docker-compose up -d 명령어를 수행하면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 아마 이렇게 실행하시면 m1 맥북의 경우에는 mysql docker image를 찾을 수 없다고 나올 수 있습니다.&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;b&gt;docker image를 pull받을 때 플랫폼을 명시적으로 작성&lt;/b&gt;해주면 해결됩니다. 그래서 보통 관련 플랫폼을 명시한 이미지를 먼저 pull하고 수행하면 잘 동작하는 것을 알 수 있습니다.&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;다음 명령어를 미리 수행하여 docker image를 pull 받으시면 됩니다. (mysql 5, 8 버전에 현재 가장 최근 버전에 대한 이미지 정보입니다.)&lt;/p&gt;
&lt;pre id=&quot;code_1656134627011&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# mysql 8버전
docker pull --platform linux/amd64 mysql:8.0.29

# mysql 5버전
docker pull --platform linux/amd64 mysql:5.7.38&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;a href=&quot;https://github.com/developiaa/blog/tree/main/docker/mysql&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;github&lt;/a&gt;에서 확인하실 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도움이 되셨다면 star 한번 부탁드립니다 :)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>DataBase/Mysql</category>
      <category>docker</category>
      <category>docker compose</category>
      <category>M1</category>
      <category>MYSQL</category>
      <author>developia</author>
      <guid isPermaLink="true">https://developia.tistory.com/37</guid>
      <comments>https://developia.tistory.com/entry/Mysql-docker-compose%EB%A1%9C-mysql-%EC%84%A4%EC%B9%98-m1-%EB%A7%A5%EB%B6%81#entry37comment</comments>
      <pubDate>Sat, 25 Jun 2022 21:00:49 +0900</pubDate>
    </item>
    <item>
      <title>[Spring] Test 코드에서 @Slf4j 사용하기</title>
      <link>https://developia.tistory.com/entry/Spring-Test-%EC%BD%94%EB%93%9C%EC%97%90%EC%84%9C-Slf4j-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0</link>
      <description>&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;일반적으로 스프링 부트로 개발을 할 때 lombok 라이브러리는 거의 필수이므로, @Slf4j를 쉽게 어노테이션 형식으로 사용하곤 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(@Slf4j는&lt;span&gt;&amp;nbsp;&lt;/span&gt;Simple Logging Facade for Java의 줄임말로 로깅을 위해서 사용된다고 보면 된다.)&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_1651582355859&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Slf4j
@RequiredArgsConstructor
@RequestMapping(&quot;/v1/api/members&quot;)
@RestController
public class MemberController {

    @PostMapping
    public String createMember(@RequestBody @Validated MemberCreateRequest memberCreateRequest) {
        log.info(&quot;정보 확인 -&amp;gt;{}&quot;, memberCreateRequest);
        return &quot;success&quot;;
    }
}&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;프로젝트 경로에서 test 내부에 테스트 코드를 만들고 일반적인 서버에서 사용하듯 클래스 최상위에 동일하게 적어주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1651582392373&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Slf4j
@SpringBootTest
class OrderControllerTest {&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 기본 세팅에서는 테스트코드에서는 @Slf4j라고 쓴다고 해서 바로 사용할 수 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;gradle설정이 추가로 필요&lt;/b&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;build.gradle 파일에 dependencies 항목에 다음과 같이 추가하면 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1651582556494&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;testCompileOnly 'org.projectlombok:lombok'
testAnnotationProcessor 'org.projectlombok:lombok'&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 넣어주고 sync를 다시 맞추고 테스트 코드에서 적으면 잘 동작하는 것을 확인할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Framework/Spring</category>
      <category>SLF4j</category>
      <category>로깅</category>
      <author>developia</author>
      <guid isPermaLink="true">https://developia.tistory.com/36</guid>
      <comments>https://developia.tistory.com/entry/Spring-Test-%EC%BD%94%EB%93%9C%EC%97%90%EC%84%9C-Slf4j-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0#entry36comment</comments>
      <pubDate>Tue, 3 May 2022 21:57:02 +0900</pubDate>
    </item>
    <item>
      <title>[Spring] Domain time mapping</title>
      <link>https://developia.tistory.com/entry/Spring-Domain-time-mapping</link>
      <description>&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;스프링에서 도메인 엔티티를 생성할 때 db 컨벤션에 따라 createdAt, updatedAt을 자주 사용하곤 하는데 이 때 다음과 같은 어노테이션을 자주 사용하곤 한다.&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;@CreationTimestamp, @UpdateTimestamp&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;우선, @CreationTimestamp는 insert와 같은 DML(Data Manipulation Language)이 이루어질 때 자동적으로 현재시간을 입력해주는 어노테이션이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 @UpdateTimestamp는 DML중 update 쿼리가 발생할 때, 자동적으로 현재시간을 입력해주는 어노테이션이다.&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 class=&quot;less&quot;&gt;&lt;code&gt;@CreationTimestamp
@Column(name = &quot;created_at&quot;)
private LocalDateTime createdAt;

@UpdateTimestamp
@Column(name = &quot;updated_at&quot;)
private LocalDateTime updatedAt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 해당 어노테이션은 import문을 보면 hibernate에서 오는 것을 알 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;hibernate가 안좋다거나 하는 것은 아니지만, 스프링 프레임워크에서도&amp;nbsp; 이와 동일한 것을 제공한다. 그것은 @CreatedDate 어노테이션이다.(수정시에는 @LastModifiedDate로 제공해준다.)&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;하이버네이트를 자주 사용하기에, 문제는 없고 굳이 차이가 있다면 스프링에서 제공하는 @CreatedDate는 @EnableJpaAuditing을 해주어야한다. 하이버네이트의 경우에는 안해줘도 된다는 점이다. @EnableJpaAuditing은 간단히 말해서 특정 데이터를 보고 있다가 생성 또는 수정이 발생하면 자동으로 값을 넣어주는 기능이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아무래도 프레임워크가 제공해주는 스프링만에 기능을 사용하는 경우에는 @CreatedDate, @LastModifiedDate를 사용하는 편이 좋을 것 같다.&lt;/p&gt;</description>
      <category>Framework/Spring</category>
      <category>@CreatedDate</category>
      <category>@CreationTimestamp</category>
      <category>@LastModifiedDate</category>
      <category>@UpdateTimestamp</category>
      <author>developia</author>
      <guid isPermaLink="true">https://developia.tistory.com/34</guid>
      <comments>https://developia.tistory.com/entry/Spring-Domain-time-mapping#entry34comment</comments>
      <pubDate>Mon, 25 Apr 2022 23:16:09 +0900</pubDate>
    </item>
    <item>
      <title>[Mysql] Data Truncated error</title>
      <link>https://developia.tistory.com/entry/Mysql-Data-Truncated-error</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Mysql 사용 중에 다음과 같은 에러를 보게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;data truncated for column&lt;/blockquote&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;p data-ke-size=&quot;size16&quot;&gt;해당 에러는 일반적으로 db의 설정된 자료형에 범위보다 큰 데이터를 넣는 경우 발생한다.&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;업데이트를 원하는 데이터는 varchar(10)이었고, 데이터의 크기는 딱 11글자였다. 그렇기에 한글자가 잘려서 표현되었다.&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;나의 경우에는 dev에는 varchar(20)으로 해서 잘 되었지만 qa서버에서 10으로 해두고 깜빡하고 설정을 해두지 않았기 때문이었다;;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이래서 qa 서버가 존재하는 듯..&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;varchar 크기를 증가시키면 해당 에러는 해결된다.&amp;nbsp;&lt;/p&gt;</description>
      <category>DataBase/Mysql</category>
      <category>error</category>
      <category>MYSQL</category>
      <author>developia</author>
      <guid isPermaLink="true">https://developia.tistory.com/33</guid>
      <comments>https://developia.tistory.com/entry/Mysql-Data-Truncated-error#entry33comment</comments>
      <pubDate>Fri, 15 Apr 2022 20:51:04 +0900</pubDate>
    </item>
    <item>
      <title>[Java] 객체 복사에 대한 고찰</title>
      <link>https://developia.tistory.com/entry/Java-%EA%B0%9D%EC%B2%B4-%EB%B3%B5%EC%82%AC%EC%97%90-%EB%8C%80%ED%95%9C-%EA%B3%A0%EC%B0%B0</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;제목은 거창하게 객체 복사에 대한 고찰이라고 적었지만 사실 개발자라면 흔히 들어본 shallow copy, deep copy 부분에 대한 포스팅이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;shallow copy는 얕은 복사라는 뜻으로 보통 주소값(참조값)을 복사한다는 뜻이고,&amp;nbsp;deep copy는 깊는 복사라는 뜻으로 주소값이 아닌 값 자체를 복사한다는 뜻이다.&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;이러한 부분을 상세히 이해하려면 stack, heap에 대하여 좀 더 공부를 하여야한다. 또 이 부분을 자세히 공부하려면 메모리에 대하여 공부를 하여야 한다. (역시 공부는 끝이 없..)&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;1번 예제)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;int a = 1;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 이런식으로 코드를 작성하게 되는 경우 변수 a와 1은 각자 다른 곳에 저장된다. 변수 a는 지역변수이므로 스택에 저장되며, 숫자 1은 상수이므로 상수풀이라고 하는 곳에 저장이 된다.&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;2번 예제)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;String test1 = &quot;abc&quot;;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;String test2 = new String(&quot;abc&quot;);&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 2번 예제는 String이 조금 특별히 취급되는 부분이다. 우선 자바에서 new 라고 생성하는 부분은 동적으로 생성되는 부분인 heap영역에서 생성된다. 그렇기 때문에 new String()방식으로 생성된 부분은 객체 방식으로 생성된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 처음처럼 바로 할당된 경우는 어떻게 될까? 정답은 리터럴로 생성되게 된다. 이럴경우 String test3 = &quot;abc&quot;라고 다른 부분에서 선언할 경우에도 &quot;abc&quot;라는 값이 새로 생성되는 것이 아니고 메모리에는 딱 하나만 올라가게 된다.&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1144&quot; data-origin-height=&quot;632&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/L7UTQ/btrzlhVJbfU/6xOkbytKFbIdPwHJYF2os0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/L7UTQ/btrzlhVJbfU/6xOkbytKFbIdPwHJYF2os0/img.png&quot; data-alt=&quot;https://www.journaldev.com/wp-content/uploads/2012/11/String-Pool-Java1.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/L7UTQ/btrzlhVJbfU/6xOkbytKFbIdPwHJYF2os0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FL7UTQ%2FbtrzlhVJbfU%2F6xOkbytKFbIdPwHJYF2os0%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;735&quot; height=&quot;406&quot; data-origin-width=&quot;1144&quot; data-origin-height=&quot;632&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.journaldev.com/wp-content/uploads/2012/11/String-Pool-Java1.png&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 그림은 Cat이라는 문자열로 예시를 들고 있는 데 s1, s2변수는 모두 같은 것을 가리키는 것을 알 수 있다.&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_1649945397318&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Developia {
    public String name;
    public Integer money;

    public Developia() {
    }

    public Developia(String name, Integer money) {
        this.name = name;
        this.money = money;
    }

    public String getName() {
        return name;
    }

    public Integer getMoney() {
        return money;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setMoney(Integer money) {
        this.money = money;
    }

    @Override
    public String toString() {
        return &quot;Developia{&quot; +
                &quot;money=&quot; + money +
                '}';
    }
    
    // 금액 차감
    public void spendMoney(Integer money) {
        this.money -= money;
    }


}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선&amp;nbsp; 돈이 연관되면 누구나 이해를 쉽게 할 수 있으니 통장과 유사하게 멤버변수로 name, money를 가지는 클래스를 작성해보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 기본적인 getter, setter와 편의를 위해 toString()를 오버라이드하였고, spendMoney메서드를 만들었다.&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_1649945547091&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Developia developiaMain = new Developia(&quot;A&quot;, 10000);
Developia developia1 = developiaMain;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 developiaMain이라는 A라는 사람의 통장에는 10000원을 가지고 있다. (생성자로 생성)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 = 연산자로 developia1이라는 객체에 할당하였다. (값을 복사)&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;그럼 이때 A가 1000원을 썼다면 복사한 developi1은 어떻게 될까?&lt;/p&gt;
&lt;pre id=&quot;code_1649945787643&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;developia1.spendMoney(1000);
System.out.println(&quot;developia1 = &quot; + developia1);
System.out.println(&quot;developiaMain = &quot; + developiaMain);&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;288&quot; data-origin-height=&quot;44&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/D3vI4/btrzpWJRcTg/szBI1Vu6lSRUnsa932ck10/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/D3vI4/btrzpWJRcTg/szBI1Vu6lSRUnsa932ck10/img.png&quot; data-alt=&quot;실행 결과&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/D3vI4/btrzpWJRcTg/szBI1Vu6lSRUnsa932ck10/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FD3vI4%2FbtrzpWJRcTg%2FszBI1Vu6lSRUnsa932ck10%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;288&quot; height=&quot;44&quot; data-origin-width=&quot;288&quot; data-origin-height=&quot;44&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;실행 결과&lt;/figcaption&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;이런 경우를 얕은 복사라고 한다. 얕은 복사는 주소값을 복사하여 서로 같은 부분을 바라본다. 그렇기 때문에 A가 돈을 1000원을 썼다하더라도 같은 주소를 바라보고 있기 때문에 developia1에 값도 1000원이 차감된 것을 알 수 있다.&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가지 알아보도록 하겠다.&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;다음 코드를 Developia class에 추가한다. 첫번째 방법은 직접 객체를 생성하여 복사하는 방법이다.&lt;/p&gt;
&lt;pre id=&quot;code_1649946298139&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public Developia(Developia developia) {
        this.name = developia.name;
        this.money = developia.money;
    }&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;역시 동일하게 테스트를 진행해본다.&lt;/p&gt;
&lt;pre id=&quot;code_1649946380674&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Developia developiaMain2 = new Developia(&quot;A&quot;, 10000);
Developia developia2 = new Developia();
developia2.setName(developiaMain2.getName());
developia2.setMoney(developiaMain2.getMoney());

developia2.spendMoney(1000);
System.out.println(&quot;developia2 = &quot; + developia2);
System.out.println(&quot;developiaMain2 = &quot; + developiaMain2);&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;293&quot; data-origin-height=&quot;49&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bsZYsB/btrzprXFNJ1/s0mzciYkelGkXhENXDfC41/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bsZYsB/btrzprXFNJ1/s0mzciYkelGkXhENXDfC41/img.png&quot; data-alt=&quot;실행결과&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bsZYsB/btrzprXFNJ1/s0mzciYkelGkXhENXDfC41/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbsZYsB%2FbtrzprXFNJ1%2Fs0mzciYkelGkXhENXDfC41%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;293&quot; height=&quot;49&quot; data-origin-width=&quot;293&quot; data-origin-height=&quot;49&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;실행결과&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번에는 developia2가 1000원을 소비했지만 main은 돈이 그대로인것을 알 수 있다. 자세히 코드를 살펴보면 main에서 name과 money를 가져와 setter메소드를 이용하여 값을 넣는 것을 알 수 있다.&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;단 이러한 방식은 실무에서 쓰일 수 없을 수도 있다. 이러한 방식 중에서 setMoney와 같은 메서드를 외부에 공개하지 않을 수 있기 때문이다. 일부러 money와 같은 필드를 만든 이유도 이 때문이다. 돈과 관련된 setter를 외부에 퍼블릭하게 쓰게 될 경우 다른 개발자들이 의도와 다르게 잘못 사용할 가능성이 높기 때문이다.&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;span&gt;다음 코드를 Developia class에 추가한다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1649946959604&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    // 복사 생성자를 이용한 방법
    public Developia(Developia developia) {
        this.name = developia.name;
        this.money = developia.money;
    }

    // 복사 팩토리 메소드를 이용한 방법
    public static Developia newObject(Developia developia) {
        // 기본 생성자 필요
        Developia d = new Developia();
        d.name = developia.name;
        d.money = developia.money;
        return d;
    }&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1649947174951&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 복사 생성자를 이용한 방법
Developia developiaMain2 = new Developia(&quot;A&quot;, 10000);
Developia developia2 = new Developia(developiaMain2);

developia2.spendMoney(1000);
System.out.println(&quot;developia2 = &quot; + developia2);
System.out.println(&quot;developiaMain2 = &quot; + developiaMain2);


// 복사 팩토리 메소드를 이용한 방법
Developia developiaMain3 = new Developia(&quot;A&quot;, 10000);
Developia developia3 = Developia.newObject(developiaMain3);

developia3.spendMoney(1000);
System.out.println(&quot;developia3 = &quot; + developia3);
System.out.println(&quot;developiaMain3 = &quot; + developiaMain3);&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;295&quot; data-origin-height=&quot;118&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dFAXYp/btrzrL1WyUl/VZjiD4qnRUkBlY5xIzdkBK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dFAXYp/btrzrL1WyUl/VZjiD4qnRUkBlY5xIzdkBK/img.png&quot; data-alt=&quot;실행결과&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dFAXYp/btrzrL1WyUl/VZjiD4qnRUkBlY5xIzdkBK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdFAXYp%2FbtrzrL1WyUl%2FVZjiD4qnRUkBlY5xIzdkBK%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;295&quot; height=&quot;118&quot; data-origin-width=&quot;295&quot; data-origin-height=&quot;118&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;실행결과&lt;/figcaption&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;복사 생성자는 Developia 타입을 통째로 받는 생성자를 만들어서 클래스 내부에서 새로 할당한 방법이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 복사 팩토리 메소드의 경우에는 복사 전용 메소드를 만드는 방식이다. static 메소드를 생성하기에 메모리적으로 손해가 발생할 수도 있지만 자주 객체를 복사하는 경우나 명시적으로 복사 메소드를 나타내기 위해서는 좋은 방법이다.&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;마지막 방법은 Cloneable interface를 구현하는 것이다. Developia 클래스를 다음과 같이 변경한다.&lt;/p&gt;
&lt;pre id=&quot;code_1649947551515&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Developia implements Cloneable {
	
    ...
    
    @Override
    public Developia clone() throws CloneNotSupportedException {
        return (Developia) super.clone();
    }
}&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;Cloneable 인터페이스는 들어가보면 사실 아무것도 없는 인터페이스이다. 이는 단순히 복제해도 되는 클래스임을 암시하는 용도로서 사용하는 것이다. 그래서 이를 믹스인 인터페이스라고도 하는 데, 이는 클래스가 자신의 타입에 추가하여 구현할 수 있는 타입을 말한다. 선택 가능한 기능을 제공하고, 그 기능을 제공받고자 하는 클래스에서 선언한다.&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;Cloneable 인터페이스를 처음 구현하면 clone 메소드는 접근제어자가 protected에 Object 타입을 반환하는 메소드가 생성되는데, 이를 적절히 변경해주어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 clone 메소드를 작성하여 호출하는데 만약 Cloneable 인터페이스를 구현하지 않는 경우 CloneNotSupportedException이 발생하므로 유의하도록 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1649947988059&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Developia developiaMain5 = new Developia(&quot;A&quot;, 10000);

try {
    Developia developia5 = developiaMain5.clone();
    developia5.spendMoney(1000);

    System.out.println(&quot;developia5 = &quot; + developia5);
    System.out.println(&quot;developiaMain5 = &quot; + developiaMain5);
} catch (CloneNotSupportedException e) {
    e.printStackTrace();
}&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;295&quot; data-origin-height=&quot;47&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FIKfz/btrzq6Zq5BX/BScKdZ5izmsK7EEYcvEqL0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FIKfz/btrzq6Zq5BX/BScKdZ5izmsK7EEYcvEqL0/img.png&quot; data-alt=&quot;실행결과&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FIKfz/btrzq6Zq5BX/BScKdZ5izmsK7EEYcvEqL0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFIKfz%2Fbtrzq6Zq5BX%2FBScKdZ5izmsK7EEYcvEqL0%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;295&quot; height=&quot;47&quot; data-origin-width=&quot;295&quot; data-origin-height=&quot;47&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;실행결과&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Cloneable 인터페이스를 구현한 방법도 잘 되는 것을 알 수 있다. 다만 이러한 방법은 예외를 던지기 때문에 유의해서 사용해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(하지만 배열은 clone 기능을 제대로 사용하는 유일한 예로 사용된다)&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;이렇게 객체를 복사하는 방법 4가지를 알아보았는 데, 자주 사용하는 방법은 복사 생성자 방법이나 복사 팩토리 메소드 방법이다. 물론 다른 방법들도 다른 방식에서는 유용하게 사용할 수 있으므로 알아두는 편이 좋을 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Language/Java</category>
      <category>clone</category>
      <category>cloneable</category>
      <category>Deep Copy</category>
      <category>shallow copy</category>
      <author>developia</author>
      <guid isPermaLink="true">https://developia.tistory.com/32</guid>
      <comments>https://developia.tistory.com/entry/Java-%EA%B0%9D%EC%B2%B4-%EB%B3%B5%EC%82%AC%EC%97%90-%EB%8C%80%ED%95%9C-%EA%B3%A0%EC%B0%B0#entry32comment</comments>
      <pubDate>Fri, 15 Apr 2022 00:01:53 +0900</pubDate>
    </item>
  </channel>
</rss>