<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>kid_chang.log</title>
        <link>https://velog.io/</link>
        <description>개강했기에 가끔씩 업로드.</description>
        <lastBuildDate>Mon, 24 Oct 2022 06:40:46 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <copyright>Copyright (C) 2019. kid_chang.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/kid_chang" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[eclipse JDBC 연동 오류]]></title>
            <link>https://velog.io/@kid_chang/eclipse-JDBC-%EC%97%B0%EB%8F%99-%EC%98%A4%EB%A5%98</link>
            <guid>https://velog.io/@kid_chang/eclipse-JDBC-%EC%97%B0%EB%8F%99-%EC%98%A4%EB%A5%98</guid>
            <pubDate>Mon, 24 Oct 2022 06:40:46 GMT</pubDate>
            <description><![CDATA[<pre><code class="language-java">package com.postgresqltutorial;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;




public class App {

    public static void main(String[] args) {
        App app = new App();
        app.connection();
    }

    private final String url = &quot;jdbc:postgresql://localhost:5432/postgres&quot;;
    private final String user = &quot;postgres&quot;;
    private final String password = &quot;sql041279!&quot;;


    public Connection connection () {
        Connection conn = null;
        try {
            conn = DriverManager.getConnection(url, user, password);
            System.out.println(&quot;connected server successfully&quot;);

        } catch (SQLException e) {
            System.out.println(e.getMessage());
        }
        return conn;
    }

}
</code></pre>
<p>위와 같은 코드작성시에 
<code>no suitable driver found for jdbc</code>
라는 에러가 발생할 수 있다.</p>
<p>경로설정도 다 잘했다고 생각한다면
마지막으로 설정 - java - installed JREs 에서 작동하는 자바 버전의 설정에 들어가 jdbc 파일을 직접 import 해준다.</p>
<p><img src="https://velog.velcdn.com/images/kid_chang/post/73cc5f4c-d2e1-4313-ac83-bc64241a9ae8/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL] 20220124]]></title>
            <link>https://velog.io/@kid_chang/TIL-20220124</link>
            <guid>https://velog.io/@kid_chang/TIL-20220124</guid>
            <pubDate>Mon, 24 Jan 2022 16:45:25 GMT</pubDate>
            <description><![CDATA[<h1 id="노드">노드</h1>
<h2 id="자바스크립트-원리">자바스크립트 원리</h2>
<h3 id="호출스택-이벤트-루프-태스크-큐-백그라운드">호출스택, 이벤트 루프 태스크 큐, 백그라운드.</h3>
<p>기본적으로 런타임 구조는
호출스택 | 백그라운드 | 태스크 큐 | 이벤트 루프로 이루어져있다.</p>
<p>호출스택은 LIFO 구조로 annoymous라는 전역 컨텍스트가 제일 먼저 쌓이고 그다음부터 코드들이 쌓인다. 그리고 실행은 역순으로 진행된다.
그리고 비동기로 작동할때에는 백그라운드에서 이벤트가 발생하고, 이벤트에 조건이 만족되어 콜백함수가 실행되면 이때 태스크 큐로 보낸다. 태스크 큐에서는 호출스택에 아무것도 없으면 이벤트루프를 통해 호출 스택으로 이동해 실행된다. 이로인해 호출 스택에 무언가 있다면 그 함수들이 모두 실행되야 이벤트루프를 통해 전달된다는 특징이 있다. 그렇기에 만약 setTimeout(<del>~</del>,3000)를 실행하더라도 완벽히 3000밀리세컨드 후에 실행된다는 보장을 할 수없다.</p>
<h4 id="논-블로킹-io">논 블로킹 I/O</h4>
<p>논 블로킹이란 이전 작업이 완료될 때까지 대기하지 않고 다음작업을 수행하는 것이다.
자바스크립트상에서 돌아가는 것이 아닌 I/O 작업은 동시에 처리될 수 있다.
하지만 블로킹이 가능한 작업이더라도, 논 블로킹 방식으로 처리하지 않으면 블로킹 방식으로 처리되기에 이를 유의하여 코딩해야한다.</p>
<p>블로킹 형식</p>
<pre><code class="language-js">function longRunningTask(){
  //오래걸리는 작업~~
  console.log(&quot;done&quot;);
}

console.log(&quot;start&quot;);
longRunningTask();
console.log(&quot;END&quot;);</code></pre>
<pre><code>결과는
----------------
start
done
END</code></pre><p>논 블로킹 형식</p>
<pre><code class="language-js">function longRunningTask(){
  //오래걸리는 작업~~
  console.log(&quot;done&quot;);
}

console.log(&quot;start&quot;);
setTimeout(longRunningTask, 0);
console.log(&quot;END&quot;);</code></pre>
<pre><code>결과는
----------------
start
END
done</code></pre><p>즉, setTimeout(콜백함수, 0)을 이용해 논 블로킹을 만드는 방법중 하나이다. 
(setTimeout의 딜레이값을 0 으로 설정하더라도, 기본적인 지연시간이 있다. HTML5 브라우저는 4ms, node에서는 1ms)</p>
<p>논 블로킹 개념을 보면서 이전에 얼핏 학습한 동기 비동기가 떠올라서 차이점에 대해 알아봤다.
<code>[논 블로킹, 블로킹 | 동기, 비동기 ]</code> 이 4가지의 차이점에 대해서는
<a href="https://cotak.tistory.com/136">https://cotak.tistory.com/136</a>, <a href="https://evan-moon.github.io/2019/09/19/sync-async-blocking-non-blocking/#%EB%8F%99%EA%B8%B0-%EB%B0%A9%EC%8B%9D--%EB%85%BC%EB%B8%94%EB%A1%9D%ED%82%B9-%EB%B0%A9%EC%8B%9D">https://evan-moon.github.io/2019/09/19/sync-async-blocking-non-blocking/#동기-방식--논블록킹-방식</a>  두 개의 블로그를 읽으면서 어렴풋이 이해했다.</p>
<p>블로그 내용을 간단히 요약해서 내 해석대로 풀어내자면
개념적인 측면으로 봤을때 블로킹, 논 블로킹은 프로세스의 사용권(?)과 관련되어있고 동기, 비동기는 수행순서와 관련이 있다.
두 블로그에서 야자감독과 학생, 사장과 직원의 입장에서 풀어냈는데, 난 야자감독과 학생의 입장에서 정리.</p>
<p>동기 + 블로킹 =&gt; 감독과 학생이 동시에 들어오고 야자가 끝날때까지 감독은 학생들의 야자시간이 끝났나 안끝났나만 계속 확인한다. 그리고 야자시간이 끝나면 퇴근한다. (여기서 감독은 시간을 확인하는 것 외에는 아무것도 할수없는 즉, 관리감독말고는 다른 행동을 할수 있는 권리(표현이 이상하긴 하지만 프로세스의 사용권이 뺏겼다는 것을 뜻함)가 없다.</p>
<p>동기 + 논 블로킹 =&gt; 감독과 학생이 동시에 들어오고 야자가 끝날때까지 감독은 핸드폰도 보고 밖에도 나가는 등 자기가 원하는 걸 모두 할 수 있다.
하지만 계속 야자가 끝났는지는 확인을 해야하고, 야자가 끝나야지만 퇴근이 가능하다.</p>
<p>비동기 + 논 블로킹 =&gt; 야자가 시작하면 학생들은 들어와서 공부를 한다. 감독은.. 자기가 감독이 맞나싶을정도로 무책임하게 출석만 부르고(아니면 출석조차도 안부르고) 퇴근한다. 야자가 진행중인지 끝났는지 관심도 없다.</p>
<p>이렇게 분류할 수 있다.</p>
<p>(<a href="https://nodejs.org/ko/docs/guides/">https://nodejs.org/ko/docs/guides/</a> 의 내용도 시간나면 보자.)
(<a href="http://latentflip.com/loupe/">http://latentflip.com/loupe/</a> 이벤트루프 시각적으로 표현)</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React] Wanted(원티드) 클론코딩]]></title>
            <link>https://velog.io/@kid_chang/React-Wanted%EC%9B%90%ED%8B%B0%EB%93%9C-%ED%81%B4%EB%A1%A0%EC%BD%94%EB%94%A9</link>
            <guid>https://velog.io/@kid_chang/React-Wanted%EC%9B%90%ED%8B%B0%EB%93%9C-%ED%81%B4%EB%A1%A0%EC%BD%94%EB%94%A9</guid>
            <pubDate>Fri, 21 Jan 2022 07:19:47 GMT</pubDate>
            <description><![CDATA[<h1 id="클론코딩-개요">클론코딩 개요</h1>
<p>프로젝트자체는 프론트와 백이 연동되지만,
이 게시글에는 제가 담당한 프론트에 관한 내용만 기재합니다.
(1.21기준 이미지나 gif는 삽입 준비중)</p>
<ul>
<li>개발기간 : 14일 (1월 8일 ~ 1월 21일)</li>
<li>개발인원 : front 1명, back 1명</li>
</ul>
<h1 id="기술-스택">기술 스택</h1>
<p>처음적는거라 이렇게 적는게 맞는지는 모르겠지만....</p>
<ul>
<li><strong>프론트엔드</strong>
React
Redux
styled-components
axios-RESTful API</li>
</ul>
<h1 id="구현-사항">구현 사항</h1>
<p><strong>1. 로그인 / 회원가입 연동 및 자동로그인
2. 마이 원티드 페이지.
3. 채용 - 채용공고 화면 제작.
4. 채용 - 메인 제작.
5. 기업상세화면.
6. 검색기능.
8. 직군별 연봉.
9. 커뮤니티.
10. 이벤트 페이지</strong></p>
<h2 id="상세">상세</h2>
<h3 id="gnb-global-navigation-bar">GNB (Global Navigation Bar)</h3>
<ul>
<li>로그인, 회원가입 기능
원티드는 (회원가입/로그인)으로 버튼이 통합되어있고, 누르면 이메일을 먼저입력한다. 이메일이 DB에 있는지 확인하는 api를 통해서 있으면 회원가입 폼을, 없으면 로그인 폼을 보여준다. </li>
<li>자동로그인
로그인시 발급되는 userIdx와 jwt를 localStorage에 저장해서 새로고침하더라도 로그인상태가 유지되도록 구성.(야매이긴한듯)</li>
<li>로그인되면 그에 맞게 일부 내용 변경</li>
<li>로그아웃 기능 (로그아웃시 localStorage값 제거)</li>
<li>NAV바에서 검색 구현
쿼리스트링을 통해서 키워드를 전달하면 기업과 포지션이 각각 리스트로 리턴되어 이를 기반으로 화면에 표시해준다. <h3 id="홈-화면">홈 화면</h3>
</li>
<li>홈의 캐러셀들은 원티드+나 아티클이고, 이는 계획에 없는 부분이라 임의의 내용들로만 채워넣음.</li>
<li>로그인시 홈의 이력서 안내부분이 변경되고 하단 캐러셀이 생겨남<h3 id="채용-탭">채용 탭</h3>
</li>
<li>채용부분에는 로그인이 되어있으면 ~~님! 바로 지원해볼까요? 캐러셀과 wanted ai가 제안하는 합격률 높은 포지션 캐러셀이 보인다.</li>
<li>각 채용공고나 회사별 아이템들은 모두 좋아요와 팔로우 버튼을 누르면 백으로 보내서 마이원티드등에서도 확인이 가능하도록 되어있다.</li>
<li>저장된 태그중 랜덤으로 2개를 골라서 태그에 맞는 기업들을 보여주는 캐러셀<h4 id="채용-공고-리스트-탭">채용 공고 리스트 탭</h4>
</li>
<li>무한스크롤로 아이템들을 볼 수 있도록 구성했다.<h4 id="각-채용-포지션-탭">각 채용 포지션 탭</h4>
</li>
<li>각 포지션별로 index가 할당되어있고 이를 uri 파라미터로 받아와서 api통신-&gt; 페이지에 뿌려준다. 이 탭에는 포지션이 속한 기업으로의 링크, 기업 팔로우, 포지션 북마크, 포지션 좋아요, 지원하기 기능이 구현되어있고 이또한 rest api를 이용해서 다른화면에서도 확인이 가능하다.</li>
</ul>
<h4 id="각-기업-탭">각 기업 탭</h4>
<ul>
<li>각 포지션별로 index가 할당되어있고 이를 uri 파라미터로 받아와서 api통신-&gt; 페이지에 뿌려준다.</li>
<li>실제 페이지에서 이미지 캐러셀이 끝에 도달하면 다시 맨처음으로 이동시켜줘서, 똑같이 클론할때도 맨앞으로 이동하도록 구현했다.</li>
<li>기업에 등록된 포지션들은 북마크도 누르면 연동되고 기업자체에도 팔로우가 가능하다.<h3 id="이벤트-탭">이벤트 탭</h3>
</li>
<li>이벤트는 태그별로 검색이 가능하게 구현했다. 캐러셀과 모달을 이용해서 태그를 선택하고 이에 맞춰 쿼리스트링을 이용해 필터링이 가능하다.<h3 id="이력서">이력서</h3>
비로그인시 이력서 안내 페이지로 연결되고, 로그인시 이력서 리스트를 보여준다. 
이력서를 제작하는 페이지도 퍼블리싱은 했지만, api와 연동하지않아서 기능상으로는 작동하지 않는다. <h3 id="커뮤니티">커뮤니티</h3>
우선 각 게시판별로 글들이 다르도록 구성되어있다.
각 게시글은 생성과 수정이 가능하고, 댓글은 생성과 삭제가 가능하다.</li>
</ul>
<h3 id="마이원티드-관련">마이원티드 관련</h3>
<p>네비게이션 바에서 아바타 이미지를 누르면 모달창이 뜨는데 여기서 mywanted와 지원 현황, 좋아요, 북마크 가 구현되어있다.</p>
<h4 id="마이원티드-탭">마이원티드 탭</h4>
<p>여기에서는 개인정보와 관심사 지원현황 북마크 좋아요 등 종합적인 정보를 볼 수 있다.</p>
<h5 id="관심사">관심사</h5>
<p>이를 누르면 관심사를 설정하는 탭으로 넘어가고 값들을 저장할 수 있다. 이 값들또한 서버에 저장되어서 다시확인해도 그대로 유지된다.</p>
<h4 id="지원현황">지원현황</h4>
<p>모달창에서나 마이원티드 탭내의 지원현황을 눌러서 접근이 가능하다. 여기서 지원했던 포지션들의 리스트를 확인 할 수 있다.</p>
<h4 id="좋아요-북마크">좋아요, 북마크</h4>
<p>각각 값을 받아오는데로 화면에 표현해주고 여기도 마찬가지로 좋아요나 북마크 해제가 가능하다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[react] 캐러셀(Carousel) 만들기.]]></title>
            <link>https://velog.io/@kid_chang/react-%EC%BA%90%EB%9F%AC%EC%85%80Carousel-%EB%A7%8C%EB%93%A4%EA%B8%B0</link>
            <guid>https://velog.io/@kid_chang/react-%EC%BA%90%EB%9F%AC%EC%85%80Carousel-%EB%A7%8C%EB%93%A4%EA%B8%B0</guid>
            <pubDate>Wed, 15 Dec 2021 11:29:35 GMT</pubDate>
            <description><![CDATA[<h1 id="캐러셀을-만들어보자">캐러셀을 만들어보자.</h1>
<p>인터넷에서 얻어낸 캐러셀 만드는 법은 한번에 한 이미지씩 넘어가도록 구현하는 방법만 있는거같길래 그 내용들을 참고해서 넷플릭스의 캐러셀처럼 여러 컨텐츠를 한번에 넘기도록 구현했다.</p>
<h3 id="carouseltestjs">CarouselTesT.js</h3>
<pre><code class="language-js">import &quot;./CarouselTesT.css&quot;;
import { useEffect, useRef, useState } from &quot;react&quot;;

function CarouselTesT() {
  const container_Carousel = useRef();
  const [nowX, setNowX] = useState(0);
  useEffect(() =&gt; {
    container_Carousel.current.style.transform = `translateX(${nowX}vw)`;
  }, [nowX]);
  // useState 말고 useEffect를 이용해야할듯.
  const clickLeftButton = () =&gt; {
    // setNowX(nowX + 20);
    setNowX((prop) =&gt; prop + 20);
    console.log(`it&#39;s work ${nowX}`);
  };
  const clickRightButton = () =&gt; {
    setNowX(nowX - 20);
    console.log(`it&#39;s work ${nowX}`);
  };
  return (
    &lt;div className=&quot;body&quot; style={{ overflow: &quot;hidden&quot; }}&gt;
      &lt;div&gt;{nowX}&lt;/div&gt;
      &lt;label className=&quot;left&quot; onClick={clickLeftButton}&gt;
        left
      &lt;/label&gt;
      &lt;label className=&quot;right&quot; onClick={clickRightButton}&gt;
        right
      &lt;/label&gt;
      &lt;div className=&quot;container_Carousel&quot; ref={container_Carousel}&gt;
        &lt;div className=&quot;inner&quot;&gt;
          &lt;img src={&quot;img/img1.jpg&quot;} alt=&quot;&quot; /&gt;
        &lt;/div&gt;
        &lt;div className=&quot;inner&quot;&gt;
          &lt;img src={&quot;img/img2.jpg&quot;} alt=&quot;&quot; /&gt;
        &lt;/div&gt;
        &lt;div className=&quot;inner&quot;&gt;
          &lt;img src={&quot;img/img1.jpg&quot;} alt=&quot;&quot; /&gt;
        &lt;/div&gt;
        &lt;div className=&quot;inner&quot;&gt;
          &lt;img src={&quot;img/img2.jpg&quot;} alt=&quot;&quot; /&gt;
        &lt;/div&gt;
        &lt;div className=&quot;inner&quot;&gt;
          &lt;img src={&quot;img/img1.jpg&quot;} alt=&quot;&quot; /&gt;
        &lt;/div&gt;
        &lt;div className=&quot;inner&quot;&gt;
          &lt;img src={&quot;img/img2.jpg&quot;} alt=&quot;&quot; /&gt;
        &lt;/div&gt;
        &lt;div className=&quot;inner&quot;&gt;
          &lt;img src={&quot;img/img1.jpg&quot;} alt=&quot;&quot; /&gt;
        &lt;/div&gt;
        &lt;div className=&quot;inner&quot;&gt;
          &lt;img src={&quot;img/img2.jpg&quot;} alt=&quot;&quot; /&gt;
        &lt;/div&gt;
        &lt;div className=&quot;inner&quot;&gt;
          &lt;img src={&quot;img/img1.jpg&quot;} alt=&quot;&quot; /&gt;
        &lt;/div&gt;
        &lt;div className=&quot;inner&quot;&gt;
          &lt;img src={&quot;img/img2.jpg&quot;} alt=&quot;&quot; /&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  );
}

export default CarouselTesT;</code></pre>
<h3 id="carouseltestcss">CarouselTesT.css</h3>
<pre><code class="language-css">.container_Carousel{
    width: 300vw;
    transition: transform 0.5s;
}

.inner img{
    width: 10%;
    float: left;

}

.left{
    position: absolute;
    z-index: 10;
    top: 30%;
    transform: translateY(-50%);
    padding: 10px;
    cursor: pointer;
    color: white;
    font-weight: 900;
    ;
}

.right{
    position: absolute;
    z-index: 10;
    top: 30%;
    right: 10px;
    transform: translateY(-50%);
    padding: 10px;
    cursor: pointer;
    color: white;
    font-weight: 900;
}</code></pre>
<p>useState를 이용해서 버튼 누를때마다 10씩 더하거나 빼도록 하였고,
useRef를 이용해서 스타일을 넣을 태그를 선택했다.
그리고 useEffect를 이용해서 nowX값이 변할때마다 style을 바꾸도록 만들었다.</p>
<p>뼈대 html과 css는
<a href="https://www.youtube.com/watch?v=qHzSQrLjxlQ&amp;t=293s">https://www.youtube.com/watch?v=qHzSQrLjxlQ&amp;t=293s</a> (코딩애플)
<a href="https://www.youtube.com/watch?v=JryRu5zby3A">https://www.youtube.com/watch?v=JryRu5zby3A</a> (코남) 를 참고했다.</p>
<p>맨처음엔 useState와 버튼에 클릭되는 함수만을 이용해서 변하도록 하려했지만,
한번클릭할때 작동되지않고 그 다음번 클릭때 이전 변동값이 적용되어서 골머리를 앓았다.
<img src="https://images.velog.io/images/kid_chang/post/57298103-7501-4f9b-a3d6-15a7840ad9f5/ezgif-7-82109355f6.gif" alt="">
useState는 비동기방식이라 리렌더링 되기전까지는 적용되지않는다고해서, useState로 적용된 값을 즉각적으로 useEffect로 받고, 변동이 감지되면 이 훅에서 즉각적으로 style에 수정되도록 하였다. </p>
<p>아무 이미지 3장만 준비하고 위의 코드를 그대로 복붙하면 쉽게 캐러셀을 구현할 수 있다. 이를 응용해서 넷플릭스 클론코딩에도 적용해봤다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL]20211024]]></title>
            <link>https://velog.io/@kid_chang/TIL20211024</link>
            <guid>https://velog.io/@kid_chang/TIL20211024</guid>
            <pubDate>Sun, 24 Oct 2021 13:00:07 GMT</pubDate>
            <description><![CDATA[<h1 id="자바">자바</h1>
<h2 id="스레드">스레드</h2>
<h3 id="프로세스">프로세스</h3>
<p>운영체제에서는 실행중인 하나의 애플리케이션을 프소세스라고 한다.
만약 메모장 2개를 실행하면 메모장 에플리케이션 2개의 프로세스를 실행한 것이다.</p>
<h3 id="스레드-1">스레드</h3>
<p>한 가지 작업을 실해하기 위해 순차적으로 실행할 코드를 실처럼 이어놓았다고 해서 유래된 이름이다. 하나의 스레드는 하나의 코드 실행 흐름이기 때문에 한 프로세스 내에 스레드가 2개라면 2개의 코드 실행 흐름이 생긴다는 의미이다.
또한, 스레드 사이에서 객체들을 공유해서 사용할 수도 있다.</p>
<h3 id="멀티-태스킹">멀티 태스킹</h3>
<p>운영체제가 두 가지 이상의 작업을 동시에 처리하는 것. 즉, 병렬로 연결시켜 실행하는 것이다.
하지만 멀티 태스킹이 멀티 프로세스를 뜻하는 것은 아니다. 하나의 프로세스 내에서도 스레드를 통해 여러 작업을 동시에 처리할 수 있다.
동영상 플레이어의 경우 하나의 프로세스에서 기본적으로 영상 재생과 음성 재생, 두 가지 스레드 즉, 멀티 스레드가 발생한다고 볼 수 있다. </p>
<p>운영체제에서 할당받은 메모리를 가지고 실행하기에 각 프로세스는 서로 독립적이다.
 하지만 스레드의 경우 프로세스에 할당해준 한정된 메모리를 공유하기에 하나의 스레드가 예외를 발생시키면 프로세스 자체가 종료될 수 있어 다른 스레드에 영향을 준다.</p>
<h3 id="thread-클래스">thread 클래스</h3>
<p> 이 클래스는 Runnable을 매개갑으로 갖는다.
 <code>Thread thread = new Thread(Runnable target);</code>
 이때 Runnable은 인터페이스 타입이기 때문에 구현 객체를 만들어 대입해야한다.
구현 클래스에선 run()을 재정의해서 작업 스레드가 실행할 코드를 만들어야함.</p>
<p>즉, 이런 식이다.</p>
<pre><code class="language-java">class Task implements Runnable {
  public void run() {
    //스레드가 실행할 코드
  }
}

Runnable task = new Task();
Thread thread = new Thread(task);</code></pre>
<p>더 간단히 만들려면</p>
<pre><code class="language-java">Thread thread = new Thread( new Runnable() {
  public void run() {
    //스레드가 실행할 코드
  }
} );</code></pre>
<p>이러한 익명 객체 생성 방식으로도 많이 사용된다고 한다.</p>
<p>그리고 작업 스레드는 생성즉시 실행되는 것이 아니라, <code>thread.start();</code> 처럼 start()메소드를 실행해야한다.</p>
<pre><code class="language-java">import java.awt.*;
public class Main {
      public static void main(String[] args) {
         Thread thread = new Thread(new Runnable() {
             @Override
             public void run() {
                 Toolkit toolkit = Toolkit.getDefaultToolkit();
                 for(int i = 0 ; i&lt;5; i++) {
                     toolkit.beep();
                     try {Thread.sleep(500);} catch(Exception e) {}
                 }
             }
         });
         thread.start();

         for(int i = 0; i&lt;5; i++) {
             System.out.println(&quot;띵 &quot;);
             try {Thread.sleep(500);} catch(Exception e) {}
         }
      }
}</code></pre>
<p>스레드를 이용해서 비프음과 출력이 각각의 클래스에서 동시에 작동되도록 하는 코드이다.</p>
<p>또한, Runnable인터페이스로 작업내용을 만들지 않고, Thread의 하위클래스로 작업 스레드를 정의해서 사용해도 된다.</p>
<pre><code class="language-java">public class WorkerThread extends Thread {
    @Override
    public void run() {
        //스레드가 실행할 코드
    }
}
Thread thread = new WorkerThread();

// 상속 + 익명 객체이용
import java.awt.*;
public class Main {
      public static void main(String[] args) {
         Thread thread = new Thread() {
             @Override
             public void run() {
                 Toolkit toolkit = Toolkit.getDefaultToolkit();
                 for(int i = 0 ; i&lt;5; i++) {
                     toolkit.beep();
                     try {Thread.sleep(500);} catch(Exception e) {}
                 }
             }
         };
         thread.start();

         for(int i = 0; i&lt;5; i++) {
             System.out.println(&quot;띵 &quot;);
             try {Thread.sleep(500);} catch(Exception e) {}
         }
      }
}</code></pre>
<p>이런식으로.</p>
<h3 id="동기화-메소드">동기화 메소드</h3>
<p>여러 스레드에서 같은 객체(공유 객체)를 사용할 떄 예상치못한 경우가 발생한다. user1스레드가 A라는 객체의 a라는 값을 1이라고 정하고 2초를 기다리는 동안 user2스레드가 A라는 객체의 a라는 값을 2라고 바꿔놓고 2초간 기다린다면, 전체 2초 후에 user1이나 user2나 모두 a값을 2로 가지게 되어 user1이 원하던 값을 나중에는 얻을 수 없게 된다. </p>
<p>멀티 스레드 프로그램에서 단 하나의 스레드만 실행할 수 있는 코드 영역을 임계 영역 이라고 하고, 이를 지정하기 위해 동기화 메소드를 사용해 이 문제를 해결한다.</p>
<p>스레드가 객체내부의 동기화 메소드를 실행하면 즉시 객체에 잠금을 걸어 다른 스레드가 동기화 메소드를 실행하지 못하도록 한다.</p>
<pre><code class="language-java">public synchronised void method() {
  //임계영역, 단 하나의 스레드만 실행
}</code></pre>
<p>동기화 메소드는 메소드 전체내용이 임계 영역이므로 메소드 실행즉시 객체에는 잠금이 일어나고, 메소드 종료시 잠금이 풀린다.
만약, 동기화 메소드가 여러개 있다면, 스레드가 이들 중 하나를 실행할 때 다른 스레드는 해당 메소드는 물론, 다른 동기화 메소드들도 실행할 수 없다. 
하지만 다른 스레드에서 일반 메소드는 실행이 가능하다.</p>
<p>만약 위의 A객체의 예를 여기에 적용하면 setMemory()라는 메소드를 synchronized로 만든다면, user1 스레드는 2초후에 1이라는 값을 출력하고 user2는 앞의 스레드가 끝나고 2초 후에 2라는 값을 출력한다.</p>
<h3 id="스레드-상태">스레드 상태</h3>
<p>스레드는 start()메소드가 호출되면 <code>실행 대기 상태</code>가 된다. 이후 운영체제가 하나의 스레드를 선택해 CPU가 run()메소드를 실행하도록 하는데, 이때가 <code>실행 상태</code> 이다. 이 상태일때 스레드는 run()메소드가 끝나기전 다시 실행 대기 상태로 돌아갈 수 있다.
이렇게 실행 대기와 실행 상태를 번갈아 가면서 스레드마다의 run()메소드를 조금씩 실행 할 수 있다. 경우에 따라 <code>일시 정지</code> 상태에 가기도 하는 데 이 상태는 스레드가 실행할 수 없는 상태이다. 이때는 바로 실행 상태가 될 수 없고, 실행 대기 상태를 거쳐야 한다.</p>
<p>스레드의 상태를 변경하는 것을 <code>스레드 상태 제어</code>라고 한다.</p>
<h3 id="스레드-상태-제어-메소드">스레드 상태 제어 메소드</h3>
<p><code>interrupt()</code>: 일시 정지 상태의 스레드에서 Interruptedexception을 발생시켜, 예외 처리 코드(catch)에서 실행 대기로 가거나 종료 상태로 갈 수 있도록 한다.
<code>sleep</code>: 주어진 시간동안 스레드를 일시 정지 상태로 만듭니다. 주어진 시간이 지나면 자동적으로 실행 대기 상태가 됩니다.</p>
<p>만약 sleep을 이용해 정지상태에 있을 때에 주어진 시간이 되기전에 interrupt()메소드가 호출되면 InterruptedException이 발생하기에 이에 관한 예외처리도 필요하다.</p>
<h3 id="스레드의-안전한-종료">스레드의 안전한 종료</h3>
<p>스레드는 run() 메소드가 끝나면 자동적으로 종료되므로, 메소드가 정상적으로 종료되도록 유도하는 것이 중요하다.</p>
<h4 id="1-stop-플래그를-이용하는-방법">1. stop 플래그를 이용하는 방법.</h4>
<pre><code class="language-java">~~~
boolean stop= false;
public void run() {
while(!stop){
  // 반복할 코드 작성.
  }
}</code></pre>
<p>이런 식으로 boolean형의 stop플래그를 이용해서 종료시킬 수 있다.</p>
<p>이를 구현한다면 아래코드와 같다.</p>
<pre><code class="language-java">public class StopFlagExample {
    public static void main(String[] args)  {
        PrintThread printThread = new PrintThread();
        printThread.start();

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
        }

        printThread.setStop(true);
    }
}
-----------------------------------------------------------------

public class PrintThread extends Thread {
    private boolean stop;

    public void setStop(boolean stop) {
      this.stop = stop;
    }

    public void run() {    
        while(!stop) {
            System.out.println(&quot;실행 중&quot;);
        }    
        System.out.println(&quot;실행 종료&quot;);
    }
}</code></pre>
<h4 id="2-interrupt-메소드를-이용하는-방법">2. interrupt() 메소드를 이용하는 방법</h4>
<p>interrupt() 메소드는 스레드가 일시정지 상태에 있을 때 InterruptedException을 발생시키는 역할을 한다.
이를 이용하면 run()메소드를 정상 종료할 수 있습니다.</p>
<pre><code class="language-java">Class ThreadA
~~
ThreadB threadB = new ThreadB();
threadB.start();
~~~
threadB.interrupt();
------------------------------------------------------------
Class ThreadB
public void run() {
  try{
  while(true) {
    ~~~~
    Thread.sleep(1);
  }
  }catch(InterruptedException e) {
  }
  //스레드가 사용한 자원 정리.
}</code></pre>
<p>ThreadA가 ThreadB의 interrupt() 메소드를 실행하게 되면 ThreadB가 sleep() 메소드로 일시 정지 상태가 될 때 ThreadB에서 InterruptedException이 발생하여 예외 처리(catch) 블록으로 이동합니다.
결국, ThreadB는 while문을 빠져나와 run() 메소드를 정상 종료하게 된다.
또한 주목할만한 점이 있다. 스레드가 실행 대기 또는 실행 상태에 있을 때 interrupt() 메소드가 실행되면 즉시 InterruptedException이 발생하지 않고, 스레드가 미래에 일시 정지상태가 되면 발생한다. 따라서 스레드가 일시 정지 상태가 되지 않으면 interrupt() 메소드 호출은 아무 의미가 없어진다. 그렇기에 짧은 시간이나마 일시 정지시키기 위해 Thread.sleep(1)을 사용한다.</p>
<p>이 방법을 사용하지 않는다면, boolean연산자를 리턴하는  Thread.interrupted()를 이용할 수도 있다.</p>
<pre><code class="language-java">while(true) {
  if(Thread.interrupted()) {
    break;
  }
}</code></pre>
<h3 id="데몬-스레드">데몬 스레드</h3>
<p>이 스레드는 주 스레드의 작업을 돕는 보조역할을 한다.
<code>thread.setDaemon(true);</code> 를 이용해 설정할 수 있고, 실행은 <code>thread.start();</code> 을 이용하지만, 주 스레드가 종료될 때 자동으로 종료된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL]20211004]]></title>
            <link>https://velog.io/@kid_chang/TIL20211004</link>
            <guid>https://velog.io/@kid_chang/TIL20211004</guid>
            <pubDate>Mon, 04 Oct 2021 04:46:31 GMT</pubDate>
            <description><![CDATA[<h1 id="웹">웹</h1>
<pre><code>&lt;a href=&quot;#&quot; onclick=&quot;addP(); this.onclick=&#39;&#39;;&quot;&gt;더 보기&lt;/a&gt;  
    &lt;!-- this.onclick=&#39;&#39;;는 한번만 클릭되도록 만들기 위함. onclick이 한번 실행되면 this를 통해 이 코드에서의 onclick 명령을 &#39;&#39;으로 변경시켜 다음번엔 클릭해도 아무것도 작동되지 않도록 함.--&gt;</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL]20210928]]></title>
            <link>https://velog.io/@kid_chang/TIL20210928</link>
            <guid>https://velog.io/@kid_chang/TIL20210928</guid>
            <pubDate>Tue, 28 Sep 2021 13:22:53 GMT</pubDate>
            <description><![CDATA[<h1 id="c">C</h1>
<pre><code class="language-c">int main(){

    int ary[3][4] = { {1,2,3,4},{5,6,7,8},{9,10,11,12}};
    int (*pa)[4]; //4칸짜리 배열덩어리 전체를 가리키는 포인터.
    int i, j;
    pa=ary;
    for(i=0;i&lt;3;i++){
        for(j=0;j&lt;4;j++){
            printf(&quot;%5d&quot;,pa[i][j]);
        }
        printf(&quot;\n&quot;);
    }
}</code></pre>
<hr>
<p>쌉소리 주의. 다 틀린말일 수도...
2차원 배열과 배열 포인터. 
배열 포인터는 배열을 가리키는 포인터로 2차원 배열의 이름(묶음 묶음들 -&gt;즉, 열(column))의 주소 단위로 저장한다.(주소에서 +1을 하면 묶음 내부에서 한칸 이동이 아닌 다음 열로 이동.)
{배열의 주소라고 하지않는 이유는 배열 맨앞 한 칸을 가리키는 것이 아닌 배열 한 줄 전체를 지시함을 표시하기위함임}</p>
<p>1차원 배열은 논리적인 배열 요소 이지만 1차원 요소를 여러개 나열한 2차원 배열은 전체로 보면 1차원 배열 맨 앞의 주소를 여러개 가지고 있는 일반적인 배열이다.</p>
<p>위의 코드에서 {x, x, x, x}이라는 논리적인 1차원 배열이 여러개일때 주소+1을 하면 다음번의 1차원 배열로 넘어간다.</p>
<p>그렇기 때문에 int (<em>pa)[4];를 통해서 int[4](4칸짜리 int형 배열)을 담을 함수를 만든다. *pa는 한 줄(열(column))씩 묶는 포인터. 이 코드는 포인터 함수를 이용한 것은 맞지만, *</em>&quot;포인터 배열&quot;<strong>이 아니다.! **배열 포인터</strong>이다.</p>
<p>arr[3][4]일때 2차원 배열의 논리적 입장에서는 arr[0], arr[1], arr[2] 세 덩이로 구분된다.
<code>int (*pa)[4];</code>는 {1,2,3,4}덩어리, {5,6,7,8}덩어리, {9,10,11,12}덩어리 각각을 가리키기위해 (*pa)를 쓴 것이고 각각의 덩어리 내부는 4칸으로 구성되어있기에 [4]를 사용. (int[4]라고 생각.)</p>
<p>복잡해서 다시 요약하자면
4칸짜리 1차원 배열 내부는 포인터로 접근시키고 이 묶음들은 &quot;일반적인&quot; 배열로(arr[0], arr[1]처럼) 인식 코드이다...</p>
<blockquote>
<p><a href="https://blockdmask.tistory.com/56">https://blockdmask.tistory.com/56</a> 누군가 잘 정리한 글을 보자 
그냥. 요약. 
포인터 배열: 포인터들(주소)를 배열에 담은 것. 선언예시: <code>char* arr[3];</code>
배열 포인터: 배열을 가리키는 포인터. 선언예시: <code>char (*arr)[3];</code></p>
</blockquote>
<hr>
<h2 id="2차원-배열의-요소를-참조하는-원리">2차원 배열의 요소를 참조하는 원리.</h2>
<p><code>arr[3][4]</code>배열에 1~12숫자를 차례대로 넣는다고 가정하자.
7번째 물리적 요소를 접근하는 방법</p>
<ol>
<li>7번째 물리적 요소는 두 번째 부분배열(col 덩어리)에 속함으로 시작 위치를 구해야함. (밑의 값중 100단위는 메모리 번지)
ary+1 -&gt; 100(1<em>sizeof(arr[0])) -&gt; 100 + 16 -&gt; 116
이때 sizeof(arr[0])은 ary가 가리키는 첫 번째 <strong>부분배열</strong>의 크기.
arr[1]에 접근했다면 이제 이 배열 안에서 추가적인 접근을 해줘야하는데
(arr+1)+2 하면 당연히 안된다. 저러면 arr+3이 되고 부분배열자체를 건너뛰고 다음 3번째의 부분배열에 접근하는 것이다.
\</em>(arr+1) -&gt; arr[1]
*(arr+1) +2 -&gt; *(arr+1) + (2 * sizeof(arr[1][0])) -&gt; 116 + 8 -&gt; 124
이런 방식으로 접근 해야한다. 부분배열 밖을 겉돌때는 *가 없고 부분배열 내부를 접근할땐 *가 사용된다는 것을 잘 알아두자.
124는 배열의 주소값임으로 상자안의 값을 사용하려면 <code>*(*(arr+1)+2)</code> -&gt; <code>arr[1][2]</code>로 접근하면 된다.</li>
</ol>
<blockquote>
<p><strong>정리</strong>
<code>int ary[3][4];</code> 가 있을때.
<code>&amp;ary</code> : (1) 2차원 배열 &quot;전체&quot;의 주소
<code>ary</code> : (2) 첫 번째 부분배열의 주소 // sizeof -&gt; 48바이트
<code>&amp;ary[0]</code> : (3) 첫 번째 부분배열의 주소 // sizeof -&gt; 4바이트
<code>ary[0]</code> : (4) 첫 번째 부분배열의 첫 번째 배열 요소의 주소 // sizeof -&gt; 16바이트
<code>&amp;ary[0][0]</code> : (5) 첫 번째 부분배열의 첫 번째 배열 요소의 주소 // sizeof -&gt; 4바이트
<br>2, 3번이 거의 흡사하고 4, 5번이 거의 흡사하다.
서로의 차이점은 전자들의 경우 배열 또는 부분배열이고 후자의 경우 단순한 주소이다.
배열은 주소역할뿐 아니라 논리적으로 변수의 기능도 하기에 &quot;같다&quot;고 할수는 없다.</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL]20210926]]></title>
            <link>https://velog.io/@kid_chang/TIL20210926</link>
            <guid>https://velog.io/@kid_chang/TIL20210926</guid>
            <pubDate>Sun, 26 Sep 2021 14:40:42 GMT</pubDate>
            <description><![CDATA[<h1 id="c">C</h1>
<h2 id="문자열-상수-관련">문자열 상수 관련.</h2>
<p>1.</p>
<pre><code class="language-c">int main(void){

    char *dessert= &quot;apple&quot;; //문자열을 주소이다!!. 주소에 접근한 후 상자를 열어 값을 수정해야하지, 주소 값을 apple, banana로 바꿀려니까 안되지.

    printf(&quot;%s %p\n&quot;,dessert,dessert);
    dessert=&quot;banana&quot;; 
    printf(&quot;%s %p\n&quot;,dessert,dessert); // 문자열은 상수. 포인터로 주소에 접근해서 상자 내부의 값을 변경하는 것이 아니라, 다른 상자 주소를 가리키도록 만드는 것.
}</code></pre>
<p>2.</p>
<pre><code class="language-c">int main(void){

    char str[80]; //char* 을 이용해 칸 수 제한을 없애든지, str[80]등으로 칸 수 제한을 두던지.
    scanf(&quot;%s&quot;,str); // scanf();는 공백이 없는 연속된 문자열을 입력받음.
    printf(&quot;%s\n&quot;,str);
    scanf(&quot;%s&quot;,str);
    printf(&quot;%s\n&quot;,str);
    // &quot;apple jam&quot; 입력하면
    // apple
    // jam
    // 이렇게 출력됨.
}</code></pre>
<p><code>apple jam</code> 을 입력하면 버퍼에 두 단어가 임시저장되고, scanf에서는 공백을 기준으로 끊기때문에 <code>apple</code> 만을 가져간다. 그 후, 다시 scanf에서 <code>jam</code>을 가져간다.</p>
<h2 id="gets">gets</h2>
<p>공백이나 탭 문자도 입력이 필요할 경우 <code>gets()</code> 을 이용한다.</p>
<pre><code class="language-c">int main(void){

    char str[80]; //char* 을 이용해 칸 수 제한을 없애든지, str[80]등으로 칸 수 제한을 두던지.
    gets(str);
    printf(&quot;%s\n&quot;,str);
}</code></pre>
<p><code>apple jam</code> 을 입력하면 그대로 출력된다.</p>
<blockquote>
<p>scanf는 스페이스바, 탭, 엔터 입력값을 <code>/0</code> 으로 변환하고, gets는 엔터 입력값만 <code>/0</code>으로 바꾸고 나머지는 다 본래의 값을 보관한다.</p>
</blockquote>
<h2 id="fgets">fgets</h2>
<p>앞의 scanf, gets는 버퍼에서 가져오는 문자열의 크기와 선언한 배열의 크기를 비교하지 않기때문에, 입력받다가 할당되지 않은 메모리 공간을 침범하는 문제가 발생할 수 있다. 이를 예방하기위해 fgets를 사용한다.</p>
<pre><code class="language-c">fgets(str, sizeof(str), stdin);</code></pre>
<p>배열명, 배열의 크기, 표준 입력 순으로 작성한다.
배열 크기는 -1을 하지 않아도 알아서 마지막 한칸은 <code>\0</code>으로 생각하고 입력을 받아준다.
그리고 마지막의 표준 입력은, scanf와 gets는 기본적으로 표준입력을 사용하지만, fgets는 입력 버퍼를 선택할 수 있다. 다른 것과 마찬가지로 표준입력을 사용할 것이기에 stdin으로 사용.</p>
<hr>
<p>fgets는 엔터 입력값인 <code>\n</code>을 <code>\0</code>으로 바꾸는 앞의 함수들과 다르게 개행문자까지 저장하고 마지막에 널 문자를 붙인다. 그렇기 때문에 밑의 경우처럼 %s뒤에 문자를 더 작성하면 개행 된 후 &quot;입니다&quot;가 출력된다. 이를 예방하기위해 <code>str[strlen(str)-1]=&#39;\n&#39;;</code> 을 이용한다. strlen(str)의 자리에는 <code>\0</code>이 있고 그 한 칸앞에 <code>\n</code> 이 있기에 -1을 붙여준다.</p>
<pre><code class="language-c">int main(void){

    char str[80]; //char* 을 이용해 칸 수 제한을 없애든지, str[80]등으로 칸 수 제한을 두던지.
    fgets(str,sizeof(str),stdin);
    str[strlen(str)-1]=&#39;\n&#39;;
    printf(&quot;%s입니다.&quot;,str);
}</code></pre>
<h3 id="scanf-getchar---gets-fgets의-버퍼-공유-문제와-해결방안">scanf, getchar  | gets, fgets의 버퍼 공유 문제와 해결방안.</h3>
<p>scanf() 함수는 \n(줄바꿈문자)를 가져오지 않고, 마지막에 \0(널문자)를 붙인다.</p>
<p>getchar 함수 또한 scanf와 비슷할듯?( 얘는 잘 모르겠음)</p>
<p>gets() 함수는 \n(줄바꿈문자)까지 가져오고, \n을 \0으로 대체 한다.</p>
<p>fgets() 함수는 \n(줄바꿈문자)까지 가져오고, 추가적으로 \0을 붙인다.</p>
<p><strong>즉, scanf와 getchar는 버퍼에 <code>\n</code>을 남긴다. 개행문자 전까지의 값을 메모리에 가져온 후에 <code>\0</code>을 붙인다. gets나 fgets는 <code>\n</code>까지 가져온다.
이 차이로 인해 문제가 생긴다. 
scanf나 getchar로 문자를 입력받으면 버퍼에 <code>\n</code>이 남아서 다음번에 버퍼에서 값을 가져오려할때 이 <code>\n</code>만 입력받고 함수를 끝낸다.</strong></p>
<p>이를 해결하기 위해 </p>
<pre><code class="language-c">1.
getchar();
2.
scanf(&quot;%*c&quot;);
3.
fgetc(stdin);</code></pre>
<p>함수를 이용.
위 코드들은 작동방식에서 조금의 차이는 있지만, 결론적으로 버퍼의 맨 앞 한칸을 가져와서 버린다.</p>
<h2 id="puts-fputs">puts, fputs</h2>
<pre><code class="language-c">put(str); // 자동 줄 바꿈.
put(str,stdout); // 줄 바꾸지 않음.</code></pre>
<h2 id="strcat-strncat">strcat, strncat</h2>
<p>문자열을 뒤에 이어 붙인다.</p>
<pre><code class="language-C">char str[80]= &quot;straw&quot;;
strcat(str, &quot;berry&quot;); --&gt; strawberry
strncat(str, &quot;piece&quot; ,3); --&gt; strawpie</code></pre>
<p>주의사항, 사용할 배열은 초기화 되있어야함. 이어붙일때 널 문자 위치를 기준으로 하기 때문.</p>
<h2 id="strcmp-strncmp">strcmp, strncmp</h2>
<p>문자열 비교.
<code>strcmp(str1, str2);</code>
str1과 str2가 똑같이 대 or 소 문자일 경우만 정확한 비교가 됨.
각 자리 수마다 비교해서 str1이 str2보다 사전에 나중에 나오면(아스키 코드값이 크면) 1을 반환, 그 반대면 -1을 반환. 같으면 0을 반환한다.</p>
<h2 id="strcpy-함수-만들어보기">strcpy 함수 만들어보기.</h2>
<pre><code class="language-c">char *my_strcpy(char *pd, char *ps);

int main(void){

    char str[80]=&quot;starwberry&quot;;

    printf(&quot;before : %s\n&quot;, str);
    my_strcpy(str,&quot;apple&quot;);
    printf(&quot;after : %s\n&quot;, str);

    return 0;
}

char *my_strcpy(char *pd, char *ps){
    char *po  = pd; //예전 파이썬 알고리즘 할때 공부한 내용. pd는 주소값이 계속 변하기때문에, 초기 메모리 위치를 기억할 친구가 하나 필요.

    while(*ps != &#39;\0&#39;){
        *pd=*ps; //배열이 아니기 때문에 문자열 상수가 아님. 그럼으로 내부수정이 가능. *pd로 주소의 상자를 열고 *ps로 다른 상자의 내용물을 그대로 복사.
    pd++;
    ps++;

    }
    *pd=&#39;\0&#39;; 
    return po;
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL]20210925]]></title>
            <link>https://velog.io/@kid_chang/20210925</link>
            <guid>https://velog.io/@kid_chang/20210925</guid>
            <pubDate>Sat, 25 Sep 2021 09:21:33 GMT</pubDate>
            <description><![CDATA[<h1 id="c">C</h1>
<h2 id="버퍼">버퍼.</h2>
<p>버퍼란 프로그램을 실행하는 중에 운영체제가 자동으로 할당하는 메모리의 저장공간이다.</p>
<p>scanf를 이용해서 값을 변수에 저장할 때의 과정을 보면
입력된 값이 바로 변수에 저장되지 않고, 버퍼라는 공간에 일시적으로 저장된다. 그 후 변수에 할당된 양 만큼만 이동된다.
만약 <code>scanf(&quot;%c&quot;, &amp;ch);</code> 코드를 이용해 abc를 입력했다면, 버퍼에 a b c \0 이 저장되고, %c 즉 글자 하나만 저장해야함으로 버퍼에서 a 하나만 빼서 ch에 저장한다. 그러면 버퍼에는 b c \0 이 남게 된다.</p>
<p>책의 코드를 보면</p>
<pre><code class="language-c">int main(void){

    char ch;
    int i;

    for(i=0; i&lt;3; i++){
        scanf(&quot;%c&quot;, &amp;ch);
        printf(&quot;%c\n&quot;,ch);
    }
    return 0;
}</code></pre>
<p>얼핏보면 입력을 3번 할 수 있는 것 처럼 보이지만, 첫번째 입력시에 <code>tiger</code> 을 입력한다면 버퍼 5칸에 값이 모두 저장되고 <code>scanf</code> 에 for문에 순환될때 마다 t 하나, i 하나, g 하나 를 순서대로 제공한다. 그렇기에 입력은 한번밖에 못한 꼴이 된다.
scanf나 getchar등의 명령어는 버퍼에 있는 값을 우선적으로 가져오려하고, 버퍼에 값이 없다면 사용자의 입력을 받는다. 사용자의 입력을 버퍼에 저장하는 것은 운영체제가 하는 일이고 입력을 변수에 저장하는 명령어들(scanf, getchar)은 버퍼에서 값을 긁어오는 기능을 수행한다 생각하면 이해가 쉽다.</p>
<h2 id="getchar">getchar();</h2>
<p><code>getchar()</code> 는 버퍼 <strong>&quot;한칸만&quot;</strong> 리턴해주거나 제거한다. 남은 버퍼를 모두 제거하려면 <code>while(getchar() != &#39;\n&#39;);</code> 을 사용.</p>
<h1 id="웹">웹</h1>
<h2 id="css">css</h2>
<h3 id="속성--속성값-선택자--속성--속성값-선택자--속성--속성값-선택자--속성--속성값-선택자--속성--속성값-선택자--속성--속성값-선택자">[속성 = 속성값] 선택자 | [속성 ~= 속성값] 선택자 | [속성 |= 속성값] 선택자 | [속성 ^= 속성값] 선택자 | [속성 $= 속성값] 선택자 | [속성 *= 속성값] 선택자</h3>
<p><code>=</code>의 경우 속성값이 딱 하나, 그리고 완전 일치할때만. 
<code>~=</code>는 속성값이 여러개 이더라도 원하는 속성값이 있다면 선택됨. 
<code>|=</code>는 속성값 또는 속성값+-의 조합(속성값-<code>~~</code>) 딱 하나의 경우에만 적용됨. 
<code>^=</code> 는 속성값이 원하는 단어이거나 원하는 단어로 시작하는 경우.(eng으로 설정하면 eng, english 등 가능)<br><code>$=</code> 는 설정한 값으로 끝나는 값이 선택됨.
<code>*=</code> 는 일부 속성값이 일치하면 됨.</p>
<pre><code>a[class=&quot;_blank&quot;] {~}
        &lt;li&gt;&lt;a href=&quot;#&quot; class=&quot;_blank&quot;&gt;HTML&lt;/a&gt;&lt;/li&gt; &lt;--선택.--&gt;
        &lt;li&gt;&lt;a class=&quot;_blank _asdf&quot; href=&quot;#&quot;&gt;CSS Selector&lt;/a&gt;&lt;/li&gt; &lt;--선택 X.--&gt;


a[class ~= &quot;_blank&quot;] {~}
        &lt;li&gt;&lt;a href=&quot;#&quot; class=&quot;_blank&quot;&gt;HTML&lt;/a&gt;&lt;/li&gt; &lt;--선택.--&gt;
        &lt;li&gt;&lt;a class=&quot;_blank _asdf&quot; href=&quot;#&quot;&gt;CSS Selector&lt;/a&gt;&lt;/li&gt; &lt;--선택.--&gt;
a[title |= &quot;us&quot;] {  /* 속성값이 &quot;us&quot;이거나 &quot;us-&quot;로 시작하는 요소를 찾는 선택자 */~~~}
        &lt;li&gt;&lt;a href=&quot;#&quot; title=&quot;us-english&quot;&gt;영어&lt;/a&gt;&lt;/li&gt;</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL]20210916]]></title>
            <link>https://velog.io/@kid_chang/TIL20210916</link>
            <guid>https://velog.io/@kid_chang/TIL20210916</guid>
            <pubDate>Thu, 16 Sep 2021 10:46:21 GMT</pubDate>
            <description><![CDATA[<p>어렵고 이해안되는 것들을 내가 이해할 수 있는 느낌으로 풀어써본다.</p>
<h1 id="자바">자바</h1>
<h2 id="익명-객체-익명-클래스">익명 객체 (익명 클래스)</h2>
<p>익명 객체는 이름이 없는 객체이다. 
익명 객체는 한번쓰고 버리는 등 이후에 사용하지 않아 자식 클래스를 굳이 선언하지 않으려 한다. 즉, 클래스의 장점인 재사용성을 포기하는 거 같다.</p>
<p>책에서는</p>
<ul>
<li>일반적인 경우
<code>class 자식클래스1 extends 부모클래스 { ... }</code>
<code>부모클래스 변수별칭 = new 자식클래스1();</code></li>
<li>익명 객체를 사용할 경우
<code>부모클래스 변수 = new 부모클래스() { ... } ;</code></li>
</ul>
<p>이렇다는데 솔직히 글자량 달라진거 말고는 이해가 안됐다.</p>
<p>좀 더보고 한번에 이해가게 풀이하자면</p>
<p>오히려 챕터이름이 &quot;익명 객체&quot; 라서 더 헷갈린 거 같다.
&quot;익명 클래스를 내부에서 선언하는 이름을 가진 객체&quot; 가 내가 이해하기엔 더 쉬운거 같다.
<code>부모클래스 [변수1 | 필드1] = new 부모클래스() { ... } ;</code> 를 보면 뒤에 <code>{ ... };</code> 를 제외하면 일반적으로 부모클래스로 객체하나 만드는 것과 동일하다. 
여기서 extends를 통해서 새롭게 자식클래스를 만드는 대신 이 자식클래스에 적을 내용들을 <code>{ ... }</code> 에 적어준다. 
일단, 내가 느껴지는 바로는 <strong>자식클래스</strong>의 이름은 안적으니 익명이지만 <strong>&quot;변수1&quot;</strong> 또는 <strong>&quot;필드1&quot;</strong>이라는 이름을 가지고 있으니까 객체가 익명? 인지 모르겠다.</p>
<h3 id="요약">요약.</h3>
<pre><code class="language-java">1. 익명 자식 객체
부모클래스 [변수 | 필드] = new 부모클래스(매개값, ...) {
  // &quot;자식클래스&quot;처럼 부모클래스에 얹혀 추가적으로 사용할 필드
  // &quot;자식클래스&quot;처럼 부모클래스에 얹혀 추가적으로 사용할 매소드
};   // ; 필수!

-----------------


2. 익명 구현 객체

인터페이스 [변수 | 필드] = new 인터페이스() {
  // 인터페이스에 선언된 추상 메소드의 실체 메소드 선언(재정의)
  // 필드
  // 메소드
}; // ; 필수!</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL]20210913]]></title>
            <link>https://velog.io/@kid_chang/TIL20210913</link>
            <guid>https://velog.io/@kid_chang/TIL20210913</guid>
            <pubDate>Mon, 13 Sep 2021 06:50:17 GMT</pubDate>
            <description><![CDATA[<h1 id="자바">자바</h1>
<h2 id="인터페이스-구현">인터페이스 구현</h2>
<p>하나의 인터페이스를 통해 여러 객체들을 사용할 수 있다.
<code>public interface 인터페이스명</code> 을 통해 선언.</p>
<p>인터페이스는 상수 필드와 추상메소드만을 구성 멤버로 가진다.
또한, 객체로 생성될 수 없기에 생성자를 가질 수 없다.</p>
<h3 id="추상메소드">추상메소드</h3>
<p>인터페이스로 호출된 메소드는 최종적으로 객체에서 실행됨.
remind: 추상 메소드는 리턴 타입, 메소드 이름, 매개 변수만 있고, {}를 붙이지 않는다.</p>
<h3 id="구현">구현</h3>
<p>개발코드가 인터페이스 메소드를 호출하면 인터페이스는 객체의 메소드를 호출합니다.
객체는 인터페이스에서 정의된 추상 메소드와 <strong>동일한</strong> 메소드 이름, 매개 타입, 리턴 타입을 가진 실체 메소드를 가지고 있어야한다. 이러한 객체를 인터페이스의 ** <code>구현 객체</code> <strong>라고 하고, 구현 객체를 생성하는 클래스를 **<code>구현 클래스</code></strong>라고 함.</p>
<h4 id="구현-클래스">구현 클래스</h4>
<p>implements 키워드가 들어감.
<code>public class 구현클래스이름 implements 인터페이스이름 { }</code></p>
<p>* 추상메소드와 관련된 메소드는 무조건 public을 생략할 수 없음 *</p>
<p>인터페이스로 구현 객체를 사용하려면</p>
<pre><code class="language-java">인터페이스 변수;
변수 = 구현객체;
//또는
인터페이스 변수 = 구현객체;</code></pre>
<p>형태로 작성한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL]20210911]]></title>
            <link>https://velog.io/@kid_chang/TIL20210911</link>
            <guid>https://velog.io/@kid_chang/TIL20210911</guid>
            <pubDate>Sat, 11 Sep 2021 05:04:34 GMT</pubDate>
            <description><![CDATA[<h1 id="자바">자바</h1>
<h2 id="getter-setter-메소드를-이용해-필드를-보호하기"><code>Getter</code>, <code>Setter</code> 메소드를 이용해 필드를 보호하기.</h2>
<p>객체지향 프로그래밍에서 객체의 필드를 객체 외부에서 직접적으로 접근하는 것을 막는다. 객체의 무결성을 보호하기 위해서이다. (자동차는 음수를 가질 수 없는데, 외부에서 임의로 음수가 되도록 조작한다던가 등)
이를 위해 객체의 필드 값을 <strong>메소드</strong>를 통해 조작하는 것을 선호한다.
그리고 이앞에 Setter 메소드임을 알리기위해 <code>set</code>을 붙인다.</p>
<pre><code class="language-java">void setSepeed(double speed){
    if(speed &lt; 0) {
        this.speed = 0;
        return;
} else {
    this.speed = speed;
}</code></pre>
<p>또한, <code>Getter</code> 메소드도 Setter 메소드를 만들면서 private로 설정된 필드를 접근하기위해, 아니면 클래스 외부에 전달될 때 환산된 값을 보내줘야할 경우 사용한다.</p>
<pre><code class="language-java">double getSpeed(){
    double km = speed*1.6;
    return km;
}</code></pre>
<p>참고로 boolean일 경우 <code>get</code> 대신 <code>is</code> 를 앞에 붙인다.</p>
<h2 id="상속">상속.</h2>
<p>기존의 클래스를 재활용한다.
만약 SportsCar라는 클래스를 만들때 기존의 Car 클래스를 상속해온다면 굳이 새롭게 패달, 브레이크등의 코드를 새롭게 짤 필요가 없어진다.</p>
<pre><code class="language-java">class SportsCar extends Car { ... }</code></pre>
<p>하지만 </p>
<ol>
<li>다중상속 (extends Car, Car2)은 불가능하다.</li>
<li>부모Class의 private도 상속되지 않는다. (default는 가능)</li>
</ol>
<h3 id="부모-생성자-호출">부모 생성자 호출</h3>
<p>자식 객체가 생성되면 자동으로 부모 객체도 만들어진다. (내부적으로 만들어지는 순서는 부모 객체-&gt;자식 객체 순) 
객체는 실행될 때 생성자가 필요한데, 부모 객체 또한 만들어진다.</p>
<h4 id="자식-객체가-생성자를-명시하지-않는다면">자식 객체가 생성자를 명시하지 않는다면</h4>
<p>(기본 생성자를 사용하기위해)</p>
<pre><code class="language-java">public 자식_생성자(){
    super(); // 부모의 기본 생성자 호출.
}</code></pre>
<p>이런 식으로 알아서 구성된다.</p>
<h4 id="만약-직접-자식-생성자를-선언한다면">만약 직접 자식 생성자를 선언한다면</h4>
<pre><code class="language-java">public 자식_생성자(매개변수1, 매개변수2){
    super(매개값1, 매개값2);
}</code></pre>
<p>이런식으로 구성한다.</p>
<p>예제</p>
<pre><code class="language-java">//부모 클래스
public class People{
    public String name;
    public String ssn;

public People(String name, String ssn){
    this.name=name;
    this.snn=ssn;
    }
}

//자식 클래스
public class Studnet extends People{
    public int studentNo;

    public Student(String name, String ssn, int studentNo){
    super(name, ssn);
    this.studentNo=studentNo;
    }
}</code></pre>
<p>부모 클래스에는 기본 생성자가 없고 매개값을 받는 생성자만 있다. 
그렇기에 자식 클래스에서는 super(name,ssn)으로 생성자를 호출해야만 한다.
<strong>부모 생성자를 호출할때는 무조건 super를 사용한다. 
부모 클래스 이름이 People이라고 자식 클래스 생성자 밑에 그걸 적는 게 절대 아니다! 부모 생성자를 호출하는 기능은 항상 super()이고, 괄호에 매개변수가 들어가는지, 들어간다면 몇 개가 들어가는지만 적어주면 된다.</strong>
즉, 부모의 기본 생성자를 호출할때는 super()을 적는 건 마음대로이고,
매개변수가 있는 부모의 생성자를 호출할때는 super(매개변수1, 2, ...)를 통해 호출한다.</p>
<h3 id="오버라이딩메소드-재정의">오버라이딩(메소드 재정의)</h3>
<p>자식클래스에서 부모클래스의 일부 메소드를 다시 정의하는 것.
재정의할 때 주의해야할 점.</p>
<ol>
<li>부모의 메소드와 동일한 시그니처(리턴 타입, 메소드 이름, 매개 변수 목록)를 가져야한다.  (어찌보면 당연. 하나라도 틀리다면 다른 메소드가 될테니.)</li>
<li>접근 제한을 더 강하게 재정의할 수 없다.</li>
<li>새로운 예외를 throws할 수 없다는데 아직 안배움.</li>
</ol>
<p>여기서 2번 문항을 자세히 보자면 
부모 메소드가 public 접근 제한을 가지고 있다면 이를 오버라이딩할때 default나 private처럼 더 강한 접근 제한으로 변경이 불가능하지만, 반대로 강한 접근 제한에서 public등 약한 접근 제한으로 수정은 가능하다.</p>
<p>오버라이딩 후, 만약 재정의 되지않은 기존의 부모 메소드를 쓰고 싶은 경우 <code>super.부모메서드</code>를 통해 호출이 가능하다.</p>
<p>만약, 부모와 자식 클래스에 A 메소드가 공동으로 있고, 오버라이딩 되었다면, 자식 클래스의 A 메소드안에서 if문을 통해 참이면 어떤 값을 실행하거고 거짓이면 super.A를 통해 부모 클래스의 A메소드를 실행하도록 만드는 것도 가능하다.</p>
<p><strong>final 을 붙이면 상속이 불가능하다. 당연히 재정의도 안된다.</strong></p>
<h4 id="protected-접근-제한자">protected 접근 제한자</h4>
<p>이는 같은 패키지 내에서는 public처럼 마음대로 쓸 수 있지만, 다른 패키지에서는 new를 이용한 일반적인 접근은 불가능 하고 무조건 extends를 통해 가능하다. 하지만 여기에도 제약이 있는데 상속으로 이용할 때에도 new를 쓸 수는 없고 <code>super</code> 를 무조건 이용해야 한다. 그러면 <code>this.</code> 을 통해 필드와 메소드의 접근이 가능해진다.</p>
<h3 id="클래스-생성자에서-메소드-실행법">클래스 생성자에서 메소드 실행법.</h3>
<p>문제를 보다가 알게됬는데,</p>
<blockquote>
<p>생성자에서 <code>this(&quot;대한민국&quot;);</code>  처럼 <code>this</code>를 이용해 자신의 메소드를 실행할 수 있다.</p>
</blockquote>
<h3 id="다형성">다형성</h3>
<p>사용 방법은 동일(동일한 필드나 메소드)하지만 다양한 실행결과가 나오도록 만드는 성질</p>
<h4 id="클래스-간의-자동-타입-변환">클래스 간의 자동 타입 변환</h4>
<p>자식 클래스가 부모 클래스의 타입으로 변하는 것은 가능하지만, 부모 클래스에서 선언된 필드와 메소드만 접근이 가능하다. 부모의 타입으로 작동하지만 참조하는 객체는 원래의 자식 객체가 맞다. 하지만 타입 자체에는 자식만 가지고 있는 필드 메소드가 없기에 접근이 안된다. <strong>단, 메소드가 자식 클래스에서 재정의(오버라이딩)되었다면 자식이 가지고이있는 메소드가 호출된다.</strong>
반대로, 부모 클래스가 자식 클래스의 타입으로 변하는 것은 불가능.</p>
<h4 id="필드의-다형성">필드의 다형성</h4>
<pre><code class="language-java">Tire.frontLeftTire = new Tire();
// 를
Tire.frontLeftTire = new HankookTire();
// 로 교체가 가능하다. (내부에 물론 같은 메서드 등만이 사용가능하지만)</code></pre>
<h4 id="매개-변수의-다양성">매개 변수의 다양성</h4>
<p>말로 설명하는 게 어려워 책의 코드를 그대로 가져왔다.</p>
<pre><code class="language-java">public class Vehicle {
  public void run(){
    System.out.println(&quot;차량이 달린다&quot;);
  }
}</code></pre>
<pre><code class="language-java">public class Driver{
  public void drive(Vehicle vehicle){
  vehicle.run();
  }
}
</code></pre>
<pre><code class="language-java">public class Bus extends Vehicle {
  @Override
  public void run(){
    System.out.println(&quot;버스가 달린다.&quot;);
  }
}</code></pre>
<pre><code class="language-java">public class Taxi extends Vehicle {
  @Override
  public void run(){
    System.out.println(&quot;택시가 달린다.&quot;);
  }
}</code></pre>
<pre><code class="language-java">public class DriverExample(String[] args){
  Driver driver = new Driver();
  Bus bus = new Bus();
  Taxi taxi = new Taxi();

  driver.drive(bus); // 자동 타입 변환 Vehicle vehicle = bus;
  driver.dirve(taxi);// 자동 타입 변환 Vehicle vehicle = taxi;
}</code></pre>
<p>위 코드를 보면 bus나 taxi에 추가되는 필드나 메소드가 없어 모든 코드들이 정상적으로 작동한다. 또한, 위에서 말한것 처럼 (자식 메소드에서 생긴 필드와 메소드는 못쓰는 것과 다르게) <strong>예외적으로</strong> 오버라이드 된 메소드는 부모객체에서도 여전히 오버라이드된 상태로 작동하기때문에 <code>버스가 달린다.</code>, <code>택시가 달린다.</code> 등이 출력된다. </p>
<h4 id="강제-타입-변환">강제 타입 변환</h4>
<p>강제 타입 변환은 부모 타입을 자식 타입으로 변환하는 것. 단, 자식 타입이 부모 타입으로 자동 타입 변환한 후 다시 자식 타입으로 변환할 때 강제 타입 변환을 사용할 수 있습니다.</p>
<p><strong><code>자식타입 변수 = (자식타입) 부모타입;</code></strong></p>
<pre><code class="language-java">Parent parent = new Child(); // 자동 타입 변환
Child child = (Child) parent; // 강제 타입 변환</code></pre>
<h4 id="객체-타입-확인-instanceof-연산자">객체 타입 확인 (instanceof 연산자)</h4>
<p><strong><code>좌항(객체) instanceof 우항(타입)</code></strong>
좌항의 객체가 우항의 인스턴스 즉, 우항의 타입으로 객체가 생성되었다면 ture이고, 아니면 false이다. (타입 변환되었다면, 모든 변환 전 오리지널의 타입을 뜻함.)</p>
<p>이를 이용해서 강제 타입 변환 전에 객체가 우항의 인스턴스가 맞는지 확인을 거치는 코드를 만들 수 있다. 타입 변환이 불가능한데 강제로 변환하다간 ClassCastException 오류가 발생한다.</p>
<pre><code class="language-java">if(parent instanceof child){ // 좌측의 child에는 Parent 와 Child의 인스턴스(parent, child) 모두 들어갈 수 있다.
  Child child = (child) parent;
}</code></pre>
<h3 id="추상-클래스-abstract">추상 클래스 (abstract)</h3>
<p>부모 클래스 자식 클래스와 비슷한 개념이지만 내가 확 체감되는 차이는 
부모 자식 관계의 클래스에서는 부모 클래스를 new를 통해 인스턴스로 만들 수 있지만, 추상 클래스와 실체 클래스 관계에서는 추상 클래스가 <code>public abstract class 클래스_이름 { ... }</code> 형태로 구성되어있으며, 추상 클래스만을 따로 new를 통해 인스턴스로 만들 수 없다. 오직, 추상 클래스의 필드와 메소드는 추상 클래스를 상속 받은 실체 클래스를 통해서만 확인할 수 있다. 즉, extends 를 통해서만 호출이 가능하다.</p>
<h4 id="추상-메소드와-재정의">추상 메소드와 재정의</h4>
<p>추상 클래스에서 모든 실체들이 가지고 있는 메소드의 선언이 동일하지만 실행 내용은 각 실체마다 달라야 할 경우엔 추상 메소드를 선언하면 된다. 
예를 들어 동물 이라는 추상 클래스에서 sound 라는 메소드를 선언하고 싶을때 모든 동물은 울음소리를 가지지만 각자 내는 소리가 다름으로 한 메소드로 선언하기는 어렵다. 이때 추상 메소드 sound를 선언한 후 메소드 내용물은 각 클래스에서 다시 설정하도록 하면 된다.</p>
<p><code>[public | protected] abstract 리턴타입 메소드이름(매개변수, ...);</code></p>
<p>이렇게 ** <code>추상 메소드</code>를 만들면 하위 클래스가 반드시 실행 내용을 채워야한다.** 그렇지 않으면 컴파일 에러가 발생한다. 이게 추상 메소드의 강력한 이유이다.</p>
<p>sound 추상 메소드를 만든 후에는 실체 클래스는</p>
<pre><code class="language-java">// 추상 클래스
public abstract class Animal {
  public abstract void sound();
}
// 실체 클래스
public class Dog extends Animal {
  @Override
  public void sound(){
    System.out.println(&quot;멍멍&quot;); // 비어있던 추상 메소드 재정의.
  }
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL]20210910]]></title>
            <link>https://velog.io/@kid_chang/TIL20210910</link>
            <guid>https://velog.io/@kid_chang/TIL20210910</guid>
            <pubDate>Sat, 11 Sep 2021 03:25:29 GMT</pubDate>
            <description><![CDATA[<h2 id="자바">자바</h2>
<h3 id="인스턴스로-선언-vs-정적으로-선언">인스턴스로 선언 vs 정적으로 선언</h3>
<p>필드를 선언할 때 인스턴스 필드로 선언할지 정적으로 선언할 지 판단 기준이 있어야한다.
--&gt; 객체마다 가지고 있어야할 데이터라면 인스턴스 필드로 선언하고, 객체마다가 아닌 공용으로 쓸 데이터라면 정적 필드로 선언하는 것이 좋다.</p>
<h2 id="인스턴스-멤버">인스턴스 멤버</h2>
<p><code>new</code>로 인스턴스를 생성할때 스택영역에 이름과 &#39;힙영역으로 가는 주소&#39;가 있고, 힙 영역에는 각 인스턴스별로 필드가 존재한다. 하지만 메소드는 메소드 영역에 따로 보관되며 같은 클래스에서 만들어 진 여러 인스턴스가 공동으로 사용한다. 그러면 필드만 인스턴스 필드라고 부르지 왜 메소드도 인스턴스 메소드냐 싶은데, 이는 메소드안에 인스턴스 필드가 사용되는 경우가 있기 때문이다. 아무리 메소드 내부이지만 인스턴스 필드를 사용하려면 객체가 필요하기 때문에, 정적(static) 관련과 다르게 인스턴스라고 말한다.</p>
<h2 id="정적-멤버">정적 멤버</h2>
<p>필드나 메소드 앞에 <code>static</code>을 붙여서 선언할 수 있다.
클래스의 필드에 파이(3.14)를 선언한다면 이 값이 굳이 힙 영역의 모든 인스턴스에 하나하나 포함될 필요가 없기에 static을 사용해 같은 종류의 인스턴스끼리는 필드를 공유하도록 만든다.
또한, 정적 메소드 내부에 인스턴스 필드를 포함한다면 인스턴스 메소드로 선언하고 포함하지 않는다면 정적 메소드로 선언한다.</p>
<pre><code class="language-java">String color;
void setColor(String color) { this.color = color } // 인스턴스 필드를 포함함.
static int plus(int x, int y) { return x + y } // 인스턴스 필드를 포함하지 않음.</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL]20210909]]></title>
            <link>https://velog.io/@kid_chang/TIL20210909</link>
            <guid>https://velog.io/@kid_chang/TIL20210909</guid>
            <pubDate>Thu, 09 Sep 2021 12:26:12 GMT</pubDate>
            <description><![CDATA[<h2 id="자바">자바</h2>
<h3 id="메소드를-사용하면서-매개-변수의-갯수를-모를-때">메소드를 사용하면서 매개 변수의 갯수를 모를 때.</h3>
<ol>
<li><pre><code class="language-java">int sum1(int[] values) {코드}
// 위 메소드가 포함된 클래스를 사용하면
result1=myCom.sum1(new int[] {1,2,3})</code></pre>
</li>
<li><pre><code class="language-java">int sum2(int ... values) {코드}
// 위 메소드가 포함된 클래스를 사용하면 ( 코드에 &quot;...&quot; 그대로가 맞다.)
result2=myCom.sum2(1,2,3);</code></pre>
1번은 배열로 매소드를 지정했으므로 new 를 이용해 리스트를 만들어 매개 변수에 제공해야하고, 2번 매소드는 <code>...</code>을 통해 인자를 받기로 했기에 매개 변수를 입력할 때 쉼표로 나열하면 된다.</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL]20210906]]></title>
            <link>https://velog.io/@kid_chang/TIL20210906</link>
            <guid>https://velog.io/@kid_chang/TIL20210906</guid>
            <pubDate>Mon, 06 Sep 2021 08:23:49 GMT</pubDate>
            <description><![CDATA[<h2 id="자바">자바</h2>
<h3 id="인풋-방법">인풋 방법</h3>
<pre><code class="language-js">import java.util.Scanner;
        Scanner scanner = new Scanner(System.in);
        String strNum1=scanner.nextLine();</code></pre>
<h3 id="연산자-우선순위">연산자 우선순위</h3>
<p>모르고있던 부분. 단항 연산자( ++, --, ~, !), 부호 연산자(+, -), 대입 연산자 (=, +=, -=, 등) 은 오른쪽에서 왼쪽 방향으로 연산을 수행</p>
<p><img src="https://images.velog.io/images/kid_chang/post/0caf33e9-cb74-406d-b0eb-e0fafada7933/image.png" alt="">
일반적일때.</p>
<p><img src="https://images.velog.io/images/kid_chang/post/075de973-52e9-4060-925d-ecf923432f16/image.png" alt=""></p>
<p>특수한 경우.</p>
<blockquote>
<p>*<em>정리: *</em></p>
</blockquote>
<ol>
<li>단항, 이항, 삼항 연산자 순으로 우선순위를 가진다. </li>
<li>산술, 비교 논리, 대입 연산자 순으로 우선순위를 가진다.</li>
<li>단항, 부호, 대입 연산자를 제외한 모든 연산의 방향은 왼쪽에서 오른쪽이다.</li>
<li>복잡한 연산식에는 괄호를 사용해서 우선순위를 정한다.</li>
</ol>
<h3 id="문자열-결합-연산자">문자열 결합 연산자(+)</h3>
<p>간혹 + 연산자가 산술 연산자인지 문자열 연산자인지 판단하기 어려운 경우가 있다.
<code>&quot;jdk&quot;+3+3.0&quot;</code> --&gt; jdk33.0
<code>&quot;3+3.0+&quot;JDK&quot;</code> --&gt; 6.0jdk
왼쪽에서 오른쪽으로 타입이 유동적인 느낌으로 연산된다는 점을 참고.</p>
<h3 id="비교-연산자에서의-자동-형-변환">비교 연산자에서의 자동 형 변환</h3>
<p><code>&#39;A&#39;==65 --&gt; 65==65 --&gt; true</code>
<code>&#39;3==3.0 --&gt; 3.0==3.0 --&gt; true</code>
이렇게 자동으로 피연산자들의 타입을 일치시켜준다.
단, 예외가 하나 있는데 <code>0.1==0.1f --&gt; false</code> 이다.
이는 부동 소수점이 0.1을 정확히 표현할 수 없기 때문이다.</p>
<p>이에 대해 찾아봤는데 자세한 내용은 <a href="https://codingdog.tistory.com/entry/c%EC%96%B8%EC%96%B4-double%ED%98%95-vs-float%ED%98%95-%EC%96%B4%EB%96%A4-%EC%B0%A8%EC%9D%B4%EA%B0%80-%EC%9E%88%EC%9D%84%EA%B9%8C%EC%9A%94">https://codingdog.tistory.com/entry/c%EC%96%B8%EC%96%B4-double%ED%98%95-vs-float%ED%98%95-%EC%96%B4%EB%96%A4-%EC%B0%A8%EC%9D%B4%EA%B0%80-%EC%9E%88%EC%9D%84%EA%B9%8C%EC%9A%94</a> 이 글을 참고하고,
결론적으로 말하자면 </p>
<pre><code class="language-java">        float F= 0.1f;
        double D=0.1;

        System.out.printf(&quot;%.20f\n%.20f&quot;,F,D);    

result:
0.10000000149011612000
0.10000000000000000000</code></pre>
<p>또한, 자연스럽게 생긴 의문이 double을 float으로 바꾸면 false가 나올까 이다.</p>
<p>float은 double에 비해 0.1을 덜 정확하게 표현하기 때문에 float이 부동 소수점의 표현이 더 큰 double로 형변환을 하면 <code>0.10000000149011612000</code> 여기뒤에 0을 더 붙이는 꼴밖에 되지 않지만, double을 float으로 형변환 한다면 부동 소수점의 표현 범위가 더 축소되면서 <code>0.10000000000000000000</code>에서 <code>0.10000000149011612000</code>으로 변하기 때문이라고 추측한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL]20210903]]></title>
            <link>https://velog.io/@kid_chang/TIL20210903</link>
            <guid>https://velog.io/@kid_chang/TIL20210903</guid>
            <pubDate>Fri, 03 Sep 2021 17:07:50 GMT</pubDate>
            <description><![CDATA[<h2 id="웹">웹</h2>
<h3 id="fliter">.fliter()</h3>
<p><code>[1, 2, 3, 4].fliter(function);</code>
이 코드는 1, 2, ,3, 4를 순서대로 function에 넣는다.
function에 따라 리턴되는 값이 참이면 숫자를 유지하고, 그렇지 않다면 리스트에서 제거해준다.</p>
<h3 id="fetch">fetch()</h3>
<p>fetch()는 네트워크를 통해 정보를 가져온다. <code>fetch(https://www.~~~);</code> 을 이용하면 된다.</p>
<h3 id="then">.then()</h3>
<p>이는 비동기 방식으로 작동된다는데 이 방식이 뭔지 몰라 찾아봤다.</p>
<blockquote>
<p><a href="https://private.tistory.com/24">https://private.tistory.com/24</a>
동기는 말 그대로 동시에 일어난다는 뜻입니다. 요청과 그 결과가 동시에 일어난다는 약속인데요. 바로 요청을 하면 시간이 얼마가 걸리던지 요청한 자리에서 결과가 주어져야 합니다.
요청과 결과가 한 자리에서 동시에 일어남
A노드와 B노드 사이의 작업 처리 단위(transaction)를 동시에 맞추겠다.
비동기(Asynchronous : 동시에 일어나지 않는)</p>
</blockquote>
<ul>
<li>비동기는 동시에 일어나지 않는다를 의미합니다. 요청과 결과가 동시에 일어나지 않을거라는 약속입니다. 
요청한 그 자리에서 결과가 주어지지 않음
노드 사이의 작업 처리 단위를 동시에 맞추지 않아도 된다.
<br>동기와 비동기는 상황에 따라서 각각의 장단점이 있습니다. 
<br>동기방식은 설계가 매우 간단하고 직관적이지만 결과가 주어질 때까지 아무것도 못하고 대기해야 하는 단점이 있고, 
<br>비동기방식은 동기보다 복잡하지만 결과가 주어지는데 시간이 걸리더라도 그 시간 동안 다른 작업을 할 수 있으므로 자원을 효율적으로 사용할 수 있는 장점이 있습니다.</li>
</ul>
<p>fetch()를 통해 url의 정보를 가져오는데 얼마나 시간이 소요될지 알수 없으므로, 비동기 방식을 이용한다는 것이다.</p>
<pre><code class="language-js">p.then(onFulfilled, onRejected);

p.then(function(value) {
  // 이행
}, function(reason) {
  // 거부
});</code></pre>
<p>화살표 함수를 이용해서 코드를 줄여나가도 된다.</p>
<p>오늘 제작한 것.
<a href="https://lounge-vanlia.netlify.app/">https://lounge-vanlia.netlify.app/</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL]20210902]]></title>
            <link>https://velog.io/@kid_chang/TIL20210902</link>
            <guid>https://velog.io/@kid_chang/TIL20210902</guid>
            <pubDate>Thu, 02 Sep 2021 16:14:58 GMT</pubDate>
            <description><![CDATA[<h2 id="opp의-4대-특성">OPP의 4대 특성</h2>
<p>캡슐화: 변수나 메소드가 목적에 집중하도록 묶은 것.
추상화: 객체의 공통적인 또는 필수적인 요소들을 뽑아내는 것.
다형성: 같은 이름으로의 실행 결과가 다양한 객체를 활용하는 것. 
------ override: 기존의 메소드를 재정의 overload: 이름은 같지만, 파라미터를 변경함.
상속: 상위 클래스의 객체를 하위 클래스의 객체가 상속하여 기능 확장및 변경. (재사용)</p>
<h2 id="알고리즘">알고리즘</h2>
<h3 id="11557-yangjojang-of-the-year-백준">11557. Yangjojang of The Year (백준)</h3>
<pre><code class="language-py">R=int(input())
n=[]
for _ in range(R):
    cnt = int(input())
    for _ in range(cnt):
        n.append(list(input().split()))
    alcohol = sorted(n, key = lambda x: -int(x[1]))
    print(alcohol[0][0])</code></pre>
<h3 id="11656-접미사-배열-백준">11656. 접미사 배열 (백준)</h3>
<pre><code class="language-py">k=input()
a=[]

kLen=len(k)
for i in range(kLen):
    a.append(k[kLen-i-1:])

a.sort()
for i in a:
    print(i)</code></pre>
<h2 id="웹">웹</h2>
<h3 id="addeventlistener-에서-submit과-click-form-과-input-text">addEventListener 에서 submit과 click, form 과 input text</h3>
<pre><code class="language-html">&lt;form id=&quot;todo-form&quot;&gt;
      &lt;input id=&quot;todo-input&quot; type=&quot;text&quot; placeholder=&quot;Write your todo List and press Enter!&quot;&gt;
    &lt;/form&gt;</code></pre>
<pre><code class="language-js">const todoForm=document.querySelector(&quot;#todo-form&quot;);
const todoList=document.querySelector(&quot;#todo-list&quot;);
const todoInput=document.querySelector(&quot;#todo-input&quot;);

function handleTodo(event){
    event.preventDefault();
}
todoForm.addEventListener(&quot;submit&quot;,handleTodo);
todoInput.addEventListener(&quot;click&quot;,handleTodo);</code></pre>
<p>addEventListener을 이용할때 Form에서는 submit, input text에서는 click을 해야 정상적으로 handleTodo가 작동된다.
text 입장에서는 단순히 input 된 것이지만, form 입장에선 내부의 요소가 submit됬다고 이해.</p>
<h2 id="json-을-통한-string으로의-변환과-js-object로의-변환">JSON 을 통한 string으로의 변환과 js object로의 변환.</h2>
<p><code>JSON.stringify()</code> ()안에 무엇을 넣든 string으로 변환시킴.
<code>JSON.parse()</code> ()안에 들어간 string을 js규칙에 맞춰 변환시킴.</p>
<p>JSON.stringify([1, 2, 3, 4]); --&gt; &quot;[1, 2, 3, 4]&quot;
JSON.parse(&quot;[1, 2, 3, 4]&quot;); --&gt; [1, 2, 3, 4]</p>
<p><code>localStorage</code>에는 리스트 등은 저장할 수 없고, 오직 string만 저장할 수 있어서, 이때 유용하게 JSON을 쓸 수 있다.</p>
<h2 id="function-shortcut">&quot;function&quot; shortcut</h2>
<pre><code class="language-js">if (savedTodo!=null){
  parsedTodo.forEach((element) =&gt; {
  console.log(element));
    }
}</code></pre>
<p>위 코드는</p>
<pre><code class="language-js">function say(event){
    console.log(event);
}

if (savedTodo!=null){
    const parsedTodo = JSON.parse(savedTodo);
    parsedTodo.forEach(say);
}</code></pre>
<p>이 코드를 간략히 줄인것이다. 
function을 만드는 대신 <code>forEach((element)=&gt;{~~~element})</code> 을 이용해 element도 넘겨줄수있다.
이때 <code>=&gt;</code>를 화살표 함수 라고 한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL]20210901]]></title>
            <link>https://velog.io/@kid_chang/TIL20210901</link>
            <guid>https://velog.io/@kid_chang/TIL20210901</guid>
            <pubDate>Wed, 01 Sep 2021 15:04:48 GMT</pubDate>
            <description><![CDATA[<h2 id="알고리즘">알고리즘</h2>
<h3 id="1764-듣보잡-백준">1764. 듣보잡 (백준)</h3>
<p>리스트는 추가할때 append
set은 추가할때 add</p>
<blockquote>
<p>집합 관련 참고.
[<a href="https://zetawiki.com/wiki/Python_%EB%A6%AC%EC%8A%A4%ED%8A%B8_%ED%95%A9%EC%A7%91%ED%95%A9,_%EA%B5%90%EC%A7%91%ED%95%A9,_%EC%B0%A8%EC%A7%91%ED%95%A9,_%EB%8C%80%EC%B9%AD%EC%B0%A8">https://zetawiki.com/wiki/Python_%EB%A6%AC%EC%8A%A4%ED%8A%B8_%ED%95%A9%EC%A7%91%ED%95%A9,_%EA%B5%90%EC%A7%91%ED%95%A9,_%EC%B0%A8%EC%A7%91%ED%95%A9,_%EB%8C%80%EC%B9%AD%EC%B0%A8</a> ]</p>
</blockquote>
<pre><code class="language-py">N, M = map(int, input().split())
n, m = [], []
cnt=0
num=[]
for i in range(N):
    n.append(input())
for j in range(M):
    m.append(input())

result=sorted((list(set(n) &amp; set(m))))

print(len(result))
for i in result:
    print(i)</code></pre>
<p>리스트라면 이중 for을 이용해야됬지만, 이는 시간초과라는 결과가 나왔다.
그러므로 set은 &amp; 을 통해 중복되는 것들만을 선택하는 방법이 필요하다.
set 자체가 매우 빠른 속도를 가지고 있어 시간단축에도 효과적이다.</p>
<h2 id="웹">웹</h2>
<h3 id="documentcreateelement">document.createElement(&quot;&quot;);</h3>
<p>&quot;&quot; 안에 <code>h</code>, <code>img</code>, <code>h1</code> 등을 넣어 html에 요소를 더해줄 수 있다. </p>
<h3 id="documentbodyappendchild">document.body.appendChild(~);</h3>
<p>body 맨 밑에 요소를 넣어준다.
밑의 createElement()와 appendChild(~); 를 이용해 만든 소스를 보면 사용법을 알기쉽다. <code>prependChild()</code> 도 있는데, 이는 body 맨 앞에 요소를 넣어준다.</p>
<pre><code class="language-js">const creImg = document.createElement(&quot;img&quot;);
creImg.src=`./img/${choseIMG}`
console.log(creImg);
document.body.appendChild(creImg);</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL]20210831]]></title>
            <link>https://velog.io/@kid_chang/TIL20210831</link>
            <guid>https://velog.io/@kid_chang/TIL20210831</guid>
            <pubDate>Tue, 31 Aug 2021 10:19:53 GMT</pubDate>
            <description><![CDATA[<h2 id="웹">웹</h2>
<h3 id="-와---">+ 와  ` `</h3>
<p>greeting.innerText = `Hello ${username}`;
greeting.innerText = &quot;Hello&quot; + username;</p>
<p>위의 두가지 출력법 모두 사용할 수 있으나, 첫번째 방법은 백틱(`) 기호를 사용해야한다는 것을 주의.</p>
<h3 id="strings를-반복할때-팁">strings를 반복할때. 팁.</h3>
<p>log나 html에서 username이라는 문자열을 여러곳에서 사용해야한다고 치자.
매번 &quot;username&quot;을 하는 것보다는 <code>const USERNAME_KEY=&quot;username&quot;;</code> 이라고 하는 것이 훨씬 오류를 줄일 수 있다. 문자열을 매번 입력하면 사소한 오타를 잡기 힘들지만 상수로 만든다면 오타가 생기면 바로 알수 있다.!</p>
<h3 id="setinterval">setInterval()</h3>
<p><code>setInterval(function,5000);</code> function을 5초간격으로 실행한다.</p>
<h3 id="padstart">padStart()</h3>
<p><code>padStart(2,&quot;0&quot;)</code> 을 이용하면 자릿수 2가 만족하지 않을때(0,1 ... 9), 앞자리(그래서 start)에 &quot;0&quot;을 붙여준다.</p>
<h2 id="알고리즘">알고리즘</h2>
<h3 id="1436-영화감독-숌-백준">1436. 영화감독 숌 (백준)</h3>
<pre><code class="language-py">n = int(input())
default = 666
count = 0

while True:
    if &#39;666&#39; in str(default):
        count+=1
    if count == n:
        print(default)
        break
    default+=1</code></pre>
<h3 id="10814-나이순-정렬-성공-백준">10814. 나이순 정렬 성공 (백준)</h3>
<pre><code class="language-py">n= int(input())
a=[]
for _ in range(n):
    a.append(list(input().split()))

a.sort(key=lambda x: (int(x[0])))

for member in a:
    print(member[0], member[1])</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL]20210829]]></title>
            <link>https://velog.io/@kid_chang/TIL20210829</link>
            <guid>https://velog.io/@kid_chang/TIL20210829</guid>
            <pubDate>Sun, 29 Aug 2021 05:12:52 GMT</pubDate>
            <description><![CDATA[<h2 id="알고리즘">알고리즘</h2>
<h3 id="10828-스택-백준">10828. 스택 (백준)</h3>
<pre><code class="language-py">import sys

N = int(sys.stdin.readline())
stack = []
for _ in range(N):
    command = sys.stdin.readline().split()
    com = command[0]
    if com == &quot;push&quot;:
        stack.append(command[1])
    elif com == &quot;pop&quot;:
        if len(stack) == 0:
            print(-1)
        else:
            print(stack.pop())

    elif com == &quot;size&quot;:
        print(len(stack))
    elif com == &quot;empty&quot;:
        if len(stack) == 0:
            print(1)
        else:
            print(0)
    elif com == &#39;top&#39;:
        if len(stack) == 0:
            print(-1)
        else:
            print(stack[-1])</code></pre>
<h3 id="10845-큐-백준">10845. 큐 (백준)</h3>
<pre><code class="language-py">import sys

N = int(sys.stdin.readline())
stack = []
for _ in range(N):
    command = sys.stdin.readline().split()
    com = command[0]
    if com == &quot;push&quot;:
        stack.append(command[1])
    elif com == &quot;pop&quot;:
        if len(stack) == 0:
            print(-1)
        else:
            print(stack.pop(0))

    elif com == &quot;size&quot;:
        print(len(stack))
    elif com == &quot;empty&quot;:
        if len(stack) == 0:
            print(1)
        else:
            print(0)

    elif com == &#39;front&#39;:
      if len(stack) == 0:
        print(-1)
      else:
        print(stack[0])


    elif com == &#39;back&#39;:
        if len(stack) == 0:
            print(-1)
        else:
            print(stack[-1])</code></pre>
<h3 id="10866-덱-백준">10866. 덱 (백준)</h3>
<pre><code class="language-py">import sys

N = int(sys.stdin.readline())
stack = []
for _ in range(N):
    command = sys.stdin.readline().split()
    com = command[0]
    if com == &quot;push_front&quot;:
        stack.insert(0,command[1])
    elif com==&quot;push_back&quot;:
        stack.append(command[1])
    elif com == &quot;pop_front&quot;:
        if len(stack) == 0:
            print(-1)
        else:
            print(stack.pop(0))
    elif com == &quot;pop_back&quot;:
        if len(stack) == 0:
            print(-1)
        else:
            print(stack.pop())

    elif com == &quot;size&quot;:
        print(len(stack))
    elif com == &quot;empty&quot;:
        if len(stack) == 0:
            print(1)
        else:
            print(0)

    elif com == &#39;front&#39;:
      if len(stack) == 0:
        print(-1)
      else:
        print(stack[0])


    elif com == &#39;back&#39;:
        if len(stack) == 0:
            print(-1)
        else:
            print(stack[-1])</code></pre>
<h3 id="9012-괄호-백준">9012. 괄호 (백준)</h3>
<pre><code class="language-py">import sys

N=int(sys.stdin.readline())

for _ in range(N):
    cnt1=0
    cnt2=0
    no=0
    A=sys.stdin.readline()
    for i in range(len(A)):
        if A[i]==&quot;)&quot;:
            cnt2+=1
        if A[i]==&quot;(&quot;:
            cnt1+=1

        if cnt2&gt;cnt1:
            no=1


    if no==1:
        print(&quot;NO&quot;)
    elif cnt1==cnt2:
        print(&quot;YES&quot;)
    else:
        print(&quot;NO&quot;)</code></pre>
<p>이 문제는 단순히 <code>(</code>, <code>)</code> 괄호 갯수를 카운트 하는 것이 아니라, 괄호의 열림과 닫힘의 순서위치가 맞아떨어져야한다. 이를 주의.</p>
<h3 id="1748-수-이어-쓰기-1-백준">1748. 수 이어 쓰기 1 (백준)</h3>
<p>메모리 초과.</p>
<pre><code class="language-py">import sys

N=int(sys.stdin.readline())

A=&#39;&#39;.join(str(i) for i in range(1, N+1))
print(len(A))</code></pre>
<p>정답.</p>
<pre><code class="language-py"> n = input()
n_len = len(n) - 1
c = 0
i = 0
while i &lt; n_len:
    c += 9 * (10 ** i) * (i + 1)
    i += 1
c += ((int(n) - (10 ** n_len)) + 1) * (n_len + 1)
print(c)

## 11일 경우
# n=11, n_len =1, while문 1번 순환...
#   c= 9*1*1=9
# c=(11-10+1)*2=4, 9+4
# while의 c는 1~9까지, 밖의 c는 10~11까지의 len

## 121일 경우
# n=121, n_len=2, while문 2번 순환...
#   c= 9*1*1
#   i=1
#   c= 9*10*2 (2는 10~99일때 2자리값임으로.)
#   c= 9+ 180+ (121-100+1(=99))*3 = 255

# while문으로 1~9, 10~99,100~999 등 자릿수 꽉차는 값 계산, 밖에서 나머지 계산.</code></pre>
<h2 id="웹">웹</h2>
<h3 id="input-관련">input 관련.</h3>
<pre><code class="language-html">&lt;input required maxlength=&quot;15&quot; type=&quot;text&quot; placeholder=&quot;What is your name?&quot; /&gt;
&lt;button&gt;Log In&lt;/button&gt;
</code></pre>
<p>여기서 required 는 내용물이 입력된 상태를 요구하는 것이다.
button을 누르면 이 required가 유효한지 유효성 검사를 진행해야하는데, 이를 위해서는 form을 이용해 내용물을 묶어줘야한다.</p>
<pre><code>&lt;form&gt;
  &lt;div id=&quot;login-form&quot;&gt;
   &lt;input required maxlength=&quot;15&quot; type=&quot;text&quot; placeholder=&quot;What is your name?&quot; /&gt;
   &lt;button&gt;Log In&lt;/button&gt;
 &lt;/div&gt;
 &lt;/form&gt;</code></pre><p> 이렇게 묶어주면, js 없이 유효성검사를 통해 required를 만족하는지 확인할 수 있다.</p>
<p>또한, form을 통해 묶어준다면 js에서 코딩할 필요없이 submit을 할 방법이 많아진다. input타입의 submit또는 button으로.</p>
<h3 id="preventdefault">preventDefault()</h3>
<pre><code class="language-js">const loginForm=document.querySelector(&quot;#login-form&quot;);
const loginInput=document.querySelector(&quot;#login-form input&quot;);

function onLoginSubmit(event) {
  event.preventDefault();
  console.log(loginInput.value);
}


loginForm.addEventListener(&quot;click&quot;, onLoginSubmit);</code></pre>
<p>preventDefault() 이 코드에서는 자동으로 페이지가 새로고침되는 것을 막아준다.</p>
<p>실제로 <code>preventDefault()</code>가  하는 일은 어떠한 event의 디폴트값의 수행을 막는 것이다.</p>
<p>a태그를 이용한 하이퍼링크도 이를 이용하면 아무리 클릭해도 링크에 접속되지 않도록 막아준다.</p>
]]></description>
        </item>
    </channel>
</rss>