<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>standzzl.log</title>
        <link>https://velog.io/</link>
        <description>study notebook</description>
        <lastBuildDate>Mon, 06 Nov 2023 14:05:49 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>standzzl.log</title>
            <url>https://velog.velcdn.com/images/seonjin_dev/profile/e3cf1d75-8a2c-4d24-97ce-6258b75966b4/image.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. standzzl.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/seonjin_dev" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[Spring] 서울열린데이터광장 OpenAPI 활용하기]]></title>
            <link>https://velog.io/@seonjin_dev/Spring-%EC%84%9C%EC%9A%B8%EC%97%B4%EB%A6%B0%EB%8D%B0%EC%9D%B4%ED%84%B0%EA%B4%91%EC%9E%A5-OpenAPI-%ED%99%9C%EC%9A%A9%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@seonjin_dev/Spring-%EC%84%9C%EC%9A%B8%EC%97%B4%EB%A6%B0%EB%8D%B0%EC%9D%B4%ED%84%B0%EA%B4%91%EC%9E%A5-OpenAPI-%ED%99%9C%EC%9A%A9%ED%95%98%EA%B8%B0</guid>
            <pubDate>Mon, 06 Nov 2023 14:05:49 GMT</pubDate>
            <description><![CDATA[<p><a href="https://github.com/hseonjin/KostaSpring/tree/main/springapi"><strong>전체코드보기</strong></a></p>
<hr>
<h3 id="_활용-데이터-_">[_활용 데이터 _]</h3>
<p><a href="https://data.seoul.go.kr/dataList/OA-16007/S/1/datasetView.do"><strong>서울시 동물병원 인허가 정보</strong></a>
<a href="http://openapi.seoul.go.kr:8088/sample/json/LOCALDATA_020301/1/5/"><strong>JSON 미리보기</strong></a></p>
<hr>
<h3 id="_코드분석-_">[_코드분석 _]</h3>
<h3 id="dto"><em>DTO</em></h3>
<p>DTO의 경우 필요한 정보만 정의해도 좋고, 모두 생성해도 무방하다
나의 경우 필요한 정보만 정의하고 생성자와 setter/getter를 만들어 주었다</p>
<h3 id="service"><em>Service</em></h3>
<pre><code class="language-java">  int startIdx = (pageInfo.getCurPage() - 1) * 10 + 1;</code></pre>
<ul>
<li>현재 페이지에 따라 API를 호출하기 위한 시작 인덱스를 계산<br/>

</li>
</ul>
<pre><code class="language-java">  StringBuilder urlBuilder = new StringBuilder(&quot;http://openapi.seoul.go.kr:8088&quot;);
  urlBuilder.append(&quot;/&quot;+URLEncoder.encode(&quot;4864596d7173656f3131306649487165&quot;, &quot;UTF-8&quot;));
  urlBuilder.append(&quot;/&quot;+URLEncoder.encode(&quot;json&quot;, &quot;UTF-8&quot;));
  urlBuilder.append(&quot;/&quot;+URLEncoder.encode(&quot;LOCALDATA_020301&quot;, &quot;UTF-8&quot;));
  urlBuilder.append(&quot;/&quot;+URLEncoder.encode(startIdx+&quot;&quot;, &quot;UTF-8&quot;));
  urlBuilder.append(&quot;/&quot;+URLEncoder.encode(startIdx+10+&quot;&quot;, &quot;UTF-8&quot;));</code></pre>
<p>💡샘플 URL(<a href="http://openapi.seoul.go.kr:8088/%EC%9D%B8%EC%A6%9D%ED%82%A4/json/LOCALDATA_020301/1/5/)%EC%97%90">http://openapi.seoul.go.kr:8088/인증키/json/LOCALDATA_020301/1/5/)에</a> 따라 작성</p>
<ul>
<li><code>**SpringBuilder**</code>는 문자열을 동적으로 조작하고 연결할 때 사용되는 클래스</li>
<li>String을 사용하는 경우 문자열을 변경할 때마다 새로운 객체가 생성되기 때문에 성능 향상을 위해 가변 문자열을 다룰 수 있는 StringBuilder를 사용하는 것<br/>

</li>
</ul>
<pre><code class="language-java">// request
URL url = new URL(urlBuilder.toString());
HttpURLConnection conn = (HttpURLConnection) url.openConnection(); 
conn.setRequestMethod(&quot;GET&quot;);
conn.setRequestProperty(&quot;Content-type&quot;, &quot;application/json&quot;);

// response
BufferedReader br;
int resultCode = conn.getResponseCode();
if(resultCode&gt;=200 &amp;&amp; resultCode&lt;=300) { // 정상
    br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
    } else { // 에러
    br = new BufferedReader(new InputStreamReader(conn.getErrorStream()));
    }

StringBuilder resBuilder = new StringBuilder();
String line;
while ((line = br.readLine()) != null) {
    resBuilder.append(line);
}

br.close();
conn.disconnect();

System.out.println(resBuilder.toString());</code></pre>
<ul>
<li><p>위에서 구성한 URL 문자열로 생성한 URL 객체를 통해 HTTP 연결을 생성</p>
</li>
<li><p>API 응답 데이터를 읽기 위해 BufferedReader를 선언</p>
</li>
<li><p>HTTP 응답 코드를 확인하고 결과에 따라 API 응답 스트림을 읽을 BufferedReader를 초기화</p>
</li>
<li><p>API 응답 데이터를 저장하기 위해 StringBuilder를 생성하고, 한 줄씩 읽어와 데이터를 추가</p>
</li>
<li><p>BufferedReader를 닫고 HTTP 연결을 종료</p>
<br/>
```java
JSONParser parser = new JSONParser();
JSONObject mobj = (JSONObject) parser.parse(resBuilder.toString());
JSONObject LOCALDATA_020301 = (JSONObject) mobj.get("LOCALDATA_020301");
Long list_total_count = (Long) LOCALDATA_020301.get("list_total_count");
JSONArray row = (JSONArray) LOCALDATA_020301.get("row");
```
</li>
<li><p>API 응답 페이터를 파싱하여 저장할 리스트를 초기화</p>
</li>
<li><p>JSONParser 객체를 생성하여 API 응답 데이터와, 객체, 객체 내에서 필요한 정보를 파싱</p>
</li>
<li><p><a href="http://openapi.seoul.go.kr:8088/sample/json/LOCALDATA_020301/1/5/">JSON 데이터 구조</a>를 살펴보자.</p>
<ul>
<li>“LOCALDATA_020301&quot; 최상위 객체가 &quot;list_total_count&quot; 필드와  &quot;row&quot; 배열을 가진다</li>
<li>list_total_count 필드는 전체 데이터 항목 수를 나타낸다 → 이후에 페이징 처리에서 활용</li>
<li>row 배열에는 동물병원 정보를 설명하는 각각의 객체를 가지고 있다<br/>
```java
List<AnimalClinic> acList = new ArrayList<>();
for(int i=0; i<row.size(); i++) {
JSONObject acJson = (JSONObject) row.get(i);
String trdStatNm = (String) acJson.get("TRDSTATENM");
String siteTel = (String) acJson.get("SITETEL");
String rdnwhlAddr = (String) acJson.get("RDNWHLADDR");
String bplcNm = (String) acJson.get("BPLCNM");
String x = (String) acJson.get("X");
String y = (String) acJson.get("Y");
acList.add(new AnimalClinic(trdStatNm, siteTel, rdnwhlAddr, bplcNm, x, y));
}
```</li>
</ul>
</li>
<li><p>앞서 추출한 <strong><code>row</code></strong> 배열에서 각 동물병원의 정보를 추출하고, asList에 추가</p>
<br/>
```java
// 페이지 정보
int allPage = (int)Math.ceil(list_total_count.doubleValue()/10);
int startPage = (pageInfo.getCurPage()-1)/10*10+1;
int endPage = Math.min(startPage+10-1, allPage);

</li>
</ul>
<p>pageInfo.setAllPage(allPage);
pageInfo.setStartPage(startPage);
pageInfo.setEndPage(endPage);
if(pageInfo.getCurPage()&gt;allPage) pageInfo.setCurPage(allPage);</p>
<pre><code>
- 전체 페이지 수, 시작 페이지, 끝 페이지 계산
- 파라미터로 받은 pageInfo 객체에 계산한 페이지 정보를 설정
&lt;br/&gt;
```java
return acList;</code></pre><ul>
<li>처리된 동물병원 정보를 리스트 형태로 반환</li>
</ul>
<hr>
<h3 id="controller"><em>Controller</em></h3>
<pre><code class="language-java">  @Controller
@RequestMapping(&quot;/&quot;)
public class SeoulApiController {
    @Autowired
    private SeoulApiService service;
    @GetMapping(value = {&quot;clinic&quot;, &quot;clinic/{page}&quot;})
    public ModelAndView animalClinicList(@PathVariable(required=false) Integer page) {
        PageInfo pageInfo = new PageInfo();
        if(page!=null) {// url에 page 값이 없다면 기본값 1로 지정
            pageInfo.setCurPage(page);
        } else {
            pageInfo.setCurPage(1);
        }
        ModelAndView mav = new ModelAndView();
        try {
            List&lt;AnimalClinic&gt; acList = service.animalClinicList(pageInfo);
            mav.addObject(&quot;acList&quot;, acList);
            mav.addObject(&quot;pageInfo&quot;, pageInfo);
            mav.setViewName(&quot;animalclinic&quot;);
        } catch (Exception e) {
            e.printStackTrace();
            mav.addObject(&quot;err&quot;, &quot;서울시 동물병원 허가 정보 조회 실패&quot;);
            mav.setViewName(&quot;error&quot;);
        }
        return mav;
    }
}</code></pre>
<ul>
<li>SeoulApiService 타입의 빈을 주입하여 컨트롤러에서 사용</li>
<li>둘 이상의 URL 패턴을 정의하는 경우 value임을 명시하고 중괄호 안에 나열하여 사용</li>
<li><strong><code>@PathVariable(required=false)</code></strong> URL에서 가져온 page 값을 변수에 할당할 때, 해당 매개변수가 필수가 아니라는 것을 나타냄</li>
<li>if문을 통해 page 값이 없는 경우, 기본값을 1로 설정</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[이것이 자바다] 18. 데이터 입출력]]></title>
            <link>https://velog.io/@seonjin_dev/%EC%9D%B4%EA%B2%83%EC%9D%B4-%EC%9E%90%EB%B0%94%EB%8B%A4-18.-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%9E%85%EC%B6%9C%EB%A0%A5</link>
            <guid>https://velog.io/@seonjin_dev/%EC%9D%B4%EA%B2%83%EC%9D%B4-%EC%9E%90%EB%B0%94%EB%8B%A4-18.-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%9E%85%EC%B6%9C%EB%A0%A5</guid>
            <pubDate>Sat, 16 Sep 2023 10:03:43 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/seonjin_dev/post/fba9ec09-dd5d-401a-a9f3-4aae28afd00b/image.png" alt=""></p>
<p>📚 이것이 자바다 [개정판]</p>
<hr>
<h2 id="sec01-입출력-스트림">sec01. 입출력 스트림</h2>
<blockquote>
<ul>
<li>데이터 입출력 : 데이터가 키보드, 파일, 프로그램으로부터 입출력, 저장 또는 전송되는 모든 것의 총칭</li>
</ul>
</blockquote>
<ul>
<li>스트림 : 단방향으로 데이터가 흐르는 것</li>
</ul>
<hr>
<h2 id="sec02-바이트-출력-스트림">sec02. 바이트 출력 스트림</h2>
<blockquote>
<ul>
<li>그림, 멀티미디어, 문자 등 모든 종류의 데이터 출력 시 사용</li>
</ul>
</blockquote>
<ul>
<li>최상위 클래스 <code>OutputStream</code></li>
<li>하위 클래스 <ul>
<li><code>FileOutputStream</code></li>
<li><code>PrintStream</code></li>
<li><code>BufferedOutputStream</code></li>
<li><code>DataOutputStream</code></li>
</ul>
</li>
</ul>
<pre><code class="language-java">public class WriteEx {
    public static void main(String[] args) {
        try {
            OutputStream os = new FileOutputStream(&quot;test1.db&quot;);

            // 1. 1byte씩 출력하는 경우
            byte a= 10, b=20, c=30; 
            os.write(a); // 1byte씩 출력
            os.write(b);
            os.write(c);

            // 2. 바이트 배열로 출력하는 경우
            byte[] array = {10,20,30}; 
            os.write(array); // 배열의 모든 바이트 출력
            // 특정 인덱스까지 출력하는 경우 os.write(array, 0, 1);

            // 공통부분
            os.flush(); // 내부 버퍼에 잔류하는 바이트를 출력 후 비움
            os.close(); // 출력 스트림을 닫고 사용 메모리 해제
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
// OutputStream은 내부에 작언 buffer를 가지고 있다
// write()는 버퍼에 바이트를 저장하고, 끝 1byte를 순서대로 출력한다
// flush()는 내부 버터에 잔류하는 모든 바이트 출력 후 버퍼를 비운다
// close()로 더이상 출력 스트림을 사용하지 않을 경우 메모리를 해제한다</code></pre>
<hr>
<h2 id="sec03-바이트-입력-스트림">sec03. 바이트 입력 스트림</h2>
<blockquote>
</blockquote>
<ul>
<li>최상위 클래스 <code>InputStream</code></li>
<li>하위 클래스 <ul>
<li><code>FileInputStream</code></li>
<li><code>BufferedInputStream</code></li>
<li><code>DataInputStream</code></li>
</ul>
</li>
</ul>
<pre><code class="language-java"> public class ReadEx {
    public static void main(String[] args) {
        try {
            InputStream is = new FileInputStream(&quot;test1.db&quot;);

            // 1. 1byte씩 입력하는 경우
            while(true) {
                int data = is.read(); // 1byte씩 읽기
                if(data == -1) break; 
                // 더이상 읽을 수 없는 경우(끝) -1 반환하기 때문
                System.out.println(data);
            }

            // 2. 바이트 배열로 출력하는 경우
            byte[] data = new byte[100];
            while(true) {
                int num = is.read(data);
                if(num == -1) break; // 파일 끝에 도달한 경우
                for(int i=0; i&lt;num; i++) {
                    System.out.println(data[i]); // 읽은 데이터 출력
                }
            }

            // 공통 부분
            is.close(); // 입력 스트림을 닫고 사용 메모리 해제
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch(IOException e) {
            e.printStackTrace();
        }
    }
}</code></pre>
<hr>
<h2 id="-파일-복사-방법">++ 파일 복사 방법</h2>
<pre><code class="language-java">// FileInputStream에서 읽은 바이트를 바로 FileOutputStream으로 출력
public class CopyEx {
    public static void main(String[] args) throws Exception {
        String originalFileName = &quot;k.jpg&quot;;
        String targetFileName = &quot;k_copy.jpg&quot;;

        InputStream is = new FileInputStream(originalFileName);
        OutputStream os = new FileOutputStream(targetFileName);

        byte[] data = new byte[1024]; // 읽은 파일을 저장할 배열
        while (true) {
            int num = is.read(data);
            if (num == -1)break;
            os.write(data, 0, num); // 읽은 바이트 수만큼 출력
        }
        os.flush(); // 내부 버퍼 잔류 바이트 출력 후 비움
        os.close();
        is.close();

        System.out.println(&quot;복사 성공&quot;);
    }
}</code></pre>
<h2 id="sec04-문자-입출력-스트림">sec04. 문자 입출력 스트림</h2>
<blockquote>
<p>문자 입출력 시 사용</p>
</blockquote>
<ul>
<li>최상위 클래스 <code>Write</code>(출력) / <code>Reader</code>(입력)</li>
<li>하위 클래스 <ul>
<li><code>FileWriter</code> / <code>FileReader</code></li>
<li><code>PrintWriter</code></li>
<li><code>BufferedWriter</code> / <code>bufferedReader</code></li>
<li><code>OutputStreamWriter</code> / <code>InputStreamReader</code></li>
</ul>
</li>
</ul>
<p>&lt;문자 출력&gt;</p>
<pre><code class="language-java">public class WriteEx {
    public static void main(String[] args) {
        try {
            // 문자 기반 출력 스트림 생성
            Writer writer = new FileWriter(&quot;test.txt&quot;);

            // 1. 1문자씩 출력
            char a = &#39;A&#39;;
            writer.write(a);
            char b = &#39;B&#39;;
            writer.write(b);

            // 2. char 배열 출력
            char[] arr = {&#39;C&#39;,&#39;D&#39;,&#39;E&#39;};
            writer.write(arr);

            // 3. 문자열 출력
            writer.write(&quot;FGH&quot;);

            // 버퍼 잔류 문자 출력, 비움
            writer.flush();
            // 출력 스트림 닫고 메모리 해제
            writer.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
// 파일 생성 결과 : ABCDEFGH</code></pre>
<p>&lt;문자 읽기&gt;</p>
<pre><code class="language-java">public class ReadEx {
    public static void main(String[] args) {
        try {
            Reader reader = null;

            // 1. 1문자씩 읽기
            reader = new FileReader(&quot;test.txt&quot;);
            while (true) {
                int data = reader.read(); // 문자 읽음
                if (data == -1)
                    break; // 파일을 다 읽으면 while문 종료
                System.out.println((char) data); // 읽은 문자 출력
            }
            reader.close();
            System.out.println();

            // 2. 문자 배열로 읽기
            reader = new FileReader(&quot;test.txt&quot;);
            char[] data = new char[100]; // 문자를 저장할 배열 생성
            while (true) {
                int num = reader.read(data);
                if (num == -1) break;
                for (int i = 0; i &lt; num; i++) { // 읽은 문자 수만큼 출력
                    System.out.println(data[i]);
                }
            }
            reader.close();

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}</code></pre>
<hr>
<h2 id="sec05-보조-스트림">sec05. 보조 스트림</h2>
<blockquote>
<p>다른 스트림과 연결되어 여러 가지 편리한 기능을 제공해주는 스트림
자체적으로 입출력을 수행할 수 없음
-&gt; 직접 생성된 입출력 스트림에 연결하여 사용
<code>보조스트림 변수 = new 보조스트림(입출력스트림);</code></p>
</blockquote>
<ul>
<li><code>BufferedInputStream</code> <code>BufferedOutputStream</code></li>
</ul>
<h3 id="sec06-문자-변환-스트림-inputstreamreader">sec06. 문자 변환 스트림 <code>InputStreamReader</code></h3>
<blockquote>
<p>바이트 스트림을 문자 스트림으로 변환
문자를 바로 입출력하는 편리함 제공, 문자셋의 종류 지정 가능</p>
</blockquote>
<pre><code class="language-java">// InputStream을 Reader로 변환
InputStream is = new FileInputStream(&quot;test.txt&quot;);
Reader reader = new InputStreamReader(is);

// OutputStream을 Writer로 변환
OutputStream os = new FileOutputStream(&quot;test.txt&quot;);
Writer writer = new OutputStreamReader(os);

// 예제
public class CharacterConvertStreamEx {

    public static void main(String[] args) throws Exception{
        write(&quot;문자 변환 스트림을 사용합니다.&quot;);
        String data = read();
        System.out.println(data);
    }

    public static void write(String str) throws Exception {
        //FileOutputStream에 OutputStreamWriter 보조스트림 연결
        OutputStream os = new FileOutputStream(&quot;test.txt&quot;);
        Writer writer = new OutputStreamWriter(os, &quot;UTF-8&quot;);
        writer.write(str); // 보조스트림을 이용하여 문자 출력
        writer.flush();
        writer.close();
    }

    public static String read() throws Exception {
        //InputStream에 InputStreamReader 보조스트림을 연결
        InputStream is = new FileInputStream(&quot;test.txt&quot;);
        Reader reader = new InputStreamReader(is, &quot;UTF-8&quot;);
        char[] data = new char[100];
        int num = reader.read(data); // 보조스트림을 이용하여 문자 입력
        reader.close();
        String str = new String(data, 0, num); // 배열에서 읽은 문자 수만큼 반환
        return str;
    }
}</code></pre>
<h3 id="sec07-성능-향상-스트림-buffered">sec07. 성능 향상 스트림 <code>Buffered~</code></h3>
<blockquote>
<p>성능 향상을 위해 프로그램이 중간에 메모리 버퍼와 작업하도록 설정
데이터가 쌓이기를 기다렸다가 꽉 차는 순간 데이터를 한번에 보냄</p>
</blockquote>
<pre><code class="language-java">public class BufferEx {
    public static void main(String[] args) throws Exception{
        // FileReader에 BufferedReader 보조스트림 연결
        BufferedReader br = new BufferedReader(new FileReader(&quot;test.txt&quot;));

        int lineNo = 1;
        while(true) {
            String str = br.readLine(); // 한 행을 읽음

            if(str == null) break; // 더이상 읽을 내용이 없으면 while문 종료
            System.out.println(lineNo + &quot;\t&quot; + str);
            lineNo++;
        }
        br.close();
    }
}</code></pre>
<h3 id="sec08-기본-타입-스트림-datastream">sec08. 기본 타입 스트림 <code>Data~Stream</code></h3>
<blockquote>
<p>기본 타입인 boolean, char, short, int, long, float, double 값 입출력 가능</p>
</blockquote>
<pre><code class="language-java">public class DataInputOutputStreamEx {
    public static void main(String[] args) throws Exception{
        // DateOutputStream 생성
        FileOutputStream fos = new FileOutputStream(&quot;test.db&quot;);
        DataOutputStream dos = new DataOutputStream(fos);

        // 기본 타입 출력
        dos.writeUTF(&quot;홍길동&quot;);
        dos.writeDouble(95.5);
        dos.writeInt(1);

        dos.writeUTF(&quot;차길동&quot;);
        dos.writeDouble(90.3);
        dos.writeInt(2);

        dos.flush();
        dos.close();
        fos.close();

        // DataInputStream 생성
        FileInputStream fis = new FileInputStream(&quot;test.db&quot;);
        DataInputStream dis = new DataInputStream(fis);

        // 기본 타입 출력
        for(int i=0; i&lt;2; i++) {
            String name = dis.readUTF();
            double score = dis.readDouble();
            int order = dis.readInt();
            System.out.println(name + &quot;:&quot; + score + &quot;:&quot; + order);
        }
        dis.close();
        fis.close();
    }
}</code></pre>
<h3 id="sec10-객체-스트림-objectstream">sec10. 객체 스트림 <code>Object~Stream</code></h3>
<blockquote>
<p>메모리에 생성된 객체를 파일 또는 네트워크로 출력
객체 출력시 필드값을 일렬로 늘어선 바이트로 변경하는 과정 -&gt; 직렬화
직렬화된 바이트를 객체의 필드값으로 복원하는 과정 -&gt; 역직렬화</p>
</blockquote>
<pre><code class="language-java">class Member implements Serializable {
    private static final long serialVersionUID = -622284561026719240L;
    private String id;
    private String name;
    public Member(String id, String name) {
        this.id = id;
        this.name = name;
    }
    @Override
    public String toString() {
        return id + &quot;: &quot; + name;
    }
}

class Product implements Serializable {
    private static final long serialVersionUID = -621812868470078544L;
    private String name;
    private int price;
    public Product(String name, int price) {
        this.name = name;
        this.price = price;
    }
    @Override
    public String toString() {
        return name + &quot;: &quot; + price;
    }
}

public class ObjectInputOutputStream {
    public static void main(String[] args) throws Exception{
        //FileOutputStream에 ObjectOutputStream 보조스트림 연결
        FileOutputStream fos = new FileOutputStream(&quot;object.dat&quot;);
        ObjectOutputStream oos = new ObjectOutputStream(fos);

        // 객체 생성
        Member m1 = new Member(&quot;fall&quot;, &quot;단풍이&quot;);
        Product p1 = new Product(&quot;노트북&quot;, 1500000);
        int[] arr1 = {1,2,3};

        // 객체 역직렬화하여 파일에 저장
        oos.writeObject(m1);
        oos.writeObject(p1);
        oos.writeObject(arr1);

        oos.flush();
        oos.close();
        fos.close();

        FileInputStream fis = new FileInputStream(&quot;object.dat&quot;);
        ObjectInputStream ois = new ObjectInputStream(fis);

        // 파일을 읽고 역직렬화하여 객체로 복원
        Member m2 = (Member) ois.readObject();
        Product p2 = (Product) ois.readObject();
        int[] arr2 = (int[]) ois.readObject();

        ois.close();
        fis.close();

        // 복원된 객체 내용 확인
        System.out.println(m2);
        System.out.println(p2);
        System.out.println(Arrays.toString(arr2));
    }
}</code></pre>
<hr>
<h2 id="sec11-file-files">sec11. File, Files</h2>
<blockquote>
<p>파일과 디렉토리 정보를 가지고 있는 클래스
<code>File file = new File(&quot;경로&quot;)</code>
<code>boolean isExist = file.exists();</code> 존재한다면 true 리턴</p>
</blockquote>
<p>&lt;File 클래스&gt; </p>
<pre><code class="language-java">public class FileEx {

    public static void main(String[] args) throws Exception{
        // File 객체 생성
        File dir = new File(&quot;images&quot;);
        File file1 = new File(&quot;file1.txt&quot;);
        File file2 = new File(&quot;file2.txt&quot;);
        File file3 = new File(&quot;file3.txt&quot;);

        // 존재하지 않으면 디렉토리 또는 파일 생성
        if(dir.exists() == false) {dir.mkdirs();} // 폴더 생성
        if(file1.exists() == false) {file1.createNewFile();} // 파일 생성
        if(file2.exists() == false) {file2.createNewFile();}
        if(file3.exists() == false) {file3.createNewFile();}

        // 폴더 내용 출력
        File temp = new File(&quot;D:\\seonjin\\javaStudy\\javaStudy\\ThisIsJava&quot;);
        File[] contents = temp.listFiles();
        SimpleDateFormat sdf = new SimpleDateFormat(&quot;yyyy-MM-dd a HH:mm&quot;);
        for(File file : contents) {
            System.out.printf(&quot;%-25s&quot;, sdf.format(new Date(file.lastModified())));
            if(file.isDirectory()) {
                System.out.printf(&quot;%-10s%-20s&quot;, &quot;&lt;DIR&gt;&quot;, file.getName());
            } else {
                System.out.printf(&quot;%-10s%-20s&quot;, file.length(), file.getName());
            }
            System.out.println();
        }
    }
}</code></pre>
<p>&lt;Files 클래스&gt;</p>
<pre><code class="language-java">public class FilesEx {
    public static void main(String[] args) {
        try {
            String data = &quot;&quot; 
                    + &quot;id: winter\n&quot; 
                    + &quot;email: winter@w.com\n&quot; 
                    + &quot;tel: 010-0000-0000&quot;;

            // Path 객체 생성
            Path path = Paths.get(&quot;user.txt&quot;);

            // 파일 생성 및 데이터 저장
            Files.writeString(Paths.get(&quot;user.txt&quot;), data, Charset.forName(&quot;UTF-8&quot;));

            // 파일 정보 얻기
            System.out.println(&quot;파일 유형: &quot; + Files.probeContentType(path));
            System.out.println(&quot;파일 크기: &quot; + Files.size(path) + &quot;byte&quot;);

            // 파일 읽기
            String content = Files.readString(path, Charset.forName(&quot;UTF-8&quot;));
            System.out.println(content); // 파일 내용
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[SpringBoot] MovieReviewProj - 3. Repository 생성]]></title>
            <link>https://velog.io/@seonjin_dev/SpringBoot-MovieReviewProj-3.-Repository-%EC%83%9D%EC%84%B1</link>
            <guid>https://velog.io/@seonjin_dev/SpringBoot-MovieReviewProj-3.-Repository-%EC%83%9D%EC%84%B1</guid>
            <pubDate>Tue, 12 Sep 2023 10:30:19 GMT</pubDate>
            <description><![CDATA[<h2 id="1-각-entity의-repository-생성">1. 각 Entity의 Repository 생성</h2>
<p>주의 ! interface로 생성, <code>JpaRepository&lt;Entity, PK Type&gt;</code></p>
<pre><code class="language-java">// Movie
public interface MovieRepository extends JpaRepository&lt;Movie, Long&gt; {
}
// MovieImage
public interface MovieImageRepository extends JpaRepository&lt;MovieImage, Long&gt; {
}
// Member
public interface MemberRepository extends JpaRepository&lt;Member, Long&gt; {
}
// Review
public interface ReviewRepository extends JpaRepository&lt;Review, Long&gt; {
}</code></pre>
<h2 id="2-테스트코드-실행">2. 테스트코드 실행</h2>
<h3 id="1-movierepositorytest-insert-test">1. MovieRepositoryTest (insert test)</h3>
<pre><code class="language-java">@SpringBootTest
class MovieRepositoryTest {
    @Autowired
    private MovieRepository movieRepository;

    @Autowired
    private MovieImageRepository imageRepository;

    @Commit
    @Transactional
    @Test
    public void insertMovies() {
        IntStream.rangeClosed(1, 100).forEach(i -&gt; { // 100개 데이터 삽입
            Movie movie = Movie.builder().title(&quot;제목..&quot; + i).build(); // movie 데이터 삽입
            System.out.println(&quot;-------------------&quot;);
            movieRepository.save(movie); // 삽입된 데이터 저장 -&gt; save되면 생성되는 mno값을 이용하여 movieImage 추가
            int count = (int) (Math.random() * 5) + 1; // 1~5장까지 img 삽입 가능
            for (int j = 0; j &lt; count; j++) {
                MovieImage movieImage = MovieImage.builder()
                        .uuid(String.valueOf(UUID.randomUUID()))
                        .movie(movie)
                        .imaName(&quot;test&quot; + j + &quot;.jpg&quot;)
                        .build();
                imageRepository.save(movieImage);
            }
        });
    }
}</code></pre>
<p><img src="https://velog.velcdn.com/images/seonjin_dev/post/518ff3f1-3016-451b-8b03-4d4dbfbe167d/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/seonjin_dev/post/8044b726-658d-4fdd-bb97-e5f10f0afde4/image.png" alt=""></p>
<p>-&gt; 영화마다 등록된 사진의 개수가 다른 것을 알 수 있음</p>
<h3 id="2-memberrepositorytest">2. MemberRepositoryTest</h3>
<pre><code class="language-java">@SpringBootTest
class MemberRepositoryTest {
    @Autowired
    private MemberRepository memberRepository;

    @Test
    public void insertMember() {
        IntStream.rangeClosed(1, 10).forEach(i -&gt; {
            Member member = Member.builder()
                    .email(&quot;t&quot; + i + &quot;@test.com&quot;)
                    .pw(&quot;1111&quot;)
                    .nickname(&quot;reviewer&quot; + i)
                    .build();
            memberRepository.save(member);
        });
    }
}</code></pre>
<h3 id="3-reviewrepositorytest">3. ReviewRepositoryTest</h3>
<pre><code class="language-java">@SpringBootTest
class ReviewRepositoryTest {
    @Autowired
    private ReviewRepository reviewRepository;

    @Test
    public void insertMovieReviews() {
        // 리뷰 등록
        IntStream.rangeClosed(1, 200).forEach(i -&gt; {
            // 영화번호
            Long mno = (long)(Math.random()*100) + 1;
            // 리뷰어번호
            Long mid = ((long)(Math.random()*100) + 1);
            Member member = Member.builder().mid(mid).build();

            Review movieReview = Review.builder()
                    .member(member)
                    .movie(Movie.builder().mno(mno).build())
                    .grade((int)(Math.random()*5)+1)
                    .text(&quot;소감은,,,&quot; + i)
                    .build();

            reviewRepository.save(movieReview);
        });
    }
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[SpringBoot] MovieReviewProj - 2. Entity 작성]]></title>
            <link>https://velog.io/@seonjin_dev/SpringBoot-MovieReviewProj-2.-Entity-%EC%9E%91%EC%84%B1</link>
            <guid>https://velog.io/@seonjin_dev/SpringBoot-MovieReviewProj-2.-Entity-%EC%9E%91%EC%84%B1</guid>
            <pubDate>Tue, 12 Sep 2023 10:07:52 GMT</pubDate>
            <description><![CDATA[<h2 id="1-baseentity">1. BaseEntity</h2>
<pre><code class="language-java">@MappedSuperclass
@EntityListeners(value = {AuditingEntityListener.class})
@Getter
public class BaseEntity {
    @CreatedDate
    @Column(name = &quot;regdate&quot;, updatable = false)
    private LocalDateTime regDate;

    @LastModifiedDate
    @Column(name = &quot;moddate&quot;)
    private LocalDateTime modDate;
}
// Application class에 @EnableJpaAuditing 추가</code></pre>
<blockquote>
<p>@EnableJpaAuditing : 생성일자, 수정일자 자동으로 등록</p>
</blockquote>
<hr>
<h2 id="2-movie-entity">2. Movie Entity</h2>
<pre><code class="language-java">@Entity
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Getter
@ToString
public class Movie {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long mno; // movie 번호
    private String title; // 제목
}</code></pre>
<hr>
<h2 id="3-movieimage">3. MovieImage</h2>
<pre><code class="language-java">@Entity
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Getter
@ToString(exclude = &quot;movie&quot;) // movie entity와 연관관계를 가짐을 명시
public class MovieImage {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long inum; // image 번호
    private String uuid;
    private String imaName;
    private String path;

    // M:1 (Lazy Fetch 진행)
    @ManyToOne(fetch = FetchType.LAZY)
    private Movie movie;
}</code></pre>
<hr>
<h2 id="4-member">4. Member</h2>
<pre><code class="language-sql">@Entity
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Getter
@ToString
@Table(name = &quot;m_member&quot;)
public class Member extends BaseEntity{
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long mid;
    private String email;
    private String pw;
    private String nickname;
}</code></pre>
<hr>
<h2 id="5-review">5. Review</h2>
<ul>
<li>매핑테이블은 &#39;동사&#39;나 &#39;히스토리&#39;를 의미하는 테이블이다</li>
<li>이 프로젝트에서는 &#39;회원이 영화에 평점을 준다&#39;에서 &#39;평점을 준다&#39;의 역할을 하는 것이 Review Entity이다</li>
<li>ManyToMany를 사용하는 경우에 두 엔티티간의 관계 설정은 가증하지만, 추가적인 데이터 기록이 불가능하다</li>
<li>Mapping Table을 사용하여 관계 설정과 데이터 기록을 할 수 있다</li>
<li>Mapping Table은 두 Entity의 PK를 참조하는 형태로 구성한다</li>
</ul>
<p><img src="https://velog.velcdn.com/images/seonjin_dev/post/13e1fd66-47de-4904-aa1e-bc7eb2f540cc/image.png" alt=""></p>
<pre><code class="language-sql">@Entity
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Getter
@ToString (exclude = {&quot;movie&quot;, &quot;m_member&quot;})
public class Review extends BaseEntity{
    @Id
    @GeneratedValue (strategy = GenerationType.IDENTITY)
    private Long reviewnum;

    @ManyToOne(fetch = FetchType.LAZY)
    private Movie movie; // Movie Entity와 일대다 관계

    @ManyToOne(fetch = FetchType.LAZY)
    private Member member; // Member Entity와 일대다 관계

    private int grade;

    private String text;
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[SQL] 서브쿼리]]></title>
            <link>https://velog.io/@seonjin_dev/SQL-%EC%84%9C%EB%B8%8C%EC%BF%BC%EB%A6%AC</link>
            <guid>https://velog.io/@seonjin_dev/SQL-%EC%84%9C%EB%B8%8C%EC%BF%BC%EB%A6%AC</guid>
            <pubDate>Sun, 10 Sep 2023 07:50:10 GMT</pubDate>
            <description><![CDATA[<h2 id="서브쿼리">서브쿼리</h2>
<blockquote>
<p>&lt;서브쿼리&gt;</p>
<ul>
<li>Java 객제지향의 상속과 똑같은 개념이다</li>
<li>상속당한 자식 객체는 부모 객체의 인스턴스를 사용할 수 있고, 부모는 자식객체의 인스턴스를 사용할수 없다</li>
</ul>
<p>&lt;장점&gt;</p>
<ul>
<li>서브쿼리는 쿼리를 구조화시키므로, 쿼리의 각 부분을 명확히 구분할 수 있게 해준다</li>
<li>서브쿼리는 복잡한 JOIN이나 UNION과 같은 동작을 수행할 수 있는 또 다른 방법을 제공한다</li>
<li>서브쿼리는 복잡한 JOIN이나 UNION 보다 가독성이 좋다</li>
</ul>
<p>&lt;특징&gt;
서브쿼리는 SELECT문으로만 작성 할 수 있다
반드시 괄호()안에 존재하여야 한다
괄호가 끝나고 끝에 세미콜론을 쓰지 않는다
ORDER BY를 사용 할 수 없다</p>
</blockquote>
<hr>
<h2 id="스칼라-서브쿼리">스칼라 서브쿼리</h2>
<ul>
<li>SELECT, ORDER BY 등 컬럼이 오는 위치에서 반드시 하나의 값만 반환한다<pre><code class="language-sql">SELECT *, (SELECT comm FROM emp WHERE ename = &#39;홍길동&#39;)
FROM department;</code></pre>
</li>
</ul>
<hr>
<h2 id="인라인-뷰">인라인 뷰</h2>
<ul>
<li>FROM절에서 사용</li>
<li>View<ul>
<li>재사용이 가능하도록 저장한 객체</li>
<li>가상테이블이므로 DB에 저장되지 않음</li>
</ul>
</li>
<li>인라인 뷰를 사용하는 경우 무조건 alias 지정해 주어야 한다.<pre><code class="language-sql">SELECT profno, p.name
FROM (SELECT DISTINCT profno FROM student) e 
  JOIN professor p 
      USING(profno);</code></pre>
</li>
</ul>
<hr>
<h2 id="중첩-서브쿼리">중첩 서브쿼리</h2>
<h3 id="단일행">단일행</h3>
<ul>
<li>1건 이하의 데이터를 반환한다</li>
<li>= &lt; &gt; &lt;= &gt;= &lt;&gt; 연산자 사용<pre><code class="language-sql">SELECT ename, comm 
FROM emp 
WHERE comm &lt; (SELECT comm FROM emp WHERE ename = &#39;WARD&#39;);
</code></pre>
</li>
</ul>
<p>SELECT NAME, weight
FROM student
WHERE weight &gt; (SELECT AVG(weight) FROM student WHERE deptno1 = 201);</p>
<p>-- 서브쿼리 내 join 가능
SELECT NAME, weight
FROM student
WHERE weight &gt; (SELECT AVG(s.weight) 
                FROM student s JOIN department d ON s.deptno1 = d.deptno 
                WHERE d.dname = &#39;전자공학과&#39;)</p>
<p>SELECT s.studno, s.name, e.total
FROM student s JOIN exam_01 e USING (studno)
WHERE e.total BETWEEN (SELECT min_point FROM hakjum WHERE grade = &#39;A0&#39;)
              AND (SELECT max_point FROM hakjum WHERE grade = &#39;A0&#39;);</p>
<pre><code>### 다중행
- 여러 행의 데이터를 반환한다
- In, Any, All, Some, Exists 조건 사용
```sql
-- In
SELECT e.EMPNO, e.NAME, e.position, d.DNAME
FROM emp2 e JOIN dept2 d ON E.deptno = d.dcode 
WHERE e.DEPTNO IN (SELECT dcode FROM dept2 WHERE AREA = &#39;포항본사&#39;);

-- Any : True 결과값이 하나 이상일 때 (||)
SELECT empno, NAME, POSITION, pay FROM emp2
WHERE pay &gt; ANY (SELECT pay FROM emp2 WHERE POSITION = &#39;과장&#39;);

-- All : 모든 결과값이 True일 때 (&amp;&amp;)
SELECT NAME, grade, weight FROM student
WHERE weight &lt; ALL (SELECT weight FROM student WHERE grade = 2);

-- Exists : 결과가 하나라도 존재하면 조회
SELECT profno, name
FROM professor p
WHERE EXISTS (SELECT * FROM student WHERE profno = p.profno);
</code></pre><h3 id="다중컬럼">다중컬럼</h3>
<ul>
<li>여러 컬럼의 데이터를 반환한다</li>
<li>비교 컬럼의 개수와 위치가 동일해야 한다<pre><code class="language-sql">SELECT NAME, grade, height FROM student
WHERE (grade, height) IN (SELECT grade, max(height) 
                        FROM student GROUP BY grade)
ORDER BY 2;</code></pre>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[SQL] CONSTRAINT 제약조건]]></title>
            <link>https://velog.io/@seonjin_dev/SQL-CONSTRAINT-%EC%A0%9C%EC%95%BD%EC%A1%B0%EA%B1%B4</link>
            <guid>https://velog.io/@seonjin_dev/SQL-CONSTRAINT-%EC%A0%9C%EC%95%BD%EC%A1%B0%EA%B1%B4</guid>
            <pubDate>Sun, 10 Sep 2023 07:21:45 GMT</pubDate>
            <description><![CDATA[<h3 id="제약조건">제약조건</h3>
<p>데이터의 무결성을 지키기 위해, 데이터를 입력받을 때 실행되는 검사 규칙을 의미한다</p>
<h2 id="not-null">not null</h2>
<p>null값을 허용하지 않는다</p>
<pre><code class="language-sql">CREATE TABLE Test(
    ID INT NOT NULL,
    Name VARCHAR(30)
);</code></pre>
<hr>
<h2 id="unique">unique</h2>
<p>UNIQUE 조건이 설정된 필드는 중복된 값을 저장할 수 없다</p>
<pre><code class="language-sql">CREATE TABLE Test(
    ID INT NOT NULL,
    Name VARCHAR(30) UNIQUE
);</code></pre>
<hr>
<h2 id="pk--fk">PK / FK</h2>
<pre><code class="language-sql">-- table 생성 시 제약조건을 지정하는 방법

-- 1
CREATE TABLE article (
    num INT AUTO_INCREMENT PRIMARY KEY,
    title VARCHAR(50),
    content VARCHAR(1000),
    writer VARCHAR(20) REFERENCE user(id)
);
-- 2
CREATE TABLE article (
    num INT AUTO_INCREMENT,
    title VARCHAR(50),
    content VARCHAR(1000),
    writer VARCHAR(20),
    PRIMARY KEY(num),
    FOREIGN KEY(writer) REFERENCE user(id)
);</code></pre>
<h3 id="primary-key">primary key</h3>
<p>테이블의 기본 키이다
테이블의 데이터를 쉽고 빠르게 찾도록 도와주는 역할을 한다
NOT NULL, UNIQUE의 특성을 가진다</p>
<pre><code class="language-sql">-- pk 지정
ALTER TABLE user ADD CONSTRAINT USER_PK PRIMARY KEY(id);</code></pre>
<h3 id="foreien-key">foreien key</h3>
<p>테이블의 외래 키이다
한 테이블을 다른 테이블과 연결해주는 역할을 한다
기준이 되는 테이블의 내용을 참조해서 레코드가 입력된다
참조되는 테이블의 컬럼은 반드시 UNIQUE 또는 PK로 지정되어 있어야 한다</p>
<pre><code class="language-sql">-- fk 지정
ALTER TABLE article ADD CONSTRAINT ARTICLE_USER_FK 
    FOREIGN KEY(writer) REFERENCES user(id);

-- &#39;hong&#39;이 참조 테이블(user)에 없으면 fk 제약조건 위배
INSERT INTO article VALUES(NULL, &#39;제목&#39;, &#39;내용&#39;, &#39;hong&#39;); -- error
INSERT INTO article VALUES(NULL, &#39;제목&#39;, &#39;내용&#39;, NULL); -- ok, 단, null은 가능
INSERT INTO user VALUES (&#39;hong&#39;, &#39;홍길동&#39;); -- error
INSERT INTO article VALUES(NULL, &#39;제목&#39;, &#39;내용&#39;, &#39;hong&#39;); -- success &#39;hong&#39;이 user의 id를 참조

-- 외부 테이블(article)에서 &#39;hong&#39;을 참조하고 있으면 삭제/변경할 수 없다
DELETE FROM user WHERE id=&#39;hong&#39;; -- error 
UPDATE user SET id=&#39;kong&#39; WHERE id=&#39;hong&#39;; -- error
UPDATE user SET NAME = &#39;홍홍&#39; WHERE id = &#39;hong&#39;; -- ok, 참조하지 않는 컬럼의 내용 변경 가능

ALTER TABLE article DROP CONSTRAINT ARTICLE_USER_FK; -- fk 제약조건 삭제
INSERT INTO article VALUES(NULL, &#39;송제목&#39;, &#39;송내용&#39;, &#39;song&#39;); -- ok

-- on delete cascade : B가 fk로 A을 가리키고 있을 때, A를 삭제하면 B도 같이 삭제되는 기능 (참조하는 모든 데이터 같이 삭제)
-- 설정하려는 fk 컬럼 데이터 중 제약조건에 위배되는 데이터가 있으면 제약조건을 지정할 수 없다
ALTER TABLE article ADD CONSTRAINT ARTICLE_USER_FK FOREIGN KEY(writer) REFERENCES user(id) ON DELETE CASCADE; -- error 

UPDATE article SET writer=&#39;hong&#39; WHERE writer&lt;&gt;&#39;hong&#39;; -- &#39;song&#39;을 변경 후 다시 fk 지정시 ok

DELETE FROM user WHERE id=&#39;hong&#39;; -- ok, user의 id, article의 writer가 &#39;hong&#39;인 데이터 모두 삭제됨
</code></pre>
<hr>
<h2 id="check">check</h2>
<p>값의 범위 제한</p>
<pre><code class="language-sql">CREATE TABLE temp3( 
    name VARCHAR(20) NOT NULL,
    age INT DEFAULT 1 CHECK(age&gt;0)
);

INSERT INTO temp3 (NAME) VALUES(&#39;hong&#39;);
INSERT INTO temp3 VALUES(&#39;kong&#39;, 1);
INSERT INTO temp3 VALUES(&#39;kong&#39;, -1); -- error</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[SQL] 관리구문 - DDL, DML, DCL, TCL]]></title>
            <link>https://velog.io/@seonjin_dev/SQL-%EA%B4%80%EB%A6%AC%EA%B5%AC%EB%AC%B8-DDL-DML-DCL-TCL</link>
            <guid>https://velog.io/@seonjin_dev/SQL-%EA%B4%80%EB%A6%AC%EA%B5%AC%EB%AC%B8-DDL-DML-DCL-TCL</guid>
            <pubDate>Sun, 10 Sep 2023 07:03:13 GMT</pubDate>
            <description><![CDATA[<h2 id="ddl--data-definition-language">DDL : Data Definition Language</h2>
<h3 id="1-create">1. create</h3>
<pre><code class="language-sql">-- DB 생성
CREATE DATABASE db_name;

-- Table 생성
CREATE TABLE table_name(
    column_name type constraint
);</code></pre>
<h3 id="2-alter">2. alter</h3>
<pre><code class="language-sql">-- add column type 테이블에 컬럼 추가
ALTER TABLE persons ADD email VARCHAR(255);
ALTER TABLE emp_sub ADD deptno int DEFAULT 10; -- default값 설정

-- add constraint 제약조건명 제약조건(컬럼명) : 제약조건 추가
ALTER TABLE tcons ADD CONSTRAINT tcons_no_pk PRIMARY KEY(NO); 

-- modify, rename column 테이블의 컬럼 정보 변경
ALTER TABLE persons MODIFY COLUMN city VARCHAR(255); -- 컬럼 타입 변경
ALTER TABLE emp_sub RENAME COLUMN deptno TO dcode; -- 컬럼명 변경

-- drop column 테이블의 컬럼 삭제
ALTER TABLE persons DROP COLUMN email;
</code></pre>
<h3 id="3-drop">3. drop</h3>
<pre><code class="language-sql">-- DB 삭제
DROP DATABASE db_name;

-- Table 삭제
DROP TABLE table_name;</code></pre>
<h3 id="4-truncate">4. truncate</h3>
<pre><code class="language-sql">-- truncate table 비우기 
SELECT * FROM emp_10;
TRUNCATE TABLE emp_10;</code></pre>
<hr>
<h2 id="dml--data-manipulation-language">DML : Data Manipulation Language</h2>
<h3 id="1-insert">1. insert</h3>
<pre><code class="language-sql">-- 모든 컬럼에 삽입하기 (컬럼 순서와 일치해야 함)
-- insert into table_name values (value1, value2, ...);
INSERT INTO user VALUES(&#39;park&#39;, &#39;박길동&#39;);

-- 특정 컬럼에 삽입하기
-- insert into table_name (col1, col2, ...) values (value1, value2, ...);
INSERT INTO user (id, NAME) VALUES (&#39;kong&#39;, &#39;공길동&#39;);
INSERT INTO user (NAME, id) VALUES (&#39;공길동&#39;, &#39;kong&#39;);

-- select 결과값을 삽입하기
INSERT INTO emp_sub (id, NAME) 
SELECT empno, ename FROM emp WHERE deptno = 10;</code></pre>
<h3 id="2-delete">2. delete</h3>
<pre><code class="language-sql">-- delete from table_name where 조건;

-- emp에서 이름이 hong인 데이터 삭제
DELETE FROM emp WHERE ename = &#39;hong&#39;;
</code></pre>
<h3 id="3-update">3. update</h3>
<pre><code class="language-sql">-- update table_name set col1 = val1, col2 = val2, ... where 조건;

-- emp에서 hang이 담당업무가 CLERK로 변경, 담당매니저가 7782로 변경
UPDATE emp SET job = &#39;CLERK&#39;, mgr = 7782 WHERE ename=&#39;hong&#39;;
</code></pre>
<h3 id="4-select">4. select</h3>
<hr>
<h2 id="dcl--data-controll-language">DCL : Data Controll Language</h2>
<ol>
<li>grant
```sql</li>
</ol>
<p>-- 계정 생성 (root 만 가능)
CREATE user kosta IDENTIFIED BY &#39;1234&#39;; </p>
<p>-- 계정의 비밀번호 변경
ALTER user kosta IDENTIFIED BY &#39;2345&#39;; </p>
<p>-- 계정 삭제
DROP user kosta;</p>
<p>-- kosta 계정에 kotest SELECT, INSERT, UPDATE 권한 부여
GRANT SELECT,INSERT, UPDATE ON kotest.* TO kosta;</p>
<p>-- kosta 계정에 kotest의 모든 권한 부여
GRANT ALL PRIVILEGES ON kotest.* TO kosta;</p>
<p>-- kosta 계정에 모든 DB의 모든 권한 부여
grant ALL PRIVILEGES ON <em>.</em> TO kosta;</p>
<pre><code>2. revoke
```sql
-- kosta 계정에 kotest SELECT, INSERT, UPDATE 권한 삭제
REVOKE SELECT, INSERT, UPDATE ON kotest.* FROM &#39;kosta&#39;;

-- kosta 계정에서 update 권한 삭제
REVOKE UPDATE ON kotest.* FROM &#39;kosta&#39;;

-- kosta 계정에서  모든 권한 삭제
REVOKE ALL PRIVILEGES ON *.* from &#39;kosta&#39;;</code></pre><ol start="3">
<li>roll
```sql</li>
</ol>
<p>-- DBMS 권한 중개 역할
CREATE ROLL roll_name;
GRANT 권한 TO roll_name;
GRANT roll_name TO 사용자;</p>
<pre><code>---

## TCL : Transaction Controll Language
1. commit : 변경사항 확정, 반영
2. rollback : 변경사항 취소
3. savepoint : rollback 범위 지정
```sql
START TRANSACTION; -- 트랜잭션 시작

DELETE FROM emp WHERE deptno = 40; -- 1

UPDATE emp SET job = &#39;CLERK&#39;, mgr = 7782 WHERE ename=&#39;hong&#39;; -- 2

SAVEPOINT S1; -- savepoint 생성

UPDATE emp SET comm = 100 WHERE comm IS NULL OR comm = 0; -- 3

ROLLBACK TO S1; 

UPDATE emp SET comm = comm+sal*0.1 WHERE deptno = 10; -- 4

COMMIT;

-- 결과 : ROLLBACK TO S1에 의해 1, 2, 4 쿼리만 실행된다
</code></pre><hr>
<h2 id="drop-vs-truncate-vs-delete">DROP vs. TRUNCATE vs. DELETE</h2>
<table>
<thead>
<tr>
<th>DROP</th>
<th>TRUNCATE</th>
<th>DELETE</th>
</tr>
</thead>
<tbody><tr>
<td>DDL</td>
<td>DDL/DML</td>
<td>DML</td>
</tr>
<tr>
<td>Auto-Commit / Rollback 안 됨</td>
<td>Auto-Commit / Rollback 안 됨</td>
<td>User-Commit / Rollback 가능</td>
</tr>
<tr>
<td>log 남지 않음</td>
<td>log 남지 않음</td>
<td>log 남음</td>
</tr>
<tr>
<td>테이블의 정의 삭제</td>
<td>최초의 상태, 디스크 초기화, 테이블 재사용</td>
<td>데이터만 삭제, 용량 유지</td>
</tr>
</tbody></table>
]]></description>
        </item>
        <item>
            <title><![CDATA[[SQL] DDL (Data Definition Language)]]></title>
            <link>https://velog.io/@seonjin_dev/SQL-DDL-Data-Definition-Language</link>
            <guid>https://velog.io/@seonjin_dev/SQL-DDL-Data-Definition-Language</guid>
            <pubDate>Fri, 08 Sep 2023 00:27:06 GMT</pubDate>
            <description><![CDATA[<h2 id="1-create">1. CREATE</h2>
<pre><code class="language-sql">-- DB 생성
CREATE DATABASE db_name;

-- Table 생성
CREATE TABLE table_name(
    column_name type constraint
);

-- 조건에 만족하는 데이터를 추출하여 테이블 복사
CREATE TABLE emp_sub AS
SELECT empno, ename, job, HIREDATE, sal FROM emp WHERE deptno=10;

-- 테이블을 생성할 때 데이터를 삽입하지 않고 테이블 구조만 복사
CREATE TABLE emp_t AS
SELECT * FROM emp WHERE 1=2;
</code></pre>
<h2 id="2-alter">2. ALTER</h2>
<pre><code class="language-sql">-- add column 테이블에 컬럼 추가
ALTER TABLE persons ADD email VARCHAR(255);
ALTER TABLE emp_sub ADD deptno int DEFAULT 10; -- default값 설정

-- modify column 테이블의 컬럼 정보 변경
ALTER TABLE persons MODIFY COLUMN city VARCHAR(255); -- 컬럼 타입 변경
ALTER TABLE emp_sub RENAME COLUMN deptno TO dcode; -- 컬럼명 변경

-- drop column 테이블의 컬럼 삭제
ALTER TABLE persons DROP COLUMN email;</code></pre>
<h2 id="3-drop">3. DROP</h2>
<pre><code class="language-sql">-- DB 삭제
DROP DATABASE db_name;

-- Table 삭제
DROP TABLE table_name;</code></pre>
<h2 id="4-truncate">4. TRUNCATE</h2>
<pre><code class="language-sql">-- truncate table 비우기 
SELECT * FROM emp_10;
TRUNCATE TABLE emp_10;</code></pre>
<h2 id="5-rename">5. RENAME</h2>
<pre><code class="language-sql">-- rename table 테이블명 변경
RENAME TABLE emp_sub TO emp_10;</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[이것이 자바다] 15. 컬렉션 자료구조]]></title>
            <link>https://velog.io/@seonjin_dev/%EC%9D%B4%EA%B2%83%EC%9D%B4-%EC%9E%90%EB%B0%94%EB%8B%A4-15.-%EC%BB%AC%EB%A0%89%EC%85%98-%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0</link>
            <guid>https://velog.io/@seonjin_dev/%EC%9D%B4%EA%B2%83%EC%9D%B4-%EC%9E%90%EB%B0%94%EB%8B%A4-15.-%EC%BB%AC%EB%A0%89%EC%85%98-%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0</guid>
            <pubDate>Tue, 05 Sep 2023 14:40:12 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/seonjin_dev/post/fba9ec09-dd5d-401a-a9f3-4aae28afd00b/image.png" alt=""></p>
<p>📚 이것이 자바다 [개정판]</p>
<hr>
<h2 id="sec01-컬렉션-프레임워크">sec01. 컬렉션 프레임워크</h2>
<blockquote>
</blockquote>
<ul>
<li>자바는 자료구조를 바탕으로 관련된 인터페이스와 클래스를 java.util 패키지에 포함시켜 놓았다</li>
<li>이 모든 것을 총칭하여 컬렉션 프레임워크라고 부른다</li>
<li>몇 가지 인터페이스를 통해 다양한 컬렉션 클래스를 이용할 수 있도록 설계되어 있다</li>
</ul>
<p><img src="https://hyuntaekhong.github.io/assets/images/java/java-basic25/collection01.png" alt=""></p>
<hr>
<h2 id="sec02-list-컬렉션">sec02. List 컬렉션</h2>
<blockquote>
</blockquote>
<ul>
<li>순서를 유지하고 저장한다</li>
<li>중복 저장이 가능하다</li>
</ul>
<table>
<thead>
<tr>
<th>기능</th>
<th>메소드</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>객체 추가</td>
<td>add(E e)</td>
<td>맨 끝에 객체 추가</td>
</tr>
<tr>
<td></td>
<td>add(int index, E element)</td>
<td>주어진 인덱스에 객체 추가</td>
</tr>
<tr>
<td></td>
<td>set(int index, E element)</td>
<td>주어진 인덱스의 객체를 새로운 객체로 변경</td>
</tr>
<tr>
<td>객체 검색</td>
<td>contains(Object o)</td>
<td>객체의 저장여부 확인</td>
</tr>
<tr>
<td></td>
<td>get(int index)</td>
<td>주어진 인덱스에 저장된 객체 리턴</td>
</tr>
<tr>
<td></td>
<td>isEmpty()</td>
<td>컬렉션이 비어 있는지 확인</td>
</tr>
<tr>
<td></td>
<td>size()</td>
<td>저장된 전체 객체 수 리턴</td>
</tr>
<tr>
<td>객체 삭제</td>
<td>clear()</td>
<td>저장된 모든 객체 삭제</td>
</tr>
<tr>
<td></td>
<td>remove(int index)</td>
<td>주어진 인덱스에 저장된 객체 삭제</td>
</tr>
<tr>
<td></td>
<td>remove(Object o)</td>
<td>주어진 객체 삭제</td>
</tr>
</tbody></table>
<h3 id="1-arraylist">1. ArrayList</h3>
<blockquote>
</blockquote>
<pre><code class="language-java">List&lt;E&gt; list = new ArrayList&lt;E&gt;(); // E에 지정된 타입의 객체만 저장
List&lt;E&gt; list = new ArrayList&lt;&gt;(); // E에 지정된 타입과 동일하면 생략 가능
List list = new ArrayList(); // 모든 타입의 객체 저장</code></pre>
<ul>
<li>객체를 추가하면 내부 배열에 객체가 저장된다 (null 저장 가능)</li>
<li>객체 자체를 저장하는 것이 아닌 객체의 번지를 저장한다</li>
<li>동일한 객체를 중복하여 저장하는 경우 동일한 번지가 저장된다</li>
<li>제한 없이 객체를 추가할 수 있다는 것이 일반 배열과 차이점이다</li>
<li>객체를 추가하거나 제거하면 인덱스 번호가 1씩 당겨지거나 밀려난다
  따라서, 빈번한 객체 삭제와 삽입이 일어나는 곳에서 사용하지 않는 것이 좋다<pre><code class="language-java">  list.remove(2);
   list.remove(2); 
  // 2번 인덱스를 삭제하면 기존의 3번이 2번으로 변경되므로
  // 다시 2번 인덱스를 제거할 수 있음</code></pre>
</li>
</ul>
<h3 id="2-vector">2. Vector</h3>
<blockquote>
</blockquote>
<pre><code class="language-java">List&lt;E&gt; list = new Vector&lt;E&gt;(); // E에 지정한 타입의 객체만 저장
List&lt;E&gt; list = new Vector&lt;&gt;(); // E에 지정된 타입과 동일하면 생략 가능
List list = new Vector(); // 모든 타입의 객체 저장</code></pre>
<ul>
<li>ArrayList와 동일한 내부 구조를 가지고 있으나 Vector는 동기화된 메소드로 구성되어 있다</li>
<li>멀티 스레드가 동시에 Vector() 메소드를 실행할 수 없다는 뜻으로 멀티 스레드 환경에서 안전하게 객체 변경이 가능하다</li>
</ul>
<h3 id="3-linkedlist">3. LinkedList</h3>
<blockquote>
</blockquote>
<pre><code class="language-java">List&lt;E&gt; list = new LinkedList&lt;E&gt;(); 
List&lt;E&gt; list = new LinkedList&lt;&gt;(); 
List list = new LinkedList(); </code></pre>
<ul>
<li>ArrayList와 사용 방법은 동일하지만 내부 구조는 완전히 다르다</li>
<li>LinkedList는 인접 객체를 체인처럼 연결하여 관리한다</li>
<li>특정 위치에서 객체가 변경되면 바로 앞뒤 링크만 변경하면 되므로 빈번한 객체 변경이 일어나는 곳에서 좋은 성능을 발휘한다</li>
</ul>
<hr>
<h2 id="sec03-set-컬렉션">sec03. Set 컬렉션</h2>
<blockquote>
</blockquote>
<ul>
<li>순서를 유지하지 않고 저장</li>
<li>중복 저장 안됨</li>
</ul>
<table>
<thead>
<tr>
<th>기능</th>
<th>메소드</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>객체 추가</td>
<td>add(E e)</td>
<td>주어진 객체를 저장하면 true, 중복 객체면 false 리턴</td>
</tr>
<tr>
<td>객체 검색</td>
<td>contains(Object o)</td>
<td>주어진 객체가 저장되어 있는지 여부</td>
</tr>
<tr>
<td></td>
<td>boolean containsValue(Object value)</td>
<td>주어진 값이 있는지 여부</td>
</tr>
<tr>
<td></td>
<td>isEmpty()</td>
<td>컬렉션이 비어 있는지 확인</td>
</tr>
<tr>
<td></td>
<td>Iterator<E> iterator()</td>
<td>저장된 객체를 한 번씩 가져오는 반복자 리턴</td>
</tr>
<tr>
<td></td>
<td>size()</td>
<td>저장되어 있는 전체 객체 수 리턴</td>
</tr>
<tr>
<td>객체 삭제</td>
<td>clear()</td>
<td>저장된 모든 객체를 삭제</td>
</tr>
<tr>
<td></td>
<td>remove(Object o)</td>
<td>주어진 객체를 삭제</td>
</tr>
</tbody></table>
<h3 id="1-hashset">1. HashSet</h3>
<blockquote>
</blockquote>
<pre><code class="language-java">Set&lt;E&gt; set = new HashSet&lt;E&gt;();
Set&lt;E&gt; set = new HashSet&lt;&gt;();
Set set = new HashSet();</code></pre>
<blockquote>
</blockquote>
<ul>
<li>다른 객체라도 hashCode() 리턴값이 같고 equals()가 true를 리턴하면 동일한 객체로 판단한다</li>
<li>Set 컬렉션은 인덱스로 객체를 검색해서 가져오는 메소드가 없어서 객체를 한 개씩 반복해서 가져와야 한다<ul>
<li><code>hasNext()</code> 가져올 객체가 있으면 true를 리턴하고 없으면 false를 리턴</li>
<li><code>next()</code> 컬렉션에서 하나의 객체를 가져옴</li>
<li><code>remove()</code> next()로 가져온 객체를 Set 컬렉션에서 제거</li>
</ul>
</li>
</ul>
<pre><code class="language-java">// 1. for문을 이용하는 방법
Set&lt;E&gt; set = new HashSet&lt;&gt;();
for(E e : set) {
    ...
}

// 2. iterator() 메소드로 반복자를 얻는 방법
Set&lt;E&gt; set = new HashSet&lt;&gt;();
Iterator&lt;E&gt; iterator = set.iterator();
while(iterator.hasNext()) {
    E e = iterator.next();
}</code></pre>
<h3 id="2-treeset">2. TreeSet</h3>
<blockquote>
</blockquote>
<pre><code class="language-java">TreeSet&lt;E&gt; treeSet = new TreeSet&lt;E&gt;();
TreeSet&lt;E&gt; treeSet = new TreeSet&lt;&gt;();
// 검색 관련 메소드가 TreeSet에만 정의되어 있으므로 TreeSet 타입으로 대입</code></pre>
<blockquote>
</blockquote>
<ul>
<li>이진 트리 기반 : 루트 노드에서 시작하여 각 노드에 2개의 노드를 연결한 트리 형태의 구조</li>
<li>자동 정렬되며 부모 노드 객체와 비교하여 낮으면 왼쪽, 높으면 오른쪽 자식 노드에 저장한다</li>
<li>검색 기능을 강화시킨 컬렉션이다</li>
</ul>
<h2 id="sec04-map-컬렉션">sec04. Map 컬렉션</h2>
<blockquote>
</blockquote>
<ul>
<li>Key-Value로 구성된 Entry 객체를 저장한다 (key와 value 모두 객체이다)</li>
<li>Key는 중복 저장할 수 없고, 동일한 키로 값을 저장하면 새로운 값으로 변경된다</li>
<li>Value는 중복 저장할 수 있다</li>
</ul>
<table>
<thead>
<tr>
<th>기능</th>
<th>메소드</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>객체 추가</td>
<td>put(K key, V value)</td>
<td>키와 값을 추가하고 저장되면 값을 리턴</td>
</tr>
<tr>
<td>객체 검색</td>
<td>containsKey(Object key)</td>
<td>주어진 키가 있는지 여부</td>
</tr>
<tr>
<td></td>
<td>containsValue(Object value)</td>
<td>주어진 값이 있는지 여부</td>
</tr>
<tr>
<td></td>
<td>Set(Map.Entry&lt;K,V&gt;&gt; entrySet()</td>
<td>키와 값의 쌍으로 구성된 모든 Map.Entry 객체를 Set에 담아 리턴</td>
</tr>
<tr>
<td></td>
<td>get(Object key)</td>
<td>주어진 키의 값을 리턴</td>
</tr>
<tr>
<td></td>
<td>isEmpty()</td>
<td>컬렉션이 비어있는지 여부</td>
</tr>
<tr>
<td></td>
<td>Set<K> keySet()</td>
<td>모든 키를 Set 객체에 담아 리턴</td>
</tr>
<tr>
<td></td>
<td>size()</td>
<td>저장된 키의 총 수를 리턴</td>
</tr>
<tr>
<td></td>
<td>Collection<V> values()</td>
<td>저장된 모든 값 Collection에 담아 리턴</td>
</tr>
<tr>
<td>객체 삭제</td>
<td>clear()</td>
<td>모든 Map.Entry(키와 값)를 삭제</td>
</tr>
<tr>
<td></td>
<td>remove(Object key)</td>
<td>주어진 키와 일치하는 Map.Entry를 삭제하고 삭제되면 값을 리턴</td>
</tr>
</tbody></table>
<h3 id="1-hashmap">1. HashMap</h3>
<blockquote>
</blockquote>
<pre><code class="language-java">Map&lt;K, V&gt; map = new HashMap&lt;K, V&gt;();
Map&lt;String, Integer&gt; map = new HashMap&lt;String, Integer&gt;();
Map&lt;String, Integer&gt; map = new HashMap&lt;&gt;();</code></pre>
<p>키로 사용할 객체의 hashCode() 메소드 리턴값이 같고 equals() 메소드가 true를 리턴할 경우, 동일한 키로 보고 중복 저장을 허용하지 않는다</p>
<pre><code class="language-java">// key set 컬렉션을 얻고 반복해서 키와 값 얻기
Set&lt;String&gt; keySet = map.keySet();
Iterator&lt;String&gt; keyIterator = keySet.iterator();
while(keyIterator.hasNext()) {
    String k = keyIterator.next();
    Integer v = map.get(k);
    System.out.println(k + &quot;:&quot; + v);
}

// 엔트리 Set 컬렉션을 얻고, 반복해서 키와 값을 얻기
Set&lt;Entry&lt;String, Integer&gt;&gt; entrySet = map.entrySet();
Iterator&lt;Entry&lt;String, Integer&gt;&gt; entryIterator = entrySet.iterator();
while (entryIterator.hasNext()) {
    Entry&lt;String, Integer&gt; entry = entryIterator.next();
    String k = entry.getKey();
    Integer v = entry.getValue();
    System.out.println(k + &quot;:&quot; + v);
}
System.out.println();</code></pre>
<h3 id="2-hashtable">2. Hashtable</h3>
<blockquote>
</blockquote>
<pre><code class="language-java">Map&lt;String, Integer&gt; map = new Hashtable&lt;String, Integer&gt;();
Map&lt;String, Integer&gt; map = new Hashtable&lt;&gt;();</code></pre>
<ul>
<li>HashMap와 동일한 내부 구조를 가지고 있으나 Hashtable은 동기화된 메소드로 구성되어 있다</li>
<li>멀티 스레드가 동시에 Hashtable의 메소드를 실행할 수 없다는 뜻으로 멀티 스레드 환경에서 안전하게 객체 변경이 가능하다</li>
</ul>
<blockquote>
</blockquote>
<h3 id="💡-properties-br">💡 <strong>Properties</strong> <br></h3>
<ul>
<li>Hashtable의 자식 클래스이므로 Hashtable의 특징을 그대로 가지고 있다  </li>
<li>key와 value를 String 타입으로 제한한 컬렉션이다</li>
<li>주로 프로퍼티 파일을 읽을 때 사용한다<pre><code class="language-java">// properties 파일 예시
driver=oracle.jdbc.OracleDirver
username=scott
password=tiger</code></pre>
<pre><code class="language-java">// Properties 사용 예시
Properties properties = new Properties();
properties.load(Xxx.class.getResourceAsStream(&quot;파일명.properties&quot;));</code></pre>
</li>
</ul>
<h3 id="3-treemap">3. TreeMap</h3>
<blockquote>
</blockquote>
<pre><code class="language-java">TreeMap&lt;K, V&gt; treeSet = new TreeMap&lt;K, V&gt;();
TreeMap&lt;K, V&gt; treeSet = new TreeMap&lt;&gt;();
// 검색 관련 메소드가 TreeMap에만 정의되어 있으므로 TreeMap 타입으로 대입</code></pre>
<ul>
<li>이진 트리 기반</li>
<li>TreeSet과 다른 점은 key-value가 저장된 Entry를 저장한다는 점이다</li>
<li>키를 기준으로 자동 정렬되며 부모 키 값과 비교해서 낮은 것은 왼쪽, 높은 것은 오른쪽 자식 노드에  Entry 객체를 저장한다</li>
<li>검색 기능을 강화시킨 컬렉션이다</li>
</ul>
<hr>
<h3 id="comparable-comparator">Comparable, Comparator</h3>
<blockquote>
</blockquote>
<ul>
<li>TreeSet에 저장되는 객체와 TreeMap에 저장되는 키 객체는 저장과 동시에 오름차순으로 정렬</li>
<li>단, 객체가 Comparable 인터페이스를 구현하고 있는 경우에 정렬이 된다</li>
<li>Comparable 인터페이스에는 compareTo() 메소드가 정의되어 있어 메소드 재정의가 필요하다</li>
<li>Comparable 비구현 객체를 저장하고 싶은 경우 Comparator 비교자를 제공하면 된다</li>
</ul>
<details>
<summary>Comparable 예제</summary>

<pre><code class="language-java">// Comparable
class Person implements Comparable&lt;Person&gt; { // 제네릭 타입 클래스 명시
    public String name;
    public int age;

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

    @Override
    public int compareTo(Person o) {
        if (age &lt; o.age)
            return -1; // 작으면 -1
        else if (age == o.age)
            return 0; // 같으면 0
        else
            return 1; // 크면 1
    }
}

public class ComparableEx {
    public static void main(String[] args) {
        TreeSet&lt;Person&gt; treeSet = new TreeSet&lt;Person&gt;();

        treeSet.add(new Person(&quot;홍길동&quot;, 45));
        treeSet.add(new Person(&quot;김길동&quot;, 26));
        treeSet.add(new Person(&quot;차길동&quot;, 30));

        for (Person person : treeSet) {
            System.out.println(person.name + &quot;:&quot; + person.age);
        }
    }
}</code></pre>
</details>


<details>
<summary>Comparator 예시 코드</summary>

<pre><code class="language-java">// Comparator
class Fruit {
    public String name;
    public int price;

    public Fruit(String name, int price) {
        this.name = name;
        this.price = price;
    }
}

class FruitComparator implements Comparator&lt;Fruit&gt; {
    @Override
    public int compare(Fruit o1, Fruit o2) {
        if(o1.price &lt; o2.price) return -1;
        else if(o1.price == o2.price) return 0;
        else return 1;
    }
}

public class ComparatorEx {
    public static void main(String[] args) {
        TreeSet&lt;Fruit&gt; treeSet = new TreeSet&lt;Fruit&gt;(new FruitComparator());

        treeSet.add(new Fruit(&quot;포도&quot;, 3000));
        treeSet.add(new Fruit(&quot;수박&quot;, 10000));
        treeSet.add(new Fruit(&quot;딸기&quot;, 6000));

        for(Fruit fruit : treeSet) {
            System.out.println(fruit.name + &quot;:&quot; + fruit.price);
        }
    }
}</code></pre>
</details>

<hr>
<h2 id="sec06-lifo-fifo-컬렉션">sec06. LIFO, FIFO 컬렉션</h2>
<h3 id="1-stack-lifo">1. Stack (LIFO)</h3>
<blockquote>
</blockquote>
<pre><code class="language-java">  Stack&lt;E&gt; stack = new Stack&lt;E&gt;();
  Stack&lt;E&gt; stack = new Stack&lt;&gt;();</code></pre>
<ul>
<li>Last In First Out 후입선출 - 나중에 넣은 객체가 먼저 빠져 나가는 구조</li>
<li>push(E item) : 주어진 객체를 스택에 넣는다</li>
<li>pop() : 스택의 맨 위 객체를 빼낸다</li>
</ul>
<h3 id="2-queue-fifo">2. Queue (FIFO)</h3>
<blockquote>
</blockquote>
<pre><code class="language-java">  Queue&lt;E&gt; queue = new Queue&lt;E&gt;();
  Queue&lt;E&gt; queue = new Queue&lt;&gt;();</code></pre>
<ul>
<li>First In First Out 선입선출 - 먼저 넣은 객체가 먼저 빠져 나가는 구조</li>
<li>offer(E e) : 주어진 객체를 큐에 넣는다</li>
<li>poll() : 큐에서 객체를 빼낸다</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[SQL] 날짜 함수]]></title>
            <link>https://velog.io/@seonjin_dev/SQL-%EB%82%A0%EC%A7%9C-%ED%95%A8%EC%88%98</link>
            <guid>https://velog.io/@seonjin_dev/SQL-%EB%82%A0%EC%A7%9C-%ED%95%A8%EC%88%98</guid>
            <pubDate>Tue, 05 Sep 2023 10:32:10 GMT</pubDate>
            <description><![CDATA[<h2 id="date_format"><code>DATE_FORMAT()</code></h2>
<p>날짜/시간 형식화, 주어진 date를 format에 맞게 문자열로 반환</p>
<pre><code class="language-sql">SELECT DATE_FORMAT(&#39;1999-05-24&#39;, &#39;%y %m %d&#39;); -- 99 05 24
SELECT DATE_FORMAT(&#39;1999-05-24&#39;, &#39;%Y %M %D&#39;); -- 1999 May 24th
SELECT DATE_FORMAT(NOW(), &quot;%b %m %D %H %i %s&quot;); -- Sep 09 5th 10 02 28</code></pre>
<p><img src="https://velog.velcdn.com/images/seonjin_dev/post/706ee03c-1c25-4cdc-b87a-6b0a15bb0b0c/image.png" alt=""></p>
<br>

<h2 id="curdate-current_date"><code>CURDATE()</code>, <code>CURRENT_DATE()</code></h2>
<p>system의 현재 날짜 출력</p>
<pre><code class="language-sql">SELECT CURDATE();
SELECT CURRENT_DATE();
SELECT CURDATE()+1; -- 연산 가능</code></pre>
<br>

<h2 id="curtime-current_time"><code>CURTIME()</code>, <code>CURRENT_TIME()</code></h2>
<p>system의 현재 시각 출력</p>
<pre><code class="language-java">SELECT CURTIME();
SELECT CURRENT_TIME();</code></pre>
<br>

<h2 id="now-current_timestamp"><code>NOW()</code>, <code>CURRENT_TIMESTAMP()</code></h2>
<p>system의 현재 날짜와 시간 출력</p>
<pre><code class="language-java">SELECT NOW();</code></pre>
<br>

<h2 id="year-month-day-weekday"><code>YEAR()</code>, <code>MONTH()</code>, <code>DAY()</code>, <code>WEEKDAY()</code></h2>
<p>년/월/일/요일 추출</p>
<p>YEAR() = DAYOFYEAR()</p>
<p>MONTH() = DAYOFMONTH()</p>
<p>DAY() = DAYOFMONTH()</p>
<pre><code class="language-sql">SELECT YEAR(hiredate), MONTH(hiredate), DAY(hiredate) FROM emp;
SELECT WEEKDAY(&quot;2017-01-01&quot;); -- 월요일 0 ~ 일요일 6</code></pre>
<br>

<h2 id="hour-minute-second"><code>HOUR()</code>, <code>MINUTE()</code>, <code>SECOND()</code></h2>
<p>시/분/초 추출</p>
<pre><code class="language-sql">SELECT HOUR(NOW()), MINUTE(NOW()), SECOND(NOW());</code></pre>
<br>

<h2 id="dayofweek-dayname"><code>DAYOFWEEK()</code>, <code>DAYNAME()</code></h2>
<p>해당 주에서 몇 번째 날인지 반환</p>
<pre><code class="language-sql">SELECT DAYOFWEEK(&quot;2017-06-15&quot;); -- 5(숫자로 반환), 일요일 1 ~ 토요일 7
SELECT DAYNAME(&quot;2017-06-15&quot;); -- Thursday(문자로 반환)</code></pre>
<br>

<h2 id="adddate-date_add-addtime"><code>ADDDATE()</code>, <code>DATE_ADD()</code>, <code>ADDTIME()</code></h2>
<p>연, 월, 일, 시간 더하기</p>
<pre><code class="language-sql">-- ADDDATE(date, INTERVAL value addunit)
SELECT ADDDATE(CURDATE(), INTERVAL 1 DAY);
SELECT ADDDATE(CURDATE(), INTERVAL 1 MONTH);
SELECT ADDDATE(CURDATE(), INTERVAL -1 YEAR);
SELECT DATE_ADD(CURDATE(), INTERVAL -1 YEAR);
SELECT ADDDATE(hiredate, 2) FROM emp; -- value만 있을 때, day가 defalt

-- ADDTIEM(datetime, addtime)
SELECT ADDTIME(CURTIME(), &#39;1:10:5&#39;); -- add 1 hour 10 minute 5 second
SELECT ADDTIME(NOW(), &#39;2 1:10:5&#39;); -- add 2 day 1 hour 10 minute 5 second</code></pre>
<br>

<h2 id="subdate-date_sub-subtime"><code>SUBDATE()</code>, <code>DATE_SUB()</code>, <code>SUBTIME()</code></h2>
<p>연, 월, 일, 시간 빼기</p>
<pre><code class="language-sql">-- SUBDATE(date, INTERVAL value unit)
SELECT SUBDATE(&quot;2017-06-15 09:34:21&quot;, INTERVAL 15 MINUTE);
SELECT SUBDATE(&quot;2017-06-15&quot;, INTERVAL -2 MONTH);

-- SUBTIEM(datetime, addtime)
SELECT SUBTIME(&quot;10:24:21&quot;, &quot;5&quot;); -- minus 5 second
SELECT SUBTIME(&quot;10:24:21&quot;, &quot;3:2:5&quot;); -- minus 3 hour 2 minute 5 second</code></pre>
<br>

<h2 id="extract"><code>EXTRACT()</code></h2>
<p>DATE_ADD, DATE_SUB 와 흡사한 기능을 수행하며, 날짜의 일부를 반환</p>
<pre><code class="language-sql">-- EXTRACT(UNIT FROM DATE);
SELECT CURDATE(), EXTRACT(MONTH FROM CURDATE()) AS MONTH; -- month 반환
SELECT CURDATE(), EXTRACT(YEAR FROM CURDATE()) AS YEAR; -- year 반환
SELECT CURDATE(), EXTRACT(DAY FROM CURDATE()) AS DAY; -- day 반환
SELECT CURDATE(), EXTRACT(WEEK FROM CURDATE()) AS WEEK; -- week 반환
SELECT CURDATE(), EXTRACT(QUARTER FROM CURDATE()) AS QUARTER; -- quarter 반환
SELECT CURDATE(), EXTRACT(YEAR_MONTH FROM CURDATE()) AS &quot;YEAR_MONTH&quot;;
SELECT NOW(), EXTRACT(HOUR FROM CURDATE()) AS HOUR;
SELECT NOW(), EXTRACT(MINUTE FROM CURDATE()) AS MINUTE;
SELECT NOW(), EXTRACT(SECOND FROM CURDATE()) AS SECOND;</code></pre>
<br>

<h2 id="time_to_sec"><code>TIME_TO_SEC()</code></h2>
<p>시간을 초로 변환</p>
<pre><code class="language-sql">SELECT CURTIME(), TIME_TO_SEC(CURTIME());</code></pre>
<br>

<h2 id="datediff"><code>DATEDIFF()</code></h2>
<p>두 날짜 사이의 일수를 숫자로 반환(date1 - date2)</p>
<pre><code class="language-sql">-- DATEDIFF(date1, date2) -&gt; date1 - date2
SELECT hiredate, DATEDIFF(CURDATE(), hirdate) FROM emp; 
SELECT DATEDIFF(CURDATE(), &#39;1999-05-24&#39;) 일수 FROM emp;</code></pre>
<br>

<h2 id="timediff"><code>TIMEDIFF()</code></h2>
<p>두 시간의 차이를 datetime 형태로 반환(time1 - time2)</p>
<pre><code class="language-sql">-- TIMEDIFF(time1, time2) -&gt; time1 - time2
SELECT CURTIME(), TIMEDIFF(CURTIME(), &#39;08:48:27&#39;);
SELECT TIME_TO_SEC(TIMEDIFF(CURTIME(), &#39;08:48:27&#39;));</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[정보시스템 기반 기술] 운영체제 종류]]></title>
            <link>https://velog.io/@seonjin_dev/%EC%A0%95%EB%B3%B4%EC%B2%98%EB%A6%AC%EC%82%B0%EC%97%85%EA%B8%B0%EC%82%AC-%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9C-%EC%A2%85%EB%A5%98</link>
            <guid>https://velog.io/@seonjin_dev/%EC%A0%95%EB%B3%B4%EC%B2%98%EB%A6%AC%EC%82%B0%EC%97%85%EA%B8%B0%EC%82%AC-%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9C-%EC%A2%85%EB%A5%98</guid>
            <pubDate>Tue, 05 Sep 2023 07:04:04 GMT</pubDate>
            <description><![CDATA[<h2 id="운영체제의-개념">운영체제의 개념</h2>
<ul>
<li>OS : Operating System</li>
<li>컴퓨터의 하드웨어를 쉽게 사용할 수 있도록 인터페이스를 제공해 주는 소프트웨어</li>
<li>하드웨어는 중앙처리장치, 기억장치, 통신 장치, 입출력 장치 등으로 구분된다</li>
</ul>
<hr>
<h2 id="운영체제의-목적">운영체제의 목적</h2>
<ul>
<li><strong>사용자 편리성 제공</strong> : 입출력 편의, 하드웨어 접근 편의, 효과적 자원 사용 유도</li>
<li><strong>인터페이스 기능 담당</strong> : 컴퓨터 시스템과 사용자 연결</li>
<li><strong>스케줄링 담당</strong> : 자원의 현재 상태 파악, 프로세서/메모리 등의 자원 분배를 위한 스케줄링</li>
<li><strong>자원 관리</strong> : CPU, 메모리 공간, 기억장치, 입출력 장치 등의 자원 관리</li>
<li><strong>제어 기능</strong> : 입출력 장치와 사용자 프로그램 제어</li>
<li><strong>오류 회복 기능</strong> : 소프트웨어/하드웨어의 오류 발생 시 자체 회복 시도</li>
</ul>
<hr>
<h2 id="운영체제-성능-평가-기준">운영체제 성능 평가 기준</h2>
<ul>
<li><strong>경과(반환) 시간(Turnaround)</strong> : 작업 의뢰 시간 ~ 처리 완료까지 걸린 시간</li>
<li><strong>응답(반응) 시간(Response) :</strong> 작업이 처음 실행되기 까지 걸린 시간</li>
<li><strong>사용 가능도(Availability) :</strong> 시스템을 사용 해야할 때 즉시 사용 가능한 정도</li>
<li><strong>신뢰성(Reliability) :</strong> 시스템이 주어진 문제를 정확하게 해결하는 정도</li>
<li><strong>처리량(Throughput) :</strong> 일정 시간 내에 시스템이 처리하는 일의 양</li>
</ul>
<blockquote>
<h3 id="운영체제-시간">운영체제 시간</h3>
<p>경과시간
응답시간
실행시간 : CPU가 요청한 작업을 처리하는 시간
대기시간 : 작업 요청 후 작업이 끝날 때까지 CPU가 요청한 작업을 처리하지 않는 시간</p>
</blockquote>
<hr>
<h2 id="운영체제의-기능">운영체제의 기능</h2>
<h3 id="제어-프로그램-control-program">제어 프로그램 (Control Program)</h3>
<ul>
<li>시스템 전체의 움직임을 감사, 감독, 관리, 지원하는 프로그램</li>
<li>감시 프로그램 (Supervisor) : 각종 프로그램의 실행과 시스템 전체의 작동 상태 감시 및 감독</li>
<li>작업 제어 프로그램 (Job Control) : 작업의 연속 처리를 위한 스케줄 및 시스템 자원 할당</li>
<li>데이터 관리 프로그램 (Data Management) : 주-보조기억장치 사이의 데이터 전송, 보조기억장치의 자료 갱신 및 유지보수<h3 id="처리-프로그램-processing-program">처리 프로그램 (Processing Program)</h3>
</li>
<li>주어진 문제를 응용 프로그램 감독하에 실제 데이터 처리하는 프로그램</li>
<li>언어 번역 프로그램 (Language Translator)
: 원시 프로그램을 기계어 형태의 목적 프로그램으로 번역</li>
<li><blockquote>
<p>어셈블러, 컴파일러, 인터프리터</p>
</blockquote>
</li>
<li>서비스 프로그램 (Service)
: 효율성을 위해 사용 빈도가 높음 
→ 링커, 정렬/합병 프로그램, 라이브러리, 유틸리티 프로그램</li>
<li>문제 프로그램 (Problem) 
: 특정 업무 해결을 위해 사용자가 작성</li>
</ul>
<hr>
<h2 id="쉘과-커널">쉘과 커널</h2>
<p>운영체제 = 인터페이스(쉘) + 커널</p>
<h3 id="쉘">쉘</h3>
<ul>
<li>커널을 사용자가 보다 편리하게 사용할 수 있게 해 줌</li>
<li>사용자가 입력한 명령어 라인을 읽어 필요한 시스템 기능을 실행시키는 명령어 해석기</li>
<li>시스템과 사용자 간 인터페이스 제공</li>
<li>여러 가지의 내장 명령어를 가짐<h3 id="커널">커널</h3>
</li>
<li>운영체제의 핵심 기능들이 모인 프로그램</li>
<li>프로그램과 하드웨어 간의 인터페이스 역할</li>
<li>프로세스 관리 : 스케줄링, 동기화 등</li>
<li>기억장치 관리 : 프로세스에게 메모리 할당 및 회수</li>
<li>주변장치 관리 : 입출력 장치 스케줄링 및 전반적인 관리</li>
<li>파일 관리</li>
</ul>
<hr>
<h2 id="운영체제-운용-기법">운영체제 운용 기법</h2>
<ul>
<li>일괄 처리 시스템(Batch Processing)<ul>
<li>작업량을 일정 수준까지 모아두었다가 일시에 처리하는 방식</li>
</ul>
</li>
<li>다중 프로그래밍 시스템<ul>
<li>하나의 CPU와 주기억장치를 이용하여 여러 개의 프로그램을 동시에 처리</li>
</ul>
</li>
<li>시분할 시스템(=라운드 로빈)<ul>
<li>CPU를 여러 사용자가 공유하고 있지만 마치 독점하고 있는 것처럼 느끼도록 처리하는 방식</li>
<li>다중 프로그래밍 방식과 결합하여 모든 작업이 동시에 진행되는 것처럼 대화식 처리 가능</li>
<li>CPU의 전체 사용 시간을 작업 시간량으로 나누어 작업 처리</li>
</ul>
</li>
<li>다중 처리 시스템<ul>
<li>여러 개의 CPU와 하나의 주기억장치를 이용해 여러 개의 프로그램을 동시에 처리</li>
</ul>
</li>
<li>분산 처리 시스템<ul>
<li>여러 개의 프로세서를 통신회선으로 연결하여 하나의 작업 처리</li>
<li>중앙 집중형 시스템보다 소프트웨어 개발이 어려움</li>
<li>여러 사용자가 데이터를 공유(자원 공유)</li>
<li>시스템의 점진적 확장이 용이하고, 사용 가능도가 향상</li>
<li>연산 속도의 향상과 신뢰성 증진의 특징이 있음</li>
</ul>
</li>
</ul>
<hr>
<h2 id="운영체제의-종류">운영체제의 종류</h2>
<h3 id="1-윈도즈-계열-운영체제">1. 윈도즈 계열 운영체제</h3>
<ul>
<li>MS-DOS의 멀티태스킹 기능과 GUI 환경을 제공하는 응용 프로그램</li>
<li>마이크로소프트사가 개발한 운영체제</li>
<li>그래픽 사용자 인터페이스 (GUI) 제공</li>
<li>선점형 멀티태스킹 방식 제공</li>
<li>자동감지 기능 제공 - 하드웨어 설치 시 필요한 시스템 환경을 자동으로 구성</li>
<li>OLE 사용 - 개체를 현재 작성 중인 문서에 자유롭게 연결 또는 삽입하여 편집할 수 있게 하는 기능 제공<h3 id="2-유닉스-계열-운영체제">2. 유닉스 계열 운영체제</h3>
</li>
<li>90% 이상 C언어로 구현되어 있는 운영체제</li>
<li>범용 다중 사용자 방식의 시분할 운영체제</li>
<li>다양한 시스템에 서로 인식 가능, 멀티 태스킹 지원</li>
<li>대화식 운영체제 - 사용자의 입력 → 시스템의 수행</li>
<li>다중 작업</li>
<li>다중 사용자</li>
<li>이식성 : 다른 하드웨어 기종으로 쉽게 이식 가능</li>
<li>계층적 파일 시스템 제공 : 계층적 트리 구조를 가져 통합적인 파일 관리 용이<h3 id="3-리눅스-계열-운영체제">3. 리눅스 계열 운영체제</h3>
</li>
<li>프리 소프트웨어 정책을 가지고, 자유롭고 재배포가 가능한 운영체제</li>
<li>유닉스의 호환 커널</li>
</ul>
<br>

<table>
<thead>
<tr>
<th>리눅스</th>
<th>유닉스</th>
</tr>
</thead>
<tbody><tr>
<td>대부분 무료, 일부 유료</td>
<td>대부분 유료</td>
</tr>
<tr>
<td>개발자, 일반 사용자</td>
<td>대형 시스템 관리자</td>
</tr>
<tr>
<td>오픈소스 개발</td>
<td>사업자에 의해 배포 (비용 수반)</td>
</tr>
<tr>
<td>GUI 제공, 파일시스템 지원, BASH 셀 사용</td>
<td>커맨드 기반 (GUI 제공하는 추세), 파일 시스템 제공</td>
</tr>
</tbody></table>
]]></description>
        </item>
        <item>
            <title><![CDATA[[이것이 자바다] 13. 제네릭]]></title>
            <link>https://velog.io/@seonjin_dev/%EC%9D%B4%EA%B2%83%EC%9D%B4-%EC%9E%90%EB%B0%94%EB%8B%A4-13.-%EC%A0%9C%EB%84%A4%EB%A6%AD</link>
            <guid>https://velog.io/@seonjin_dev/%EC%9D%B4%EA%B2%83%EC%9D%B4-%EC%9E%90%EB%B0%94%EB%8B%A4-13.-%EC%A0%9C%EB%84%A4%EB%A6%AD</guid>
            <pubDate>Wed, 30 Aug 2023 22:48:04 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/seonjin_dev/post/fba9ec09-dd5d-401a-a9f3-4aae28afd00b/image.png" alt=""></p>
<p>📚 이것이 자바다 [개정판]</p>
<hr>
<h2 id="sec01-제네릭이란">sec01. 제네릭이란?</h2>
<blockquote>
</blockquote>
<ul>
<li>결정되지 않은 타입을 파라미터로 처리하고 객체 생성 시점에 구체적인 타입으로 대체하는 기능</li>
<li>제네릭 타입으로 선언 후 구체적인 타입을 지정하지 않으면 Object 타입이 암묵적으로 사용된다
✨ 타입 파라미터를 대체하는 타입은 클래스 및 인터페이스이다
✨ 기본 타입은 타입 파라미터의 대체 타입이 될 수 없다</li>
</ul>
<pre><code class="language-java">public class Box&lt;T&gt; { // 결정되지 않은 content의 타입을 T라는 파라미터로 정의
    public T content;
}

Box&lt;String&gt; box = new Box&lt;String&gt;(); // 타입 파라미터를 String으로 대체
box.content = &quot;안녕&quot;;
String content = box.content; // 강제 타입 변환 필요 없이 String값을 얻음

// 변수 선언할 때와 동일한 타입으로 호출하고 싶으면
// 생성자 호출 시 생성자에는 타입을 명시하지 않고 &lt;&gt;만 붙일 수 있다
Box&lt;Integer&gt; box = new Box&lt;&gt;(); // 타입 파라미터를 Integer으로 대체
Integer box = box.content;</code></pre>
<hr>
<h2 id="sec03-제네릭-메소드">sec03. 제네릭 메소드</h2>
<pre><code class="language-java">// 타입 파라미터가 메소드 선언부에서 정의된다
public &lt;타입파라미터&gt; 리턴타입 메소드명(매개변수) {}

class Box&lt;T&gt; {
    private T t;

    public T getT() {
        return t;
    }
}

public class GenericEx5 {
    public static &lt;T&gt; Box&lt;T&gt; boxing(T t) { // 메소드 생성
        Box&lt;T&gt; box = new Box&lt;T&gt;();
        box.setT(t);;
        return box;
    }

    public static void main(String[] args) {
    Box&lt;Integer&gt; box1 = boxing(100); // 메소드 호출
    int intValue = box1.getT();
    System.out.println(intValue);

    Box&lt;String&gt; box2 = boxing(&quot;hi&quot;);
    String strValue = box2.getT();
    System.out.println(strValue);
    }
}</code></pre>
<hr>
<h2 id="sec04-제한된-타입-파라미터">sec04. 제한된 타입 파라미터</h2>
<blockquote>
</blockquote>
<ul>
<li>타입 파라미터를 대체하는 구체적인 타입을 제한할 필요가 있다</li>
<li>예를 들어 숫자 연산을 위한 제네릭 메소드는 Number 또는 정수, 실수 클래스로 제한된다</li>
<li>이처럼 특정 타입과 자식 또는 구현 관계에 있는 타입만 대체할 수 있는 것을 제한된 타입 파라미터라 한다</li>
</ul>
<pre><code class="language-java">public &lt;T extends 상위타입&gt; 리턴타입 메소드(매개변수) { }

public &lt;T extends Number&gt; boolean compart(T t1, T t2) {
    double v1 = t1.doubleValue();
    double v2 = t2.doubleValue();
    return (v1 == v2);
}</code></pre>
<hr>
<h2 id="sec05-와일드카드-파라미터">sec05. 와일드카드 파라미터</h2>
<p><img src="https://velog.velcdn.com/images/seonjin_dev/post/f2517b0e-8c6c-4135-8df0-280796516d42/image.jpg" alt=""></p>
<pre><code class="language-java">// 1. 대체타입으로 Student와 자식 클래스인 HighStudent와 MiddleStudent만 가능
리턴타입 메소드명(제네릭타입&lt;? extends Student&gt; 변수) {}

// 2. 대체타입으로 Worker와 부모 클래스인 Person만 가능
리턴타입 메소드명(제네릭타입&lt;? super 부모클래스&gt; 변수) {}

// 3. 어떤 타입이든 가능
리턴타입 메소드명(제네릭타입&lt;?&gt; 변수) {}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[이것이 자바다] 12. java.base 모듈]]></title>
            <link>https://velog.io/@seonjin_dev/%EC%9D%B4%EA%B2%83%EC%9D%B4-%EC%9E%90%EB%B0%94%EB%8B%A4-12.-java.base-%EB%AA%A8%EB%93%88</link>
            <guid>https://velog.io/@seonjin_dev/%EC%9D%B4%EA%B2%83%EC%9D%B4-%EC%9E%90%EB%B0%94%EB%8B%A4-12.-java.base-%EB%AA%A8%EB%93%88</guid>
            <pubDate>Wed, 30 Aug 2023 14:12:01 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/seonjin_dev/post/fba9ec09-dd5d-401a-a9f3-4aae28afd00b/image.png" alt=""></p>
<p>📚 이것이 자바다 [개정판]</p>
<hr>
<h2 id="sec03-object-클래스-최상위-클래스">sec03. Object 클래스 (최상위 클래스)</h2>
<h3 id="1-객체-동등-비교-equals">1. 객체 동등 비교 <code>equals()</code></h3>
<p>객체 번지 비교 후 boolean값 리턴</p>
<h3 id="2-객체-해시코드-hashcode">2. 객체 해시코드 <code>hashCode()</code></h3>
<p>객체의 메모리 번지를 이용하여 해시코드를 생성하므로 객체마다 다른 정수값 리턴
두 객체가 동등한지 비교할 때 주로 사용한다</p>
<h3 id="3-객체-문자-정보-tostring">3. 객체 문자 정보 <code>toString()</code></h3>
<p>객체를 문자열로 표현한 문자 정보를 리턴</p>
<hr>
<h2 id="sec05-문자열-클래스">sec05. 문자열 클래스</h2>
<h3 id="1-string">1. <code>String</code></h3>
<p>문자열을 저장하고 조작할 때 사용
<code>String str = new String(byte[] bytes);</code> 
기본 문자셋으로 byte 배열을 디코딩하여 String 객체로 생성</p>
<h3 id="2-stringbuilder">2. <code>StringBuilder</code></h3>
<p>효율적인 문자열 조작 기능이 필요할 때 (문자열 변경 작업이 잦은 경우) 사용
String을 결합하는 경우는 내부 문자열을 수정하는 것이 아닌 새로운 객체를 생성하므로 비효율적이다
toString()을 제외하고 메소드 체이닝 가능 (메소드 연속 호출)</p>
<table>
<thead>
<tr>
<th>메소드</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>append(기본값, 문자열)</td>
<td>문자열을 끝에 추가</td>
</tr>
<tr>
<td>insert(위치, 기본값, 문자열)</td>
<td>문자열을 지정 위치에 추가</td>
</tr>
<tr>
<td>delete(시작 위치, 끝 위치)</td>
<td>문자열 일부 삭제</td>
</tr>
<tr>
<td>replace(시작 위치, 끝 위치, 문자열)</td>
<td>문자열 일부 대체</td>
</tr>
<tr>
<td>toString()</td>
<td>완성된 문자열 리턴</td>
</tr>
</tbody></table>
<h3 id="3-stringtokenizer">3. <code>StringTokenizer</code></h3>
<p>구분자로 연결된 문자열을 분리할 때 사용</p>
<p><code>StringTokenizer st = new StringTokenizer(전체 문자열, &quot;구분자&quot;);</code> </p>
<table>
<thead>
<tr>
<th>메소드</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>countTokens()</td>
<td>분리할 수 있는 문자열의 총 수</td>
</tr>
<tr>
<td>hasMoreTokens()</td>
<td>남아 있는 문자열이 있는지 여부</td>
</tr>
<tr>
<td>nextToken()</td>
<td>문자열을 하나씩 가져옴, 없다면 예외 발생</td>
</tr>
</tbody></table>
<hr>
<h2 id="sec06-포장-클래스">sec06. 포장 클래스</h2>
<ul>
<li>기본 타입의 값을 갖는 객체를 생성한 것</li>
<li>Byte, <strong>Character</strong>, Short, <strong>Integer</strong>, Long, Float, Double, Boolean</li>
<li>boxing: 기본 타입의 값 → 포장 객체 <code>Integer obj = 100;</code></li>
<li>unboxing: 포장 객체 → 기본 타입의 값 <code>int value = obj;</code>
✨ 포장 클래스를 비교할 때는 비교 연산자 대신 <code>equals()</code> 메소드를 사용한다</li>
</ul>
<hr>
<h2 id="sec12-어노테이션">sec12. 어노테이션</h2>
<ol>
<li>컴파일 시 사용하는 정보 전달</li>
<li>빌드 툴이 코드를 자동으로 생성할 때 사용하는 정보 전달</li>
<li>실행 시 특정 기능을 처리할 때 사용하는 정보 전달</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[[이것이 자바다] 11. 예외 처리]]></title>
            <link>https://velog.io/@seonjin_dev/%EC%9D%B4%EA%B2%83%EC%9D%B4-%EC%9E%90%EB%B0%94%EB%8B%A4-11.-%EC%98%88%EC%99%B8-%EC%B2%98%EB%A6%AC</link>
            <guid>https://velog.io/@seonjin_dev/%EC%9D%B4%EA%B2%83%EC%9D%B4-%EC%9E%90%EB%B0%94%EB%8B%A4-11.-%EC%98%88%EC%99%B8-%EC%B2%98%EB%A6%AC</guid>
            <pubDate>Tue, 29 Aug 2023 14:57:56 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/seonjin_dev/post/fba9ec09-dd5d-401a-a9f3-4aae28afd00b/image.png" alt=""></p>
<p>📚 이것이 자바다 [개정판]</p>
<hr>
<h2 id="sec01-예외와-예외-클래스">sec01. 예외와 예외 클래스</h2>
<blockquote>
</blockquote>
<ul>
<li>에러(Error): 프로그램 코드에 의해 수습될 수 없는 심각한 오류</li>
<li>예외(Exception): 프로그램 코드에 의해 수습될 수 있는 다소 미약한 오류<ul>
<li>일반 예외(Exception): 컴파일러가 예외 처리 코드 여부를 검사하는 예외</li>
<li>실행 예외(Runtime Exception): 컴파일러가 예외 처리 코드 여부를 검사하지 않는 예외</li>
</ul>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/seonjin_dev/post/094feaab-1a10-46a4-8845-cfacb21dc8e0/image.png" alt=""></p>
<br>

<h2 id="sec02-예외-처리-코드">sec02. 예외 처리 코드</h2>
<blockquote>
</blockquote>
<ul>
<li>예외 발생 시 프로그램의 갑작스러운 종료를 막고 정상 실행을 유지할 수 있도록 처리하는 코드</li>
<li>생성자 내부, 메소드 내부에서 작성되며, 중괄호는 생략할 수 없다</li>
</ul>
<pre><code class="language-java">try { 
    // 예외 발생 가능 코드
} catch(예외클래스 e) {
    // 예외 처리
} finally {
    // 항상 실행;
}</code></pre>
<h3 id="finally"><code>finally</code></h3>
<blockquote>
</blockquote>
<ul>
<li>예외 발생여부와 관계없이 실행되어야 하는 코드 입력</li>
<li>정상 실행 되어도,</li>
<li>예외가 발생되어도,</li>
<li>try-catch 블록에서 return문으로 메소드를 종료해도,
  <strong>⇒ 항상 실행된다</strong></li>
</ul>
<h3 id="예외-정보를-얻는-3가지-방법">예외 정보를 얻는 3가지 방법</h3>
<blockquote>
</blockquote>
<ul>
<li><code>System.out.println(e.getMessage());</code> 예외가 발생한 이유 리턴</li>
<li><code>System.out.println(e.toString());</code> 예외가 발생한 이유와 예외의 종류를 리턴</li>
<li><code>e.printStackTrace();</code> 예외가 어디서 발생했는지 추적한 내용까지 출력</li>
</ul>
<br>


<h2 id="sec03-예외-종류에-따른-처리">sec03. 예외 종류에 따른 처리</h2>
<blockquote>
</blockquote>
<ul>
<li>다중 catch를 사용하여 발생하는 예외에 따라 예외 처리 코드를 다르게 작성할 수 있다<br></li>
<li>catch 블록이 여러 개여도 catch 블록은 단 하나만 실행된다
  → 하나의 예외가 발생하면 즉시 실행을 멈추고 해당 catch 블록으로 이동하기 때문이다<br></li>
<li>처리할 예외 클래스들이 상속 관계에 있을 때는 하위 클래스의 catch 블록 먼저 작성한다
  → 예외 발생 시 catch 블록이 위에서부터 차례로 검사 대상이 되므로 상위 클래스가 먼저 검사 대상이 되면 하위 클래스가 모두 포함이 되기 때문이다<br></li>
<li>두 개 이상의 예외를 하나의 catch 블록으로 동일하게 예외 처리하고 싶을 때
  <code>catch(NullPointerException | NumberFormatException e)</code> 와 같이 처리한다</li>
</ul>
<br>


<h2 id="sec05-예외-떠넘기기">sec05. 예외 떠넘기기</h2>
<blockquote>
</blockquote>
<ul>
<li><code>리턴타입 메소드명(매개변수) throws 예외클래스1, 예외클래스2;</code></li>
<li><code>throws</code> 를 통해 메소드를 호출한 곳으로 예외를 떠넘긴다</li>
</ul>
<pre><code class="language-java">public void method2() **throws ClassNotFoundException** { // 떠넘기기
    Class.forName(&quot;java.lang.String2&quot;);
}

public void method1() {
    try {
            method2(); // method2() 호출
    } catch(ClassNotFoundException e) { // 호출한 곳에서 예외 처리
        SYstem.out.println(&quot;예외 처리: &quot; + e.getMessage());
    }
}</code></pre>
<br>

<h2 id="sec06-사용자-정의-예외">sec06. 사용자 정의 예외</h2>
<blockquote>
</blockquote>
<ul>
<li>표준 라이브러리에 존재하지 않는 예외를 직접 클래스를 정의하여 사용하는 것</li>
</ul>
<pre><code class="language-java">public class InsufficientException extends Exception {
    public InsufficientException() { // 기본 생성자
    }
    public InsufficientException(String message) { // 예외를 입력 받는 생성자
        super(message);
    }
}
// 예외 메시지를 부모 생성자 매개값으로 넘기는데, 
// 예외 객체의 공통 메소드인 getMessage()의 리턴값으로 사용하기 위함이다</code></pre>
<h3 id="예외-발생-시키기">예외 발생 시키기</h3>
<pre><code class="language-jsx">// 직접 try-catch문으로 처리하는 방법
void method() {
    try {
        ...
        throw new Exception(&quot;예외메시지&quot;);
        ...
    } catch(Exception e) {
        String message = e.getMessage();
    }
}</code></pre>
<pre><code class="language-jsx">// 호출한 곳에 떠넘기는 방법
void method() throws Exception {
    ...
    throw new Exception(&quot;예외메시지&quot;);
    ...
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[이것이 자바다] 08. 인터페이스]]></title>
            <link>https://velog.io/@seonjin_dev/%EC%9D%B4%EA%B2%83%EC%9D%B4-%EC%9E%90%EB%B0%94%EB%8B%A4-08.-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4</link>
            <guid>https://velog.io/@seonjin_dev/%EC%9D%B4%EA%B2%83%EC%9D%B4-%EC%9E%90%EB%B0%94%EB%8B%A4-08.-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4</guid>
            <pubDate>Tue, 29 Aug 2023 14:52:53 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/seonjin_dev/post/fba9ec09-dd5d-401a-a9f3-4aae28afd00b/image.png" alt=""></p>
<p>📚 이것이 자바다 [개정판]</p>
<hr>
<h2 id="sec02-인터페이스-선언">sec02. 인터페이스 선언</h2>
<blockquote>
</blockquote>
<ul>
<li>인터페이스는 두 객체를 연결하는 역할을 한다</li>
<li><code>implements</code><ul>
<li>해당 클래스가 인터페이스를 통해 사용할 수 있다는 뜻</li>
<li>인터페이스의 추상 메소드를 정의한 메소드가 있다는 뜻</li>
</ul>
</li>
<li>변수의 타입으로 사용할 수 있고, 기본값 null으로 설정된다</li>
<li>사용하려면 new 생성자를 이용하여 변수에 구현 객체를 대입</li>
</ul>
<pre><code class="language-java">public class B interface 인터페이스명 {
// public 상수 필드
// public 추상 메소드, 디폴트 메소드, 정적 메소드
// private 메소드, 정적 메소드
}</code></pre>
<p><img src="https://velog.velcdn.com/images/seonjin_dev/post/76d53fd0-5a81-4d50-90f1-e187e678e69c/image.png" alt=""></p>
<br>

<h2 id="sec0307-인터페이스-멤버">sec03~07. 인터페이스 멤버</h2>
<blockquote>
</blockquote>
<ol>
<li><code>public static final 타입 상수명 = 값;</code> (상수 필드)</li>
<li><code>public abstract 리턴타입 메소드명(매개변수);</code> (추상 메소드)<ol>
<li>메소드 선언부만 작성</li>
</ol>
</li>
<li><code>default 리턴타입 메소드명(매개변수);{}</code> (디폴트 메소드)<ol>
<li>완전한 실행 코드를 가진 디폴트 메서드 선언 가능</li>
<li>상수 필드를 읽거나 추상 메소드를 호출하는 코드 작성</li>
</ol>
<ul>
<li>예시       <pre><code class="language-java">  default void setMete(boolean mute) {
          if(mute) {
              System.out.println(&quot;무음처리&quot;);
              setVolume(MAX_VOLUME); // 추상메소드 호출
          } else {
              System.out.println(&quot;무음해제&quot;);
          }
      }</code></pre>
</li>
</ul>
</li>
<li><code>public|private static 리턴타입 메소드명(매개변수){}</code> (정적 메소드)<ol>
<li>구현 객체가 없이 인터페이스만으로 호출할 수 있다</li>
<li>중괄호 안에는 상수 필드만 작성할 수 있다</li>
</ol>
</li>
<li><code>private</code> (private 메소드, private 정적 메소드)<ol>
<li>private 메소드 : 디폴트 메소드 안에서만 호출 가능</li>
<li>private 정적 메소드 : 디폴트, 정적 메소드 안에서 호출 가능</li>
</ol>
</li>
</ol>
<br>

<h2 id="sec08-다중-인터페이스-구현">sec08. 다중 인터페이스 구현</h2>
<blockquote>
</blockquote>
<ul>
<li><code>구현클래스명 implements 인터페이스A, 인터페이스B{}</code></li>
<li>구현 객체는 여러 개의 인터페이스를 implements 할 수 있다</li>
</ul>
<br>

<h2 id="sec09-인터페이스-상속">sec09. 인터페이스 상속</h2>
<blockquote>
</blockquote>
<ul>
<li><code>interface 자식인터페이스 extends 부모인터페이스1, 2, ..{}</code></li>
<li>인터페이스도 다른 인터페이스를 상속할 수 있다</li>
<li>클래스와 달리 다중 상속을 허용한다</li>
<li>자식 인터페이스의 구현 클래스는 부모 인터페이스의 모든 추상 메소드를 재정의 해야 한다</li>
</ul>
<br>

<h2 id="sec10-타입-변환">sec10. 타입 변환</h2>
<blockquote>
</blockquote>
<ul>
<li>자동 타입 변환<ul>
<li><code>인터페이스 변수 = 구현객체;</code></li>
<li>부모 클래스가 인터페이스를 구현하고 있다면 자식 클래스도 인터페이스 타입으로 자동 타입 변환 될 수 있다</li>
</ul>
</li>
<li>강제 타입 변환<ul>
<li><code>구현클래스 변수 = (구현클래스) 인터페이스변수;</code></li>
</ul>
</li>
</ul>
<br>

<h2 id="sec11-다형성">sec11. 다형성</h2>
<blockquote>
</blockquote>
<ul>
<li>메소드 재정의 + 자동 타입 변환 → 다형성</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[이것이 자바다] 07. 상속]]></title>
            <link>https://velog.io/@seonjin_dev/%EC%9D%B4%EA%B2%83%EC%9D%B4-%EC%9E%90%EB%B0%94%EB%8B%A4-07.-%EC%83%81%EC%86%8D-ga1xkjq2</link>
            <guid>https://velog.io/@seonjin_dev/%EC%9D%B4%EA%B2%83%EC%9D%B4-%EC%9E%90%EB%B0%94%EB%8B%A4-07.-%EC%83%81%EC%86%8D-ga1xkjq2</guid>
            <pubDate>Tue, 29 Aug 2023 14:47:56 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/seonjin_dev/post/fba9ec09-dd5d-401a-a9f3-4aae28afd00b/image.png" alt=""></p>
<p>📚 이것이 자바다 [개정판]</p>
<hr>
<h2 id="sec02-클래스-상속">sec02. 클래스 상속</h2>
<blockquote>
</blockquote>
<ul>
<li><code>public class 자식클래스 extends 부모클래스{}</code></li>
<li>부모 클래스의 필드와 메소드를 자식 클래스에 물려주는 것</li>
<li>자식 클래스를 선언할 때 상속받을 부모 클래스를 선택한다</li>
<li>자바는 다중 상속을 허용하지 않으므로, extends 뒤에는 단 하나의 부모 클래스만 올 수 있다</li>
</ul>
<br>

<h2 id="sec03-부모-생성자-호출">sec03. 부모 생성자 호출</h2>
<blockquote>
</blockquote>
<ul>
<li>자식 객체를 생성하면 부모 객체가 먼저 생성된 다음 자식 객체가 생성된다</li>
<li>참조변수는 자식 객체의 주소를 받고 부모 객체를 상속한다</li>
<li>super()는 컴파일 과정에서 자동 추가되어 부모의 기본 생성자를 호출한다</li>
<li>부모 객체에 기본생성자가 없다면 자식 클래스에 에러가 발생한다</li>
<li>기본 생성자는 super()을 생략할 수 있지만, 매개변수가 있는 생성자의 경우 super(매개변수, …)를 생략할 수 없다</li>
</ul>
<pre><code class="language-java">// 자식 생성자를 선언할 때 부모의 생성자를 호출한 후 사용
public 자식클래스() {
    super(매개값, ...);</code></pre>
<br>

<h2 id="sec04-메소드-재정의-오버라이딩">sec04. 메소드 재정의 (오버라이딩)</h2>
<blockquote>
</blockquote>
<ul>
<li>부모 메소드 중 자식 클래스가 사용하기에 적합하지 않은 경우, 자식 클래스에서 메소드를 재정의하는 것이다</li>
<li>오버라이딩이 되었다면 자식 메소드가 우선적으로 사용된다</li>
<li>규칙<ul>
<li>부모 메소드의 선언부(리턴타입, 메소드명, 매개변수)와 동일해야 한다</li>
<li>접근 제한자를 더 강하게 오버라이딩 할 수는 없다 (public→private 불가능)</li>
<li>새로운 예외를 throws할 수 없다</li>
</ul>
</li>
</ul>
<blockquote>
<p><strong>@Override 애노테이션</strong>
컴파일 시 정확히 오버라이딩 되었는지 체크해주는 역할 
생략 가능하다</p>
</blockquote>
<ul>
<li><code>super.메소드명();</code>을 통해 부모 메소드를 호출하고 변경/추가 할 내용을 작성한다</li>
</ul>
<br>


<h2 id="sec05-final-클래스메소드">sec05. final 클래스&amp;메소드</h2>
<blockquote>
</blockquote>
<ul>
<li>final 필드는 초기값 설정 후 값을 변경할 수 없다</li>
<li>final 클래스는 최종 클래스이므로 더 이상 상속할 수 없다</li>
<li>final 메소드는 최종 메소드이므로 오버라이딩 할 수 없다</li>
</ul>
<blockquote>
</blockquote>
<p>💡 <strong>final 클래스, final 메소드</strong>
최종적인 클래스이므로 더 이상 상속할 수 없다
최종적인 메소드이므로 오버라이딩 할 수 없는 메소드가 된다</p>
<br>

<h2 id="sec07-타입-변환">sec07. 타입 변환</h2>
<h3 id="자동-타입-변환-upcasting">자동 타입 변환 (Upcasting)</h3>
<blockquote>
</blockquote>
<ul>
<li><code>부모타입 변수 = 자식타입객체;</code></li>
<li>자식은 부모로부터 상속 받으므로 부모와 동일 취급</li>
<li>부모 타입으로 자동 타입 변환이 이루어지면?</li>
<li>자식 객체를 참조하지만, 부모 클래스 멤버만 접근 할 수 있다</li>
<li>단, 자식 클래스에 오버라이딩된 메소드가 있다면 그 메소드를 호출한다 → 다형성 관련<pre><code class="language-java">  Cat cat = new Cat();
  Animal animal = cat;
  // 또는
  Animal animal = new Cat();
  // cat == animal -&gt; true</code></pre>
</li>
</ul>
<h3 id="강제-타입-변환-downcasting">강제 타입 변환 (Downcasting)</h3>
<ul>
<li><code>자식타입 변수 = (자식타입) 부모타입객체;</code></li>
<li>부모 타입은 자식 타입으로 자동 변환되지 않으므로 캐스팅 연산자를 사용한다</li>
<li>자식 객체가 부모 타입으로 자동 변환된 후 다시 자식 타입으로 변환할 때만 강제 타입 변환을 사용할 수 있다</li>
<li>자식 타입에 선언된 필드와 메소드를 꼭 사용해야 하는 경우 필요로 한다</li>
</ul>
<br>


<h2 id="sec08-다형성polymorphism">sec08. 다형성(polymorphism)</h2>
<blockquote>
</blockquote>
<ul>
<li>자동 타입 변환 + 메소드 오버라이딩 ⇒ 다형성</li>
<li>사용 방법은 동일하지만 실행 결과가 다양하게 나오는 성질</li>
<li>사용 방법이 동일하다는 것은 동일한 메소드를 가지고 있다는 것 (오버라이딩을 통해 실행 결과가 다양하게 나온다)</li>
</ul>
<h3 id="필드-다형성-필드-타입-동일-대입-객체의-차이">필드 다형성: 필드 타입 동일, 대입 객체의 차이</h3>
<pre><code class="language-java">class Car {
    String tire;
}

class CarMain {
    Car myCar = new Car();
    myCar.tire = new HankookTire(); // 한국타이어 장착
    myCar.tire = new KumhoTire(); // 금호타이어 장착

// 한국타이어, 금호타이어에 메소드 오버라이딩이 된 경우 
// 각 객체의 오버라이딩된 메소드가 호출된다</code></pre>
<h3 id="매개변수-다형성">매개변수 다형성</h3>
<pre><code class="language-java">// Bus와 Taxi 객체는 Vihicle를 상속함
// 클래스 타입(Vehicle)의 매개변수를 가진 메소드인 경우에
// 자동 타입 변환으로 인해 Vehicle의 자식 객체 제공도 가능하다

public class Driver {
    // 클래스 타입의 매개변수를 가짐
    public void drive(Vehicle cehicle) {
        vehicle.run();
    }
}

// Main
Driver driver = new Driver();

// 매개값으로 Bus/Taxi 객체 제공
Bus bus = new Bus(); 
driver.drive(bus)
// 또는
driver.drive(new Taxi());</code></pre>
<br>

<h2 id="sec09-객체-타입-확인">sec09. 객체 타입 확인</h2>
<blockquote>
</blockquote>
<ul>
<li><code>객체 instanceof 타입;</code></li>
<li>변수가 참조하는 객체의 타입을 확인하고자 할 때 사용한다</li>
<li>좌항의 객체가 우항의 타입이면 true, 아니면 false 산출</li>
</ul>
<blockquote>
</blockquote>
<p>💡 Java12부터 instanceof 연산의 결과가 true일 경우, 우측 타입 변수를 사용할 수 있으므로 강제 타입 변환이 필요없다.
<code>if(parent instanceof CHild child) {}</code> → child 변수 사용</p>
<br>

<h2 id="sec10-추상-클래스">sec10. 추상 클래스</h2>
<blockquote>
</blockquote>
<ul>
<li><code>public abstract class 클래스명 {}</code></li>
<li><code>abstract 리턴타입 메소드명(매개변수, ...)</code></li>
<li>공통적인 필드나 메소드를 추출해서 선언한 클래스</li>
<li>실체 클래스의 부모 역할을 한다</li>
<li>new 연산자를 사용해서 객체를 직접 생성할 수 없다</li>
<li>실체 클래스를 만들기 위한 부모 클래스로만 사용된다(상속필수)</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[이것이 자바다] 06. 클래스]]></title>
            <link>https://velog.io/@seonjin_dev/%EC%9D%B4%EA%B2%83%EC%9D%B4-%EC%9E%90%EB%B0%94%EB%8B%A4-06.-%ED%81%B4%EB%9E%98%EC%8A%A4</link>
            <guid>https://velog.io/@seonjin_dev/%EC%9D%B4%EA%B2%83%EC%9D%B4-%EC%9E%90%EB%B0%94%EB%8B%A4-06.-%ED%81%B4%EB%9E%98%EC%8A%A4</guid>
            <pubDate>Tue, 29 Aug 2023 14:41:28 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/seonjin_dev/post/fba9ec09-dd5d-401a-a9f3-4aae28afd00b/image.png" alt=""></p>
<p>📚 이것이 자바다 [개정판]</p>
<hr>
<h2 id="sec01-객체-지향-프로그래밍">sec01. 객체 지향 프로그래밍</h2>
<h3 id="1-객체란">1. 객체란?</h3>
<blockquote>
<ul>
<li>객체 = 속성(필드) + 동작(메소드)</li>
</ul>
</blockquote>
<ul>
<li>물리적으로 존재하거나 개념적인 것 중에서 다른 것과 식별 가능한 것</li>
</ul>
<h3 id="2-oop의-특징">2. OOP의 특징</h3>
<blockquote>
</blockquote>
<ul>
<li>캡슐화<ul>
<li>필드와 메소드를 하나로 묶고 실제 구현 내용을 외부에 감추는 것이다</li>
<li>외부의 잘못된 사용으로 인해 객체가 손상되지 않도록 하기 위함이다</li>
<li>접근 제한자를 통해 노출할 것인지 숨길 것인지 결정한다</li>
</ul>
</li>
<li>상속<ul>
<li>코드의 재사용성을 높여준다</li>
<li>유지 보수 시간을 최소화시켜 준다</li>
<li>자식 객체는 부모 객체의 기능을 물려받고 기능을 추가하여 확장한다</li>
</ul>
</li>
<li>다형성<ul>
<li>사용 방법은 동일하지만 실행 결과가 다양하게 나오는 성질이다</li>
</ul>
</li>
</ul>
<br>

<h2 id="sec02-객체와-클래스">sec02. 객체와 클래스</h2>
<blockquote>
</blockquote>
<ul>
<li>클래스 ⇒ 인스턴스화 (클래스로부터 객체를 만드는 과정) ⇒ 인스턴스(객체)</li>
<li>하나의 클래스로부터 여러 개의 인스턴스를 만들 수 있다</li>
</ul>
<br>

<h2 id="sec03-클래스-선언">sec03. 클래스 선언</h2>
<pre><code class="language-java">// 클래스 선언
public class 클래스명 {
    // 객체 생성
    클래스 변수 = new 클래스(); 
  // 스택에 저장된 객체의 주소를 힙에 생성된 객체가 참조

    // 필드 선언
    type fieldName;

    // 생성자 선언 (클래스명과 동일)
    ClassName() {...} 

    // 메소드 선언
    type methodName() {...}</code></pre>
<blockquote>
<p>💡 <strong>하나의 소스 파일에 여러 개의 클래스를 선언하는 경우</strong>
파일명과 동일한 클래스만 공개(public)  클래스로 선언할 수 있다</p>
</blockquote>
<blockquote>
<p>💡 <strong>필드와 지역(로컬)변수의 차이점</strong>
필드 : 클래스 내에 선언, 객체 내부에 존재하며 객체 내/외부 어디든 사용 가능
변수 : 생성자나 메소드 내에서 선언되어 그 내부에서만 사용 가능</p>
</blockquote>
<br>

<h2 id="sec04-객체-생성과-클래스-변수">sec04. 객체 생성과 클래스 변수</h2>
<blockquote>
</blockquote>
<ul>
<li><code>클래스 변수 = new 클래스();</code></li>
<li>클래스로부터 객체를 생성하려면 객체 생성 연산자인 <code>new</code> 가 필요하다</li>
<li>new 연산자는 객체를 생성시킨 후객체의 주소를 리턴한다</li>
</ul>
<br>

<h2 id="sec05-클래스의-구성-멤버">sec05. 클래스의 구성 멤버</h2>
<pre><code class="language-java">public class ClassName {
    // 필드 선언
    타입 fieldName;

    // 생성자 선언
    ClassName() {...}

    // 메소드 선언
    타입 methodName() {...}</code></pre>
<blockquote>
</blockquote>
<ul>
<li>필드<ul>
<li>객체의 데이터를 저장하는 역할   <br>
></li>
</ul>
</li>
<li>생성자<ul>
<li>new 연산자로 객체를 생성할 때 객체 초기화 역할</li>
<li>메소드와 비슷하지만 리턴 타입이 없고, 클래스 이름과 동일하다</li>
<li>모든 클래스에는 생성자가 존재한다<br>
></li>
</ul>
</li>
<li>메소드<ul>
<li>객체가 수행할 동작</li>
<li>객체와 객체간의 상호 작용을 위해 호출된다</li>
</ul>
</li>
</ul>
<br>

<h2 id="sec06-필드-선언과-사용">sec06. 필드 선언과 사용</h2>
<blockquote>
</blockquote>
<ul>
<li><code>타입 필드명 = 초기값;</code> <code>타입 필드명;</code></li>
<li>필드명은 첫 문자를 소문자로 하고 캐멀 스타일로 작성한다</li>
<li>초기값을 설정하지 않은 필드는 객체 생성 시 타입의 기본값으로 초기화된다</li>
<li>필드는 객체의 데이터이므로 객체가 존재해야만 사용할 수 있다</li>
<li>외부 객체에서 사용할 때는 도트 연산자(.)를 사용한다</li>
</ul>
<pre><code class="language-java">class Car2 {
    // 필드 선언
    String model = &quot;그랜저&quot;;
    String color = &quot;balck&quot;;
    int maxSpeed = 350;
    int speed;
}

public **class** CarMain2 {
    public static void main(String[] args) {
        // Car 객체 생성
        Car2 myCar = new Car2();

        // Car 객체의 필드값 읽기
        System.out.println(&quot;모델명: &quot; + myCar.model);
        System.out.println(&quot;색상: &quot; + myCar.color);
        System.out.println(&quot;최고속도: &quot; + myCar.maxSpeed);
        System.out.println(&quot;현재속도: &quot; + myCar.speed);

        // Car 객체의 필드값 변경
        myCar.speed = 60;
        System.out.println(&quot;수정된 속도: &quot; + myCar.speed);
    }

}</code></pre>
<br>

<h2 id="sec07-생성자-선언과-호출">sec07. 생성자 선언과 호출</h2>
<h3 id="1-생성자">1. 생성자</h3>
<blockquote>
</blockquote>
<ul>
<li><code>클래스 변수 = new 클래스();</code> → 생성자 호출</li>
<li>new 연산자는 객체를 생성한 후 객체를 초기화하는 역할을 한다<pre><code class="language-java">// 생성자 선언
ClassName(매개변수, ...) {
  // 객체 초기화 코드
}
// 생성자 호출
ClassName 변수명 = new ClassName(매개변수);</code></pre>
</li>
</ul>
<h3 id="2-생성자-오버로딩">2. 생성자 오버로딩</h3>
<blockquote>
</blockquote>
<ul>
<li>매개값을 통해 객체의 필드를 다양하게 초기화하기 위한 방법</li>
<li>매개변수를 달리하는 생성자를 여러 개 생성하는 것이다<pre><code class="language-java">Car() {...}
Car(String model) {...}
Car(String model, String color) {...}
Car(String model, String color, int maxSpeed) {...}</code></pre>
</li>
</ul>
<h3 id="3-다른-생성자-호출">3. 다른 생성자 호출</h3>
<pre><code class="language-java">// model만 초기화하는 생성자
Car3(String model) {
    this(model, &quot;은색&quot;, 250); // #1 생성자 호출
}

// model과 color를 초기화하는 생성자
Car3(String model, String color) {
    this(model, color, 250); // #1 생성자 호출
}

// #1 모든 필드를 초기화하는 생성자 (공통코드로 사용되는 생성자)
Car3(String model, String color, int maxSpeed) {
    this.model = model;
    this.color = color;
    this.maxSpeed = maxSpeed;
}</code></pre>
<br>

<h2 id="sec08-메소드-선언과-호출">sec08. 메소드 선언과 호출</h2>
<blockquote>
</blockquote>
<ul>
<li>메소드 선언: 객체의 동작을 실행 블록으로 정의하는 것</li>
<li>메소드 호출: 실행 블록을 실제로 실행하는 것</li>
<li><code>return문</code> : 메소드의 실행을 강제 종료하고 호출한 곳으로 돌아간다</li>
<li>메소드명은 첫 문자를 소문자로 시작하고 캐멀 스타일로 작성한다</li>
</ul>
<pre><code class="language-java">// 리턴값이 있는 메소드 선언
리턴타입 메소드명 (매개변수, ...) { 실행코드 };

// 리턴값이 없는 메소드 선언
void 메소드명 (매개변수, ...) { 실행코드 };

// 메소드 호출
타입 변수 = 메소드명();</code></pre>
<br>

<h2 id="sec09-10-인스턴스-멤버--정적-멤버">sec09-10. 인스턴스 멤버 &amp; 정적 멤버</h2>
<blockquote>
</blockquote>
<ul>
<li>인스턴스(instance) 멤버<ul>
<li>객체에 소속되어 객체를 생성해야만 사용할 수 있는 멤버</li>
<li>객체를 생성하고 참조변수명으로 접근한다<br></li>
</ul>
</li>
<li>정적(static) 멤버<ul>
<li>클래스에 고정되어 객체 없이도 사용할 수 있는 멤버</li>
<li>클래스명으로 접근한다</li>
<li>정적 필드는 필드 선언과 동시에 초기값을 주는 것이 일반적이다</li>
<li>공용적인 필드는 정적 필드로 선언하는 것이 좋다</li>
<li>인스턴스 멤버 사용 불가, this 사용 불가<ul>
<li>→ 객체 생성한 경우 가능<pre><code class="language-java">public class Car {
// 인스턴스 필드 선언
int speed;
// 인스턴스 메소드 선언
void run() {
System.out.println(speed + &quot;으로 달립니다.&quot;);
}
static void simulate() {
// 객체 생성
Car myCar = new Car();
// 인스턴스 멤버 사용
myCar.speed = 200;
myCar.run();
}
public static void main(String[] args) {
// 정적 메소드 호출
simulate();
// 객체 생성
Car myCar = new Car();
// 인스턴스 멤버 사용
myCar.speed = 30;
myCar.run();
}
}</code></pre>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<br>      

<h2 id="sec11-final-필드와-상수">sec11. final 필드와 상수</h2>
<blockquote>
</blockquote>
<ul>
<li><code>final</code> 초기값이 저장되면 이것이 최종값이 되어 수정할 수 없다</li>
<li>필드 선언 시에 초기값을 대입하거나, 생성자에서 초기값을 대입한다</li>
<li>상수 이름은 모두 대문자로 작성하고, 언더바(_)로 단어를 연결한다</li>
</ul>
<pre><code class="language-java">    // 상수 선언 및 초기화
    static final double EARTH_RADIUS = 6400;

    // 상수 선언
    static final double EARTH_SURFACE_AREA;

    // 정적 블록에서 상수 초기화
    static {
        EARTH_SURFACE_AREA = 4 * Math.PI * EARTH_RADIUS * EARTH_RADIUS;
    }</code></pre>
<br>      

<h2 id="sec13-접근-제한자">sec13. 접근 제한자</h2>
<blockquote>
</blockquote>
<ul>
<li>객체의 무결성을 유지하게 위해서는 객체의 필드를 외부에서 변경하거나 메소드를 호출할 수 없도록 막아야 한다</li>
<li>클래스, 멤버변수, 메서드, 생성자에서 사용될 수 있다</li>
<li><code>public</code> 접근 제한이 없음</li>
<li><code>protected</code> 같은 패키지 내, 다른 패키지의 자손클래스에서 접근 가능(상속하는 경우)</li>
<li><code>(default)</code> 같은 패키지 내에서만 접근 가능, 아무것도 붙이지 않은 상태</li>
<li><code>private</code> 같은 클래스 내에서만 접근 가능
<img src="https://velog.velcdn.com/images/seonjin_dev/post/6a4fa279-522b-4800-b223-5cce9d59aa2f/image.png" alt=""></li>
</ul>
<br>      

<h2 id="sec14-getter-setter">sec14. Getter, Setter</h2>
<blockquote>
</blockquote>
<ul>
<li>객체지향프로그래밍에서는 객체의 무결성이 중요하기 때문에 직접적인 필드 접근을 막고 메소드를 통해 접근하는 것을 선호한다</li>
<li><code>private</code> 제어자를 사용하는 경우!!</li>
<li><code>setter()</code>데이터를 검증하여 유효한 값만 필드에 저장한다 (데이터 접근, 수정)</li>
<li><code>getter()</code>부적절한 데이터인 경우 적절한 값으로 변환하여 리턴한다 (변경한 데이터 읽기)</li>
</ul>
<pre><code class="language-java">private 타입 fieldName;

// getter
public 타입 **getF**ieldName() {
    return fieldName;
}

public boolean **isF**ieldName

// setter
public void setFieldName(타입 fieldName) {
    this.fieldName = fieldName;
}</code></pre>
<br>      

<h2 id="sec15-싱글톤-패턴">sec15. 싱글톤 패턴</h2>
<blockquote>
</blockquote>
<ul>
<li>단 한 개의 객체만 생성해서 사용하고 싶은 경우에 적용할 수 있다</li>
<li>생성자를 private 접근 제한하여 외부에서의 생성자 호출을 막는 것이 핵심</li>
<li>싱글톤 패턴이 제공하는 정적 메소드를 통해 간접적으로 객체를 얻을 수 있다</li>
</ul>
<pre><code class="language-java">public class 클래스 {
    // private 접근 권한을 갖는 정적 필드 선언과 초기화
    // 자신의 클래스 타입으로 정적 필드를 선언하고 
    // 미리 객체를 생성하여 초기화
    private static 클래스 singleton = new 클래스();

    // private 접근 권한을 갖는 생성자 선언
    private 클래스() {}

    // public 접근 권한을 갖는 정적 메소드 선언
    // 정적 메소드를 public으로 선언하여 정적 필드값을 리턴할 수 있다
    // -&gt; 외부에서 객체를 얻는 유일한 방법
    public static 클래스 getInstance() {
        return singleton;
    }
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[이것이 자바다] 05. 참조 타입]]></title>
            <link>https://velog.io/@seonjin_dev/%EC%9D%B4%EA%B2%83%EC%9D%B4-%EC%9E%90%EB%B0%94%EB%8B%A4-05.-%EC%B0%B8%EC%A1%B0-%ED%83%80%EC%9E%85</link>
            <guid>https://velog.io/@seonjin_dev/%EC%9D%B4%EA%B2%83%EC%9D%B4-%EC%9E%90%EB%B0%94%EB%8B%A4-05.-%EC%B0%B8%EC%A1%B0-%ED%83%80%EC%9E%85</guid>
            <pubDate>Tue, 29 Aug 2023 02:13:16 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/seonjin_dev/post/fba9ec09-dd5d-401a-a9f3-4aae28afd00b/image.png" alt=""></p>
<p>📚 이것이 자바다 [개정판]</p>
<hr>
<h2 id="sec01-데이터-타입-분류">sec01. 데이터 타입 분류</h2>
<blockquote>
</blockquote>
<ul>
<li>자바의 데이터 타입은 기본 타입과 참조 타입으로 분류된다</li>
<li>참조 타입(reference type)<ol>
<li>배열타입</li>
<li>열거타입</li>
<li>클래스</li>
<li>인터페이스</li>
</ol>
</li>
</ul>
<blockquote>
<p>✍🏻 기본 타입 변수 vs. 참조 타입 변수
[기본 타입 변수]  <code>int age = 25;</code> , <code>double price = 100.5;</code>
선언된 변수는 값 자체를 저장하고 있다</p>
</blockquote>
<p>[참조 타입 변수]  <code>String name = &quot;자바&quot;;</code> <code>String job = &quot;programmer&quot;;</code>
선언된 변수는 객체가 생성된 메모리 번지를 저장한다</p>
<blockquote>
</blockquote>
<p><img src="https://velog.velcdn.com/images/seonjin_dev/post/f37c9c83-cf76-4d27-ae0f-43fe66824888/image.png" alt=""></p>
<br>

<h2 id="sec02-메모리-사용-영역">sec02. 메모리 사용 영역</h2>
<blockquote>
</blockquote>
<ul>
<li>java 명령어로 JVM이 구동되면 운영체제에서 할당받은 메모리를 사용
<img src="https://velog.velcdn.com/images/seonjin_dev/post/b0f18ab7-cf72-4157-a811-d2583a1e9d7f/image.png" alt=""></li>
</ul>
<table>
<thead>
<tr>
<th>메소드 영역</th>
<th>클래스별로 상수, 정적 필드, 메소드 코드, 생성자 코드 등이 저장</th>
</tr>
</thead>
<tbody><tr>
<td>힙 영역</td>
<td>new 연산자를 통해 생성한 객체 저장, 메소드 영역과 스택 영역의 상수와 변수를 통해 객체의 번지를 참조한다.런타임 시 동적으로 할당하여 사용하는 메모리 영역</td>
</tr>
<tr>
<td>스택 영역</td>
<td>메소드를 호출할 때 저장되고, 호출이 끝날 때 제거</td>
</tr>
</tbody></table>
<br>

<h2 id="sec05-문자열string-타입">sec05. 문자열(String) 타입</h2>
<br>

<h2 id="sec06-배열array-타입">sec06. 배열(Array) 타입</h2>
<h3 id="1-배열">1. 배열</h3>
<blockquote>
</blockquote>
<p>배열은 같은 타입의 값만 관리한다</p>
<ul>
<li>배열의 길이는 늘리거나 줄일 수 없다</li>
<li>배열을 생성한 경우 항목은 모두 해당 타입의 기본값으로 초기화된다</li>
</ul>
<pre><code class="language-java">// 배열 변수 선언
타입[] 변수명;
타입 변수명[];

// 배열 생성
타입[] 변수명 = {값0, 값1, 값2, ...};
타입[] 변수명 = new 타입[길이];

// 😨 배열 변수를 미리 선언한 후에 값 목록을 변수에 대입할 수 없다
타입[] 변수명;
변수명 = {값0, 값1, 값2, ...};</code></pre>
<h3 id="2-다차원-배열">2. 다차원 배열</h3>
<pre><code class="language-java">// 배열 변수 선언
타입[][] 변수명;
타입 변수명[][];
타입[] 변수명[];

// 배열 생성
타입[] 변수명 = {
        {값0, 값1, 값2, ...},
        {값0, 값1, 값2, ...},
        {값0, 값1, 값2, ...}
}
타입[][] 변수명 = new 타입[1차원 길이][2차원 길이];</code></pre>
<blockquote>
<p>스택 메모리에 1차원의 주소 저장, 1차원 인덱스에 2차원 주소 저장</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/seonjin_dev/post/86f9ddc7-dd44-4f5c-a85b-14a1c992afd7/image.png" alt=""></p>
<h3 id="3-객체를-참조하는-배열">3. 객체를 참조하는 배열</h3>
<blockquote>
</blockquote>
<ul>
<li>참조 타입 배열은 각 항목에 객체의 번지를 저장한다</li>
</ul>
<pre><code class="language-java">String[] strArr = new String[4];
strArr[0] = &quot;Java&quot;;
strArr[1] = &quot;Java&quot;;
strArr[2] = &quot;Python&quot;;
strArr[3] = new String(&quot;Java&quot;);</code></pre>
<p><img src="https://velog.velcdn.com/images/seonjin_dev/post/7e9f1614-b770-4bdc-b4d5-0b0b5e0bf4c8/image.png" alt=""></p>
<br>

<h2 id="sec11-main-메소드의-string-args-매개변수-용도">sec11. main() 메소드의 String[] args 매개변수 용도</h2>
<blockquote>
</blockquote>
<ul>
<li>윈도우의 명령 프롬프트 또는 맥OS의 터미널에서 프로그램을 실행할 때 요구하는 값이 있을 수 있다</li>
<li>예를 들어 두 수를 입력받아 덧셈을 수행하는 Sum 프로그램을 실행해보자.
<code>java Sum 10 20</code></li>
<li>공백으로 구분된 10과 20은 문자열로 취급되며  Stirng[] 배열의 항목 값으로 구성된다
<code>public static void main(String[] args) {...}</code></li>
<li>main() 메소드가 호출될 때 String배열인 args 변수에 배열 항목 값으로 저장되어 매개값으로 사용된다</li>
</ul>
<br>

<h2 id="sec12-열거enum-타입">sec12. 열거(Enum) 타입</h2>
<blockquote>
</blockquote>
<p>몇 가지로 한정된 값을 갖는 데이터 (계절, 요일 등)</p>
<blockquote>
</blockquote>
<ul>
<li>한정된 값을 갖는 타입을 의미한다</li>
<li>모두 대문자로 작성하며, 여러 단어일 경우 언더바(_)로 연결하는 것이 관례</li>
</ul>
<pre><code class="language-java">public enum Week {
    MONDAY,
    TUESDAY,
    WEDNESDAY,
    THURSDAY,
    FRIDAY,
    SATURDAY,
    SUNDAY
}</code></pre>
<pre><code class="language-java">Week today; // 하나의 데이터 타입이므로 변수를 선언하고 사용해야 한다
Week today = Week.SUNDAY;
Week birthday = null; // 참조 타입이므로 null 대입이 가능하다</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JPA] Spring Data JPA란?]]></title>
            <link>https://velog.io/@seonjin_dev/JPA-Spring-Data-JPA%EB%9E%80</link>
            <guid>https://velog.io/@seonjin_dev/JPA-Spring-Data-JPA%EB%9E%80</guid>
            <pubDate>Mon, 28 Aug 2023 23:20:56 GMT</pubDate>
            <description><![CDATA[<p><img src="https://media.licdn.com/dms/image/D4D12AQHLYmtJRpByHw/article-cover_image-shrink_600_2000/0/1684745697758?e=2147483647&v=beta&t=xxVJAj2hp9bdUyx-X0IQ5Mr7gxO1Fd02IZPH-uYRj7o" alt=""></p>
<p>📚 코드로 배우는 스프링 부트 웹 프로젝트</p>
<hr>
<h2 id="spring-data-jpa-java-persistence-api">Spring Data JPA (Java Persistence API)</h2>
<ul>
<li>Java 언어를 통해 데이터베이스와 같은 영속 계층을 처리하고자 하는 스펙</li>
<li>Java Persistence API의 약어로 ORM을 Java 언어에 맞게 사용하는 스펙</li>
<li>스프링 부트는 JPA의 다양한 구현체 중 &quot;Hibernate&quot;라는 구현체를 이용한다</li>
</ul>
<br>

<h2 id="orm-object-relational-mapping">ORM (Object Relational Mapping)</h2>
<ul>
<li><p>ORM은 객체지향 패러다임을 관계형 데이터베이스에 보존하는 기술</p>
</li>
<li><p>패러다임 입장에서 객체지향 패러다임을 관계형 패러다임으로 매핑</p>
</li>
<li><p>객체지향의 구조가 관계형 데이터베이스와 유사하다는 점에서 시작한다</p>
<ul>
<li>DB Table == Java Class</li>
<li>DB Row == Java Instance</li>
<li>DB Relation == Java Reference    </li>
</ul>
</li>
<li><p>DB에서는 Entity(개체, 데이터)인 반면, Java에서는 Data+Method(객체)라는 차이가 있을 뿐이다</p>
</li>
<li><p>결국, ORM은 객체지향과 관계형 사이의 변환 기법을 의미한다</p>
</li>
<li><p>테이블과 객체가 매핑되어 메소드로 데이터를 조회해 바로 객체에 담을 수 있음을 의미한다
<code>User user = userRepository.findByUserId(String userId);</code></p>
</li>
</ul>
<br>

<h2 id="jpa-사용하기">JPA 사용하기</h2>
<ul>
<li>JAP 개발에 필요한 것<ul>
<li>JPA를 통해 관리하게되는 Entity 객체를 위한 Entity Class 필요</li>
<li>Entity 객체들을 처리하는 기능을 가진 Repository 필요</li>
</ul>
</li>
<li>Repository는 스프링이 자동으로 객체를 생성하고 실행하는 구조이므로 
JAP에서 제공하는 인터페이스를 하나 정의하는 작업만으로 충분하다</li>
</ul>
<hr>
<h3 id="1-spring-data-jap를-위한-스프링-부트-설정">1. Spring Data JAP를 위한 스프링 부트 설정</h3>
<ul>
<li>자동으로 필요한 테이블을 생성하거나 SQL 등을 확인하기 위한 추가 설정<pre><code class="language-java">// application.properties
spring.datasource.driver-class-name=org.mariadb.jdbc.Driver
spring.datasource.url=jdbc:mariadb://localhost:포트번호/DB명
spring.datasource.username=DB아이디
spring.datasource.password=DB비밀번호
</code></pre>
</li>
</ul>
<p>spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.show-sql=true</p>
<pre><code>
### 2. Entity 패키지 내부에 클래스 작성
```java
@Entity // 해당 클래스가 엔티티를 위한 클래스임을 선언하는 부분
@Table(name = &quot;memo&quot;) // 엔티티 클래스를 어떤 테이블로 생성할 것인지 선언하는 부분
@ToString
@Getter // getter 메소드 생성
@Builder // 객체 생성 처리
@AllArgsConstructor // Builder 컴파일 에러 발생 방지
@NoArgsConstructor // Builder 컴파일 에러 발생 방지
public class Memo {
    @Id // PK로 지정할 필드
    @GeneratedValue(strategy = GenerationType.IDENTITY) // 자동생성(일련번호)
    private Long mno;
    }

    @Column(length = 200, nullable = false) // 추가될 필드의 정보 저장
    private String memoText;</code></pre><h3 id="3-repository-패키지-내부에-jparepository-작성">3. Repository 패키지 내부에 JpaRepository 작성</h3>
<pre><code class="language-java">// interface
public interface MemoRepository extends JpaRepository&lt;Memo, Long&gt; {
} // &lt;entity type, @id type&gt;</code></pre>
<ul>
<li>JpaRepository 인터페이스를 상속하는 것만으로 작업이 끝난다</li>
<li>스프링이 내부적으로 인터페이스 타입에 맞는 객체를 생성하여 빈으로 등록</li>
</ul>
<br>

<h2 id="jpql-java-persistence-query-language">JPQL (Java Persistence Query Language)</h2>
<ul>
<li>특정 범위의 객체를 검색하는 경우</li>
<li>like 처리가 필요한 경우</li>
<li>여러 검색 조건이 필요한 경우</li>
</ul>
<hr>
<h3 id="1-쿼리-메소드">1. 쿼리 메소드</h3>
<ul>
<li>메소드 이름 자체가 쿼리의 구문으로 처리되는 기능</li>
</ul>
<h3 id="2-query">2. @Query</h3>
<ul>
<li>SQL과 유사하게 엔티티 클래스의 정보를 이용해 쿼리를 작성하는 기능</li>
<li>필요한 데이터만 선별적으로 추출하는 기능 가능</li>
</ul>
<h3 id="3-querydsl-등의-동적-쿼리-처리-기능">3. Querydsl 등의 동적 쿼리 처리 기능</h3>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Spring boot] 프로젝트 생성]]></title>
            <link>https://velog.io/@seonjin_dev/Spring-boot-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%83%9D%EC%84%B1</link>
            <guid>https://velog.io/@seonjin_dev/Spring-boot-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%83%9D%EC%84%B1</guid>
            <pubDate>Mon, 28 Aug 2023 16:48:07 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/seonjin_dev/post/ca5ac49b-d172-46d1-988b-ae9abd00990e/image.png" alt=""></p>
<p>✨ 깃허브 링크 :  <a href="https://github.com/hseonjin/MovieReview.git">MovieReview Project</a></p>
<p>📚 코드로 배우는 스프링 부트 웹 프로젝트</p>
<hr>
<h2 id="스프링부트-프로젝트-생성">스프링부트 프로젝트 생성</h2>
<blockquote>
<p><a href="https://start.spring.io/">spring initializr</a> 바로가기</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/seonjin_dev/post/4488156b-a897-4185-a6a8-cab7d3305e1d/image.png" alt=""></p>
<ol>
<li>Project 유형, Language, Spring Boot 버전, Project 정보, 라이브러리 선택 후 GENERATE</li>
<li>.zip 파일 압축 해제하여 IntelliJ에서 프로젝트 폴더 Open</li>
<li>File → Project Settings → SDK version 설정 후 Gradle Build</li>
<li>Application Run (ctrl + shift + F10)<pre><code>.   ____          _            __ _ _
/\\ / ___&#39;_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | &#39;_ | &#39;_| | &#39;_ \/ _` | \ \ \ \
\\/  ___)| |_)| | | | | || (_| |  ) ) ) )
&#39;  |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot ::               (v3.0.10)
</code></pre></li>
</ol>
<p>// 생략</p>
<p>Tomcat initialized with port(s): 8080 (http)
Starting service [Tomcat]
Starting Servlet engine: [Apache Tomcat/10.1.12]
Initializing Spring embedded WebApplicationContext
Root WebApplicationContext: initialization completed in 956 ms
LiveReload server is running on port 35729
Tomcat started on port(s): 8080 (http) with context path &#39;&#39;</p>
<pre><code>
&lt;br&gt;
&lt;br&gt;

&gt;주의! 스프링 부트 버전과 Java 버전을 맞춰주어야 한다
- &amp;nbsp;&amp;nbsp;&amp;nbsp3.x 버전에서는 Java 17 이상 버전 사용
- &amp;nbsp;&amp;nbsp;&amp;nbsp;2.x 버전에서는 Java 11 사용</code></pre>]]></description>
        </item>
    </channel>
</rss>