<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>im-shung.log</title>
        <link>https://velog.io/</link>
        <description>아침형 인간이 목표 </description>
        <lastBuildDate>Tue, 28 Feb 2023 03:56:05 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>im-shung.log</title>
            <url>https://velog.velcdn.com/images/im-shung/profile/7356f15c-5c9e-468d-ad6f-ac79ca4f4eff/image.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. im-shung.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/im-shung" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[배열과 문자열] 순열 확인]]></title>
            <link>https://velog.io/@im-shung/%EB%B0%B0%EC%97%B4%EA%B3%BC-%EB%AC%B8%EC%9E%90%EC%97%B4-%EC%88%9C%EC%97%B4-%ED%99%95%EC%9D%B8</link>
            <guid>https://velog.io/@im-shung/%EB%B0%B0%EC%97%B4%EA%B3%BC-%EB%AC%B8%EC%9E%90%EC%97%B4-%EC%88%9C%EC%97%B4-%ED%99%95%EC%9D%B8</guid>
            <pubDate>Tue, 28 Feb 2023 03:56:05 GMT</pubDate>
            <description><![CDATA[<h1 id="q-문자열-두-개가-주어졌을-때-이-둘이-서로-순열-관계에-있는지-확인하는-메서드를-작성하라">Q. 문자열 두 개가 주어졌을 때 이 둘이 서로 순열 관계에 있는지 확인하는 메서드를 작성하라.</h1>
<h2 id="span-stylecolorred첫-번째-방법-정렬하라span"><span style="color:red">첫 번째 방법: 정렬하라</span></h2>
<h3 id="두-문자열이-순열관계에-있다는-말이-무슨-의미인지-설명해-보라-그-정의에-따라-문자열을-확인할-수-있겠는가">두 문자열이 순열관계에 있다는 말이 무슨 의미인지 설명해 보라. 그 정의에 따라 문자열을 확인할 수 있겠는가?</h3>
<p>순열 관계라는 것은 두 문자열에서 사용된 문자는 같은데 문자의 순서만 다른 형태라는 것을 의미한다. 따라서 문자열을 정렬하면 둘 다 같은 결과가 나와야 한다.</p>
<h3 id="시간-복잡도">시간 복잡도</h3>
<p>정렬은 O(n log n)의 시간이 걸린다. </p>
<blockquote>
<p> Java 정렬 방식 시간 복잡도</p>
</blockquote>
<ul>
<li>Arrays.sort()<ul>
<li>DualPivotQuicksort</li>
<li>평균 : O(nlog(n)) / 최악 : O(n^2)<pre><code class="language-java">public static void sort(char[] a) {
    DualPivotQuicksort.sort(a, 0, a.length - 1, null, 0, 0);
}</code></pre>
</li>
</ul>
</li>
<li>Collections.sort()<ul>
<li>TimeSort (삽입정렬과 합병정렬을 결합한 정렬)</li>
<li>평균, 최악 : O(nlog(n))<pre><code class="language-java">public static &lt;T extends Comparable&lt;? super T&gt;&gt; void sort(List&lt;T&gt; list) {
    list.sort(null);
}</code></pre>
</li>
</ul>
</li>
</ul>
<h3 id="코드">코드</h3>
<pre><code class="language-java">public class QuestionA {    
    public static String sort(String s) {
        char[] content = s.toCharArray();
        java.util.Arrays.sort(content);
        return new String(content);
    }

    public static boolean permutation(String s, String t) {
        return sort(s).equals(sort(t));
    }    

    public static void main(String[] args) {
        String[][] pairs = {{&quot;apple&quot;, &quot;papel&quot;}, {&quot;carrot&quot;, &quot;tarroc&quot;}, {&quot;hello&quot;, &quot;llloh&quot;}};
        for (String[] pair : pairs) {
            String word1 = pair[0];
            String word2 = pair[1];
            boolean anagram = permutation(word1, word2);
            System.out.println(word1 + &quot;, &quot; + word2 + &quot;: &quot; + anagram);
        }
    }
}</code></pre>
<hr>
<h2 id="span-stylecolorred-두-번째-방법-문자열에-포함된-문자-출현-횟수가-같은지-검사하라span"><span style="color:red"> 두 번째 방법: 문자열에 포함된 문자 출현 횟수가 같은지 검사하라</span></h2>
<p>순열의 정의, 즉 두 문자열이 동일한 문자 개수를 갖고 있다는 점을 이용해서 알고리즘을 구현합니다. 배열 두 개 사용해서 각 문자열 내의 문자 출현 횟수를 기록한 다음, 두 배열을 비교한다.</p>
<pre><code class="language-java">public class QuestionB {    
    public static boolean permutation(String s, String t) {
        if (s.length() != t.length()) return false; // Permutations must be same length

        int[] letters = new int[128]; // Assumption: ASCII
        for (int i = 0; i &lt; s.length(); i++) {
            letters[s.charAt(i)]++;
        }

        for (int i = 0; i &lt; t.length(); i++) {
            letters[t.charAt(i)]--;
            if (letters[t.charAt(i)] &lt; 0) {
                return false;
            }
        }

        return true; // letters array has no negative values, and therefore no positive values either
    }

    public static void main(String[] args) {
        String[][] pairs = {{&quot;apple&quot;, &quot;papel&quot;}, {&quot;carrot&quot;, &quot;tarroc&quot;}, {&quot;hello&quot;, &quot;llloh&quot;}};
        for (String[] pair : pairs) {
            String word1 = pair[0];
            String word2 = pair[1];
            boolean anagram = permutation(word1, word2);
            System.out.println(word1 + &quot;, &quot; + word2 + &quot;: &quot; + anagram);
        }
    }
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[배열과 문자열] 중복 체크]]></title>
            <link>https://velog.io/@im-shung/%EB%B0%B0%EC%97%B4%EA%B3%BC-%EB%AC%B8%EC%9E%90%EC%97%B4-%EC%A4%91%EB%B3%B5%EC%9D%B4-%EC%97%86%EB%8A%94%EA%B0%80</link>
            <guid>https://velog.io/@im-shung/%EB%B0%B0%EC%97%B4%EA%B3%BC-%EB%AC%B8%EC%9E%90%EC%97%B4-%EC%A4%91%EB%B3%B5%EC%9D%B4-%EC%97%86%EB%8A%94%EA%B0%80</guid>
            <pubDate>Tue, 28 Feb 2023 03:21:34 GMT</pubDate>
            <description><![CDATA[<h1 id="문자열이-주어졌을-때-이-문자열에-같은-문자가-중복되어-등장하는지-확인하는-알고리즘을-작성하라">문자열이 주어졌을 때, 이 문자열에 같은 문자가 중복되어 등장하는지 확인하는 알고리즘을 작성하라.</h1>
<p>우선 ASCII 문자열인지 유니코드 문자열인지 확인한다. ASCII 문자열이라고 가정하고 문제를 풀어보겠다. </p>
<ol>
<li>문자 집합에서 i번째 문자가 배열 내에 존재하는지 표시하는 불린(boolean) 배열을 사용하는 것이다. 같은 원소에 두 번 접근하면 바로 false를 리턴한다.</li>
<li>문자열의 길이가 문자 집합의 크기보다 클 경우 바로 false를 반환해도 된다. 결국 256 문자를 한 번씩만 사용해서 길이가 280인 문자열을 만들 수는 없으니까 말이다.</li>
</ol>
<pre><code class="language-java">public class QuestionA {
    public static boolean isUniqueChars(String str) {
        if (str.length() &gt; 128) {
            return false;
        }
        boolean[] char_set = new boolean[128];
        for (int i = 0; i &lt; str.length(); i++) {
            int val = str.charAt(i);
            if (char_set[val]) return false;
            char_set[val] = true;
        }
        return true;
    }

    public static void main(String[] args) {
        String[] words = {&quot;abcde&quot;, &quot;hello&quot;, &quot;apple&quot;, &quot;kite&quot;, &quot;padle&quot;};
        for (String word : words) {
            System.out.println(word + &quot;: &quot; + isUniqueChars(word));
        }
    }

}</code></pre>
<blockquote>
<p><a href="https://github.com/careercup/CtCI-6th-Edition/blob/master/Java/Ch%2001.%20Arrays%20and%20Strings/Q1_01_Is_Unique/QuestionA.java">https://github.com/careercup/CtCI-6th-Edition/blob/master/Java/Ch%2001.%20Arrays%20and%20Strings/Q1_01_Is_Unique/QuestionA.java</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[JUnit 5 테스트 ]]></title>
            <link>https://velog.io/@im-shung/JUnit-5-%ED%85%8C%EC%8A%A4%ED%8A%B8</link>
            <guid>https://velog.io/@im-shung/JUnit-5-%ED%85%8C%EC%8A%A4%ED%8A%B8</guid>
            <pubDate>Thu, 23 Feb 2023 11:37:30 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>DB에 데이터를 저장하는 로직을 짜는 중인데 매번 수동으로 테스트하는 것이 힘들어서 테스트코드를 작성해보려고 한다.</p>
</blockquote>
<h1 id="junit-5-테스트">JUnit 5 테스트</h1>
<h2 id="개요">개요</h2>
<p>JUnit은 Java 생태계에서 가장 널리 사용되는 단위 테스트 프레임워크 중 하나입니다. JUnit5는 Java 8 이상의 새로운 기능을 지원합니다. </p>
<h3 id="junit-5--junit-platform--junit-jupiter--junit-vintage">JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage</h3>
<blockquote>
<ul>
<li>Junit Platform
JVM 위에서 테스트 프레임워크를 시작하기 위한 기반을 제공한다. 플랫폼에서 실행되는 테스트 프레임워크를 개발하기 위한 <a href="https://junit.org/junit5/docs/current/api/org.junit.platform.engine/org/junit/platform/engine/TestEngine.html">TestEngine API</a>를 정의한다.
IDEs(IntelliJ, Eclipse, Visual Studio Code)와 build tools(Gradle, Maven)에도 존재한다.</li>
</ul>
</blockquote>
<blockquote>
<ul>
<li>JUnit Jupiter
JUnit 5에서 테스트 및 확장을 작성하기 위한 프로그래밍 모델과 확장 모델의 조합이다. Jupiter 하위 프로젝트는 플랫폼에서 Jupiter 기반 테스트를 실행하기 위한 TestEngine을 제공한다.</li>
</ul>
</blockquote>
<blockquote>
<ul>
<li>JUnit Vintage
플랫폼에서 JUnit 3 및 JUnit 4 기반 테스트를 실행하기 위한 Test Engine을 제공한다. </li>
</ul>
</blockquote>
<h2 id="단위-테스트-repository-layer">단위 테스트 Repository Layer</h2>
<ul>
<li>DAO 계층을 단위 테스트하려면 먼저 메모리 내 테스트 데이터베이스가 필요합니다. 이는 @AutoConfigureTestDatabase를 사용하여 달성할 수 있습니다.</li>
<li>auto-configuration을 비활성하고, 대신 JPA 테스트와 관련된 구성만 적용하는 @DataJpaTest를 사용합니다. <ul>
<li>MySQL 등의 외부 DB를 사용하기 위해서는 (replace = Replace.NONE) 속성을 주어야 합니다.</li>
<li>테스트 종료 후 롤백도 같이 수행합니다</li>
</ul>
</li>
</ul>
<pre><code class="language-java">@ExtendWith(SpringExtend.class)
@DataJpaTest 
@AutoConfigureTestDatabase(replace = Replace.NONE)
class UserRepositoryTest {

    @Autowired
    UserRepository userRepository;

    @Test
    void save() {
        // given
        String userId = &quot;ADMIN&quot;;
        UserEntity user = UserEntity.builder().userId(userId).build();

        // when
        final UserEntity saveUser = userRepository.save(user);

        // then
        assertEquals(userId, saveUser.getUserId());
    }
}</code></pre>
<blockquote>
<p><a href="https://howtodoinjava.com/spring-boot2/testing/spring-boot-2-junit-5/">https://howtodoinjava.com/spring-boot2/testing/spring-boot-2-junit-5/</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[최단 경로 문제란]]></title>
            <link>https://velog.io/@im-shung/%EC%B5%9C%EB%8B%A8-%EA%B2%BD%EB%A1%9C-%EB%AC%B8%EC%A0%9C</link>
            <guid>https://velog.io/@im-shung/%EC%B5%9C%EB%8B%A8-%EA%B2%BD%EB%A1%9C-%EB%AC%B8%EC%A0%9C</guid>
            <pubDate>Thu, 23 Feb 2023 01:48:47 GMT</pubDate>
            <description><![CDATA[<h1 id="최단-경로-문제란">최단 경로 문제란</h1>
<ul>
<li>가중 그래프에서 </li>
<li>간선의 가중치의 합이 </li>
<li>최소가 되는 경로를 찾는 문제</li>
</ul>
<h2 id="문제의-종류">문제의 종류</h2>
<blockquote>
<ul>
<li>단일 출발 최단 경로
어떤 하나의 정점에서 출발하여 나머지 모든 정점 까지의 최단 경로를 찾는 문제</li>
</ul>
</blockquote>
<blockquote>
<ul>
<li>단일 도착 최단 경로
모든 정점에서 출발하여 어떤 하나의 정점까지의 최단 경로를 찾는 문제
그래프 내의 간선들을 뒤집으면 단일 출발 최단거리 문제로 바뀔 수 있다.</li>
</ul>
</blockquote>
<blockquote>
<ul>
<li>단일 쌍 최단 경로
어떤 정점 v에서 v&#39;로 가능한 최단경로를 구하는 문제</li>
</ul>
</blockquote>
<blockquote>
<ul>
<li>전체 쌍 최단 경로
모든 정점 쌍들 사이의 최단 경로를 찾는 문제</li>
</ul>
</blockquote>
<h2 id="주요-알고리즘">주요 알고리즘</h2>
<blockquote>
<ul>
<li>BFS(완전탐색 알고리즘)
가중치가 없거나 모든 가중치가 동일한 그래프에서 최단경로를 구하는 경우 가장 빠르다</li>
</ul>
</blockquote>
<blockquote>
<ul>
<li>다익스트라 알고리즘
음이 아닌 가중 그래프에서의 단일 쌍, 단일 출발, 단일 도착 최단 경로 문제</li>
</ul>
</blockquote>
<blockquote>
<ul>
<li>벨만-포드 알고리즘
가중 그래프에서의 단일 쌍, 단일 출발, 단일 도착 최단 경로 문제</li>
</ul>
</blockquote>
<blockquote>
<ul>
<li>플로이드-워셜 알고리즘
전체 쌍 최단 경로 문제</li>
</ul>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[Spring Cloud Config Server에서 Private Github Repository의 yml 설정 정보 접근하기]]></title>
            <link>https://velog.io/@im-shung/Spring-Cloud-Config-Server-SSH-%EC%84%A4%EC%A0%95%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@im-shung/Spring-Cloud-Config-Server-SSH-%EC%84%A4%EC%A0%95%ED%95%98%EA%B8%B0</guid>
            <pubDate>Wed, 15 Feb 2023 02:59:41 GMT</pubDate>
            <description><![CDATA[<p><strong>Spring Cloud Config Server</strong>에서 <strong>Private Github Repository</strong>에 있는 <strong>yml</strong> 설정을 가져오는 것을 구현해보겠습니다.</p>
<p>두 개의 repository가 필요합니다.</p>
<ul>
<li>Spring Cloud Config Server를 담당하는 프로젝트 repo </li>
<li>yml 파일이 있는 repo</li>
</ul>
<p>yml 파일을 private 하게 관리하기 위해서 이러한 구성을 따릅니다.</p>
<p>우선 yml 파일이 있는 repo부터 만들어보겠습니다.
<img src="https://velog.velcdn.com/images/im-shung/post/0da2c552-5474-44d5-a2e4-0a4fb73de0ae/image.png" alt="">
yml 파일 하나를 git private repository에 올립니다. 매우 간단..!! 
파일 안에는 원하는 설정 정보들을 적어주세요.</p>
<p>그리고 Spring Cloud Config Server 프로젝트를 생성하겠습니다.
저는 Spring Boot과 Gradle를 사용했습니다. build.gradle에 다음 요소를 넣어줬습니다. </p>
<pre><code class="language-build.gradle">implementation &#39;org.springframework.cloud:spring-cloud-config-server&#39;</code></pre>
<p>그리고 Main Application에 <code>@EnableConfigServer</code>를 붙여줍니다.</p>
<pre><code class="language-java">import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;

@SpringBootApplication
@EnableConfigServer
public class ConfigServiceApplication {

    public static void main(String[] args) {
        SpringApplication.run(ConfigServiceApplication.class, args);
    }

}
</code></pre>
<p>그 다음에 <code>application.yml</code>를 수정할 것입니다.
resources 하위에 원래는 <code>application.properties</code>가 들어있는데 yml로 확장자를 바꿔줬습니다.
<img src="https://velog.velcdn.com/images/im-shung/post/06f168d6-0fb5-4d4c-91e6-12e0a0ea4a9d/image.png" alt=""></p>
<p>다음 처럼 yml를 작성해야 합니다.</p>
<pre><code class="language-yml">server:
  port: 8888

spring:
    cloud:
      config:
        server:
          git:
            uri: git@gitserver.com:team/repo1.git
            ignoreLocalSshSettings: true
            privateKey: |
                         -----BEGIN RSA PRIVATE KEY-----
                         MIIEpgIBAAKCAQEAx4UbaDzY5xjW6hc9jwN0mX33XpTDVW9WqHp5AKaRbtAC3DqX
                         IXFMPgw3K45jxRb93f8tv9vL3rD9CUG1Gv4FM+o7ds7FRES5RTjv2RT/JVNJCoqF
                         ol8+ngLqRZCyBtQN7zYByWMRirPGoDUqdPYrj2yq+ObBBNhg5N+hOwKjjpzdj2Ud
                         1l7R+wxIqmJo1IYyy16xS8WsjyQuyC0lL456qkd5BDZ0Ag8j2X9H9D5220Ln7s9i
                         oezTipXipS7p7Jekf3Ywx6abJwOmB0rX79dV4qiNcGgzATnG1PkXxqt76VhcGa0W
                         DDVHEEYGbSQ6hIGSh0I7BQun0aLRZojfE3gqHQIDAQABAoIBAQCZmGrk8BK6tXCd
                         fY6yTiKxFzwb38IQP0ojIUWNrq0+9Xt+NsypviLHkXfXXCKKU4zUHeIGVRq5MN9b
                         BO56/RrcQHHOoJdUWuOV2qMqJvPUtC0CpGkD+valhfD75MxoXU7s3FK7yjxy3rsG
                         EmfA6tHV8/4a5umo5TqSd2YTm5B19AhRqiuUVI1wTB41DjULUGiMYrnYrhzQlVvj
                         5MjnKTlYu3V8PoYDfv1GmxPPh6vlpafXEeEYN8VB97e5x3DGHjZ5UrurAmTLTdO8
                         +AahyoKsIY612TkkQthJlt7FJAwnCGMgY6podzzvzICLFmmTXYiZ/28I4BX/mOSe
                         pZVnfRixAoGBAO6Uiwt40/PKs53mCEWngslSCsh9oGAaLTf/XdvMns5VmuyyAyKG
                         ti8Ol5wqBMi4GIUzjbgUvSUt+IowIrG3f5tN85wpjQ1UGVcpTnl5Qo9xaS1PFScQ
                         xrtWZ9eNj2TsIAMp/svJsyGG3OibxfnuAIpSXNQiJPwRlW3irzpGgVx/AoGBANYW
                         dnhshUcEHMJi3aXwR12OTDnaLoanVGLwLnkqLSYUZA7ZegpKq90UAuBdcEfgdpyi
                         PhKpeaeIiAaNnFo8m9aoTKr+7I6/uMTlwrVnfrsVTZv3orxjwQV20YIBCVRKD1uX
                         VhE0ozPZxwwKSPAFocpyWpGHGreGF1AIYBE9UBtjAoGBAI8bfPgJpyFyMiGBjO6z
                         FwlJc/xlFqDusrcHL7abW5qq0L4v3R+FrJw3ZYufzLTVcKfdj6GelwJJO+8wBm+R
                         gTKYJItEhT48duLIfTDyIpHGVm9+I1MGhh5zKuCqIhxIYr9jHloBB7kRm0rPvYY4
                         VAykcNgyDvtAVODP+4m6JvhjAoGBALbtTqErKN47V0+JJpapLnF0KxGrqeGIjIRV
                         cYA6V4WYGr7NeIfesecfOC356PyhgPfpcVyEztwlvwTKb3RzIT1TZN8fH4YBr6Ee
                         KTbTjefRFhVUjQqnucAvfGi29f+9oE3Ei9f7wA+H35ocF6JvTYUsHNMIO/3gZ38N
                         CPjyCMa9AoGBAMhsITNe3QcbsXAbdUR00dDsIFVROzyFJ2m40i4KCRM35bC/BIBs
                         q0TY3we+ERB40U8Z2BvU61QuwaunJ2+uGadHo58VSVdggqAo0BSkH58innKKt96J
                         69pcVH/4rmLbXdcmNYGm6iu+MlPQk4BUZknHSmVHIFdJ0EPupVaQ8RHT
                         -----END RSA PRIVATE KEY-----</code></pre>
<p><strong>port</strong> 번호와 <strong>uri</strong>, <strong>privateKey</strong>를 자신에 맞게 수정하시면 됩니다. </p>
<p><strong>uri 부분은 yml 파일이 있는 repo로 가서 SSH 부분 링크를 복사해서 넣으면 됩니다</strong>.
<img src="https://velog.velcdn.com/images/im-shung/post/f0715a37-0d2a-49b3-b91e-c7e65d93ced8/image.png" alt=""></p>
<p><strong>privateKey</strong>를 위해서 SSH Key를 생성하고 등록해야 합니다.</p>
<p>아무 디렉토리를 만들고 터미널을 열어서 다음 명령어를 치면 </p>
<pre><code class="language-bash">ssh-keygen -m PEM -t rsa -b 4096 -f config_server_deploy_key.rsa</code></pre>
<p><img src="https://velog.velcdn.com/images/im-shung/post/7a3da958-5a94-47a5-9e27-4b9206ff76c1/image.png" alt="">
공개키(<code>config_server_deploy_key.rsa.pub</code>)와 기본키(<code>config_server_deploy_key.rsa</code>)가 만들어집니다.</p>
<p>*<em>이 공개키를 yml이 있는 repo의 Deploy Key로 등록할 겁니다! *</em>
<img src="https://velog.velcdn.com/images/im-shung/post/f3cd3671-413c-4b02-b289-eadf9c87dc43/image.png" alt=""></p>
<p>yml이 있는 repo의 Settings &gt; Deploy Keys &gt; Add deploy key 를 클릭해주세요
그리고 만들었던 공개키를 복사 &amp; 붙여넣기 해줍니다.
<img src="https://velog.velcdn.com/images/im-shung/post/c50b8e21-3b0f-4d12-b59c-3a50c91ec44a/image.png" alt=""></p>
<p>다시 Spring Cloud Config Server 프로젝트의 application.yml 파일로 가서 privateKey 부분에 개인키를 복사 &amp; 붙여넣기 해줍니다.
<code>|</code> 와 <code>-----BEGIN RSA PRIVATE KEY-----</code> <code>-----END RSA PRIVATE KEY-----</code>를 빼먹지 않도록 조심해주세요. </p>
<blockquote>
<p>application.properties를 사용하신다면 privateKey 작성시 <a href="https://github.com/spring-cloud/spring-cloud-config/issues/1392#issuecomment-824766085">다음 링크</a>를 참고해주세요</p>
</blockquote>
<pre><code class="language-yml">server:
  port: 8888

spring:
    cloud:
      config:
        server:
          git:
            uri: git@gitserver.com:team/repo1.git
            ignoreLocalSshSettings: true
            privateKey: |
                         -----BEGIN RSA PRIVATE KEY-----
                         MIIEpgIBAAKCAQEAx4UbaDzY5xjW6hc9jwN0mX33XpTDVW9WqHp5AKaRbtAC3DqX
                         IXFMPgw3K45jxRb93f8tv9vL3rD9CUG1Gv4FM+o7ds7FRES5RTjv2RT/JVNJCoqF
                         ol8+ngLqRZCyBtQN7zYByWMRirPGoDUqdPYrj2yq+ObBBNhg5N+hOwKjjpzdj2Ud
                         1l7R+wxIqmJo1IYyy16xS8WsjyQuyC0lL456qkd5BDZ0Ag8j2X9H9D5220Ln7s9i
                         oezTipXipS7p7Jekf3Ywx6abJwOmB0rX79dV4qiNcGgzATnG1PkXxqt76VhcGa0W
                         DDVHEEYGbSQ6hIGSh0I7BQun0aLRZojfE3gqHQIDAQABAoIBAQCZmGrk8BK6tXCd
                         fY6yTiKxFzwb38IQP0ojIUWNrq0+9Xt+NsypviLHkXfXXCKKU4zUHeIGVRq5MN9b
                         BO56/RrcQHHOoJdUWuOV2qMqJvPUtC0CpGkD+valhfD75MxoXU7s3FK7yjxy3rsG
                         EmfA6tHV8/4a5umo5TqSd2YTm5B19AhRqiuUVI1wTB41DjULUGiMYrnYrhzQlVvj
                         5MjnKTlYu3V8PoYDfv1GmxPPh6vlpafXEeEYN8VB97e5x3DGHjZ5UrurAmTLTdO8
                         +AahyoKsIY612TkkQthJlt7FJAwnCGMgY6podzzvzICLFmmTXYiZ/28I4BX/mOSe
                         pZVnfRixAoGBAO6Uiwt40/PKs53mCEWngslSCsh9oGAaLTf/XdvMns5VmuyyAyKG
                         ti8Ol5wqBMi4GIUzjbgUvSUt+IowIrG3f5tN85wpjQ1UGVcpTnl5Qo9xaS1PFScQ
                         xrtWZ9eNj2TsIAMp/svJsyGG3OibxfnuAIpSXNQiJPwRlW3irzpGgVx/AoGBANYW
                         dnhshUcEHMJi3aXwR12OTDnaLoanVGLwLnkqLSYUZA7ZegpKq90UAuBdcEfgdpyi
                         PhKpeaeIiAaNnFo8m9aoTKr+7I6/uMTlwrVnfrsVTZv3orxjwQV20YIBCVRKD1uX
                         VhE0ozPZxwwKSPAFocpyWpGHGreGF1AIYBE9UBtjAoGBAI8bfPgJpyFyMiGBjO6z
                         FwlJc/xlFqDusrcHL7abW5qq0L4v3R+FrJw3ZYufzLTVcKfdj6GelwJJO+8wBm+R
                         gTKYJItEhT48duLIfTDyIpHGVm9+I1MGhh5zKuCqIhxIYr9jHloBB7kRm0rPvYY4
                         VAykcNgyDvtAVODP+4m6JvhjAoGBALbtTqErKN47V0+JJpapLnF0KxGrqeGIjIRV
                         cYA6V4WYGr7NeIfesecfOC356PyhgPfpcVyEztwlvwTKb3RzIT1TZN8fH4YBr6Ee
                         KTbTjefRFhVUjQqnucAvfGi29f+9oE3Ei9f7wA+H35ocF6JvTYUsHNMIO/3gZ38N
                         CPjyCMa9AoGBAMhsITNe3QcbsXAbdUR00dDsIFVROzyFJ2m40i4KCRM35bC/BIBs
                         q0TY3we+ERB40U8Z2BvU61QuwaunJ2+uGadHo58VSVdggqAo0BSkH58innKKt96J
                         69pcVH/4rmLbXdcmNYGm6iu+MlPQk4BUZknHSmVHIFdJ0EPupVaQ8RHT
                         -----END RSA PRIVATE KEY-----</code></pre>
<p>끝입니다. !! </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Spring Cloud Config Server, yml 파일, illegal base64 character 2d 오류 ]]></title>
            <link>https://velog.io/@im-shung/Spring-Cloud-Config-Server-yml-%ED%8C%8C%EC%9D%BC-illegal-base64-character-2d-%EC%98%A4%EB%A5%98</link>
            <guid>https://velog.io/@im-shung/Spring-Cloud-Config-Server-yml-%ED%8C%8C%EC%9D%BC-illegal-base64-character-2d-%EC%98%A4%EB%A5%98</guid>
            <pubDate>Wed, 15 Feb 2023 02:28:21 GMT</pubDate>
            <description><![CDATA[<pre><code class="language-yml">  spring:
    cloud:
      config:
        server:
          git:
            uri: git@gitserver.com:team/repo1.git
            ignoreLocalSshSettings: true
            hostKey: someHostKey
            hostKeyAlgorithm: ssh-rsa
            privateKey: |
                         -----BEGIN RSA PRIVATE KEY-----
                         MIIEpgIBAAKCAQEAx4UbaDzY5xjW6hc9jwN0mX33XpTDVW9WqHp5AKaRbtAC3DqX
                         IXFMPgw3K45jxRb93f8tv9vL3rD9CUG1Gv4FM+o7ds7FRES5RTjv2RT/JVNJCoqF
                         ol8+ngLqRZCyBtQN7zYByWMRirPGoDUqdPYrj2yq+ObBBNhg5N+hOwKjjpzdj2Ud
                         1l7R+wxIqmJo1IYyy16xS8WsjyQuyC0lL456qkd5BDZ0Ag8j2X9H9D5220Ln7s9i
                         oezTipXipS7p7Jekf3Ywx6abJwOmB0rX79dV4qiNcGgzATnG1PkXxqt76VhcGa0W
                         DDVHEEYGbSQ6hIGSh0I7BQun0aLRZojfE3gqHQIDAQABAoIBAQCZmGrk8BK6tXCd
                         fY6yTiKxFzwb38IQP0ojIUWNrq0+9Xt+NsypviLHkXfXXCKKU4zUHeIGVRq5MN9b
                         BO56/RrcQHHOoJdUWuOV2qMqJvPUtC0CpGkD+valhfD75MxoXU7s3FK7yjxy3rsG
                         EmfA6tHV8/4a5umo5TqSd2YTm5B19AhRqiuUVI1wTB41DjULUGiMYrnYrhzQlVvj
                         5MjnKTlYu3V8PoYDfv1GmxPPh6vlpafXEeEYN8VB97e5x3DGHjZ5UrurAmTLTdO8
                         +AahyoKsIY612TkkQthJlt7FJAwnCGMgY6podzzvzICLFmmTXYiZ/28I4BX/mOSe
                         pZVnfRixAoGBAO6Uiwt40/PKs53mCEWngslSCsh9oGAaLTf/XdvMns5VmuyyAyKG
                         ti8Ol5wqBMi4GIUzjbgUvSUt+IowIrG3f5tN85wpjQ1UGVcpTnl5Qo9xaS1PFScQ
                         xrtWZ9eNj2TsIAMp/svJsyGG3OibxfnuAIpSXNQiJPwRlW3irzpGgVx/AoGBANYW
                         dnhshUcEHMJi3aXwR12OTDnaLoanVGLwLnkqLSYUZA7ZegpKq90UAuBdcEfgdpyi
                         PhKpeaeIiAaNnFo8m9aoTKr+7I6/uMTlwrVnfrsVTZv3orxjwQV20YIBCVRKD1uX
                         VhE0ozPZxwwKSPAFocpyWpGHGreGF1AIYBE9UBtjAoGBAI8bfPgJpyFyMiGBjO6z
                         FwlJc/xlFqDusrcHL7abW5qq0L4v3R+FrJw3ZYufzLTVcKfdj6GelwJJO+8wBm+R
                         gTKYJItEhT48duLIfTDyIpHGVm9+I1MGhh5zKuCqIhxIYr9jHloBB7kRm0rPvYY4
                         VAykcNgyDvtAVODP+4m6JvhjAoGBALbtTqErKN47V0+JJpapLnF0KxGrqeGIjIRV
                         cYA6V4WYGr7NeIfesecfOC356PyhgPfpcVyEztwlvwTKb3RzIT1TZN8fH4YBr6Ee
                         KTbTjefRFhVUjQqnucAvfGi29f+9oE3Ei9f7wA+H35ocF6JvTYUsHNMIO/3gZ38N
                         CPjyCMa9AoGBAMhsITNe3QcbsXAbdUR00dDsIFVROzyFJ2m40i4KCRM35bC/BIBs
                         q0TY3we+ERB40U8Z2BvU61QuwaunJ2+uGadHo58VSVdggqAo0BSkH58innKKt96J
                         69pcVH/4rmLbXdcmNYGm6iu+MlPQk4BUZknHSmVHIFdJ0EPupVaQ8RHT
                         -----END RSA PRIVATE KEY-----
</code></pre>
<p><a href="https://docs.spring.io/spring-cloud-config/docs/current/reference/html/#_spring_cloud_config_server">공식 문서</a>를 통해서 ssh 설정을 하는데 <span style="color:red"><strong>illegal base64 character 2d</strong></span> 오류가 발생했다.
| 표시도 넣었고, -----BEGIN RSA PRIVATE KEY----- 주석도 잘 넣었는데 왜 오류가 나지??
yml를 properties로도 바꿔보고 했지만 결과는 똑같았다. </p>
<p>혹시나 하고 </p>
<pre><code class="language-yml">hostKey: someHostKey
hostKeyAlgorithm: ssh-rsa</code></pre>
<p>이 부분을 빼고 </p>
<pre><code class="language-yml">  spring:
    cloud:
      config:
        server:
          git:
            uri: git@gitserver.com:team/repo1.git
            ignoreLocalSshSettings: true
            privateKey: |
                         -----BEGIN RSA PRIVATE KEY-----
                         MIIEpgIBAAKCAQEAx4UbaDzY5xjW6hc9jwN0mX33XpTDVW9WqHp5AKaRbtAC3DqX
                         IXFMPgw3K45jxRb93f8tv9vL3rD9CUG1Gv4FM+o7ds7FRES5RTjv2RT/JVNJCoqF
                         ol8+ngLqRZCyBtQN7zYByWMRirPGoDUqdPYrj2yq+ObBBNhg5N+hOwKjjpzdj2Ud
                         1l7R+wxIqmJo1IYyy16xS8WsjyQuyC0lL456qkd5BDZ0Ag8j2X9H9D5220Ln7s9i
                         oezTipXipS7p7Jekf3Ywx6abJwOmB0rX79dV4qiNcGgzATnG1PkXxqt76VhcGa0W
                         DDVHEEYGbSQ6hIGSh0I7BQun0aLRZojfE3gqHQIDAQABAoIBAQCZmGrk8BK6tXCd
                         fY6yTiKxFzwb38IQP0ojIUWNrq0+9Xt+NsypviLHkXfXXCKKU4zUHeIGVRq5MN9b
                         BO56/RrcQHHOoJdUWuOV2qMqJvPUtC0CpGkD+valhfD75MxoXU7s3FK7yjxy3rsG
                         EmfA6tHV8/4a5umo5TqSd2YTm5B19AhRqiuUVI1wTB41DjULUGiMYrnYrhzQlVvj
                         5MjnKTlYu3V8PoYDfv1GmxPPh6vlpafXEeEYN8VB97e5x3DGHjZ5UrurAmTLTdO8
                         +AahyoKsIY612TkkQthJlt7FJAwnCGMgY6podzzvzICLFmmTXYiZ/28I4BX/mOSe
                         pZVnfRixAoGBAO6Uiwt40/PKs53mCEWngslSCsh9oGAaLTf/XdvMns5VmuyyAyKG
                         ti8Ol5wqBMi4GIUzjbgUvSUt+IowIrG3f5tN85wpjQ1UGVcpTnl5Qo9xaS1PFScQ
                         xrtWZ9eNj2TsIAMp/svJsyGG3OibxfnuAIpSXNQiJPwRlW3irzpGgVx/AoGBANYW
                         dnhshUcEHMJi3aXwR12OTDnaLoanVGLwLnkqLSYUZA7ZegpKq90UAuBdcEfgdpyi
                         PhKpeaeIiAaNnFo8m9aoTKr+7I6/uMTlwrVnfrsVTZv3orxjwQV20YIBCVRKD1uX
                         VhE0ozPZxwwKSPAFocpyWpGHGreGF1AIYBE9UBtjAoGBAI8bfPgJpyFyMiGBjO6z
                         FwlJc/xlFqDusrcHL7abW5qq0L4v3R+FrJw3ZYufzLTVcKfdj6GelwJJO+8wBm+R
                         gTKYJItEhT48duLIfTDyIpHGVm9+I1MGhh5zKuCqIhxIYr9jHloBB7kRm0rPvYY4
                         VAykcNgyDvtAVODP+4m6JvhjAoGBALbtTqErKN47V0+JJpapLnF0KxGrqeGIjIRV
                         cYA6V4WYGr7NeIfesecfOC356PyhgPfpcVyEztwlvwTKb3RzIT1TZN8fH4YBr6Ee
                         KTbTjefRFhVUjQqnucAvfGi29f+9oE3Ei9f7wA+H35ocF6JvTYUsHNMIO/3gZ38N
                         CPjyCMa9AoGBAMhsITNe3QcbsXAbdUR00dDsIFVROzyFJ2m40i4KCRM35bC/BIBs
                         q0TY3we+ERB40U8Z2BvU61QuwaunJ2+uGadHo58VSVdggqAo0BSkH58innKKt96J
                         69pcVH/4rmLbXdcmNYGm6iu+MlPQk4BUZknHSmVHIFdJ0EPupVaQ8RHT
                         -----END RSA PRIVATE KEY-----
</code></pre>
<p>이렇게 진행했더니 정상적으로 작동했다.. 😠🫣</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[부하를 잘 견디는 프로그램]]></title>
            <link>https://velog.io/@im-shung/%EB%B6%80%ED%95%98%EB%A5%BC-%EC%9E%98-%EA%B2%AC%EB%94%94%EB%8A%94-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%A8</link>
            <guid>https://velog.io/@im-shung/%EB%B6%80%ED%95%98%EB%A5%BC-%EC%9E%98-%EA%B2%AC%EB%94%94%EB%8A%94-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%A8</guid>
            <pubDate>Sat, 11 Feb 2023 15:02:35 GMT</pubDate>
            <description><![CDATA[<p>스트레스, 부하, 성능을 잘 견디는 프로그램을 만들려면</p>
<ul>
<li>자바 문법과 자바에서 어떻게 메모리를 사용하는지</li>
<li>네트워크, 파일 입출력은 어떤건지</li>
<li>동시성 제어를 신경써야 하는지</li>
</ul>
<p>운영체제나 네트워크 운영체제(내부 Cache) 같은 지식이 필요하다. </p>
<p>그런 잘 설계된 어플리케이션 위에서 부하 테스트를 하면서 병목 현상을 제거한다. 이를 최적화 튜닝한다고 볼 수 있다. </p>
<p>jmeter이나 ngrinder 같은 부하 테스트 tool을 사용할 수도 있다. (private망 내에서 테스트 하면 과금이 안된다.)</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Spotify OAuth2.0 기능 구현]]></title>
            <link>https://velog.io/@im-shung/Spotify-OAuth2.0-%EA%B8%B0%EB%8A%A5-%EA%B5%AC%ED%98%84</link>
            <guid>https://velog.io/@im-shung/Spotify-OAuth2.0-%EA%B8%B0%EB%8A%A5-%EA%B5%AC%ED%98%84</guid>
            <pubDate>Sat, 11 Feb 2023 06:18:27 GMT</pubDate>
            <description><![CDATA[<h1 id="용어-설명">용어 설명</h1>
<ul>
<li><strong>유저(Resource Owner)</strong><ul>
<li>Spotify 계정을 갖고 있는 사람</li>
</ul>
</li>
<li><strong>클라이언트(Client)</strong><ul>
<li>리소스에 접근하려는 애플리케이션</li>
<li>유저의 정보를 Spotify에게 요청하고, 유저에게 서비스를 제공합니다.</li>
<li>프로젝트에서는 Spring Boot 서버에 해당합니다.</li>
</ul>
</li>
<li><strong>인증 서버(Authorization Server)</strong><ul>
<li>스포티파이 인증 서버로, 유저의 정보를 보관하고 있습니다.</li>
<li>유저로부터 인증을 받아 Client에게 유저의 정보를 제공합니다.</li>
<li>인증 및 인가를 수행하는 서버로 리소스에 대한 액세스 토큰을 발행합니다.</li>
<li><code>https://accounts.spotify.com</code></li>
</ul>
</li>
<li><strong>리소스 서버(Resource Server)</strong><ul>
<li>리소스를 호스팅하는 서버로 액세스 토큰의 유효 여부를 확인하고 해당 리소스에 대한 접근을 허용합니다.</li>
<li><code>https://api.spotify.com</code></li>
</ul>
</li>
<li><strong>인증 코드(Authorization Code)</strong><ul>
<li>사용자가 로그인에 성공하고 나서 받는 코드이며 이후 액세스 토큰을 발행할 때 필요합니다.</li>
</ul>
</li>
<li><strong>클라이언트 ID(Client ID), 클라이언트 보안 비밀번호(Client Secret Password)</strong><ul>
<li>등록된 클라이언트에게 발급하는 정보로 인증하는 데 사용됩니다.</li>
</ul>
</li>
<li><strong>권한 범위(Scope)</strong><ul>
<li>리소스 접근 범위를 의미합니다.</li>
</ul>
</li>
<li><strong>리다이렉트 URI(Redirect URI)</strong><ul>
<li>인증 서버가 인증 후 응답을 보낼 클라이언트 URI에 해당합니다.</li>
</ul>
</li>
</ul>
<h1 id="과정">과정</h1>
<blockquote>
<p><strong>Spotify  Authorization Guide</strong>를 참고해주세요.
<a href="https://developer.spotify.com/documentation/general/guides/authorization/code-flow/">https://developer.spotify.com/documentation/general/guides/authorization/code-flow/</a></p>
</blockquote>
<h2 id="front-1-request-user-authorization인가-요청">[Front] 1. Request User Authorization(인가 요청)</h2>
<h4 id="request-필수-항목">Request 필수 항목</h4>
<ul>
<li>client_id: Spotify App에서 발급한 Client ID (<a href="https://developer.spotify.com/documentation/general/guides/authorization/app-settings/">참고</a>)</li>
<li>response_type: <code>Code</code></li>
<li>redirect_uri: Spotify App에서 등록한 redirect_uri와 동일해야 함</li>
</ul>
<p>프론트에서 Spotify쪽으로 인가 요청을 보냅니다. 요청이 처리되면, 스포티파이 로그인 화면이 보일 것입니다. 사용자가 로그인 하면, 지정된 redirect_uri로 다시 리디렉션됩니다.</p>
<h4 id="response">Response</h4>
<ul>
<li>code: Access Token을 발행하기 위한 인가 코드</li>
<li>state</li>
</ul>
<h2 id="front-2-backend로-인가-코드-전달">[Front] 2. BackEnd로 인가 코드 전달</h2>
<p>code를 parsing해서 백엔드로 보낸다.</p>
<pre><code>https://my-domain.com/callback?code=NApCCg..BkWtQ&amp;state=34fFs29kd09</code></pre><p>프론트 쪽은 잘 몰라서 <a href="https://velog.io/@pakxe/React-%EC%A0%95%EB%A7%90-%EC%89%BD%EB%8B%A4-%EC%B9%B4%EC%B9%B4%EC%98%A4-%EC%86%8C%EC%85%9C-%EB%A1%9C%EA%B7%B8%EC%9D%B8-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%90%EC%84%9C-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B3%A0-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0">이곳 블로그</a>를 참고해 주세요.</p>
<h2 id="back-3-access-token-요청">[Back] 3. Access Token 요청</h2>
<p>프론트에서 받은 코드를 사용해서 Spotify 서버로 Access Token을 요청합니다.</p>
<h4 id="request-필수-항목-1">Request 필수 항목</h4>
<p>Request Body Paramter</p>
<ul>
<li>grant_type: <code>authorization_code</code></li>
<li>code: 프론트에서 받은 code</li>
<li>redirect_uri</li>
</ul>
<p>Header Parameter</p>
<ul>
<li>Authorization: <code>Authorization: Basic &lt;base64 encoded client_id:client_secret&gt;</code><ul>
<li>클라이언트 Id는 Base64로 인코딩해야 한다.</li>
</ul>
</li>
<li>Content-Type: <code>application/x-www-form-urlencoded</code></li>
</ul>
<p>액세스 토큰을 사용하여 Spotify Web API에 요청할 수 있습니다. 요청 안에 Authorization 헤더를 포함해야 합니다.</p>
<ul>
<li>Authorization: <code>Bearer &lt;Access Token&gt;</code></li>
</ul>
<h4 id="response-1">Response</h4>
<ul>
<li>access_token</li>
<li>token_type: 항상 <code>Bearer</code></li>
<li>scope</li>
<li>expires_in</li>
<li>refresh_token<ul>
<li>code의 유효기간이 만료되면, /api/token 요청 시 refresh token을 사용한다. 그러면 새 access_token과 새 refresh_token이 발급된다.</li>
</ul>
</li>
</ul>
<h2 id="back-4-refreshed-access-token-요청">[Back] 4. Refreshed Access Token 요청</h2>
<h4 id="request">Request</h4>
<p>Request Body Parameter</p>
<ul>
<li>grant_type: <code>refresh_token</code></li>
<li>refresh_token</li>
</ul>
<p>Header Parameter</p>
<ul>
<li>Authorization: <code>Authorization: Basic &lt;base64 encoded client_id:client_secret&gt;</code></li>
<li>Content-Type: <code>application/x-www-form-urlencoded</code> </li>
</ul>
<blockquote>
<p><a href="https://galid1.tistory.com/106">https://galid1.tistory.com/106</a>
<a href="https://tech.kakao.com/2023/01/19/social-login/">https://tech.kakao.com/2023/01/19/social-login/</a>
<a href="https://www.baeldung.com/spring-security-5-oauth2-login">https://www.baeldung.com/spring-security-5-oauth2-login</a>
<a href="https://velog.io/@kimujin99/Spring-React-%EC%B9%B4%EC%B9%B4%EC%98%A4-%EC%86%8C%EC%85%9C-%EB%A1%9C%EA%B7%B8%EC%9D%B8-JWT-0">https://velog.io/@kimujin99/Spring-React-%EC%B9%B4%EC%B9%B4%EC%98%A4-%EC%86%8C%EC%85%9C-%EB%A1%9C%EA%B7%B8%EC%9D%B8-JWT-0</a></p>
</blockquote>
<hr>
<h1 id="정리">정리</h1>
<blockquote>
<p>최종 목표
: Spotify 계정으로 로그인, 로그인 유지는 JWT 토큰 검증으로 판단, Spotify의 access token은 저장 후 추천 서비스 요청 헤더에 부착한다.</p>
</blockquote>
<ul>
<li>회원가입 서비스는 x, Spotify 계정으로만 로그인가능하게 만들어야합니다.</li>
<li>Spotify로부터 받은 access token은 Spotify Api 호출에 사용합니다.</li>
<li>Spotify 계정을 갖고 있는 유저는 이미 검증된 것이므로 JWT 토큰을 발급합니다. </li>
<li>즉 회원가입 과정이 생략됩니다. 로그인은 Spotify Auth 기능을 이용합니다.</li>
<li><code>토큰의 목적</code>이 중요합니다.</li>
</ul>
<h2 id="앞으로-만들어야-할-로직">앞으로 만들어야 할 로직</h2>
<ul>
<li><code>user-service</code><ul>
<li>회원테이블 만들기</li>
<li>Spotify 계정 조회를 통해 email를 가져와서 회원 테이블에 등록시키기</li>
<li>클라이언트에게 JWT 토큰 발급하기 </li>
</ul>
</li>
<li><code>apigateway-service</code><ul>
<li>access_token 저장하기 </li>
<li>recommend-service로 가는 API에 access_token 부착하기</li>
<li>JWT 토큰 유효 검증하기 </li>
</ul>
</li>
</ul>
<h2 id="계속-생각해-볼-것">계속 생각해 볼 것</h2>
<ul>
<li>기술적 어려움이 뭐가 있을까?</li>
<li>난이도 높은 API 개발</li>
<li>도전적인 것, 실수한 것, 극복한 것 기록하자</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[제네릭(Generic)]]></title>
            <link>https://velog.io/@im-shung/%EC%A0%9C%EB%84%A4%EB%A6%ADGeneric</link>
            <guid>https://velog.io/@im-shung/%EC%A0%9C%EB%84%A4%EB%A6%ADGeneric</guid>
            <pubDate>Sat, 04 Feb 2023 07:09:28 GMT</pubDate>
            <description><![CDATA[<h1 id="개념">개념</h1>
<p><span style="color:blue">제네릭(Generic)</span>이란 결정되지 않은 타입을 파라미터로 처리하고 실제 사용할 때 파라미터를 구체적인 타입으로 대체시키는 기능이다.</p>
<pre><code class="language-java">public class Box {
    public ? content
}</code></pre>
<p>다양한 내용물을 저장할 Box 클래스를 선언하려고 한다. conent의 타입을 무엇으로 해야 할까? </p>
<ul>
<li>Object 타입?</li>
</ul>
<p>모든 클래스의 루트 클래스인 Object를 넣으면 되지 않을까? </p>
<p>그럴듯하지만 객체의 내용물을 꺼낼 때 문제가 생긴다. content의 타입을 모르기 때문에 매번 instanceof 연산자로 타입을 조사해야 한다. 이는 좋은 방법이 아니다. </p>
<p>Box를 생성하기 전에 우리는 어떤 내용물을 넣을지 이미 알고 있다. 따라서 Box를 생성할 때 저장할 내용물의 타입을 미리 알려주면 Box는 content에 무엇이 대입되고, 읽을 때 어떤 타입으로 제공할지를 알게 된다. 이것이 제네릭이다.</p>
<pre><code class="language-java">public class Box&lt;T&gt; {
    public T content
}</code></pre>
<p><span style="color:blue">&lt;T&gt;</span>는 T가 타입 파라미터임을 뜻하는 기호이다. &lt;Integer&gt;, &lt;String&gt; 등 타입을 넣을 수 있다. 
<span style="background-color:#FFFFF0">T에 대체되는 타입은 클래스 및 인터페이스이어야 한다. int, char 같은 기본 타입은 들어갈 수 T가 될 수 없다.</span></p>
<blockquote>
<p>T는 단지 이름이다. 어떤 알파벳을 써도 상관없다.</p>
</blockquote>
<h2 id="사용-예시">사용 예시</h2>
<pre><code class="language-java">public class Main {

    public static void main(String[] args)  {
        Box&lt;String&gt; box1 = new Box&lt;&gt;();
        box1.content = &quot;안녕하세요&quot;;
        String str = box1.content;
        System.out.println(str);

        Box&lt;Integer&gt; box2 = new Box&lt;&gt;();
        box2.content = 100;
        int value = box2.content;
        System.out.println(value);
    }

}</code></pre>
<h2 id="타입-파라미터의-제한">타입 파라미터의 제한</h2>
<p>타입 파라미터를 제한할 수 있다. 제한된 타입 파라미터를 <span style="color:blue">bounded type parameter</span> 라고 한다. </p>
<h3 id="사용-예시-1">사용 예시</h3>
<p><span style="background-color:#FFFFF0">이제 Box의 T 타입은 Number와 Number의 자식, Number의 구현 관계에 있는 타입만 가능하다. 상위 타입은 클래스와 인터페이스가 들어올 수 있다.</span></p>
<pre><code class="language-java">public class Box&lt;T extends Number&gt;{
    public T content;
}</code></pre>
<blockquote>
<p>T타입을 String으로 선언하면 오류가 발생한다. 
<img src="https://velog.velcdn.com/images/im-shung/post/a0e4f628-90dd-41ae-8282-06c3ddf48c0b/image.png" alt=""></p>
</blockquote>
<h2 id="와일드카드-타입-파라미터">와일드카드 타입 파라미터</h2>
<p>제네릭 타입을 매개값이나 리턴 타입으로 사용할 때 타입 파라미터로 <span style="color:blue">?(와일드카드)</span>를 사용할 수 있다.</p>
<h3 id="extends와-super">extends와 super</h3>
<p><span style="color:blue">&lt;? extends 타입&gt;</span>와 <span style="color:blue">&lt;? super 타입&gt;</span>의 차이는 다음과 같다.
<img src="https://velog.velcdn.com/images/im-shung/post/3fef40db-34aa-499d-b121-b0310845ff87/image.png" alt=""></p>
<p> https://jojozhuang.github.io/programming/java-core-generics/</p>


<h3 id="사용-예시-2">사용 예시</h3>
<h4 id="applicant-클래스---타입-파라미터-사용하는-클래스">Applicant 클래스 - 타입 파라미터 사용하는 클래스</h4>
<pre><code class="language-java">public class Applicant&lt;T&gt;{

    public T kind;

    public Applicant(T kind) {
        this.kind = kind;
    }
}</code></pre>
<h4 id="person-클래스와-자식-클래스들">Person 클래스와 자식 클래스들</h4>
<pre><code class="language-java">public class Person {

}

class Worker extends Person {

}

class Student extends Person {

}

class HighStudent extends Student {

}

class MiddleStudent extends Student {

}</code></pre>
<h4 id="와일드카드-타입-파라미터---매개값">와일드카드 타입 파라미터 - 매개값</h4>
<ol>
<li><p>Applicant&lt;<strong>?</strong>&gt; applicant: 어떤 타입이든 가능</p>
</li>
<li><p>Applicant&lt;<strong>? extends Student</strong>&gt; applicant: Student와 Student의 자손 클래스만 가능</p>
</li>
<li><p>Applicant&lt;<strong>? super Worker</strong>&gt; applicant: Worker와 Worker의 조상 클래스만 가능</p>
<pre><code class="language-java">public class Course {

 public static void registerCourse(Applicant&lt;?&gt; applicant) {
     System.out.println(applicant.kind.getClass().getSimpleName() + &quot;이(가) Course를 등록함&quot;);
 }

 public static void regeisterCourseOnlyStudent(Applicant&lt;? extends Student&gt; applicant) {
     System.out.println(applicant.kind.getClass().getSimpleName() + &quot;이(가) CourseOnlyStudent를 등록함&quot;);
 }

 public static void registerCourseOnlyWorker(Applicant&lt;? super Worker&gt; applicant) {
     System.out.println(applicant.kind.getClass().getSimpleName() + &quot;이(가) CourseOnlyWorker를 등록함&quot;);
 }
}
</code></pre>
</li>
</ol>
<pre><code>
#### 코드에 적용
&gt; 매개 타입이 맞지 않아 오류가 나는 모습이다. 
주석처리 해주자.
![](https://velog.velcdn.com/images/im-shung/post/b26be2d3-a355-4813-80c4-59a6dc97f6b1/image.png)

```java
public class Main {

    public static void main(String[] args)  {

        // 모든 사람이 신청 가능
        System.out.println(&quot;모든 사람이 신청 가능&quot;);
        Course.registerCourse(new Applicant&lt;Person&gt;(new Person()));
        Course.registerCourse(new Applicant&lt;Worker&gt;(new Worker()));
        Course.registerCourse(new Applicant&lt;Student&gt;(new Student()));
        Course.registerCourse(new Applicant&lt;HighStudent&gt;(new HighStudent()));
        Course.registerCourse(new Applicant&lt;MiddleStudent&gt;(new MiddleStudent()));
        System.out.println();

        // 학생만 신청 가능
        System.out.println(&quot;학생만 신청 가능&quot;);
//        Course.regeisterCourseOnlyStudent(new Applicant&lt;Person&gt;(new Person()));
//        Course.regeisterCourseOnlyStudent(new Applicant&lt;Worker&gt;(new Worker()));
        Course.regeisterCourseOnlyStudent(new Applicant&lt;Student&gt;(new Student()));
        Course.regeisterCourseOnlyStudent(new Applicant&lt;HighStudent&gt;(new HighStudent()));
        Course.regeisterCourseOnlyStudent(new Applicant&lt;MiddleStudent&gt;(new MiddleStudent()));
        System.out.println();

        //직장인 및 일반인만 신청 가능
        System.out.println(&quot;직장인 및 일반인만 신청 가능&quot;);
        Course.registerCourseOnlyWorker(new Applicant&lt;Person&gt;(new Person()));
        Course.registerCourseOnlyWorker(new Applicant&lt;Worker&gt;(new Worker()));
//        Course.registerCourseOnlyWorker(new Applicant&lt;Student&gt;(new Student()));
//        Course.registerCourseOnlyWorker(new Applicant&lt;HighStudent&gt;(new HighStudent()));
//        Course.registerCourseOnlyWorker(new Applicant&lt;MiddleStudent&gt;(new MiddleStudent()));
    }

}
</code></pre><pre><code>// 실행결과
모든 사람이 신청 가능
Person이(가) Course를 등록함
Worker이(가) Course를 등록함
Student이(가) Course를 등록함
HighStudent이(가) Course를 등록함
MiddleStudent이(가) Course를 등록함

학생만 신청 가능
Student이(가) CourseOnlyStudent를 등록함
HighStudent이(가) CourseOnlyStudent를 등록함
MiddleStudent이(가) CourseOnlyStudent를 등록함

직장인 및 일반인만 신청 가능
Person이(가) CourseOnlyWorker를 등록함
Worker이(가) CourseOnlyWorker를 등록함</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[어노테이션(Annotation)]]></title>
            <link>https://velog.io/@im-shung/%EC%96%B4%EB%85%B8%ED%85%8C%EC%9D%B4%EC%85%98Annotation</link>
            <guid>https://velog.io/@im-shung/%EC%96%B4%EB%85%B8%ED%85%8C%EC%9D%B4%EC%85%98Annotation</guid>
            <pubDate>Sat, 04 Feb 2023 06:56:47 GMT</pubDate>
            <description><![CDATA[<h1 id="개념">개념</h1>
<p>코드에서 @으로 작성되는 요소를 <span style="color:blue">어노테이션(Annotation)</span>이라고 한다. 어노테이션은 클래스 또는 인터페이스를 컴파일하거나 실행할 때 어떻게 처리해야 할 것인지를 알려주는 설정 정보이다. </p>
<p>어노테이션은 다음 세 가지 용도로 사용된다.</p>
<h4 id="1-컴파일-시-사용하는-정보-전달">1. 컴파일 시 사용하는 정보 전달</h4>
<h4 id="2-빌드-툴이-코드를-자동으로-생성할-때-사용하는-정보-전달">2. 빌드 툴이 코드를 자동으로 생성할 때 사용하는 정보 전달</h4>
<h4 id="3-실행-시-특정-기능을-처리할-때-사용하는-정보-전달">3. 실행 시 특정 기능을 처리할 때 사용하는 정보 전달</h4>
<h2 id="어노테이션-정의">어노테이션 정의</h2>
<h3 id="타입">타입</h3>
<p>@Override 어노테이션을 살펴보면 <span style="color:blue">@interface</span>로 정의되어 있다. 어노테이션을 정의하는 방법은 인터페이스를 정의하는 것과 유사하다. </p>
<pre><code class="language-java">@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {}</code></pre>
<h3 id="속성">속성</h3>
<p>속성은 타입과 이름으로 구성되며, 이름 뒤에 괄호를 붙인다.</p>
<ul>
<li>String value()</li>
<li>int number()</li>
</ul>
<pre><code class="language-java">@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface PrintAnnotation {

    String value() default &quot;-&quot;;
    int nubmer() default 15;
}</code></pre>
<p>어노테이션 정의 시 적용 대상과 유지 기간을 정의한다.</p>
<ul>
<li><span style="color:gray">@Target(ElementType.METHOD)</span>: 어노테이션 적용 대상을 명시한다.</li>
<li><span style="color:gray">@Retention(RetentionPolicy.SOURCE)</span>: 어노테이션을 언제까지 유지할 것인지를 지정한다.</li>
</ul>
<h2 id="어노테이션-적용-대상">어노테이션 적용 대상</h2>
<p>Enum 클래스인 <span style="color:blue">ElementType</span>에 대상 종류들이 정의되어 있다.</p>
<pre><code class="language-java">public enum ElementType {
    /** Class, interface (including annotation interface), enum, or record
     * declaration */
    TYPE,

    /** Field declaration (includes enum constants) */
    FIELD,

    /** Method declaration */
    METHOD,

    /** Formal parameter declaration */
    PARAMETER,

    /** Constructor declaration */
    CONSTRUCTOR,

    /** Local variable declaration */
    LOCAL_VARIABLE,

    /** Annotation interface declaration (Formerly known as an annotation type.) */
    ANNOTATION_TYPE,

    /** Package declaration */
    PACKAGE,

    /**
     * Type parameter declaration
     *
     * @since 1.8
     */
    TYPE_PARAMETER,

    /**
     * Use of a type
     *
     * @since 1.8
     */
    TYPE_USE,

    /**
     * Module declaration.
     *
     * @since 9
     */
    MODULE,

    /**
     * Record component
     *
     * @jls 8.10.3 Record Members
     * @jls 9.7.4 Where Annotations May Appear
     *
     * @since 16
     */
    RECORD_COMPONENT;
}</code></pre>
<h2 id="어노테이션-유지-정책">어노테이션 유지 정책</h2>
<pre><code class="language-java">public enum RetentionPolicy {
    /**
     * Annotations are to be discarded by the compiler.
     */
    SOURCE,

    /**
     * Annotations are to be recorded in the class file by the compiler
     * but need not be retained by the VM at run time.  This is the default
     * behavior.
     */
    CLASS,

    /**
     * Annotations are to be recorded in the class file by the compiler and
     * retained by the VM at run time, so they may be read reflectively.
     *
     * @see java.lang.reflect.AnnotatedElement
     */
    RUNTIME
}</code></pre>
<h2 id="어노테이션-설정-정보-이용">어노테이션 설정 정보 이용</h2>
<p><span style="color:blue">리플렉션</span>을 이용해서 적용 대상으로부터 어노테이션의 정보를 얻어낼 수 있다.</p>
<pre><code class="language-java">import java.lang.reflect.Method;

public class Main {

    public static void main(String[] args) throws Exception {
        Method[] declaredMethods = Service.class.getDeclaredMethods();
        for (Method method : declaredMethods) {
            // PrintAnnotaion 얻기
            PrintAnnotation printAnnotation = method.getAnnotation(PrintAnnotation.class);

            // 설정 정보를 이용해서 선 출력
            printLine(printAnnotation);

            // 메소드 호출
            method.invoke(new Service());

            // 설정 정보를 이용해서 선 출력
            printLine(printAnnotation);

        }
    }

    private static void printLine(PrintAnnotation printAnnotation) {
        if (printAnnotation != null) {
            // number 속성값 얻기
            int number = printAnnotation.nubmer();
            for (int i = 0; i &lt; number; i++) {
                // value 속성값 얻기
                String value = printAnnotation.value();
                System.out.print(value);
            }
            System.out.println();
        }
    }

}
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[Date, Calendar, LocalDateTime, SimpleDateFormat, DecimalFormat]]></title>
            <link>https://velog.io/@im-shung/Date-Calendar-LocalDateTime-SimpleDateFormat-DecimalFormat</link>
            <guid>https://velog.io/@im-shung/Date-Calendar-LocalDateTime-SimpleDateFormat-DecimalFormat</guid>
            <pubDate>Sat, 04 Feb 2023 06:31:39 GMT</pubDate>
            <description><![CDATA[<h1 id="date-클래스">Date 클래스</h1>
<p><span style="color:blue">Date</span>는 날짜를 표현하는 클래스이다. 
Date 클래스의 매개변수를 가진 생성자들은 대부분 Deprecated 되어 Date()만 주로 사용된다. 
<img src="https://velog.velcdn.com/images/im-shung/post/1d6e378e-5c8a-4161-8e7c-7b7954afec78/image.png" alt=""></p>
<p>https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/Date.html</p>

<p>Date() 생성자는 컴퓨터의 현재 날짜를 읽어 Date 객체로 만든다.</p>
<h1 id="calendar-클래스">Calendar 클래스</h1>
<p><span style="color:blue">Calendar</span> 클래스는 달력을 표현하는 추상 클래스이다. 날짜와 시간을 계산하는 방법이 지역과 문화에 따라 다르다. </p>
<p><span style="background-color:#FFFFF0"> Calendar 클래스를 사용하려면 Calendar.getInstance()로 컴퓨터에 설정되어 있는 시간대(TimeZone)을 기준으로 한 Calendar 하위 객체를 얻어서 사용한다.</span></p>
<p>Calendar의 다양한 기능은 <a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/Calendar.html">Java docs</a>에서 확인하자.</p>
<h1 id="localdatetime-클래스">LocalDateTime 클래스</h1>
<p>Date와 Calendar는 날짜와 시간 정보를 읽는 것은 가능하지만 조작하는 것은 불가능하다. java.time 패키지의 LocalDateTime 클래스는 날짜와 시간을 조작할 수 있다 LocalDateTime.now()로 현재 컴퓨터의 날짜와 시간을 읽을 수 있다.</p>
<pre><code>// 실행결과
2023-02-04T15:13:20.701662200</code></pre><h2 id="날짜-더하기-빼기">날짜 더하기, 빼기</h2>
<p>년 빼기, 년 더하기, 월 빼기, 월 더하기 등의 기능을 사용할 수 있다. <a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/time/LocalDateTime.html">Java docs</a>에 더 자세히 나와있다.
<img src="https://velog.velcdn.com/images/im-shung/post/d28a59c8-3bd3-4bbc-910f-c61b76052400/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/im-shung/post/4e59a655-7564-4d2d-93da-109b19c5b9e9/image.png" alt=""></p>
<h2 id="날짜-비교하기">날짜 비교하기</h2>
<p>이후 날짜인지, 이전 날짜인지, 동일 날짜인지에 대해 boolean 값을  리턴한다.
<img src="https://velog.velcdn.com/images/im-shung/post/d13d0238-2900-43ca-97f9-b451d1952a40/image.png" alt=""></p>
<h3 id="사용-예시">사용 예시</h3>
<pre><code class="language-java">LocalDateTime dateTime = LocalDateTime.of(2022, 2, 4, 15, 17, 0);
System.out.println(dateTime.format(DateTimeFormatter.ofPattern(&quot;yyyy.MM.dd a HH:mm:ss&quot;)));</code></pre>
<pre><code>// 실행결과
2022.02.04 오후 15:17:00</code></pre><h1 id="format-클래스">Format 클래스</h1>
<p><span style="color:blue">Format</span> 클래스는 숫자 또는 날짜를 원하는 형태의 문자열로 변환해주는 기능을 제공한다. Format은 추상 클래스로, 자식 클래스로는 <span style="color:blue">DateFormat</span>, <span style="color:blue">MessageFormat</span>, <span style="color:blue">NumberFormat</span> 클래스가 있다.</p>
<p>DateFormat 클래스의 자식인 <span style="color:blue">SimpleDateFormat</span> 클래스와 NumberFormat 클래스의 자식인 <span style="color:blue">DecimalFormat</span> 클래스를 자주 쓴다.</p>
<h2 id="simpledateformat-클래스">SimpleDateFormat 클래스</h2>
<table>
<thead>
<tr>
<th>패턴 문자</th>
<th>의미</th>
</tr>
</thead>
<tbody><tr>
<td>y</td>
<td>년</td>
</tr>
<tr>
<td>M</td>
<td>월</td>
</tr>
<tr>
<td>d</td>
<td>일</td>
</tr>
<tr>
<td>D</td>
<td>월 구분이 없는 일(1~365)</td>
</tr>
<tr>
<td>E</td>
<td>요일</td>
</tr>
<tr>
<td>a</td>
<td>오전/오후</td>
</tr>
<tr>
<td>w</td>
<td>년의 몇 번째 주</td>
</tr>
<tr>
<td>W</td>
<td>월의 몇 번째 주</td>
</tr>
<tr>
<td>H</td>
<td>시(0~23)</td>
</tr>
<tr>
<td>h</td>
<td>시(1~12)</td>
</tr>
<tr>
<td>K</td>
<td>시(0~11)</td>
</tr>
<tr>
<td>k</td>
<td>시(1~24)</td>
</tr>
<tr>
<td>m</td>
<td>분</td>
</tr>
<tr>
<td>s</td>
<td>초</td>
</tr>
<tr>
<td>S</td>
<td>밀리세컨드(1/1000초)</td>
</tr>
</tbody></table>
<h2 id="decimalformat-클래스">DecimalFormat 클래스</h2>
<h3 id="사용-예시-1">사용 예시</h3>
<pre><code class="language-java">DecimalFormat decimalFormat = new DecimalFormat(&quot;#,###.0&quot;);
String result = decimalFormat.format(1234567.89); 
System.out.println(&quot;result = &quot; + result);</code></pre>
<pre><code>// 실행결과
result = 1,234,567.9</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[Math 클래스]]></title>
            <link>https://velog.io/@im-shung/%EC%88%98%ED%95%99-%ED%81%B4%EB%9E%98%EC%8A%A4</link>
            <guid>https://velog.io/@im-shung/%EC%88%98%ED%95%99-%ED%81%B4%EB%9E%98%EC%8A%A4</guid>
            <pubDate>Sat, 04 Feb 2023 05:55:44 GMT</pubDate>
            <description><![CDATA[<h1 id="math-클래스">Math 클래스</h1>
<p>static 메소드로 기능들이 구현되어 있어 다음처럼 사용할 수 있다.</p>
<pre><code class="language-java">int v1 = Math.abs(-5.3); 
// v1 = 5</code></pre>
<table>
<thead>
<tr>
<th>구분</th>
<th>함수</th>
</tr>
</thead>
<tbody><tr>
<td>절대값</td>
<td>abs(x)</td>
</tr>
<tr>
<td>올림값</td>
<td>ceil(x)</td>
</tr>
<tr>
<td>버림값</td>
<td>floor(x)</td>
</tr>
<tr>
<td>최대값</td>
<td>max(a, b)</td>
</tr>
<tr>
<td>최소값</td>
<td>min(a, b)</td>
</tr>
<tr>
<td>랜덤값</td>
<td>random()</td>
</tr>
<tr>
<td>반올림값</td>
<td>round(x)</td>
</tr>
<tr>
<td>제곱근(square root)</td>
<td>sqrt(x)</td>
</tr>
<tr>
<td>거듭제곱(power)</td>
<td>pow(a, b)</td>
</tr>
</tbody></table>
]]></description>
        </item>
        <item>
            <title><![CDATA[포장(Wrapper) 클래스]]></title>
            <link>https://velog.io/@im-shung/%ED%8F%AC%EC%9E%A5Wrapper-%ED%81%B4%EB%9E%98%EC%8A%A4</link>
            <guid>https://velog.io/@im-shung/%ED%8F%AC%EC%9E%A5Wrapper-%ED%81%B4%EB%9E%98%EC%8A%A4</guid>
            <pubDate>Sat, 04 Feb 2023 05:50:03 GMT</pubDate>
            <description><![CDATA[<h1 id="포장wrapper-클래스">포장(Wrapper) 클래스</h1>
<p><span style="color:blue"> 포장(Wrapper) 클래스</span>는 Integer, Character 등을 말한다. 기본 타입의 값을 가질 수 있는 객체를 말한다. 
<span style="background-color:#FFFFF0">포장 객체는 기본 타입의 값을 변경할 수 없고, 단지 객체를 생성하는데 목적이 있다.</span></p>
<h2 id="박싱과-언박싱">박싱과 언박싱</h2>
<ul>
<li>boxing: 기본 타입의 값을 포장 객체로 만드는 과정</li>
<li>unboxing: 포장 객체에서 기본 타입의 값 얻어내는 과정</li>
</ul>
<h2 id="값-비교">값 비교</h2>
<p>포장 객체는 내부 값을 비교하기 위해 <span style="color:blue"> ==</span> 와 <span style="color:blue"> =!</span> 연산자를 사용할 수 없다. 이 연산은 객체의 번지를 비교하는 연산이기 때문이다. 대신 <span style="color:blue">equals()</span> 메소드를 사용하면 된다. 포장 클래스의 equals() 메소드는 내부의 값을 비교하도록 재정의되어 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[자바 문자열 클래스 String, StringBuilder, StringTokenizer]]></title>
            <link>https://velog.io/@im-shung/%EC%9E%90%EB%B0%94-%EB%AC%B8%EC%9E%90%EC%97%B4-%ED%81%B4%EB%9E%98%EC%8A%A4-String-StringBuilder-StringTokenizer</link>
            <guid>https://velog.io/@im-shung/%EC%9E%90%EB%B0%94-%EB%AC%B8%EC%9E%90%EC%97%B4-%ED%81%B4%EB%9E%98%EC%8A%A4-String-StringBuilder-StringTokenizer</guid>
            <pubDate>Sat, 04 Feb 2023 05:33:24 GMT</pubDate>
            <description><![CDATA[<h1 id="string-클래스">String 클래스</h1>
<p><span style="color:blue">String</span> 클래스는 문자열을 저장하고 조작할 때 사용한다.</p>
<ul>
<li>문자열 리터럴은 자동으로 String 객체로 생성<ul>
<li><span style="color:gray">String str = &quot;message&quot;;</span></li>
</ul>
</li>
<li>byte 배열을 디코딩해서 String 객체로 생성 <ul>
<li><span style="color:gray">String str = new String(byte[] bytes);</span></li>
</ul>
</li>
<li>특정 문자셋으로 byte 배열을 디코딩해서 String 객체로 생성<ul>
<li><span style="color:gray">String str = new String(byte[] bytes, String charestName);</span></li>
</ul>
</li>
</ul>
<h2 id="사용-예시">사용 예시</h2>
<pre><code class="language-java">public class BytesToString {

    public static void main(String[] args) throws Exception {
        String data = &quot;자바&quot;;

        // String -&gt; byte 배열 (default: UTF-8 인코딩)
        byte[] byteArray1 = data.getBytes();
        System.out.println(&quot;byteArray = &quot; + Arrays.toString(byteArray1));

        // byte 배열 -&gt; String (default: UTF-8 디코딩)
        String str1 = new String(byteArray1);
        System.out.println(&quot;str1 = &quot; + str1);

        // String -&gt; byte 배열 (EUC-KR 인코딩)
        byte[] byteArray2 = data.getBytes(&quot;EUC-KR&quot;);
        System.out.println(&quot;byteArray2 = &quot; + Arrays.toString(byteArray2));

        // byte 배열 -&gt; String (EUC-KR 디코딩)
        String str2 = new String(byteArray2, &quot;EUC-KR&quot;);
        System.out.println(&quot;str2 = &quot; + str2);

    }
}</code></pre>
<pre><code>// 실행결과
byteArray = [-20, -98, -112, -21, -80, -108]
str1 = 자바
byteArray2 = [-64, -38, -71, -39]
str2 = 자바</code></pre><p>한글 1자를 UTF-8로 인코딩하면 3바이트가 되고, EUC-KR로 인코딩하면 2바이트가 된다. 따라서 인코딩할 때 사용한 문자셋으로 디코딩을 해야만 한글이 올바르게 복원될 수 있다.</p>
<h1 id="stringbuilder-클래스">StringBuilder 클래스</h1>
<h2 id="사용-예시-1">사용 예시</h2>
<p>String은 내부 문자열을 수정할 수 없다. </p>
<pre><code class="language-java">String data = &quot;ABC&quot;;
System.out.println(data.hashCode());
data += &quot;DEF&quot;;
System.out.println(data.hashCode());</code></pre>
<pre><code>// 실행결과
64578
1923910755</code></pre><p>data 변수에 &quot;DEF&quot;를 추가하면, &quot;ABCDEF&quot;라는 새로운 String 객체를 생성한다. 그리고 data 변수는 새로 생성된 String 객체를 참조하게 된다. 따라서 <code>data += &quot;DEF&quot;;</code> 명령문 전후로 data 변수의 해시코드를 출력해보면 다르다. </p>
<p>문자열의 + 연산은 새로운 String 객체가 생성되고 이전의 객체는 버려지기 때문에 효율성이 좋다고 볼 수 없다. 잦은 문자열 변경 작업을 해야 한다면 <span style="color:blue"> StringBuilder</span>를 사용하는 것이 좋다.</p>
<p><span style="background-color:#FFFFF0">StringBuilder는 내부 버퍼(데이터를 저장하는 메모리)에 문자열을 저장해두고 그 안에서 추가, 수정, 삭제 작업을 하도록 설계되어 있다.</span></p>
<h2 id="stringbuilder의-특징">StringBuilder의 특징</h2>
<p>StringBuilder의 <a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/StringBuilder.html">Java docs</a>를 보면 다음과 같이 설명되어 있다. </p>
<blockquote>
<p>A <span style="color:red"> mutable</span> sequence of characters. This class provides an API compatible with StringBuffer, but with <span style="color:red"> no guarantee of synchronization</span>. This class is designed for use as a drop-in replacement for StringBuffer in places where the string buffer was being used by a <span style="color:red">single thread</span> (as is generally the case). Where possible, it is recommended that this class be used in preference to StringBuffer as it will be <span style="color:red">faster</span> under most implementations.</p>
</blockquote>
<p>StringBuilder의 특징을 알 수 있다.</p>
<ul>
<li>mutable : 가변성 </li>
<li>no guarantee of synchronization : 동기화를 보장하지 않음</li>
<li>single thread : StringBuffer의 싱글 스레드 버전</li>
<li>faster: StringBuffer보다 더 빠르다.</li>
</ul>
<h1 id="stringtokenizer-클래스">StringTokenizer 클래스</h1>
<p>문자열이 구분자로 연결되어 있을 경우, 구분자를 기준으로 문자열을 분리하려면 String의 split() 메소드를 이용하거나 java.util 패키지의 <span style="color:blue">StringTokenizer</span> 클래스를 이용할 수 있다.</p>
<p>다음과 같은 차이점이 있다.</p>
<ul>
<li>split() : 정규 표현식으로 구분</li>
<li>StringTokenizer: 문자로 구분</li>
</ul>
<h2 id="사용-예시-2">사용 예시</h2>
<p>StringTokenizer 객체 생성자</p>
<ul>
<li>StringTokenizer(String str)</li>
<li>StringTokenizer(String str, String delim)</li>
</ul>
<p>만약 구분자(delim)을 생략하면 공백이 기본 구분자가 된다.</p>
<pre><code class="language-java">StringTokenizer st = new StringTokenizer(&quot;this is a test&quot;);
     while (st.hasMoreTokens()) {
         System.out.println(st.nextToken());
     }</code></pre>
<pre><code>// 실행결과
this
is
a
test</code></pre><ul>
<li>hasMoreTokens() : 남아 있는 문자열이 있는 여부</li>
<li>nextToken() : 문자열을 하나씩 가져옴</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[롬복(Lombok)]]></title>
            <link>https://velog.io/@im-shung/%EB%A1%AC%EB%B3%B5Lombok</link>
            <guid>https://velog.io/@im-shung/%EB%A1%AC%EB%B3%B5Lombok</guid>
            <pubDate>Sat, 04 Feb 2023 04:53:05 GMT</pubDate>
            <description><![CDATA[<p><span style="color:blue"> 롬복(Lombok)</span>은 JDK에 포함된 표준 라이브러리는 아니지만 개발자들이 즐겨 쓰는 자동 코드 생성 라이브러리이다.</p>
<table>
<thead>
<tr>
<th align="left">이름</th>
<th align="left">설명</th>
</tr>
</thead>
<tbody><tr>
<td align="left"><strong>@NoArgsContstructor</strong></td>
<td align="left">기본(매개변수가 없는) 생성자 포함</td>
</tr>
<tr>
<td align="left"><strong>@AllArgsContstructor</strong></td>
<td align="left">모든 필드를 초기화시키는 생성자 포함</td>
</tr>
<tr>
<td align="left"><strong>@RequiredArgsContstructor</strong></td>
<td align="left">기본적으로 매개변수가 없는 생성자 포함. 만약 <em>final</em> 또는 <em>@NonNull</em> 이 붙은 필드가 있다면 이 필드만 초기화시키는 생성자 포함</td>
</tr>
<tr>
<td align="left"><strong>@Getter</strong></td>
<td align="left">Getter 메소드 포함</td>
</tr>
<tr>
<td align="left"><strong>@Setter</strong></td>
<td align="left">Setter 메소드 포함</td>
</tr>
<tr>
<td align="left"><strong>@EqualsAndHashCode</strong></td>
<td align="left">equals()와 hashCode() 메소드 포함</td>
</tr>
<tr>
<td align="left"><strong>@ToString()</strong></td>
<td align="left">toString() 메소드 포함</td>
</tr>
<tr>
<td align="left"><strong>@Data</strong></td>
<td align="left">@RequiredArgsContstructor,  @Getter, @Setter, @EqualsAndHashCode, @ToString() 어노테이션들이 합쳐진 것과 동일한 효과를 낸다.</td>
</tr>
</tbody></table>
]]></description>
        </item>
        <item>
            <title><![CDATA[자바 Obejct 클래스 equals(), hashCode(), toString()와 Record]]></title>
            <link>https://velog.io/@im-shung/%EC%9E%90%EB%B0%94-Obejct-%ED%81%B4%EB%9E%98%EC%8A%A4-equals-hashcode-toString-record</link>
            <guid>https://velog.io/@im-shung/%EC%9E%90%EB%B0%94-Obejct-%ED%81%B4%EB%9E%98%EC%8A%A4-equals-hashcode-toString-record</guid>
            <pubDate>Sat, 04 Feb 2023 04:41:56 GMT</pubDate>
            <description><![CDATA[<p>클래스를 선언할 때 extends 키워드로 다른 클래스를 상속하지 않으면 암시적으로 java.lang.Object 클래스를 상속하게 된다. 따라서 자바의 모든 클래스는 Object의 자식이거나 자손 클래스이다.</p>
<h1 id="object-클래스-메소드">Object 클래스 메소드</h1>
<ul>
<li>boolean equals(Object obj) : 객체의 번지를 비교하고 결과를 리턴</li>
<li>int hashCode() : 객체의 해시코드를 리턴</li>
<li>String toString() : 객체의 문자 정보를 리턴</li>
</ul>
<h2 id="equals-메소드">equals() 메소드</h2>
<p><span style="color:blue">equals()</span> 메소드는 비교 연산자인 <span style="color:blue">==</span>과 동일한 결과를 리턴한다. 두 객체가 동일한 객체라면 true를 리턴하고, 그렇지 않으면 false를 리턴한다.</p>
<p><span style="background-color:#FFFFF0">일반적으로 equals() 메소드는 재정의해서 동등 비교용으로 사용된다. 동등 비교란 객체가 비록 달라도 내부의 데이터가 같은지를 비교하는 것을 말한다. 예를 들어 String은 equals() 메소드를 재정의해서 내부 문자열이 같은지를 비교한다.</span> </p>
<pre><code class="language-java">public boolean equals(Object anObject) {
      if (this == anObject) {
          return true;
      }
      if (anObject instanceof String) {
          String aString = (String)anObject;
          if (coder() == aString.coder()) {
              return isLatin1() ? StringLatin1.equals(value, aString.value)
                                : StringUTF16.equals(value, aString.value);
          }
      }
      return false;
  }</code></pre>
<h2 id="hashcode-메소드">hashCode() 메소드</h2>
<p>객체의 <span style="color:blue">해시코드</span>란 객체를 식별하는 정수를 말한다. <span style="color:blue">hashCode()</span> 메소드는 객체의 메모리 번지를 이용한 해시코드를 생성해서 정수값을 리턴한다. </p>
<p><span style="background-color:#FFFFF0">일반적으로 hashCode() 메소드는 equals()와 마찬가지로 동등 비교용으로 사용된다. 객체의 데이터를 기준으로 재정의해서 새로운 정수값을 리턴한다. 객체가 다르다 할지라도 내부 데이터가 동일하다면 같은 정수값을 리턴하기 위해서이다. </span></p>
<blockquote>
<p>자바는 두 객체가 동등함을 비교할 때 hashCode나 equals() 둘 중 하나만 쓰지 않는다. hashcode()가 리턴하는 정수값이 같은지를 확인하고, 그 다음 equals() 메소드가 true를 리턴하는지를 확인하는 2단계를 거쳐서 동등 객체임을 판단한다.</p>
</blockquote>
<h2 id="tostring-메소드">toString() 메소드</h2>
<p>toString()는 객체를 문자열로 표현하는 메소드이다. &#39;클래스명@16진수해시코드&#39;로 구성된 문자열을 리턴한다. 객체의 문자 정보가 중요할 때 toString()을 재정의해서 사용하는데, 그 예로 Date 클래스와 String 클래스이다. Date 클래스는 현재 날짜와 시간을, String 클래스는 저장된 문자열을 리턴하도로 toString()을 오버라이딩했다.</p>
<hr>
<h1 id="레코드record">레코드(Record)</h1>
<p>데이터 전달을 위한 DTO(Data Transfer Object)를 작성할 떄 반복적으로 사용되는 코드를 줄이기 위해 Java 14부터 <span style="color:blue">레코드(Record)</span>가 도입되었다.</p>
<pre><code class="language-java">public class Person {
    private final String name;
    private final int age;


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

    public String name() {
        return this.name;
    }

    public int age() {
        return this.age;
    }

    @Override
    public int hashCode() {
        return super.hashCode();
    }

    @Override
    public boolean equals(Object obj) {
        return super.equals(obj);
    }

    @Override
    public String toString() {
        return super.toString();
    }
}</code></pre>
<p>위와 동일한 코드를 생성하는 레코드 선언이다. </p>
<pre><code class="language-java">public record Person(String name, int age) {

}</code></pre>
<p>이렇게 선언된 레코드 소스를 컴파일하면 변수의 타입과 이름을 이용해서 private final 필드가 자동 생성되고, 생성자 및 Getter 메소드가 자동으로 추가된다. 그리고 hashCode(), equals(), toString() 메소드를 재정의한 코드도 자동으로 추가된다.</p>
<h3 id="컴파일">컴파일</h3>
<p>Person.java를 컴파일 해서 Person.class 파일을 만들었다. </p>
<pre><code class="language-bash">$ javac Person.java</code></pre>
<h3 id="디컴파일">디컴파일</h3>
<p>class 파일의 내용을 확인하기 위해서 class 파일을 다시 java 파일로 바꿔주는 디컴파일 과정이 필요하다. 이를 위해 <a href="http://java-decompiler.github.io/#jd-gui-download">Java Decompiler</a>의 JD-GUI를 사용했다. </p>
<blockquote>
<p>참고로 자바의 javac 컴파일러 최적화 옵션이 켜져있다면 .java -&gt; .class 컴파일 과정에서 소스가 바뀔 수 있기 때문에 디 컴파일하더라도 기존의 소스와는 조금 달라질 수 있다고 한다.</p>
</blockquote>
<pre><code class="language-java">public final class Person extends Record {
  private final String name;

  private final int age;

  public Person(String paramString, int paramInt) {
    this.name = paramString;
    this.age = paramInt;
  }

  public final String toString() {
    // Byte code:
    //   0: aload_0
    //   1: &lt;illegal opcode&gt; toString : (LPerson;)Ljava/lang/String;
    //   6: areturn
    // Line number table:
    //   Java source line number -&gt; byte code offset
    //   #1    -&gt; 0
  }

  public final int hashCode() {
    // Byte code:
    //   0: aload_0
    //   1: &lt;illegal opcode&gt; hashCode : (LPerson;)I
    //   6: ireturn
    // Line number table:
    //   Java source line number -&gt; byte code offset
    //   #1    -&gt; 0
  }

  public final boolean equals(Object paramObject) {
    // Byte code:
    //   0: aload_0
    //   1: aload_1
    //   2: &lt;illegal opcode&gt; equals : (LPerson;Ljava/lang/Object;)Z
    //   7: ireturn
    // Line number table:
    //   Java source line number -&gt; byte code offset
    //   #1    -&gt; 0
  }

  public String name() {
    return this.name;
  }

  public int age() {
    return this.age;
  }
}
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[자바의 예외(Exception)]]></title>
            <link>https://velog.io/@im-shung/%EC%9E%90%EB%B0%94%EC%9D%98-%EC%98%88%EC%99%B8</link>
            <guid>https://velog.io/@im-shung/%EC%9E%90%EB%B0%94%EC%9D%98-%EC%98%88%EC%99%B8</guid>
            <pubDate>Fri, 03 Feb 2023 13:49:37 GMT</pubDate>
            <description><![CDATA[<h1 id="개념">개념</h1>
<p>개발자가 코드를 잘못 작성할 때 예외가 발생한다. 예외가 발생하면 프로그램이 곧바로 종료되는 것은 에러와 동일하지만, 예외 처리를 통해 계속 실행 상태를 유지할 수 있다.</p>
<h2 id="예외">예외</h2>
<p><img src="https://velog.velcdn.com/images/im-shung/post/d7895352-5fff-4f13-8ffd-348bd434cde5/image.png" alt=""></p>
<p>
https://www.benchresources.net/exception-hierarchy-in-java/</p>

<ul>
<li><span style="color:red">Exception Class</span><ul>
<li><span style="color:red">RuntimeException과 그 자식 클래스</span>: 컴파일러가 예외 처리 코드 여부를 검사하지 않는다.</li>
<li><span style="color:red">그 밖의 예외 클래스</span>: 컴파일러가 예외 처리 코드를 검사한다.</li>
</ul>
</li>
</ul>
<h2 id="사용-예시">사용 예시</h2>
<h3 id="try-catch-finally">try-catch-finally</h3>
<pre><code class="language-java">try {
    // 예외 발생 가능 코드를 넣는다.
} catch(예외클래스 e) {
    // 예외 처리 코드를 넣는다.
} finally {
    // 예외 발생 여부와 상관없이 항상 실행되는 코드다.
    // try 블록과 catch 블록에서 return 문을 사용하더라도 finally 블록은 항상 실행된다.
}</code></pre>
<p>예외가 발생하면 예외 객체가 catch블록의 <code>매개변수 e</code> 에 대입된다. </p>
<ul>
<li><code>e.getMessage()</code> : 예외가 발생한 이유만 리턴한다.</li>
<li><code>e.toString()</code>: 예외의 종류와 예외가 발생한 이유를 리턴해준다.</li>
<li><code>e.printStackTrace()</code>: 예외가 어디서 발생했는지 추적한 내용, 예외의 종류, 예외가 발생한 이유를 리턴해준다.</li>
</ul>
<h3 id="예외-떠넘기기">예외 떠넘기기</h3>
<p>예외는 <span style="color:blue">throws</span> 키워드로 떠넘기기가 가능하다. </p>
<pre><code class="language-java">void retuenException() throws 예외클래스 {}</code></pre>
<p>retuenException()에서 예외를 처리하지 않고 떠넘겼기 때문에 이 메소드를 호출하는 곳에서 예외를 받아 처리해야 한다. </p>
<h3 id="사용자-정의-예외">사용자 정의 예외</h3>
<p>사용자 정의 예외는 컴파일러가 체크하는 일반 예외로 선언할 수도 있고, 컴파일러가 체크하지 않는 실행 예외로 선언할 수도 있다. 통상적으로 일반 예외는 <span style="color:blue">Exception</span>의 자식 클래스로 선언하고, 실행 예외는 <span style="color:blue">RuntimeException</span>의 자식 클래스로 선언한다. </p>
<pre><code class="language-java">public vlass XXXException extends [Exception | RuntimeException] {
    public XXXException() {} // 기본 생성자
    public XXXException(String message){ // 예외 메시지를 입력받는 생성자
        super(message);
    }</code></pre>
<p><code>XXXException e.getMessage()</code> 호출 시 사용자가 정의한 message 매개변수의 값이 출력된다. message에  예외 메시지가 발생된 이유를 넣으면 된다.</p>
<h3 id="예외-발생시키기">예외 발생시키기</h3>
<p>코드로 예외를 발생시킬 수 있다. <span style="color:blue">throw</span> 키워드로 예외 객체를 제공하면 된다.</p>
<pre><code class="language-java">throw new Exception();
throw new RuntimeException();
throw new XXXException();

// 예외 메시지 정의하기
throw new Exception(&quot;예외메시지&quot;);
throw new RuntimeException(&quot;예외메시지&quot;);
throw new XXXException(&quot;예외메시지&quot;);</code></pre>
<p>throw된 예외는 <span style="color:blue">try-catch</span> 블록으로 예외를 직접 처리할 수도 있고, <span style="color:blue">throws Exception</span>으로 예외를 떠넘길 수도 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[상속 ]]></title>
            <link>https://velog.io/@im-shung/%EA%B0%9D%EC%B2%B4%EC%A7%80%ED%96%A5%EC%83%81%EC%86%8D</link>
            <guid>https://velog.io/@im-shung/%EA%B0%9D%EC%B2%B4%EC%A7%80%ED%96%A5%EC%83%81%EC%86%8D</guid>
            <pubDate>Fri, 03 Feb 2023 13:26:15 GMT</pubDate>
            <description><![CDATA[<p>자바에서 상속은 중요한 개념이다. 우리가 흔히 쓰는 <span style="color:blue">ArrayList</span>나 <span style="color:blue">HashSet</span>, <span style="color:blue">HashMap</span> 등은 상속받는 클래스인 &#39;자식 클래스&#39;이기에 상속의 개념을 잘 알아둬야 클래스를 제대로 사용할 수 있다.</p>
<p align="center">
   <img src="https://velog.velcdn.com/images/im-shung/post/d802a49f-edaf-4c6c-a647-1db40f714da2/image.png"/>
  https://data-flair.training/blogs/collection-framework-in-java/
</p>

<h1 id="개념">개념</h1>
<p>객체 지향 프로그래밍(OOP: Object Oriented Programming)에서 크게 3요소로 꼽는 캡슐화, 상속, 다형성 세 가지 중 상속을 일컫는다. 상속(inheritance)은 객체들 간의 관계를 구축하는 방법이다. </p>
<p>게임 캐릭터를 예로 들어보겠다.</p>
<pre><code class="language-java">class 궁수 {
    체력
    점프
    앞으로 가기
    뒤로 가기
    앉기
    아이템 먹기
    활 쏘기
}

class 마법사 {
    체력
    점프
    앞으로 가기
    뒤로 가기
    앉기
    아이템 먹기
    마법 쓰기
}</code></pre>
<p>궁수 Class와 마법사 Class에는 체력, 점프 등 공통점이 있다. 게임 캐릭터에게 모두 필수적인 요소들이다. 그렇다면 공통점들을 뽑아서 캐릭터 Class를 만들어보자.</p>
<pre><code class="language-java">class 캐릭터 {
    체력
    점프
    앞으로 가기
    뒤로 가기
    앉기
    아이템 먹기
}</code></pre>
<p>그리고 궁수 Class와 마법사 Class에게는 캐릭터 Class를 상속하게 한다.</p>
<pre><code class="language-java">class 궁수 extends 캐릭터{
    활 쏘기
}

class 마법사 extends 캐릭터{
    마법 쓰기
}</code></pre>
<p><span style="background-color:#FFFFF0">이렇게 캐릭터 Class를 재사용해서 중복되는 코드를 줄여 개발 시간을 단축시킨다.
또한 클래스의 수정을 최소화할 수 있다. 캐릭터 Class를 수정하면 궁수 Class와 마법사 Class에 수정 효과를 가져온다.</span></p>
<h1 id="사용-예시">사용 예시</h1>
<p>메소드 오버라이딩, 생성자, 타입 변환을 알아보자.</p>
<h2 id="메소드-오버라이딩overriding">메소드 오버라이딩(Overriding)</h2>
<p>자식 클래스는 <span style="color:blue">extends</span> 키워드를 사용해 부모 클래스를 상속받는다. 이 키워드를 선언함으로써 부모 클래스의 필드와 메서드를 사용할 수 있다. 여기서 부모 클래스의 필드와 메서드에 대해 잠깐 고민해보자. 자식 클래스는 이것들을 그대로 사용하던가? 메이플 게임을 해봤다면 알겠지만 캐릭터들의 점프는 동일하지 않다. 이중점프 하는 캐릭터도 있고 아예 날아가는 캐릭터도 있다. 이처럼 하위 클래스는 부모 클래스의 메소드의 기본 동작방법을 변경할 수 있다. 이것을 <span style="color:blue">메소드 오버라이딩(overriding)</span>이라고 한다.</p>
<p>메소드 오버라이딩(overriding)을 하면 부모 메소드는 숨겨지고 자식 메소드가 우선적으로 사용된다. </p>
<p>메소드 오버라이딩을 하려면 규칙을 지켜야 한다. 
<span style="color:red"> 첫번째, 부모 메소드의 선언부인 리턴 타입, 메소드 이름, 매개변수가 동일해야 한다. </span></p>
<pre><code class="language-java">class 부모 {
    void talk(String message) {
        System.out.println(&quot;부모: &quot; + message);  
    }

class 자식 extends 부모 {
    @Override
    void talk(String message) {
        System.out.println(&quot;자식: &quot; + message);  
    }
}</code></pre>
<p>리턴타입인 void와 메소드 이름인 talk, 매개변수 String message가 동일하다.
<span style="color:blue">@Override</span>는 컴파일 단계에서 정확히 오버라이딩이 되었는지 체크해주는 어노테이션이다. </p>
<p><span style="color:red">두번째, 접근 제한을 더 강하게 오버라이딩 할 수 없다. </span>
부모 메소드의 접근 제어자가 public 일 때, 자식 메소드를 private으로 선언할 수 없다는 것이다. </p>
<p><span style="color:red">세번째, 새로운 예외를 throws 할 수 없다.</span></p>
<h2 id="생성자">생성자</h2>
<p>자바에서 자식 객체를 생성하면 부모 객체가 먼저 생성된 다음에 자식 객체가 생성된다. 모든 객체는 생성자를 호출해야만 생성된다. 부모 생성자를 따로 넣지 않으면 컴파일러가 부모의 기본 생성자를 자동으로 추가해준다. 부모 생성자는 자식 생성자의 첫 줄에 넣어야 한다.</p>
<pre><code class="language-java">class 자식 {
    자식 () {
        super(); // 부모 생성자 호출
    }
}</code></pre>
<p>부모 생성자 호출 시 주의할 점이 있다. 부모 클래스에 기본 생성자가 없고 매개변수를 갖는 생성자만 있으면 개발자가 super(매개값)을 직접 넣어줘야 한다.</p>
<pre><code class="language-java">class 부모 {
    부모 (int age) {
        System.out.println(&quot;부모: &quot; + age);  
    }

class 자식 extends 부모 {
    자식 () {
        // 아무것도 안쓰는 거 불가능 
        super(50); // 필수로 넣어줘야 함
    }
}</code></pre>
<h2 id="타입-변환">타입 변환</h2>
<p>부모 ⇆ 자식 타입 변환에는 자동 타입 변환과 강제 타입 변환이 있다. 각각의 조건을 만족해야 타입 변환이 가능하다.</p>
<h3 id="자동-타입-변환">자동 타입 변환</h3>
<p>자동 타입 변환은 <code>A a = new B();</code> 또는 <code>B b = new B(); A a = b;</code> 식으로 가능하다. </p>
<ul>
<li>A: 부모 타입</li>
<li>B: 자식 타입</li>
</ul>
<p>자식은 부모의 필드와 메소드를 상속받았기 때문에 해당 필드와 메소드를 사용할 수 있다. 그래서 자동으로 타입이 변환될 수 있는 것이다.</p>
<p>A는 B의 바로 위의 부모가 아니어도 된다. 상속 계층에서 B의 상위 타입이기만 하면 된다.</p>
<p><span style="background-color:#FFFFF0">비록 변수 a는 자식 객체(B)를 참조하지만 변수 a가 접근가능한 멤버는 A 타입의 멤버로 한정된다. 그러나 자식 클래스에서 오바리이딩한 메소드가 있다면 부모 메소드 대신 자식 메소드가 호출된다. 이것은 다형성과 관련이 있다. </span></p>
<h3 id="강제-타입-변환">강제 타입 변환</h3>
<p>자동 타입 변환에서는 자식 객체가 부모 타입 변수로 변환이 되었다. 하지만 자식 객체가 쓸 수 있는 멤버는 부모의 멤버뿐이었다. 자식 객체가 자식에 선언된 필드나 메소드를 사용하고 싶을 때, 강제 타입 변환으로 다시 자식 타입으로 변환될 수 있다.</p>
<pre><code class="language-java">A a = new B(); // 자동 타입 변환
B b = (B) a; // 강제 타입 변환</code></pre>
<p>강제 타입 변환은 <code>B b = (B) a;</code>의 <code>(B)</code> 처럼 강제로 Casting 해야 한다.</p>
<h2 id="상속-불가능-및-제약">상속 불가능 및 제약</h2>
<ul>
<li>final class는 상속할 수 없는 클래스이다. </li>
<li>final method는 오버라이딩할 수 없는 메소드이다. </li>
</ul>
<h2 id="protected-접근-제한자">protected 접근 제한자</h2>
<p>protected는 상속과 관련이 있고, public과 default의 중간쯤에 해당하는 접근 제한을 한다.
필드, 생성자, 메소드가 protected로 선언되면 같은 패키지이거나, 자식 객체만 사용이 가능하다. 다른 패키지에 있으면 new 연산자를 사용해서 생성자를 직접 호출할 수 없으므로 super()를 사용해야 한다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[마크다운 글 색상/형광펜]]></title>
            <link>https://velog.io/@im-shung/%EB%A7%88%ED%81%AC%EB%8B%A4%EC%9A%B4-%EA%B8%80-%EC%83%89%EC%83%81%ED%98%95%EA%B4%91%ED%8E%9C</link>
            <guid>https://velog.io/@im-shung/%EB%A7%88%ED%81%AC%EB%8B%A4%EC%9A%B4-%EA%B8%80-%EC%83%89%EC%83%81%ED%98%95%EA%B4%91%ED%8E%9C</guid>
            <pubDate>Thu, 02 Feb 2023 23:06:33 GMT</pubDate>
            <description><![CDATA[<h1 id="글자색">글자색</h1>
<p><span style="color:red"> red </span>
<span style="color:#ffd33d"> yellow </span>
<span style="color:blue"> blue </span>
<span style="color:brown"> brown </span>
<span style="color:orange"> orange </span>
<span style="color:green"> green </span>
<span style="color:violet"> violet </span>
<span style="color:yellowgreen"> yellowgreen </span>
<span style="color:blueviolet"> blueviolet </span>
<span style="color:gray"> gray</span>
<span style="color:indigo"> indigo </span></p>
<pre><code class="language-css">&lt;span style=&quot;color:red&quot;&gt; red &lt;/span&gt;
&lt;span style=&quot;color:#ffd33d&quot;&gt; yellow &lt;/span&gt;
&lt;span style=&quot;color:blue&quot;&gt; blue &lt;/span&gt;
&lt;span style=&quot;color:brown&quot;&gt; brown &lt;/span&gt;
&lt;span style=&quot;color:orange&quot;&gt; orange &lt;/span&gt;
&lt;span style=&quot;color:green&quot;&gt; green &lt;/span&gt;
&lt;span style=&quot;color:violet&quot;&gt; violet &lt;/span&gt;
&lt;span style=&quot;color:yellowgreen&quot;&gt; yellowgreen &lt;/span&gt;
&lt;span style=&quot;color:blueviolet&quot;&gt; blueviolet &lt;/span&gt;
&lt;span style=&quot;color:gray&quot;&gt; gray&lt;/span&gt;
&lt;span style=&quot;color:indigo&quot;&gt; indigo &lt;/span&gt;</code></pre>
<h1 id="형광펜">형광펜</h1>
<p><span style="background-color:#fff5b1"> 노란형광펜 </span>
<span style="background-color:#FFE6E6"> 빨강형광펜 </span>
<span style="background-color:#E6E6FA"> 보라형광펜 </span>
<span style="background-color:#C0FFFF"> 파랑형광펜 </span>
<span style="background-color:#FFFFF0"> 노란형광펜 </span>
<span style="background-color:#F5F5F5"> 회색형광펜 </span>
<span style="background-color:#DCFFE4"> 초록형광펜 </span></p>
<pre><code class="language-css">&lt;span style=&quot;background-color:#fff5b1&quot;&gt; 노란형광펜 &lt;/span&gt;
&lt;span style=&quot;background-color:#FFE6E6&quot;&gt; 빨강형광펜 &lt;/span&gt;
&lt;span style=&quot;background-color:#E6E6FA&quot;&gt; 보라형광펜 &lt;/span&gt;
&lt;span style=&quot;background-color:#C0FFFF&quot;&gt; 파랑형광펜 &lt;/span&gt;
&lt;span style=&quot;background-color:#FFFFF0&quot;&gt; 노란형광펜 &lt;/span&gt;
&lt;span style=&quot;background-color:#F5F5F5&quot;&gt; 회색형광펜 &lt;/span&gt;
&lt;span style=&quot;background-color:#DCFFE4&quot;&gt; 초록형광펜 &lt;/span&gt;</code></pre>
<blockquote>
<p>더 많은 색상은 <a href="https://www.rapidtables.com/web/color/RGB_Color.html">RGB 색상표 사이트</a> 를 참고해주세요</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[회원 테이블과 회원 객체]]></title>
            <link>https://velog.io/@im-shung/%ED%9A%8C%EC%9B%90-%ED%85%8C%EC%9D%B4%EB%B8%94-%EC%83%9D%EC%84%B1</link>
            <guid>https://velog.io/@im-shung/%ED%9A%8C%EC%9B%90-%ED%85%8C%EC%9D%B4%EB%B8%94-%EC%83%9D%EC%84%B1</guid>
            <pubDate>Wed, 01 Feb 2023 14:08:22 GMT</pubDate>
            <description><![CDATA[<p><img src="blob:https://velog.io/f0e494de-879d-4bbd-97d1-392404d92b74" alt="업로드중.."></p>
<h1 id="유저">유저</h1>
<ul>
<li><strong>유저 시퀀스</strong></li>
<li><strong>패스워드</strong> - 암호화 필요</li>
<li><strong>장르</strong> - 스포티파이 장르 어떻게? <a href="https://developer.spotify.com/console/get-available-genre-seeds/">API</a>로 가져온다. 프론트쪽에서 요청해야할 듯 </li>
<li><strong>닉네임</strong> - 중복처리 되지 않는 로직 필요</li>
<li><strong>나이</strong></li>
<li><strong>성별</strong></li>
<li><strong>가입날짜</strong></li>
<li><strong>프로필이미지</strong> 
  프로필 이미지는 이미지 데이터 1개만 저장하면 된다. -&gt; 따라서 이미지 데이터를 단순히 binary로 전환하여 RDB에 저장하는 방법을 고려 -&gt; <strong>캐싱</strong>을 적용하면 database 병목현상을 줄일 수 있을 것이다.</li>
<li><strong>마지막 이용 시간</strong> - 어떻게 가져오는지? 세션??</li>
<li><strong>권한</strong> </li>
</ul>
<h2 id="mysql에-enum-타입이-있다">MySQL에 ENUM 타입이 있다.</h2>
<p><a href="https://dev.mysql.com/doc/refman/8.0/en/enum.html">https://dev.mysql.com/doc/refman/8.0/en/enum.html</a></p>
<h2 id="테이블-객체-연결">테이블-객체 연결</h2>
<p>Java Persistence API인 JPA를 쓸 것 </p>
]]></description>
        </item>
    </channel>
</rss>